]> Pileus Git - ~andy/linux/blob - drivers/staging/usbip/userspace/libsrc/vhci_driver.c
staging: usbip: userspace: libsrc: (foo*) should be (foo *)
[~andy/linux] / drivers / staging / usbip / userspace / libsrc / vhci_driver.c
1 /*
2  * Copyright (C) 2005-2007 Takahiro Hirofuchi
3  */
4
5 #include "usbip_common.h"
6 #include "vhci_driver.h"
7
8 #undef  PROGNAME
9 #define PROGNAME "libusbip"
10
11 struct usbip_vhci_driver *vhci_driver;
12
13 static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid)
14 {
15         struct sysfs_device *sudev;
16
17         sudev = sysfs_open_device("usb", busid);
18         if (!sudev) {
19                 dbg("sysfs_open_device failed: %s", busid);
20                 goto err;
21         }
22         read_usb_device(sudev, &idev->udev);
23         sysfs_close_device(sudev);
24
25         /* add class devices of this imported device */
26         struct usbip_class_device *cdev;
27         dlist_for_each_data(vhci_driver->cdev_list, cdev,
28                             struct usbip_class_device) {
29                 if (!strncmp(cdev->dev_path, idev->udev.path,
30                              strlen(idev->udev.path))) {
31                         struct usbip_class_device *new_cdev;
32
33                         /* alloc and copy because dlist is linked from only one list */
34                         new_cdev = calloc(1, sizeof(*new_cdev));
35                         if (!new_cdev)
36                                 goto err;
37
38                         memcpy(new_cdev, cdev, sizeof(*new_cdev));
39                         dlist_unshift(idev->cdev_list, (void *) new_cdev);
40                 }
41         }
42
43         return idev;
44
45 err:
46         return NULL;
47 }
48
49
50
51 static int parse_status(char *value)
52 {
53         int ret = 0;
54         char *c;
55
56
57         for (int i = 0; i < vhci_driver->nports; i++)
58                 memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
59
60
61         /* skip a header line */
62         c = strchr(value, '\n');
63         if (!c)
64                 return -1;
65         c++;
66
67         while (*c != '\0') {
68                 int port, status, speed, devid;
69                 unsigned long socket;
70                 char lbusid[SYSFS_BUS_ID_SIZE];
71
72                 ret = sscanf(c, "%d %d %d %x %lx %s\n",
73                                 &port, &status, &speed,
74                                 &devid, &socket, lbusid);
75
76                 if (ret < 5) {
77                         dbg("sscanf failed: %d", ret);
78                         BUG();
79                 }
80
81                 dbg("port %d status %d speed %d devid %x",
82                                 port, status, speed, devid);
83                 dbg("socket %lx lbusid %s", socket, lbusid);
84
85
86                 /* if a device is connected, look at it */
87                 {
88                         struct usbip_imported_device *idev = &vhci_driver->idev[port];
89
90                         idev->port      = port;
91                         idev->status    = status;
92
93                         idev->devid     = devid;
94
95                         idev->busnum    = (devid >> 16);
96                         idev->devnum    = (devid & 0x0000ffff);
97
98                         idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
99                         if (!idev->cdev_list) {
100                                 dbg("dlist_new failed");
101                                 return -1;
102                         }
103
104                         if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {
105                                 idev = imported_device_init(idev, lbusid);
106                                 if (!idev) {
107                                         dbg("imported_device_init failed");
108                                         return -1;
109                                 }
110                         }
111                 }
112
113
114                 /* go to the next line */
115                 c = strchr(c, '\n');
116                 if (!c)
117                         break;
118                 c++;
119         }
120
121         dbg("exit");
122
123         return 0;
124 }
125
126
127 static int check_usbip_device(struct sysfs_class_device *cdev)
128 {
129         char class_path[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */
130         char dev_path[SYSFS_PATH_MAX];   /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
131         int ret;
132         struct usbip_class_device *usbip_cdev;
133
134         snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
135
136         ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
137         if (ret == 0) {
138                 if (!strncmp(dev_path, vhci_driver->hc_device->path,
139                              strlen(vhci_driver->hc_device->path))) {
140                         /* found usbip device */
141                         usbip_cdev = calloc(1, sizeof(*usbip_cdev));
142                         if (!usbip_cdev) {
143                                 dbg("calloc failed");
144                                 return -1;
145                         }
146                         dlist_unshift(vhci_driver->cdev_list, usbip_cdev);
147                         strncpy(usbip_cdev->class_path, class_path,
148                                 sizeof(usbip_cdev->class_path));
149                         strncpy(usbip_cdev->dev_path, dev_path,
150                                 sizeof(usbip_cdev->dev_path));
151                         dbg("found: %s %s", class_path, dev_path);
152                 }
153         }
154
155         return 0;
156 }
157
158
159 static int search_class_for_usbip_device(char *cname)
160 {
161         struct sysfs_class *class;
162         struct dlist *cdev_list;
163         struct sysfs_class_device *cdev;
164         int ret = 0;
165
166         class = sysfs_open_class(cname);
167         if (!class) {
168                 dbg("sysfs_open_class failed");
169                 return -1;
170         }
171
172         dbg("class: %s", class->name);
173
174         cdev_list = sysfs_get_class_devices(class);
175         if (!cdev_list)
176                 /* nothing */
177                 goto out;
178
179         dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
180                 dbg("cdev: %s", cdev->name);
181                 ret = check_usbip_device(cdev);
182                 if (ret < 0)
183                         goto out;
184         }
185
186 out:
187         sysfs_close_class(class);
188
189         return ret;
190 }
191
192
193 static int refresh_class_device_list(void)
194 {
195         int ret;
196         struct dlist *cname_list;
197         char *cname;
198         char sysfs_mntpath[SYSFS_PATH_MAX];
199         char class_path[SYSFS_PATH_MAX];
200
201         ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
202         if (ret < 0) {
203                 dbg("sysfs_get_mnt_path failed");
204                 return -1;
205         }
206
207         snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
208                  SYSFS_CLASS_NAME);
209
210         /* search under /sys/class */
211         cname_list = sysfs_open_directory_list(class_path);
212         if (!cname_list) {
213                 dbg("sysfs_open_directory failed");
214                 return -1;
215         }
216
217         dlist_for_each_data(cname_list, cname, char) {
218                 ret = search_class_for_usbip_device(cname);
219                 if (ret < 0) {
220                         sysfs_close_list(cname_list);
221                         return -1;
222                 }
223         }
224
225         sysfs_close_list(cname_list);
226
227         /* seach under /sys/block */
228         ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
229         if (ret < 0)
230                 return -1;
231
232         return 0;
233 }
234
235
236 static int refresh_imported_device_list(void)
237 {
238         struct sysfs_attribute *attr_status;
239
240
241         attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
242         if (!attr_status) {
243                 dbg("sysfs_get_device_attr(\"status\") failed: %s",
244                     vhci_driver->hc_device->name);
245                 return -1;
246         }
247
248         dbg("name: %s  path: %s  len: %d  method: %d  value: %s",
249             attr_status->name, attr_status->path, attr_status->len,
250             attr_status->method, attr_status->value);
251
252         return parse_status(attr_status->value);
253 }
254
255 static int get_nports(void)
256 {
257         char *c;
258         int nports = 0;
259         struct sysfs_attribute *attr_status;
260
261         attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
262         if (!attr_status) {
263                 dbg("sysfs_get_device_attr(\"status\") failed: %s",
264                     vhci_driver->hc_device->name);
265                 return -1;
266         }
267
268         dbg("name: %s  path: %s  len: %d  method: %d  value: %s",
269             attr_status->name, attr_status->path, attr_status->len,
270             attr_status->method, attr_status->value);
271
272         /* skip a header line */
273         c = strchr(attr_status->value, '\n');
274         if (!c)
275                 return 0;
276         c++;
277
278         while (*c != '\0') {
279                 /* go to the next line */
280                 c = strchr(c, '\n');
281                 if (!c)
282                         return nports;
283                 c++;
284                 nports += 1;
285         }
286
287         return nports;
288 }
289
290 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
291 {
292         struct sysfs_driver *sdriver;
293         char sdriver_path[SYSFS_PATH_MAX];
294
295         struct sysfs_device *hc_dev;
296         struct dlist *hc_devs;
297
298         int found = 0;
299
300         snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath,
301         SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME,
302         USBIP_VHCI_DRV_NAME);
303
304         sdriver = sysfs_open_driver_path(sdriver_path);
305         if (!sdriver) {
306                 dbg("sysfs_open_driver_path failed: %s", sdriver_path);
307                 dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
308                     USBIP_VHCI_DRV_NAME ".ko are loaded!");
309                 return -1;
310         }
311
312         hc_devs = sysfs_get_driver_devices(sdriver);
313         if (!hc_devs) {
314                 dbg("sysfs_get_driver failed");
315                 goto err;
316         }
317
318         /* assume only one vhci_hcd */
319         dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
320                 strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
321                 found = 1;
322         }
323
324 err:
325         sysfs_close_driver(sdriver);
326
327         if (found)
328                 return 0;
329
330         dbg("%s not found", hc_busid);
331         return -1;
332 }
333
334
335 /* ---------------------------------------------------------------------- */
336
337 int usbip_vhci_driver_open(void)
338 {
339         int ret;
340         char hc_busid[SYSFS_BUS_ID_SIZE];
341
342         vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
343         if (!vhci_driver) {
344                 dbg("calloc failed");
345                 return -1;
346         }
347
348         ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
349         if (ret < 0) {
350                 dbg("sysfs_get_mnt_path failed");
351                 goto err;
352         }
353
354         ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
355         if (ret < 0)
356                 goto err;
357
358         /* will be freed in usbip_driver_close() */
359         vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
360                                                    hc_busid);
361         if (!vhci_driver->hc_device) {
362                 dbg("sysfs_open_device failed");
363                 goto err;
364         }
365
366         vhci_driver->nports = get_nports();
367
368         dbg("available ports: %d", vhci_driver->nports);
369
370         vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
371         if (!vhci_driver->cdev_list)
372                 goto err;
373
374         if (refresh_class_device_list())
375                 goto err;
376
377         if (refresh_imported_device_list())
378                 goto err;
379
380
381         return 0;
382
383
384 err:
385         if (vhci_driver->cdev_list)
386                 dlist_destroy(vhci_driver->cdev_list);
387         if (vhci_driver->hc_device)
388                 sysfs_close_device(vhci_driver->hc_device);
389         if (vhci_driver)
390                 free(vhci_driver);
391
392         vhci_driver = NULL;
393         return -1;
394 }
395
396
397 void usbip_vhci_driver_close()
398 {
399         if (!vhci_driver)
400                 return;
401
402         if (vhci_driver->cdev_list)
403                 dlist_destroy(vhci_driver->cdev_list);
404
405         for (int i = 0; i < vhci_driver->nports; i++) {
406                 if (vhci_driver->idev[i].cdev_list)
407                         dlist_destroy(vhci_driver->idev[i].cdev_list);
408         }
409
410         if (vhci_driver->hc_device)
411                 sysfs_close_device(vhci_driver->hc_device);
412         free(vhci_driver);
413
414         vhci_driver = NULL;
415 }
416
417
418 int usbip_vhci_refresh_device_list(void)
419 {
420         if (vhci_driver->cdev_list)
421                 dlist_destroy(vhci_driver->cdev_list);
422
423
424         for (int i = 0; i < vhci_driver->nports; i++) {
425                 if (vhci_driver->idev[i].cdev_list)
426                         dlist_destroy(vhci_driver->idev[i].cdev_list);
427         }
428
429         vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
430         if (!vhci_driver->cdev_list)
431                 goto err;
432
433         if (refresh_class_device_list())
434                 goto err;
435
436         if (refresh_imported_device_list())
437                 goto err;
438
439         return 0;
440 err:
441         if (vhci_driver->cdev_list)
442                 dlist_destroy(vhci_driver->cdev_list);
443
444         for (int i = 0; i < vhci_driver->nports; i++) {
445                 if (vhci_driver->idev[i].cdev_list)
446                         dlist_destroy(vhci_driver->idev[i].cdev_list);
447         }
448
449         dbg("failed to refresh device list");
450         return -1;
451 }
452
453
454 int usbip_vhci_get_free_port(void)
455 {
456         for (int i = 0; i < vhci_driver->nports; i++) {
457                 if (vhci_driver->idev[i].status == VDEV_ST_NULL)
458                         return i;
459         }
460
461         return -1;
462 }
463
464 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
465                 uint32_t speed) {
466         struct sysfs_attribute *attr_attach;
467         char buff[200]; /* what size should be ? */
468         int ret;
469
470         attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
471         if (!attr_attach) {
472                 dbg("sysfs_get_device_attr(\"attach\") failed: %s",
473                     vhci_driver->hc_device->name);
474                 return -1;
475         }
476
477         snprintf(buff, sizeof(buff), "%u %u %u %u",
478                         port, sockfd, devid, speed);
479         dbg("writing: %s", buff);
480
481         ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
482         if (ret < 0) {
483                 dbg("sysfs_write_attribute failed");
484                 return -1;
485         }
486
487         dbg("attached port: %d", port);
488
489         return 0;
490 }
491
492 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
493 {
494         return (busnum << 16) | devnum;
495 }
496
497 /* will be removed */
498 int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
499                 uint8_t devnum, uint32_t speed)
500 {
501         int devid = get_devid(busnum, devnum);
502
503         return usbip_vhci_attach_device2(port, sockfd, devid, speed);
504 }
505
506 int usbip_vhci_detach_device(uint8_t port)
507 {
508         struct sysfs_attribute  *attr_detach;
509         char buff[200]; /* what size should be ? */
510         int ret;
511
512         attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
513         if (!attr_detach) {
514                 dbg("sysfs_get_device_attr(\"detach\") failed: %s",
515                     vhci_driver->hc_device->name);
516                 return -1;
517         }
518
519         snprintf(buff, sizeof(buff), "%u", port);
520         dbg("writing: %s", buff);
521
522         ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
523         if (ret < 0) {
524                 dbg("sysfs_write_attribute failed");
525                 return -1;
526         }
527
528         dbg("detached port: %d", port);
529
530         return 0;
531 }