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