Initial commit
[kernel/linux-3.0.git] / drivers / staging / usbip / userspace / src / bind-driver.c
1 /*
2  *
3  * Copyright (C) 2005-2007 Takahiro Hirofuchi
4  */
5
6 #include "utils.h"
7
8 #define _GNU_SOURCE
9 #include <getopt.h>
10 #include <glib.h>
11
12
13
14 static const struct option longopts[] = {
15         {"usbip",       required_argument,      NULL, 'u'},
16         {"other",       required_argument,      NULL, 'o'},
17         {"list",        no_argument,            NULL, 'l'},
18         {"list2",       no_argument,            NULL, 'L'},
19         {"help",        no_argument,            NULL, 'h'},
20 #if 0
21         {"allusbip",    no_argument,            NULL, 'a'},
22         {"export-to",   required_argument,      NULL, 'e'},
23         {"unexport",    required_argument,      NULL, 'x'},
24         {"busid",       required_argument,      NULL, 'b'},
25 #endif
26
27         {NULL,          0,                      NULL,  0}
28 };
29
30 static const char match_busid_path[] = "/sys/bus/usb/drivers/usbip/match_busid";
31
32
33 static void show_help(void)
34 {
35         printf("Usage: usbip_bind_driver [OPTION]\n");
36         printf("Change driver binding for USB/IP.\n");
37         printf("  --usbip busid        make a device exportable\n");
38         printf("  --other busid        use a device by a local driver\n");
39         printf("  --list               print usb devices and their drivers\n");
40         printf("  --list2              print usb devices and their drivers in parseable mode\n");
41 #if 0
42         printf("  --allusbip           make all devices exportable\n");
43         printf("  --export-to host     export the device to 'host'\n");
44         printf("  --unexport host      unexport a device previously exported to 'host'\n");
45         printf("  --busid busid        the busid used for --export-to\n");
46 #endif
47 }
48
49 static int modify_match_busid(char *busid, int add)
50 {
51         int fd;
52         int ret;
53         char buff[BUS_ID_SIZE + 4];
54
55         /* BUS_IS_SIZE includes NULL termination? */
56         if (strnlen(busid, BUS_ID_SIZE) > BUS_ID_SIZE - 1) {
57                 g_warning("too long busid");
58                 return -1;
59         }
60
61         fd = open(match_busid_path, O_WRONLY);
62         if (fd < 0)
63                 return -1;
64
65         if (add)
66                 snprintf(buff, BUS_ID_SIZE + 4, "add %s", busid);
67         else
68                 snprintf(buff, BUS_ID_SIZE + 4, "del %s", busid);
69
70         g_debug("write \"%s\" to %s", buff, match_busid_path);
71
72         ret = write(fd, buff, sizeof(buff));
73         if (ret < 0) {
74                 close(fd);
75                 return -1;
76         }
77
78         close(fd);
79
80         return 0;
81 }
82
83 static const char unbind_path_format[] = "/sys/bus/usb/devices/%s/driver/unbind";
84
85 /* buggy driver may cause dead lock */
86 static int unbind_interface_busid(char *busid)
87 {
88         char unbind_path[PATH_MAX];
89         int fd;
90         int ret;
91
92         snprintf(unbind_path, sizeof(unbind_path), unbind_path_format, busid);
93
94         fd = open(unbind_path, O_WRONLY);
95         if (fd < 0) {
96                 g_warning("opening unbind_path failed: %d", fd);
97                 return -1;
98         }
99
100         ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
101         if (ret < 0) {
102                 g_warning("write to unbind_path failed: %d", ret);
103                 close(fd);
104                 return -1;
105         }
106
107         close(fd);
108
109         return 0;
110 }
111
112 static int unbind_interface(char *busid, int configvalue, int interface)
113 {
114         char inf_busid[BUS_ID_SIZE];
115         g_debug("unbinding interface");
116
117         snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
118
119         return unbind_interface_busid(inf_busid);
120 }
121
122
123 static const char bind_path_format[] = "/sys/bus/usb/drivers/%s/bind";
124
125 static int bind_interface_busid(char *busid, char *driver)
126 {
127         char bind_path[PATH_MAX];
128         int fd;
129         int ret;
130
131         snprintf(bind_path, sizeof(bind_path), bind_path_format, driver);
132
133         fd = open(bind_path, O_WRONLY);
134         if (fd < 0)
135                 return -1;
136
137         ret = write(fd, busid, strnlen(busid, BUS_ID_SIZE));
138         if (ret < 0) {
139                 close(fd);
140                 return -1;
141         }
142
143         close(fd);
144
145         return 0;
146 }
147
148 static int bind_interface(char *busid, int configvalue, int interface, char *driver)
149 {
150         char inf_busid[BUS_ID_SIZE];
151
152         snprintf(inf_busid, BUS_ID_SIZE, "%s:%d.%d", busid, configvalue, interface);
153
154         return bind_interface_busid(inf_busid, driver);
155 }
156
157 static int unbind(char *busid)
158 {
159         int configvalue = 0;
160         int ninterface = 0;
161         int devclass = 0;
162         int i;
163         int failed = 0;
164
165         configvalue = read_bConfigurationValue(busid);
166         ninterface  = read_bNumInterfaces(busid);
167         devclass  = read_bDeviceClass(busid);
168
169         if (configvalue < 0 || ninterface < 0 || devclass < 0) {
170                 g_warning("read config and ninf value, removed?");
171                 return -1;
172         }
173
174         if (devclass == 0x09) {
175                 g_message("skip unbinding of hub");
176                 return -1;
177         }
178
179         for (i = 0; i < ninterface; i++) {
180                 char driver[PATH_MAX];
181                 int ret;
182
183                 bzero(&driver, sizeof(driver));
184
185                 getdriver(busid, configvalue, i, driver, PATH_MAX-1);
186
187                 g_debug(" %s:%d.%d      -> %s ", busid, configvalue, i, driver);
188
189                 if (!strncmp("none", driver, PATH_MAX))
190                         continue; /* unbound interface */
191
192 #if 0
193                 if (!strncmp("usbip", driver, PATH_MAX))
194                         continue; /* already bound to usbip */
195 #endif
196
197                 /* unbinding */
198                 ret = unbind_interface(busid, configvalue, i);
199                 if (ret < 0) {
200                         g_warning("unbind driver at %s:%d.%d failed",
201                                         busid, configvalue, i);
202                         failed = 1;
203                 }
204         }
205
206         if (failed)
207                 return -1;
208         else
209                 return 0;
210 }
211
212 /* call at unbound state */
213 static int bind_to_usbip(char *busid)
214 {
215         int configvalue = 0;
216         int ninterface = 0;
217         int i;
218         int failed = 0;
219
220         configvalue = read_bConfigurationValue(busid);
221         ninterface  = read_bNumInterfaces(busid);
222
223         if (configvalue < 0 || ninterface < 0) {
224                 g_warning("read config and ninf value, removed?");
225                 return -1;
226         }
227
228         for (i = 0; i < ninterface; i++) {
229                 int ret;
230
231                 ret = bind_interface(busid, configvalue, i, "usbip");
232                 if (ret < 0) {
233                         g_warning("bind usbip at %s:%d.%d, failed",
234                                         busid, configvalue, i);
235                         failed = 1;
236                         /* need to contine binding at other interfaces */
237                 }
238         }
239
240         if (failed)
241                 return -1;
242         else
243                 return 0;
244 }
245
246
247 static int use_device_by_usbip(char *busid)
248 {
249         int ret;
250
251         ret = unbind(busid);
252         if (ret < 0) {
253                 g_warning("unbind drivers of %s, failed", busid);
254                 return -1;
255         }
256
257         ret = modify_match_busid(busid, 1);
258         if (ret < 0) {
259                 g_warning("add %s to match_busid, failed", busid);
260                 return -1;
261         }
262
263         ret = bind_to_usbip(busid);
264         if (ret < 0) {
265                 g_warning("bind usbip to %s, failed", busid);
266                 modify_match_busid(busid, 0);
267                 return -1;
268         }
269
270         g_message("bind %s to usbip, complete!", busid);
271
272         return 0;
273 }
274
275
276
277 static int use_device_by_other(char *busid)
278 {
279         int ret;
280         int config;
281
282         /* read and write the same config value to kick probing */
283         config = read_bConfigurationValue(busid);
284         if (config < 0) {
285                 g_warning("read bConfigurationValue of %s, failed", busid);
286                 return -1;
287         }
288
289         ret = modify_match_busid(busid, 0);
290         if (ret < 0) {
291                 g_warning("del %s to match_busid, failed", busid);
292                 return -1;
293         }
294
295         ret = write_bConfigurationValue(busid, config);
296         if (ret < 0) {
297                 g_warning("read bConfigurationValue of %s, failed", busid);
298                 return -1;
299         }
300
301         g_message("bind %s to other drivers than usbip, complete!", busid);
302
303         return 0;
304 }
305
306
307 #include <sys/types.h>
308 #include <regex.h>
309
310 #include <errno.h>
311 #include <string.h>
312 #include <stdio.h>
313
314
315
316 static int is_usb_device(char *busid)
317 {
318         int ret;
319
320         regex_t regex;
321         regmatch_t pmatch[1];
322
323         ret = regcomp(&regex, "^[0-9]+-[0-9]+(\\.[0-9]+)*$", REG_NOSUB|REG_EXTENDED);
324         if (ret < 0)
325                 g_error("regcomp: %s\n", strerror(errno));
326
327         ret = regexec(&regex, busid, 0, pmatch, 0);
328         if (ret)
329                 return 0;       /* not matched */
330
331         return 1;
332 }
333
334
335 #include <dirent.h>
336 static int show_devices(void)
337 {
338         DIR *dir;
339
340         dir = opendir("/sys/bus/usb/devices/");
341         if (!dir)
342                 g_error("opendir: %s", strerror(errno));
343
344         printf("List USB devices\n");
345         for (;;) {
346                 struct dirent *dirent;
347                 char *busid;
348
349                 dirent = readdir(dir);
350                 if (!dirent)
351                         break;
352
353                 busid = dirent->d_name;
354
355                 if (is_usb_device(busid)) {
356                         char name[100] = {'\0'};
357                         char driver[100] =  {'\0'};
358                         int conf, ninf = 0;
359                         int i;
360
361                         conf = read_bConfigurationValue(busid);
362                         ninf = read_bNumInterfaces(busid);
363
364                         getdevicename(busid, name, sizeof(name));
365
366                         printf(" - busid %s (%s)\n", busid, name);
367
368                         for (i = 0; i < ninf; i++) {
369                                 getdriver(busid, conf, i, driver, sizeof(driver));
370                                 printf("         %s:%d.%d -> %s\n", busid, conf, i, driver);
371                         }
372                         printf("\n");
373                 }
374         }
375
376         closedir(dir);
377
378         return 0;
379 }
380
381 static int show_devices2(void)
382 {
383         DIR *dir;
384
385         dir = opendir("/sys/bus/usb/devices/");
386         if (!dir)
387                 g_error("opendir: %s", strerror(errno));
388
389         for (;;) {
390                 struct dirent *dirent;
391                 char *busid;
392
393                 dirent = readdir(dir);
394                 if (!dirent)
395                         break;
396
397                 busid = dirent->d_name;
398
399                 if (is_usb_device(busid)) {
400                         char name[100] = {'\0'};
401                         char driver[100] =  {'\0'};
402                         int conf, ninf = 0;
403                         int i;
404
405                         conf = read_bConfigurationValue(busid);
406                         ninf = read_bNumInterfaces(busid);
407
408                         getdevicename(busid, name, sizeof(name));
409
410                         printf("busid=%s#usbid=%s#", busid, name);
411
412                         for (i = 0; i < ninf; i++) {
413                                 getdriver(busid, conf, i, driver, sizeof(driver));
414                                 printf("%s:%d.%d=%s#", busid, conf, i, driver);
415                         }
416                         printf("\n");
417                 }
418         }
419
420         closedir(dir);
421
422         return 0;
423 }
424
425
426 #if 0
427 static int export_to(char *host, char *busid) {
428
429         int ret;
430
431         if( host == NULL ) {
432                 printf( "no host given\n\n");
433                 show_help();
434                 return -1;
435         }
436         if( busid == NULL ) {
437                 /* XXX print device list and ask for busnumber, if none is
438                  * given */
439                 printf( "no busid given, use --busid switch\n\n");
440                 show_help();
441                 return -1;
442         }
443
444
445         ret = use_device_by_usbip(busid);
446         if( ret != 0 ) {
447                 printf( "could not bind driver to usbip\n");
448                 return -1;
449         }
450
451         printf( "DEBUG: exporting device '%s' to '%s'\n", busid, host );
452         ret = export_busid_to_host(host, busid); /* usbip_export.[ch] */
453         if( ret != 0 ) {
454                 printf( "could not export device to host\n" );
455                 printf( "   host: %s, device: %s\n", host, busid );
456                 use_device_by_other(busid);
457                 return -1;
458         }
459
460         return 0;
461 }
462
463 static int unexport_from(char *host, char *busid) {
464
465         int ret;
466
467         if (!host || !busid)
468                 g_error("no host or no busid\n");
469
470         g_message("unexport_from: host: '%s', busid: '%s'", host, busid);
471
472         ret = unexport_busid_from_host(host, busid); /* usbip_export.[ch] */
473         if( ret != 0 ) {
474                 err( "could not unexport device from host\n" );
475                 err( "   host: %s, device: %s\n", host, busid );
476         }
477
478         ret = use_device_by_other(busid);
479         if (ret < 0)
480                 g_error("could not unbind device from usbip\n");
481
482         return 0;
483 }
484
485
486 static int allusbip(void)
487 {
488         DIR *dir;
489
490         dir = opendir("/sys/bus/usb/devices/");
491         if (!dir)
492                 g_error("opendir: %s", strerror(errno));
493
494         for (;;) {
495                 struct dirent *dirent;
496                 char *busid;
497
498                 dirent = readdir(dir);
499                 if (!dirent)
500                         break;
501
502                 busid = dirent->d_name;
503
504                 if (!is_usb_device(busid))
505                         continue;
506
507                 {
508                         char name[PATH_MAX];
509                         int conf, ninf = 0;
510                         int i;
511                         int be_local = 0;
512
513                         conf = read_bConfigurationValue(busid);
514                         ninf = read_bNumInterfaces(busid);
515
516                         getdevicename(busid, name, sizeof(name));
517
518                         for (i = 0; i < ninf; i++) {
519                                 char driver[PATH_MAX];
520
521                                 getdriver(busid, conf, i, driver, sizeof(driver));
522 #if 0
523                                 if (strncmp(driver, "usbhid", 6) == 0 || strncmp(driver, "usb-storage", 11) == 0) {
524                                         be_local = 1;
525                                         break;
526                                 }
527 #endif
528                         }
529
530                         if (be_local == 0)
531                                 use_device_by_usbip(busid);
532                 }
533         }
534
535         closedir(dir);
536
537         return 0;
538 }
539 #endif
540
541 int main(int argc, char **argv)
542 {
543         char *busid = NULL;
544         char *remote_host __attribute__((unused)) = NULL;
545
546         enum {
547                 cmd_unknown = 0,
548                 cmd_use_by_usbip,
549                 cmd_use_by_other,
550                 cmd_list,
551                 cmd_list2,
552                 cmd_allusbip,
553                 cmd_export_to,
554                 cmd_unexport,
555                 cmd_help,
556         } cmd = cmd_unknown;
557
558         if (geteuid() != 0)
559                 g_warning("running non-root?");
560
561         for (;;) {
562                 int c;
563                 int index = 0;
564
565                 c = getopt_long(argc, argv, "u:o:hlLae:x:b:", longopts, &index);
566                 if (c == -1)
567                         break;
568
569                 switch (c) {
570                         case 'u':
571                                 cmd = cmd_use_by_usbip;
572                                 busid = optarg;
573                                 break;
574                         case 'o' :
575                                 cmd = cmd_use_by_other;
576                                 busid = optarg;
577                                 break;
578                         case 'l' :
579                                 cmd = cmd_list;
580                                 break;
581                         case 'L' :
582                                 cmd = cmd_list2;
583                                 break;
584                         case 'a' :
585                                 cmd = cmd_allusbip;
586                                 break;
587                         case 'b':
588                                 busid = optarg;
589                                 break;
590                         case 'e':
591                                 cmd = cmd_export_to;
592                                 remote_host = optarg;
593                                 break;
594                         case 'x':
595                                 cmd = cmd_unexport;
596                                 remote_host = optarg;
597                                 break;
598                         case 'h': /* fallthrough */
599                         case '?':
600                                 cmd = cmd_help;
601                                 break;
602                         default:
603                                 g_error("getopt");
604                 }
605
606                 //if (cmd)
607                 //      break;
608         }
609
610         switch (cmd) {
611                 case cmd_use_by_usbip:
612                         use_device_by_usbip(busid);
613                         break;
614                 case cmd_use_by_other:
615                         use_device_by_other(busid);
616                         break;
617                 case cmd_list:
618                         show_devices();
619                         break;
620                 case cmd_list2:
621                         show_devices2();
622                         break;
623 #if 0
624                 case cmd_allusbip:
625                         allusbip();
626                         break;
627                 case cmd_export_to:
628                         export_to(remote_host, busid);
629                         break;
630                 case cmd_unexport:
631                         unexport_from(remote_host, busid);
632                         break;
633 #endif
634                 case cmd_help: /* fallthrough */
635                 case cmd_unknown:
636                         show_help();
637                         break;
638                 default:
639                         g_error("NOT REACHED");
640         }
641
642         return 0;
643 }