18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2015 Karol Kosik <karo9@interia.eu> 48c2ecf20Sopenharmony_ci * 2015 Samsung Electronics 58c2ecf20Sopenharmony_ci * Author: Igor Kotrasinski <i.kotrasinsk@samsung.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Based on tools/usb/usbip/libsrc/usbip_host_driver.c, which is: 88c2ecf20Sopenharmony_ci * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> 98c2ecf20Sopenharmony_ci * 2005-2007 Takahiro Hirofuchi 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <fcntl.h> 138c2ecf20Sopenharmony_ci#include <string.h> 148c2ecf20Sopenharmony_ci#include <linux/usb/ch9.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <unistd.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "usbip_host_common.h" 198c2ecf20Sopenharmony_ci#include "usbip_device_driver.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#undef PROGNAME 228c2ecf20Sopenharmony_ci#define PROGNAME "libusbip" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define copy_descr_attr16(dev, descr, attr) \ 258c2ecf20Sopenharmony_ci ((dev)->attr = le16toh((descr)->attr)) \ 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define copy_descr_attr(dev, descr, attr) \ 288c2ecf20Sopenharmony_ci ((dev)->attr = (descr)->attr) \ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct { 338c2ecf20Sopenharmony_ci enum usb_device_speed speed; 348c2ecf20Sopenharmony_ci const char *name; 358c2ecf20Sopenharmony_ci} speed_names[] = { 368c2ecf20Sopenharmony_ci { 378c2ecf20Sopenharmony_ci .speed = USB_SPEED_UNKNOWN, 388c2ecf20Sopenharmony_ci .name = "UNKNOWN", 398c2ecf20Sopenharmony_ci }, 408c2ecf20Sopenharmony_ci { 418c2ecf20Sopenharmony_ci .speed = USB_SPEED_LOW, 428c2ecf20Sopenharmony_ci .name = "low-speed", 438c2ecf20Sopenharmony_ci }, 448c2ecf20Sopenharmony_ci { 458c2ecf20Sopenharmony_ci .speed = USB_SPEED_FULL, 468c2ecf20Sopenharmony_ci .name = "full-speed", 478c2ecf20Sopenharmony_ci }, 488c2ecf20Sopenharmony_ci { 498c2ecf20Sopenharmony_ci .speed = USB_SPEED_HIGH, 508c2ecf20Sopenharmony_ci .name = "high-speed", 518c2ecf20Sopenharmony_ci }, 528c2ecf20Sopenharmony_ci { 538c2ecf20Sopenharmony_ci .speed = USB_SPEED_WIRELESS, 548c2ecf20Sopenharmony_ci .name = "wireless", 558c2ecf20Sopenharmony_ci }, 568c2ecf20Sopenharmony_ci { 578c2ecf20Sopenharmony_ci .speed = USB_SPEED_SUPER, 588c2ecf20Sopenharmony_ci .name = "super-speed", 598c2ecf20Sopenharmony_ci }, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic 638c2ecf20Sopenharmony_ciint read_usb_vudc_device(struct udev_device *sdev, struct usbip_usb_device *dev) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci const char *path, *name; 668c2ecf20Sopenharmony_ci char filepath[SYSFS_PATH_MAX]; 678c2ecf20Sopenharmony_ci struct usb_device_descriptor descr; 688c2ecf20Sopenharmony_ci unsigned int i; 698c2ecf20Sopenharmony_ci FILE *fd = NULL; 708c2ecf20Sopenharmony_ci struct udev_device *plat; 718c2ecf20Sopenharmony_ci const char *speed; 728c2ecf20Sopenharmony_ci size_t ret; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci plat = udev_device_get_parent(sdev); 758c2ecf20Sopenharmony_ci path = udev_device_get_syspath(plat); 768c2ecf20Sopenharmony_ci snprintf(filepath, SYSFS_PATH_MAX, "%s/%s", 778c2ecf20Sopenharmony_ci path, VUDC_DEVICE_DESCR_FILE); 788c2ecf20Sopenharmony_ci fd = fopen(filepath, "r"); 798c2ecf20Sopenharmony_ci if (!fd) 808c2ecf20Sopenharmony_ci return -1; 818c2ecf20Sopenharmony_ci ret = fread((char *) &descr, sizeof(descr), 1, fd); 828c2ecf20Sopenharmony_ci if (ret != 1) { 838c2ecf20Sopenharmony_ci err("Cannot read vudc device descr file: %s", strerror(errno)); 848c2ecf20Sopenharmony_ci goto err; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci fclose(fd); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci copy_descr_attr(dev, &descr, bDeviceClass); 898c2ecf20Sopenharmony_ci copy_descr_attr(dev, &descr, bDeviceSubClass); 908c2ecf20Sopenharmony_ci copy_descr_attr(dev, &descr, bDeviceProtocol); 918c2ecf20Sopenharmony_ci copy_descr_attr(dev, &descr, bNumConfigurations); 928c2ecf20Sopenharmony_ci copy_descr_attr16(dev, &descr, idVendor); 938c2ecf20Sopenharmony_ci copy_descr_attr16(dev, &descr, idProduct); 948c2ecf20Sopenharmony_ci copy_descr_attr16(dev, &descr, bcdDevice); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci strncpy(dev->path, path, SYSFS_PATH_MAX - 1); 978c2ecf20Sopenharmony_ci dev->path[SYSFS_PATH_MAX - 1] = '\0'; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci dev->speed = USB_SPEED_UNKNOWN; 1008c2ecf20Sopenharmony_ci speed = udev_device_get_sysattr_value(sdev, "current_speed"); 1018c2ecf20Sopenharmony_ci if (speed) { 1028c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(speed_names); i++) { 1038c2ecf20Sopenharmony_ci if (!strcmp(speed_names[i].name, speed)) { 1048c2ecf20Sopenharmony_ci dev->speed = speed_names[i].speed; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Only used for user output, little sense to output them in general */ 1118c2ecf20Sopenharmony_ci dev->bNumInterfaces = 0; 1128c2ecf20Sopenharmony_ci dev->bConfigurationValue = 0; 1138c2ecf20Sopenharmony_ci dev->busnum = 0; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci name = udev_device_get_sysname(plat); 1168c2ecf20Sopenharmony_ci strncpy(dev->busid, name, SYSFS_BUS_ID_SIZE - 1); 1178c2ecf20Sopenharmony_ci dev->busid[SYSFS_BUS_ID_SIZE - 1] = '\0'; 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_cierr: 1208c2ecf20Sopenharmony_ci fclose(fd); 1218c2ecf20Sopenharmony_ci return -1; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic int is_my_device(struct udev_device *dev) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci const char *driver; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci driver = udev_device_get_property_value(dev, "USB_UDC_NAME"); 1298c2ecf20Sopenharmony_ci return driver != NULL && !strcmp(driver, USBIP_DEVICE_DRV_NAME); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int usbip_device_driver_open(struct usbip_host_driver *hdriver) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int ret; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci hdriver->ndevs = 0; 1378c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hdriver->edev_list); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci ret = usbip_generic_driver_open(hdriver); 1408c2ecf20Sopenharmony_ci if (ret) 1418c2ecf20Sopenharmony_ci err("please load " USBIP_CORE_MOD_NAME ".ko and " 1428c2ecf20Sopenharmony_ci USBIP_DEVICE_DRV_NAME ".ko!"); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistruct usbip_host_driver device_driver = { 1488c2ecf20Sopenharmony_ci .edev_list = LIST_HEAD_INIT(device_driver.edev_list), 1498c2ecf20Sopenharmony_ci .udev_subsystem = "udc", 1508c2ecf20Sopenharmony_ci .ops = { 1518c2ecf20Sopenharmony_ci .open = usbip_device_driver_open, 1528c2ecf20Sopenharmony_ci .close = usbip_generic_driver_close, 1538c2ecf20Sopenharmony_ci .refresh_device_list = usbip_generic_refresh_device_list, 1548c2ecf20Sopenharmony_ci .get_device = usbip_generic_get_device, 1558c2ecf20Sopenharmony_ci .read_device = read_usb_vudc_device, 1568c2ecf20Sopenharmony_ci .is_my_device = is_my_device, 1578c2ecf20Sopenharmony_ci }, 1588c2ecf20Sopenharmony_ci}; 159