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