GNU Linux-libre 4.14.302-gnu1
[releases.git] / tools / usb / usbip / libsrc / usbip_device_driver.c
1 /*
2  * Copyright (C) 2015 Karol Kosik <karo9@interia.eu>
3  *               2015 Samsung Electronics
4  * Author:       Igor Kotrasinski <i.kotrasinsk@samsung.com>
5  *
6  * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is:
7  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
8  *               2005-2007 Takahiro Hirofuchi
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <fcntl.h>
25 #include <string.h>
26 #include <linux/usb/ch9.h>
27
28 #include <unistd.h>
29
30 #include "usbip_host_common.h"
31 #include "usbip_device_driver.h"
32
33 #undef  PROGNAME
34 #define PROGNAME "libusbip"
35
36 #define copy_descr_attr16(dev, descr, attr)                     \
37                 ((dev)->attr = le16toh((descr)->attr))          \
38
39 #define copy_descr_attr(dev, descr, attr)                       \
40                 ((dev)->attr = (descr)->attr)                   \
41
42 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
43
44 static struct {
45         enum usb_device_speed speed;
46         const char *name;
47 } speed_names[] = {
48         {
49                 .speed = USB_SPEED_UNKNOWN,
50                 .name = "UNKNOWN",
51         },
52         {
53                 .speed = USB_SPEED_LOW,
54                 .name = "low-speed",
55         },
56         {
57                 .speed = USB_SPEED_FULL,
58                 .name = "full-speed",
59         },
60         {
61                 .speed = USB_SPEED_HIGH,
62                 .name = "high-speed",
63         },
64         {
65                 .speed = USB_SPEED_WIRELESS,
66                 .name = "wireless",
67         },
68         {
69                 .speed = USB_SPEED_SUPER,
70                 .name = "super-speed",
71         },
72 };
73
74 static
75 int read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev)
76 {
77         const char *path, *name;
78         char filepath[SYSFS_PATH_MAX];
79         struct usb_device_descriptor descr;
80         unsigned i;
81         FILE *fd = NULL;
82         struct udev_device *plat;
83         const char *speed;
84         int ret = 0;
85
86         plat = udev_device_get_parent(sdev);
87         path = udev_device_get_syspath(plat);
88         snprintf(filepath, SYSFS_PATH_MAX, "%s/%s",
89                  path, VUDC_DEVICE_DESCR_FILE);
90         fd = fopen(filepath, "r");
91         if (!fd)
92                 return -1;
93         ret = fread((char *) &descr, sizeof(descr), 1, fd);
94         if (ret < 0)
95                 return -1;
96         fclose(fd);
97
98         copy_descr_attr(dev, &descr, bDeviceClass);
99         copy_descr_attr(dev, &descr, bDeviceSubClass);
100         copy_descr_attr(dev, &descr, bDeviceProtocol);
101         copy_descr_attr(dev, &descr, bNumConfigurations);
102         copy_descr_attr16(dev, &descr, idVendor);
103         copy_descr_attr16(dev, &descr, idProduct);
104         copy_descr_attr16(dev, &descr, bcdDevice);
105
106         strncpy(dev->path, path, SYSFS_PATH_MAX);
107
108         dev->speed = USB_SPEED_UNKNOWN;
109         speed = udev_device_get_sysattr_value(sdev, "current_speed");
110         if (speed) {
111                 for (i = 0; i < ARRAY_SIZE(speed_names); i++) {
112                         if (!strcmp(speed_names[i].name, speed)) {
113                                 dev->speed = speed_names[i].speed;
114                                 break;
115                         }
116                 }
117         }
118
119         /* Only used for user output, little sense to output them in general */
120         dev->bNumInterfaces = 0;
121         dev->bConfigurationValue = 0;
122         dev->busnum = 0;
123
124         name = udev_device_get_sysname(plat);
125         strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE);
126         return 0;
127 }
128
129 static int is_my_device(struct udev_device *dev)
130 {
131         const char *driver;
132
133         driver = udev_device_get_property_value(dev, "USB_UDC_NAME");
134         return driver != NULL && !strcmp(driver, USBIP_DEVICE_DRV_NAME);
135 }
136
137 static int usbip_device_driver_open(struct usbip_host_driver *hdriver)
138 {
139         int ret;
140
141         hdriver->ndevs = 0;
142         INIT_LIST_HEAD(&hdriver->edev_list);
143
144         ret = usbip_generic_driver_open(hdriver);
145         if (ret)
146                 err("please load " USBIP_CORE_MOD_NAME ".ko and "
147                     USBIP_DEVICE_DRV_NAME ".ko!");
148
149         return ret;
150 }
151
152 struct usbip_host_driver device_driver = {
153         .edev_list = LIST_HEAD_INIT(device_driver.edev_list),
154         .udev_subsystem = "udc",
155         .ops = {
156                 .open = usbip_device_driver_open,
157                 .close = usbip_generic_driver_close,
158                 .refresh_device_list = usbip_generic_refresh_device_list,
159                 .get_device = usbip_generic_get_device,
160                 .read_device = read_usb_vudc_device,
161                 .is_my_device = is_my_device,
162         },
163 };