2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
9 static const char vhci_driver_name[] = "vhci_hcd";
11 struct usbip_vhci_driver *vhci_driver;
13 static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid)
15 struct sysfs_device *sudev;
17 sudev = sysfs_open_device("usb", busid);
19 err("sysfs_open_device %s", busid);
22 read_usb_device(sudev, &idev->udev);
23 sysfs_close_device(sudev);
25 /* add class devices of this imported device */
26 struct class_device *cdev;
27 dlist_for_each_data(vhci_driver->cdev_list, cdev, struct class_device) {
28 if (!strncmp(cdev->devpath, idev->udev.path, strlen(idev->udev.path))) {
29 struct class_device *new_cdev;
31 /* alloc and copy because dlist is linked from only one list */
32 new_cdev = calloc(1, sizeof(*new_cdev));
36 memcpy(new_cdev, cdev, sizeof(*new_cdev));
37 dlist_unshift(idev->cdev_list, (void*) new_cdev);
49 static int parse_status(char *value)
55 for (int i = 0; i < vhci_driver->nports; i++)
56 bzero(&vhci_driver->idev[i], sizeof(struct usbip_imported_device));
59 /* skip a header line */
60 c = strchr(value, '\n') + 1;
63 int port, status, speed, devid;
65 char lbusid[SYSFS_BUS_ID_SIZE];
67 ret = sscanf(c, "%d %d %d %x %lx %s\n",
68 &port, &status, &speed,
69 &devid, &socket, lbusid);
76 dbg("port %d status %d speed %d devid %x",
77 port, status, speed, devid);
78 dbg("socket %lx lbusid %s", socket, lbusid);
81 /* if a device is connected, look at it */
83 struct usbip_imported_device *idev = &vhci_driver->idev[port];
86 idev->status = status;
90 idev->busnum = (devid >> 16);
91 idev->devnum = (devid & 0x0000ffff);
93 idev->cdev_list = dlist_new(sizeof(struct class_device));
94 if (!idev->cdev_list) {
95 err("init new device");
99 if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {
100 idev = imported_device_init(idev, lbusid);
102 err("init new device");
109 /* go to the next line */
110 c = strchr(c, '\n') + 1;
119 static int check_usbip_device(struct sysfs_class_device *cdev)
121 char clspath[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */
122 char devpath[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
126 snprintf(clspath, sizeof(clspath), "%s/device", cdev->path);
128 ret = sysfs_get_link(clspath, devpath, SYSFS_PATH_MAX);
130 if (!strncmp(devpath, vhci_driver->hc_device->path,
131 strlen(vhci_driver->hc_device->path))) {
132 /* found usbip device */
133 struct class_device *cdev;
135 cdev = calloc(1, sizeof(*cdev));
140 dlist_unshift(vhci_driver->cdev_list, (void*) cdev);
141 strncpy(cdev->clspath, clspath, sizeof(cdev->clspath));
142 strncpy(cdev->devpath, devpath, sizeof(cdev->clspath));
143 dbg(" found %s %s", clspath, devpath);
151 static int search_class_for_usbip_device(char *cname)
153 struct sysfs_class *class;
154 struct dlist *cdev_list;
155 struct sysfs_class_device *cdev;
158 class = sysfs_open_class(cname);
164 dbg("class %s", class->name);
166 cdev_list = sysfs_get_class_devices(class);
171 dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
172 dbg(" cdev %s", cdev->name);
173 ret = check_usbip_device(cdev);
179 sysfs_close_class(class);
185 static int refresh_class_device_list(void)
188 struct dlist *cname_list;
191 /* search under /sys/class */
192 cname_list = sysfs_open_directory_list("/sys/class");
194 err("open class directory");
198 dlist_for_each_data(cname_list, cname, char) {
199 ret = search_class_for_usbip_device(cname);
201 sysfs_close_list(cname_list);
206 sysfs_close_list(cname_list);
208 /* seach under /sys/block */
209 ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
217 static int refresh_imported_device_list(void)
219 struct sysfs_attribute *attr_status;
222 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
224 err("get attr %s of %s", "status", vhci_driver->hc_device->name);
228 dbg("name %s, path %s, len %d, method %d\n", attr_status->name,
229 attr_status->path, attr_status->len, attr_status->method);
231 dbg("%s", attr_status->value);
233 return parse_status(attr_status->value);
236 static int get_nports(void)
239 struct sysfs_attribute *attr_status;
241 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
243 err("get attr %s of %s", "status", vhci_driver->hc_device->name);
247 dbg("name %s, path %s, len %d, method %d\n", attr_status->name,
248 attr_status->path, attr_status->len, attr_status->method);
250 dbg("%s", attr_status->value);
255 /* skip a header line */
256 c = strchr(attr_status->value, '\n') + 1;
259 /* go to the next line */
260 c = strchr(c, '\n') + 1;
268 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
270 struct sysfs_driver *sdriver;
271 char sdriver_path[SYSFS_PATH_MAX];
273 struct sysfs_device *hc_dev;
274 struct dlist *hc_devs;
278 snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/platform/%s/%s",
279 sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME,
282 sdriver = sysfs_open_driver_path(sdriver_path);
284 info("%s is not found", sdriver_path);
285 info("load usbip-core.ko and vhci-hcd.ko !");
289 hc_devs = sysfs_get_driver_devices(sdriver);
295 /* assume only one vhci_hcd */
296 dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
297 strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
302 sysfs_close_driver(sdriver);
307 err("not found usbip hc");
312 /* ---------------------------------------------------------------------- */
314 int usbip_vhci_driver_open(void)
317 char hc_busid[SYSFS_BUS_ID_SIZE];
319 vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
321 err("alloc vhci_driver");
325 ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
327 err("sysfs must be mounted");
331 ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
335 /* will be freed in usbip_driver_close() */
336 vhci_driver->hc_device = sysfs_open_device("platform", hc_busid);
337 if (!vhci_driver->hc_device) {
338 err("get sysfs vhci_driver");
342 vhci_driver->nports = get_nports();
344 info("%d ports available\n", vhci_driver->nports);
346 vhci_driver->cdev_list = dlist_new(sizeof(struct class_device));
347 if (!vhci_driver->cdev_list)
350 if (refresh_class_device_list())
353 if (refresh_imported_device_list())
361 if (vhci_driver->cdev_list)
362 dlist_destroy(vhci_driver->cdev_list);
363 if (vhci_driver->hc_device)
364 sysfs_close_device(vhci_driver->hc_device);
373 void usbip_vhci_driver_close()
378 if (vhci_driver->cdev_list)
379 dlist_destroy(vhci_driver->cdev_list);
381 for (int i = 0; i < vhci_driver->nports; i++) {
382 if (vhci_driver->idev[i].cdev_list)
383 dlist_destroy(vhci_driver->idev[i].cdev_list);
386 if (vhci_driver->hc_device)
387 sysfs_close_device(vhci_driver->hc_device);
394 int usbip_vhci_refresh_device_list(void)
396 if (vhci_driver->cdev_list)
397 dlist_destroy(vhci_driver->cdev_list);
400 for (int i = 0; i < vhci_driver->nports; i++) {
401 if (vhci_driver->idev[i].cdev_list)
402 dlist_destroy(vhci_driver->idev[i].cdev_list);
405 vhci_driver->cdev_list = dlist_new(sizeof(struct class_device));
406 if (!vhci_driver->cdev_list)
409 if (refresh_class_device_list())
412 if (refresh_imported_device_list())
417 if (vhci_driver->cdev_list)
418 dlist_destroy(vhci_driver->cdev_list);
420 for (int i = 0; i < vhci_driver->nports; i++) {
421 if (vhci_driver->idev[i].cdev_list)
422 dlist_destroy(vhci_driver->idev[i].cdev_list);
425 err("refresh device list");
430 int usbip_vhci_get_free_port(void)
432 for (int i = 0; i < vhci_driver->nports; i++) {
433 if (vhci_driver->idev[i].status == VDEV_ST_NULL)
440 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
442 struct sysfs_attribute *attr_attach;
443 char buff[200]; /* what size should be ? */
446 attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
452 snprintf(buff, sizeof(buff), "%u %u %u %u",
453 port, sockfd, devid, speed);
454 dbg("writing: %s", buff);
456 ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
458 err("write to attach failed");
462 info("port %d attached", port);
467 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
469 return (busnum << 16) | devnum;
472 /* will be removed */
473 int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
474 uint8_t devnum, uint32_t speed)
476 int devid = get_devid(busnum, devnum);
478 return usbip_vhci_attach_device2(port, sockfd, devid, speed);
481 int usbip_vhci_detach_device(uint8_t port)
483 struct sysfs_attribute *attr_detach;
484 char buff[200]; /* what size should be ? */
487 attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
493 snprintf(buff, sizeof(buff), "%u", port);
494 dbg("writing to detach");
495 dbg("writing: %s", buff);
497 ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
499 err("write to detach failed");
503 info("port %d detached", port);