usb_moded 0.86.0+mer58
usb_moded-configfs.c
Go to the documentation of this file.
1
23
24#include "usb_moded-configfs.h"
25
26#include "usb_moded-android.h"
27#include "usb_moded-common.h"
29#include "usb_moded-log.h"
30#include "usb_moded-mac.h"
31
32#include <sys/stat.h>
33
34#include <unistd.h>
35#include <fcntl.h>
36
37/* ========================================================================= *
38 * Constants
39 * ========================================================================= */
40
41/* Due to legacy these defaults must match what is required by Sony XA2 port */
42#define DEFAULT_GADGET_BASE_DIRECTORY "/config/usb_gadget/g1"
43#define DEFAULT_GADGET_FUNC_DIRECTORY "functions"
44#define DEFAULT_GADGET_CONF_DIRECTORY "configs/b.1"
45
46#define DEFAULT_GADGET_CTRL_UDC "UDC"
47#define DEFAULT_GADGET_CTRL_ID_VENDOR "idVendor"
48#define DEFAULT_GADGET_CTRL_ID_PRODUCT "idProduct"
49#define DEFAULT_GADGET_CTRL_MANUFACTURER "strings/0x409/manufacturer"
50#define DEFAULT_GADGET_CTRL_PRODUCT "strings/0x409/product"
51#define DEFAULT_GADGET_CTRL_SERIAL "strings/0x409/serialnumber"
52
53#define DEFAULT_FUNCTION_MASS_STORAGE "mass_storage.usb0"
54#define DEFAULT_FUNCTION_RNDIS "rndis_bam.rndis"
55#define DEFAULT_FUNCTION_MTP "ffs.mtp"
56
57#define DEFAULT_RNDIS_CTRL_WCEIS "wceis"
58#define DEFAULT_RNDIS_CTRL_ETHADDR "ethaddr"
59
60/* ========================================================================= *
61 * Prototypes
62 * ========================================================================= */
63
64/* ------------------------------------------------------------------------- *
65 * CONFIGFS
66 * ------------------------------------------------------------------------- */
67
68static gchar *configfs_get_conf (const char *key, const char *def);
69static void configfs_read_configuration (void);
70static int configfs_file_type (const char *path);
71static const char *configfs_function_path (char *buff, size_t size, const char *func, ...);
72static const char *configfs_unit_path (char *buff, size_t size, const char *func, const char *unit);
73static const char *configfs_config_path (char *buff, size_t size, const char *func);
74static bool configfs_mkdir (const char *path);
75static bool configfs_rmdir (const char *path);
76static const char *configfs_register_function (const char *function);
77#ifdef DEAD_CODE
78static bool configfs_unregister_function (const char *function);
79#endif //DEAD_CODE
80static const char *configfs_add_unit (const char *function, const char *unit);
81static bool configfs_remove_unit (const char *function, const char *unit);
82static bool configfs_enable_function (const char *function);
83static bool configfs_disable_function (const char *function);
84static bool configfs_disable_all_functions (void);
85static char *configfs_strip (char *str);
86bool configfs_in_use (void);
87static bool configfs_probe (void);
88static const char *configfs_udc_enable_value (void);
89static bool configfs_write_file (const char *path, const char *text);
90static bool configfs_read_file (const char *path, char *buff, size_t size);
91#ifdef DEAD_CODE
92static bool configfs_read_udc (char *buff, size_t size);
93#endif // DEAD_CODE
94static bool configfs_write_udc (const char *text);
95bool configfs_set_udc (bool enable);
96bool configfs_init (void);
97void configfs_quit (void);
98bool configfs_set_charging_mode (void);
99bool configfs_set_productid (const char *id);
100bool configfs_set_vendorid (const char *id);
101static const char *configfs_map_function (const char *func);
102bool configfs_set_function (const char *functions);
103bool configfs_add_mass_storage_lun (int lun);
104bool configfs_remove_mass_storage_lun(int lun);
105bool configfs_set_mass_storage_attr (int lun, const char *attr, const char *value);
106
107/* ========================================================================= *
108 * Data
109 * ========================================================================= */
110
111static int configfs_probed = -1;
112
113static gchar *GADGET_BASE_DIRECTORY = 0;
114static gchar *GADGET_FUNC_DIRECTORY = 0;
115static gchar *GADGET_CONF_DIRECTORY = 0;
116
117static gchar *GADGET_CTRL_UDC = 0;
118static gchar *GADGET_CTRL_ID_VENDOR = 0;
119static gchar *GADGET_CTRL_ID_PRODUCT = 0;
120static gchar *GADGET_CTRL_MANUFACTURER = 0;
121static gchar *GADGET_CTRL_PRODUCT = 0;
122static gchar *GADGET_CTRL_SERIAL = 0;
123
124static gchar *FUNCTION_MASS_STORAGE = 0;
125static gchar *FUNCTION_RNDIS = 0;
126static gchar *FUNCTION_MTP = 0;
127
128static gchar *RNDIS_CTRL_WCEIS = 0;
129static gchar *RNDIS_CTRL_ETHADDR = 0;
130
131/* ========================================================================= *
132 * Settings
133 * ========================================================================= */
134
135static gchar *configfs_get_conf(const char *key, const char *def)
136{
137 LOG_REGISTER_CONTEXT;
138
139 return config_get_conf_string("configfs", key) ?: g_strdup(def);
140}
141
154static void configfs_read_configuration(void)
155{
156 LOG_REGISTER_CONTEXT;
157
158 /* This must be done only once
159 */
160 static bool done = false;
161
162 if( done )
163 goto EXIT;
164
165 done = true;
166
167 gchar *temp_setting;
168
169 /* Gadget directories
170 */
171 GADGET_BASE_DIRECTORY =
172 configfs_get_conf("gadget_base_directory",
173 DEFAULT_GADGET_BASE_DIRECTORY);
174
175 temp_setting = configfs_get_conf("gadget_func_directory",
176 DEFAULT_GADGET_FUNC_DIRECTORY);
177 GADGET_FUNC_DIRECTORY = g_strdup_printf("%s/%s",
178 GADGET_BASE_DIRECTORY,
179 temp_setting);
180 g_free(temp_setting);
181
182 temp_setting = configfs_get_conf("gadget_conf_directory",
183 DEFAULT_GADGET_CONF_DIRECTORY);
184 GADGET_CONF_DIRECTORY =
185 g_strdup_printf("%s/%s",
186 GADGET_BASE_DIRECTORY,
187 temp_setting);
188 g_free(temp_setting);
189
190 /* Gadget control files
191 */
192 GADGET_CTRL_UDC =
193 g_strdup_printf("%s/%s",
194 GADGET_BASE_DIRECTORY,
195 DEFAULT_GADGET_CTRL_UDC);
196
197 GADGET_CTRL_ID_VENDOR =
198 g_strdup_printf("%s/%s",
199 GADGET_BASE_DIRECTORY,
200 DEFAULT_GADGET_CTRL_ID_VENDOR);
201
202 GADGET_CTRL_ID_PRODUCT =
203 g_strdup_printf("%s/%s",
204 GADGET_BASE_DIRECTORY,
205 DEFAULT_GADGET_CTRL_ID_PRODUCT);
206
207 GADGET_CTRL_MANUFACTURER =
208 g_strdup_printf("%s/%s",
209 GADGET_BASE_DIRECTORY,
210 DEFAULT_GADGET_CTRL_MANUFACTURER);
211
212 GADGET_CTRL_PRODUCT =
213 g_strdup_printf("%s/%s",
214 GADGET_BASE_DIRECTORY,
215 DEFAULT_GADGET_CTRL_PRODUCT);
216
217 GADGET_CTRL_SERIAL =
218 g_strdup_printf("%s/%s",
219 GADGET_BASE_DIRECTORY,
220 DEFAULT_GADGET_CTRL_SERIAL);
221
222 /* Functions
223 */
224 FUNCTION_MASS_STORAGE =
225 configfs_get_conf("function_mass_storage",
226 DEFAULT_FUNCTION_MASS_STORAGE);
227
228 FUNCTION_RNDIS =
229 configfs_get_conf("function_rndis",
230 DEFAULT_FUNCTION_RNDIS);
231
232 FUNCTION_MTP =
233 configfs_get_conf("function_mtp",
234 DEFAULT_FUNCTION_MTP);
235
236 /* Function control files */
237 RNDIS_CTRL_WCEIS =
238 g_strdup_printf("%s/%s/%s",
239 GADGET_FUNC_DIRECTORY,
240 FUNCTION_RNDIS,
241 DEFAULT_RNDIS_CTRL_WCEIS);
242
243 RNDIS_CTRL_ETHADDR =
244 g_strdup_printf("%s/%s/%s",
245 GADGET_FUNC_DIRECTORY,
246 FUNCTION_RNDIS,
247 DEFAULT_RNDIS_CTRL_ETHADDR);
248
249EXIT:
250 return;
251}
252
253/* ========================================================================= *
254 * Functions
255 * ========================================================================= */
256
257static int configfs_file_type(const char *path)
258{
259 LOG_REGISTER_CONTEXT;
260
261 int type = -1;
262
263 if( !path )
264 goto EXIT;
265
266 struct stat st;
267 if( lstat(path, &st) == -1 )
268 goto EXIT;
269
270 type = st.st_mode & S_IFMT;
271
272EXIT:
273 return type;
274}
275
276static const char *
277configfs_function_path(char *buff, size_t size, const char *func, ...)
278{
279 LOG_REGISTER_CONTEXT;
280
281 char *pos = buff;
282 char *end = buff + size;
283
284 snprintf(pos, end-pos, "%s", GADGET_FUNC_DIRECTORY);
285
286 va_list va;
287 va_start(va, func);
288 while( func ) {
289 pos = strchr(pos, 0);
290 snprintf(pos, end-pos, "/%s", func);
291 func = va_arg(va, char *);
292 }
293 va_end(va);
294
295 return buff;
296}
297
298static const char *
299configfs_unit_path(char *buff, size_t size, const char *func, const char *unit)
300{
301 LOG_REGISTER_CONTEXT;
302
303 return configfs_function_path(buff, size, func, unit, NULL);
304}
305
306static const char *
307configfs_config_path(char *buff, size_t size, const char *func)
308{
309 LOG_REGISTER_CONTEXT;
310
311 snprintf(buff, size, "%s/%s", GADGET_CONF_DIRECTORY, func);
312 return buff;
313}
314
315static bool
316configfs_mkdir(const char *path)
317{
318 LOG_REGISTER_CONTEXT;
319
320 bool ack = false;
321
322 if( mkdir(path, 0775) == -1 && errno != EEXIST ) {
323 log_err("%s: mkdir failed: %m", path);
324 goto EXIT;
325 }
326
327 if( configfs_file_type(path) != S_IFDIR ) {
328 log_err("%s: is not a directory", path);
329 goto EXIT;
330 }
331
332 ack = true;
333
334EXIT:
335 return ack;
336}
337
338static bool
339configfs_rmdir(const char *path)
340{
341 LOG_REGISTER_CONTEXT;
342
343 bool ack = false;
344
345 if( rmdir(path) == -1 && errno != ENOENT ) {
346 log_err("%s: rmdir failed: %m", path);
347 goto EXIT;
348 }
349
350 ack = true;
351
352EXIT:
353 return ack;
354}
355
356static const char *
357configfs_register_function(const char *function)
358{
359 LOG_REGISTER_CONTEXT;
360
361 const char *res = 0;
362
363 static char fpath[PATH_MAX];
364 configfs_function_path(fpath, sizeof fpath, function, NULL);
365
366 if( !configfs_mkdir(fpath) )
367 goto EXIT;
368
369 log_debug("function %s is registered", function);
370
371 res = fpath;
372
373EXIT:
374 return res;
375}
376
377#ifdef DEAD_CODE
378static bool
379configfs_unregister_function(const char *function)
380{
381 LOG_REGISTER_CONTEXT;
382
383 bool ack = false;
384
385 char fpath[PATH_MAX];
386 configfs_function_path(fpath, sizeof fpath, function, NULL);
387
388 if( !configfs_rmdir(fpath) )
389 goto EXIT;
390
391 log_debug("function %s is unregistered", function);
392 ack = true;
393
394EXIT:
395 return ack;
396}
397#endif
398
399static const char *
400configfs_add_unit(const char *function, const char *unit)
401{
402 LOG_REGISTER_CONTEXT;
403
404 const char *res = 0;
405
406 static char upath[PATH_MAX];
407 configfs_unit_path(upath, sizeof upath, function, unit);
408
409 if( !configfs_mkdir(upath) )
410 goto EXIT;
411
412 log_debug("function %s unit %s added", function, unit);
413
414 res = upath;
415
416EXIT:
417 return res;
418}
419
420static bool
421configfs_remove_unit(const char *function, const char *unit)
422{
423 LOG_REGISTER_CONTEXT;
424
425 bool ack = false;
426
427 static char upath[PATH_MAX];
428 configfs_unit_path(upath, sizeof upath, function, unit);
429
430 if( !configfs_rmdir(upath) )
431 goto EXIT;
432
433 log_debug("function %s unit %s removed", function, unit);
434
435 ack = true;
436
437EXIT:
438 return ack;
439}
440
441static bool
442configfs_enable_function(const char *function)
443{
444 LOG_REGISTER_CONTEXT;
445
446 bool ack = false;
447
448 const char *fpath = configfs_register_function(function);
449 if( !fpath ) {
450 log_err("function %s is not registered", function);
451 goto EXIT;
452 }
453
454 char cpath[PATH_MAX];
455 configfs_config_path(cpath, sizeof cpath, function);
456
457 switch( configfs_file_type(cpath) ) {
458 case S_IFLNK:
459 if( unlink(cpath) == -1 ) {
460 log_err("%s: unlink failed: %m", cpath);
461 goto EXIT;
462 }
463 /* fall through */
464 case -1:
465 if( symlink(fpath, cpath) == -1 ) {
466 log_err("%s: failed to symlink to %s: %m", cpath, fpath);
467 goto EXIT;
468 }
469 break;
470 default:
471 log_err("%s: is not a symlink", cpath);
472 goto EXIT;
473 }
474
475 log_debug("function %s is enabled", function);
476 ack = true;
477
478EXIT:
479 return ack;
480}
481
482static bool
483configfs_disable_function(const char *function)
484{
485 LOG_REGISTER_CONTEXT;
486
487 bool ack = false;
488
489 char cpath[PATH_MAX];
490 configfs_config_path(cpath, sizeof cpath, function);
491
492 if( configfs_file_type(cpath) != S_IFLNK ) {
493 log_err("%s: is not a symlink", cpath);
494 goto EXIT;
495 }
496
497 if( unlink(cpath) == -1 ) {
498 log_err("%s: unlink failed: %m", cpath);
499 goto EXIT;
500 }
501
502 log_debug("function %s is disabled", function);
503 ack = true;
504
505EXIT:
506 return ack;
507}
508
509static bool
510configfs_disable_all_functions(void)
511{
512 LOG_REGISTER_CONTEXT;
513
514 bool ack = false;
515 DIR *dir = 0;
516
517 if( !(dir = opendir(GADGET_CONF_DIRECTORY)) ) {
518 log_err("%s: opendir failed: %m", GADGET_CONF_DIRECTORY);
519 goto EXIT;
520 }
521
522 ack = true;
523
524 struct dirent *de;
525 while( (de = readdir(dir)) ) {
526 if( de->d_type != DT_LNK )
527 continue;
528
529 if( !configfs_disable_function(de->d_name) )
530 ack = false;
531 }
532
533 if( ack )
534 log_debug("all functions are disabled");
535
536EXIT:
537 if( dir )
538 closedir(dir);
539
540 return ack;
541}
542
543static char *configfs_strip(char *str)
544{
545 LOG_REGISTER_CONTEXT;
546
547 unsigned char *src = (unsigned char *)str;
548 unsigned char *dst = (unsigned char *)str;
549
550 while( *src > 0 && *src <= 32 ) ++src;
551
552 for( ;; )
553 {
554 while( *src > 32 ) *dst++ = *src++;
555 while( *src > 0 && *src <= 32 ) ++src;
556 if( *src == 0 ) break;
557 *dst++ = ' ';
558 }
559 *dst = 0;
560 return str;
561}
562
563bool
564configfs_in_use(void)
565{
566 LOG_REGISTER_CONTEXT;
567
568 if( configfs_probed < 0 )
569 log_debug("configfs_in_use() called before configfs_probe()");
570 return configfs_probed > 0;
571}
572
573static bool
574configfs_probe(void)
575{
576 LOG_REGISTER_CONTEXT;
577
578 configfs_read_configuration();
579
580 if( configfs_probed <= 0 ) {
581 configfs_probed = (access(GADGET_BASE_DIRECTORY, F_OK) == 0 &&
582 access(GADGET_CTRL_UDC, F_OK) == 0);
583 log_warning("CONFIGFS %sdetected", configfs_probed ? "" : "not ");
584 }
585 return configfs_in_use();
586}
587
588static const char *
589configfs_udc_enable_value(void)
590{
591 LOG_REGISTER_CONTEXT;
592
593 static bool probed = false;
594 static char *value = 0;
595
596 if( !probed ) {
597 probed = true;
598
599 /* Find first symlink in /sys/class/udc directory */
600 struct dirent *de;
601 DIR *dir = opendir("/sys/class/udc");
602 if( dir ) {
603 while( (de = readdir(dir)) ) {
604 if( de->d_type != DT_LNK )
605 continue;
606 if( de->d_name[0] == '.' )
607 continue;
608 value = strdup(de->d_name);
609 break;
610 }
611 closedir(dir);
612 }
613 }
614
615 return value ?: "";
616}
617
618static bool
619configfs_write_file(const char *path, const char *text)
620{
621 LOG_REGISTER_CONTEXT;
622
623 bool ack = false;
624 int fd = -1;
625
626 if( !path || !text )
627 goto EXIT;
628
629 log_debug("WRITE %s '%s'", path, text);
630
631 char buff[64];
632 snprintf(buff, sizeof buff, "%s\n", text);
633 size_t size = strlen(buff);
634
635 if( (fd = open(path, O_WRONLY)) == -1 ) {
636 log_err("%s: can't open for writing: %m", path);
637 goto EXIT;
638 }
639
640 int rc = write(fd, buff, size);
641 if( rc == -1 ) {
642 log_err("%s: write failure: %m", path);
643 goto EXIT;
644 }
645
646 if( (size_t)rc != size ) {
647 log_err("%s: write failure: partial success", path);
648 goto EXIT;
649 }
650
651 ack = true;
652
653EXIT:
654 if( fd != -1 )
655 close(fd);
656
657 return ack;
658}
659
660static bool
661configfs_read_file(const char *path, char *buff, size_t size)
662{
663 LOG_REGISTER_CONTEXT;
664
665 bool ack = false;
666 int fd = -1;
667
668 if( !path || !buff )
669 goto EXIT;
670
671 if( size < 2 )
672 goto EXIT;
673
674 if( (fd = open(path, O_RDONLY)) == -1 ) {
675 log_err("%s: can't open for reading: %m", path);
676 goto EXIT;
677 }
678
679 int rc = read(fd, buff, size - 1);
680 if( rc == -1 ) {
681 log_err("%s: read failure: %m", path);
682 goto EXIT;
683 }
684
685 buff[rc] = 0;
686 configfs_strip(buff);
687
688 ack = true;
689
690 log_debug("READ %s '%s'", path, buff);
691
692EXIT:
693 if( fd != -1 )
694 close(fd);
695
696 return ack;
697}
698
699#ifdef DEAD_CODE
700static bool
701configfs_read_udc(char *buff, size_t size)
702{
703 LOG_REGISTER_CONTEXT;
704
705 return configfs_read_file(GADGET_CTRL_UDC, buff, size);
706}
707#endif
708
709static bool
710configfs_write_udc(const char *text)
711{
712 LOG_REGISTER_CONTEXT;
713
714 bool ack = false;
715
716 char prev[64];
717
718 if( !configfs_read_file(GADGET_CTRL_UDC, prev, sizeof prev) )
719 goto EXIT;
720
721 if( strcmp(prev, text) ) {
722 if( !configfs_write_file(GADGET_CTRL_UDC, text) )
723 goto EXIT;
724 }
725
726 ack = true;
727
728EXIT:
729 return ack;
730
731}
732
733bool
734configfs_set_udc(bool enable)
735{
736 LOG_REGISTER_CONTEXT;
737
738 log_debug("UDC - %s", enable ? "ENABLE" : "DISABLE");
739
740 const char *value = "";
741
742 if( enable )
743 value = configfs_udc_enable_value();
744
745 return configfs_write_udc(value);
746}
747
752bool
754{
755 LOG_REGISTER_CONTEXT;
756
757 if( !configfs_probe() )
758 goto EXIT;
759
760 /* Disable */
761 configfs_set_udc(false);
762
763 /* Configure */
764 gchar *text;
765 if( (text = config_get_android_vendor_id()) ) {
766 configfs_write_file(GADGET_CTRL_ID_VENDOR, text);
767 g_free(text);
768 }
769
770 if( (text = config_get_android_product_id()) ) {
771 configfs_write_file(GADGET_CTRL_ID_PRODUCT, text);
772 g_free(text);
773 }
774
775 if( (text = config_get_android_manufacturer()) ) {
776 configfs_write_file(GADGET_CTRL_MANUFACTURER, text);
777 g_free(text);
778 }
779
780 if( (text = config_get_android_product()) ) {
781 configfs_write_file(GADGET_CTRL_PRODUCT, text);
782 g_free(text);
783 }
784
785 if( (text = android_get_serial()) ) {
786 configfs_write_file(GADGET_CTRL_SERIAL, text);
787 g_free(text);
788 }
789
790 /* Prep: charging_only */
791 configfs_register_function(FUNCTION_MASS_STORAGE);
792
793 /* Prep: mtp_mode */
794 configfs_register_function(FUNCTION_MTP);
795
796 /* Prep: developer_mode */
797 configfs_register_function(FUNCTION_RNDIS);
798 if( (text = mac_read_mac()) ) {
799 configfs_write_file(RNDIS_CTRL_ETHADDR, text);
800 g_free(text);
801 }
802 /* For rndis to be discovered correctly in M$ Windows (vista and later) */
803 configfs_write_file(RNDIS_CTRL_WCEIS, "1");
804
805 /* Leave disabled, will enable on cable connect detected */
806EXIT:
807 return configfs_in_use();
808}
809
812void
814{
815 g_free(GADGET_BASE_DIRECTORY),
816 GADGET_BASE_DIRECTORY = 0;
817 g_free(GADGET_FUNC_DIRECTORY),
818 GADGET_FUNC_DIRECTORY = 0;
819 g_free(GADGET_CONF_DIRECTORY),
820 GADGET_CONF_DIRECTORY = 0;
821
822 g_free(GADGET_CTRL_UDC),
823 GADGET_CTRL_UDC = 0;
824 g_free(GADGET_CTRL_ID_VENDOR),
825 GADGET_CTRL_ID_VENDOR= 0;
826 g_free(GADGET_CTRL_ID_PRODUCT),
827 GADGET_CTRL_ID_PRODUCT= 0;
828 g_free(GADGET_CTRL_MANUFACTURER),
829 GADGET_CTRL_MANUFACTURER= 0;
830 g_free(GADGET_CTRL_PRODUCT),
831 GADGET_CTRL_PRODUCT = 0;
832 g_free(GADGET_CTRL_SERIAL),
833 GADGET_CTRL_SERIAL = 0;
834
835 g_free(FUNCTION_MASS_STORAGE),
836 FUNCTION_MASS_STORAGE = 0;
837 g_free(FUNCTION_RNDIS),
838 FUNCTION_RNDIS = 0;
839 g_free(FUNCTION_MTP),
840 FUNCTION_MTP = 0;
841
842 g_free(RNDIS_CTRL_WCEIS),
843 RNDIS_CTRL_WCEIS = 0;
844 g_free(RNDIS_CTRL_ETHADDR),
845 RNDIS_CTRL_ETHADDR= 0;
846}
847
848/* Set a charging mode for the configfs gadget
849 *
850 * @return true if successful, false on failure
851 */
852bool
853configfs_set_charging_mode(void)
854{
855 LOG_REGISTER_CONTEXT;
856
857 bool ack = false;
858
859 if( !configfs_set_function("mass_storage") )
860 goto EXIT;
861
862 /* TODO: make this configurable */
863 configfs_set_productid("0AFE");
864
865 if( !configfs_set_udc(true) )
866 goto EXIT;
867
868 ack = true;
869
870EXIT:
871 log_debug("CONFIGFS %s() -> %d", __func__, ack);
872 return ack;
873}
874
875/* Set a product id for the configfs gadget
876 *
877 * @return true if successful, false on failure
878 */
879bool
880configfs_set_productid(const char *id)
881{
882 LOG_REGISTER_CONTEXT;
883
884 bool ack = false;
885
886 if( id && configfs_in_use() ) {
887 /* Config files have things like "0A02".
888 * Kernel wants to see "0x0a02" ... */
889 char *end = 0;
890 unsigned num = strtol(id, &end, 16);
891 char str[16];
892 if( end > id && *end == 0 ) {
893 snprintf(str, sizeof str, "0x%04x", num);
894 id = str;
895 }
896 ack = configfs_write_file(GADGET_CTRL_ID_PRODUCT, id);
897 }
898
899 log_debug("CONFIGFS %s(%s) -> %d", __func__, id, ack);
900 return ack;
901}
902
903/* Set a vendor id for the configfs gadget
904 *
905 * @return true if successful, false on failure
906 */
907bool
908configfs_set_vendorid(const char *id)
909{
910 LOG_REGISTER_CONTEXT;
911
912 bool ack = false;
913
914 if( id && configfs_in_use() ) {
915 log_debug("%s(%s) was called", __func__, id);
916
917 /* Config files have things like "0A02".
918 * Kernel wants to see "0x0a02" ... */
919 char *end = 0;
920 unsigned num = strtol(id, &end, 16);
921 char str[16];
922
923 if( end > id && *end == 0 ) {
924 snprintf(str, sizeof str, "0x%04x", num);
925 id = str;
926 }
927
928 ack = configfs_write_file(GADGET_CTRL_ID_VENDOR, id);
929 }
930
931 log_debug("CONFIGFS %s(%s) -> %d", __func__, id, ack);
932 return ack;
933}
934
935static const char *
936configfs_map_function(const char *func)
937{
938 LOG_REGISTER_CONTEXT;
939
940 if( func == 0 )
941 ;
942 else if( !strcmp(func, "mass_storage") )
943 func = FUNCTION_MASS_STORAGE;
944 else if( !strcmp(func, "rndis") )
945 func = FUNCTION_RNDIS;
946 else if( !strcmp(func, "mtp") )
947 func = FUNCTION_MTP;
948 else if( !strcmp(func, "ffs") ) // existing config files ...
949 func = FUNCTION_MTP;
950 return func;
951}
952
953/* Set active functions
954 *
955 * @param function Comma separated list of function names to
956 * enable, or NULL to disable all
957 *
958 * @return true if successful, false on failure
959 */
960bool
961configfs_set_function(const char *functions)
962{
963 LOG_REGISTER_CONTEXT;
964
965 bool ack = false;
966
967 gchar **vec = 0;
968
969 if( !configfs_in_use() )
970 goto EXIT;
971
972 if( !configfs_set_udc(false) )
973 goto EXIT;
974
975 if( !configfs_disable_all_functions() )
976 goto EXIT;
977
978 if( functions ) {
979 vec = g_strsplit(functions, ",", 0);
980 for( size_t i = 0; vec[i]; ++i ) {
981 /* Normalize names used by usb-moded itself and already
982 * existing configuration files etc.
983 */
984 const char *use = configfs_map_function(vec[i]);
985 if( !use || !*use )
986 continue;
987 if( !configfs_enable_function(use) )
988 goto EXIT;
989 }
990 }
991
992 /* Leave disabled, so that caller can adjust attributes
993 * etc before enabling */
994
995 ack = true;
996
997EXIT:
998 log_debug("CONFIGFS %s(%s) -> %d", __func__, functions, ack);
999 g_strfreev(vec);
1000 return ack;
1001}
1002
1003bool
1004configfs_add_mass_storage_lun(int lun)
1005{
1006 LOG_REGISTER_CONTEXT;
1007
1008 bool ack = false;
1009
1010 if( !configfs_in_use() )
1011 goto EXIT;
1012
1013 char unit[32];
1014 snprintf(unit, sizeof unit, "lun.%d", lun);
1015 ack = configfs_add_unit(FUNCTION_MASS_STORAGE, unit) != 0;
1016
1017EXIT:
1018 return ack;
1019}
1020
1021bool
1022configfs_remove_mass_storage_lun(int lun)
1023{
1024 LOG_REGISTER_CONTEXT;
1025
1026 bool ack = false;
1027
1028 if( !configfs_in_use() )
1029 goto EXIT;
1030
1031 char unit[32];
1032 snprintf(unit, sizeof unit, "lun.%d", lun);
1033 ack = configfs_remove_unit(FUNCTION_MASS_STORAGE, unit);
1034
1035EXIT:
1036 return ack;
1037}
1038
1039bool
1040configfs_set_mass_storage_attr(int lun, const char *attr, const char *value)
1041{
1042 LOG_REGISTER_CONTEXT;
1043
1044 bool ack = false;
1045
1046 if( !configfs_in_use() )
1047 goto EXIT;
1048
1049 char unit[32];
1050 snprintf(unit, sizeof unit, "lun.%d", lun);
1051 char path[PATH_MAX];
1052 configfs_function_path(path, sizeof path, FUNCTION_MASS_STORAGE,
1053 unit, attr, NULL);
1054 ack = configfs_write_file(path, value);
1055
1056EXIT:
1057 return ack;
1058}
gchar * android_get_serial(void)
void configfs_quit(void)
bool configfs_init(void)