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