| 1 | |
| 2 | |
| 3 | * Copyright (C) 2015 Karol Kosik <[email protected]>
|
| 4 | * 2015 Samsung Electronics
|
| 5 | * Author: Igor Kotrasinski <[email protected]>
|
| 6 | *
|
| 7 | * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is:
|
| 8 | * Copyright (C) 2011 matt mooney <[email protected]>
|
| 9 | * 2005-2007 Takahiro Hirofuchi
|
| 10 |
|
| 11 |
|
| 12 | #include <fcntl.h>
|
| 13 | #include <string.h>
|
| 14 | #include <linux/usb/ch9.h>
|
| 15 |
|
| 16 | #include <unistd.h>
|
| 17 |
|
| 18 | #include "usbip_host_common.h"
|
| 19 | #include "usbip_device_driver.h"
|
| 20 |
|
| 21 | #undef PROGNAME
|
| 22 | #define PROGNAME "libusbip"
|
| 23 |
|
| 24 | #define copy_descr_attr16(dev, descr, attr) \
|
| 25 | ((dev)->attr = le16toh((descr)->attr)) \
|
| 26 |
|
| 27 | #define copy_descr_attr(dev, descr, attr) \
|
| 28 | ((dev)->attr = (descr)->attr) \
|
| 29 |
|
| 30 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
| 31 |
|
| 32 | static struct {
|
| 33 | enum usb_device_speed speed;
|
| 34 | const char *name;
|
| 35 | } speed_names[] = {
|
| 36 | {
|
| 37 | .speed = USB_SPEED_UNKNOWN,
|
| 38 | .name = "UNKNOWN",
|
| 39 | },
|
| 40 | {
|
| 41 | .speed = USB_SPEED_LOW,
|
| 42 | .name = "low-speed",
|
| 43 | },
|
| 44 | {
|
| 45 | .speed = USB_SPEED_FULL,
|
| 46 | .name = "full-speed",
|
| 47 | },
|
| 48 | {
|
| 49 | .speed = USB_SPEED_HIGH,
|
| 50 | .name = "high-speed",
|
| 51 | },
|
| 52 | {
|
| 53 | .speed = USB_SPEED_WIRELESS,
|
| 54 | .name = "wireless",
|
| 55 | },
|
| 56 | {
|
| 57 | .speed = USB_SPEED_SUPER,
|
| 58 | .name = "super-speed",
|
| 59 | },
|
| 60 | {
|
| 61 | .speed = USB_SPEED_SUPER_PLUS,
|
| 62 | .name = "super-speed-plus",
|
| 63 | },
|
| 64 | };
|
| 65 |
|
| 66 | static
|
| 67 | int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev)
|
| 68 | {
|
| 69 | const char *path, *name;
|
| 70 | char filepath[SYSFS_PATH_MAX];
|
| 71 | struct usb_device_descriptor descr;
|
| 72 | unsigned int i;
|
| 73 | FILE *fd = NULL;
|
| 74 | struct udev_device *plat;
|
| 75 | const char *speed;
|
| 76 | size_t ret;
|
| 77 |
|
| 78 | plat = udev_device_get_parent(sdev);
|
| 79 | path = udev_device_get_syspath(plat);
|
| 80 | snprintf(filepath, SYSFS_PATH_MAX, "%s/%s",
|
| 81 | path, VUDC_DEVICE_DESCR_FILE);
|
| 82 | fd = fopen(filepath, "r");
|
| 83 | if (!fd)
|
| 84 | return -1;
|
| 85 | ret = fread((char *) &descr, sizeof(descr), 1, fd);
|
| 86 | if (ret != 1) {
|
| 87 | err("Cannot read vudc device descr file: %s", strerror(errno));
|
| 88 | goto err;
|
| 89 | }
|
| 90 | fclose(fd);
|
| 91 |
|
| 92 | copy_descr_attr(dev, &descr, bDeviceClass);
|
| 93 | copy_descr_attr(dev, &descr, bDeviceSubClass);
|
| 94 | copy_descr_attr(dev, &descr, bDeviceProtocol);
|
| 95 | copy_descr_attr(dev, &descr, bNumConfigurations);
|
| 96 | copy_descr_attr16(dev, &descr, idVendor);
|
| 97 | copy_descr_attr16(dev, &descr, idProduct);
|
| 98 | copy_descr_attr16(dev, &descr, bcdDevice);
|
| 99 |
|
| 100 | strncpy(dev->path, path, SYSFS_PATH_MAX - 1);
|
| 101 | dev->path[SYSFS_PATH_MAX - 1] = '\0';
|
| 102 |
|
| 103 | dev->speed = USB_SPEED_UNKNOWN;
|
| 104 | speed = udev_device_get_sysattr_value(sdev, "current_speed");
|
| 105 | if (speed) {
|
| 106 | for (i = 0; i < ARRAY_SIZE(speed_names); i++) {
|
| 107 | if (!strcmp(speed_names[i].name, speed)) {
|
| 108 | dev->speed = speed_names[i].speed;
|
| 109 | break;
|
| 110 | }
|
| 111 | }
|
| 112 | }
|
| 113 |
|
| 114 |
|
| 115 | dev->bNumInterfaces = 0;
|
| 116 | dev->bConfigurationValue = 0;
|
| 117 | dev->busnum = 0;
|
| 118 |
|
| 119 | name = udev_device_get_sysname(plat);
|
| 120 | strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE - 1);
|
| 121 | dev->busid[SYSFS_BUS_ID_SIZE - 1] = '\0';
|
| 122 | return 0;
|
| 123 | err:
|
| 124 | fclose(fd);
|
| 125 | return -1;
|
| 126 | }
|
| 127 |
|
| 128 | static int is_my_device(struct udev_device *dev)
|
| 129 | {
|
| 130 | const char *driver;
|
| 131 |
|
| 132 | driver = udev_device_get_property_value(dev, "USB_UDC_NAME");
|
| 133 | return driver != NULL && !strcmp(driver, USBIP_DEVICE_DRV_NAME);
|
| 134 | }
|
| 135 |
|
| 136 | static int usbip_device_driver_open(struct usbip_host_driver *hdriver)
|
| 137 | {
|
| 138 | int ret;
|
| 139 |
|
| 140 | hdriver->ndevs = 0;
|
| 141 | INIT_LIST_HEAD(&hdriver->edev_list);
|
| 142 |
|
| 143 | ret = usbip_generic_driver_open(hdriver);
|
| 144 | if (ret || hdriver->ndevs == 0)
|
| 145 | info("please load " USBIP_CORE_MOD_NAME ".ko and "
|
| 146 | USBIP_DEVICE_DRV_NAME ".ko");
|
| 147 |
|
| 148 | return ret;
|
| 149 | }
|
| 150 |
|
| 151 | struct usbip_host_driver device_driver = {
|
| 152 | .edev_list = LIST_HEAD_INIT(device_driver.edev_list),
|
| 153 | .udev_subsystem = "udc",
|
| 154 | .ops = {
|
| 155 | .open = usbip_device_driver_open,
|
| 156 | .close = usbip_generic_driver_close,
|
| 157 | .refresh_device_list = usbip_generic_refresh_device_list,
|
| 158 | .get_device = usbip_generic_get_device,
|
| 159 | .read_device = read_usb_vudc_device,
|
| 160 | .is_my_device = is_my_device,
|
| 161 | },
|
| 162 | };
|