2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
5 #include "usbip_common.h"
6 #include "vhci_driver.h"
9 #define PROGNAME "libusbip"
11 struct usbip_vhci_driver *vhci_driver;
13 static struct usbip_imported_device *
14 imported_device_init(struct usbip_imported_device *idev, char *busid)
16 struct sysfs_device *sudev;
18 sudev = sysfs_open_device("usb", busid);
20 dbg("sysfs_open_device failed: %s", busid);
23 read_usb_device(sudev, &idev->udev);
24 sysfs_close_device(sudev);
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;
34 * alloc and copy because dlist is linked
37 new_cdev = calloc(1, sizeof(*new_cdev));
41 memcpy(new_cdev, cdev, sizeof(*new_cdev));
42 dlist_unshift(idev->cdev_list, (void *) new_cdev);
54 static int parse_status(char *value)
60 for (int i = 0; i < vhci_driver->nports; i++)
61 memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
64 /* skip a header line */
65 c = strchr(value, '\n');
71 int port, status, speed, devid;
73 char lbusid[SYSFS_BUS_ID_SIZE];
75 ret = sscanf(c, "%d %d %d %x %lx %s\n",
76 &port, &status, &speed,
77 &devid, &socket, lbusid);
80 dbg("sscanf failed: %d", ret);
84 dbg("port %d status %d speed %d devid %x",
85 port, status, speed, devid);
86 dbg("socket %lx lbusid %s", socket, lbusid);
89 /* if a device is connected, look at it */
91 struct usbip_imported_device *idev = &vhci_driver->idev[port];
94 idev->status = status;
98 idev->busnum = (devid >> 16);
99 idev->devnum = (devid & 0x0000ffff);
101 idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
102 if (!idev->cdev_list) {
103 dbg("dlist_new failed");
107 if (idev->status != VDEV_ST_NULL
108 && idev->status != VDEV_ST_NOTASSIGNED) {
109 idev = imported_device_init(idev, lbusid);
111 dbg("imported_device_init failed");
118 /* go to the next line */
131 static int check_usbip_device(struct sysfs_class_device *cdev)
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];
138 struct usbip_class_device *usbip_cdev;
140 snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
142 ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
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));
149 dbg("calloc failed");
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);
165 static int search_class_for_usbip_device(char *cname)
167 struct sysfs_class *class;
168 struct dlist *cdev_list;
169 struct sysfs_class_device *cdev;
172 class = sysfs_open_class(cname);
174 dbg("sysfs_open_class failed");
178 dbg("class: %s", class->name);
180 cdev_list = sysfs_get_class_devices(class);
185 dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
186 dbg("cdev: %s", cdev->name);
187 ret = check_usbip_device(cdev);
193 sysfs_close_class(class);
199 static int refresh_class_device_list(void)
202 struct dlist *cname_list;
204 char sysfs_mntpath[SYSFS_PATH_MAX];
205 char class_path[SYSFS_PATH_MAX];
207 ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
209 dbg("sysfs_get_mnt_path failed");
213 snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
216 /* search under /sys/class */
217 cname_list = sysfs_open_directory_list(class_path);
219 dbg("sysfs_open_directory failed");
223 dlist_for_each_data(cname_list, cname, char) {
224 ret = search_class_for_usbip_device(cname);
226 sysfs_close_list(cname_list);
231 sysfs_close_list(cname_list);
233 /* search under /sys/block */
234 ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
242 static int refresh_imported_device_list(void)
244 struct sysfs_attribute *attr_status;
247 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
249 dbg("sysfs_get_device_attr(\"status\") failed: %s",
250 vhci_driver->hc_device->name);
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);
258 return parse_status(attr_status->value);
261 static int get_nports(void)
265 struct sysfs_attribute *attr_status;
267 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
269 dbg("sysfs_get_device_attr(\"status\") failed: %s",
270 vhci_driver->hc_device->name);
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);
278 /* skip a header line */
279 c = strchr(attr_status->value, '\n');
285 /* go to the next line */
296 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
298 struct sysfs_driver *sdriver;
299 char sdriver_path[SYSFS_PATH_MAX];
301 struct sysfs_device *hc_dev;
302 struct dlist *hc_devs;
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);
310 sdriver = sysfs_open_driver_path(sdriver_path);
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!");
318 hc_devs = sysfs_get_driver_devices(sdriver);
320 dbg("sysfs_get_driver failed");
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);
331 sysfs_close_driver(sdriver);
336 dbg("%s not found", hc_busid);
341 /* ---------------------------------------------------------------------- */
343 int usbip_vhci_driver_open(void)
346 char hc_busid[SYSFS_BUS_ID_SIZE];
348 vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
350 dbg("calloc failed");
354 ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
356 dbg("sysfs_get_mnt_path failed");
360 ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
364 /* will be freed in usbip_driver_close() */
365 vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
367 if (!vhci_driver->hc_device) {
368 dbg("sysfs_open_device failed");
372 vhci_driver->nports = get_nports();
374 dbg("available ports: %d", vhci_driver->nports);
376 vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
377 if (!vhci_driver->cdev_list)
380 if (refresh_class_device_list())
383 if (refresh_imported_device_list())
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);
403 void usbip_vhci_driver_close()
408 if (vhci_driver->cdev_list)
409 dlist_destroy(vhci_driver->cdev_list);
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);
416 if (vhci_driver->hc_device)
417 sysfs_close_device(vhci_driver->hc_device);
424 int usbip_vhci_refresh_device_list(void)
426 if (vhci_driver->cdev_list)
427 dlist_destroy(vhci_driver->cdev_list);
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);
435 vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
436 if (!vhci_driver->cdev_list)
439 if (refresh_class_device_list())
442 if (refresh_imported_device_list())
447 if (vhci_driver->cdev_list)
448 dlist_destroy(vhci_driver->cdev_list);
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);
455 dbg("failed to refresh device list");
460 int usbip_vhci_get_free_port(void)
462 for (int i = 0; i < vhci_driver->nports; i++) {
463 if (vhci_driver->idev[i].status == VDEV_ST_NULL)
470 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
472 struct sysfs_attribute *attr_attach;
473 char buff[200]; /* what size should be ? */
476 attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
478 dbg("sysfs_get_device_attr(\"attach\") failed: %s",
479 vhci_driver->hc_device->name);
483 snprintf(buff, sizeof(buff), "%u %u %u %u",
484 port, sockfd, devid, speed);
485 dbg("writing: %s", buff);
487 ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
489 dbg("sysfs_write_attribute failed");
493 dbg("attached port: %d", port);
498 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
500 return (busnum << 16) | devnum;
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)
507 int devid = get_devid(busnum, devnum);
509 return usbip_vhci_attach_device2(port, sockfd, devid, speed);
512 int usbip_vhci_detach_device(uint8_t port)
514 struct sysfs_attribute *attr_detach;
515 char buff[200]; /* what size should be ? */
518 attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
520 dbg("sysfs_get_device_attr(\"detach\") failed: %s",
521 vhci_driver->hc_device->name);
525 snprintf(buff, sizeof(buff), "%u", port);
526 dbg("writing: %s", buff);
528 ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
530 dbg("sysfs_write_attribute failed");
534 dbg("detached port: %d", port);