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