diff options
Diffstat (limited to 'drivers/staging/usbip')
48 files changed, 1935 insertions, 2289 deletions
diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig index dd13c022068..bd99e9e47e5 100644 --- a/drivers/staging/usbip/Kconfig +++ b/drivers/staging/usbip/Kconfig @@ -1,14 +1,13 @@ config USBIP_CORE - tristate "USB/IP support (EXPERIMENTAL)" - depends on USB && NET && EXPERIMENTAL - default N + tristate "USB/IP support" + depends on USB && NET ---help--- This enables pushing USB packets over IP to allow remote machines direct access to USB devices. It provides the USB/IP core that is required by both drivers. For more details, and to get the userspace utility - programs, please see http://usbip.sourceforge.net/. + programs, please see <http://usbip.sourceforge.net/>. To compile this as a module, choose M here: the module will be called usbip-core. @@ -18,7 +17,6 @@ config USBIP_CORE config USBIP_VHCI_HCD tristate "VHCI hcd" depends on USBIP_CORE - default N ---help--- This enables the USB/IP virtual host controller driver, which is run on the remote machine. @@ -29,7 +27,6 @@ config USBIP_VHCI_HCD config USBIP_HOST tristate "Host driver" depends on USBIP_CORE - default N ---help--- This enables the USB/IP host driver, which is run on the machine that is sharing the USB devices. @@ -40,6 +37,5 @@ config USBIP_HOST config USBIP_DEBUG bool "Debug messages for USB/IP" depends on USBIP_CORE - default N ---help--- This enables the debug messages from the USB/IP drivers. diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h index d4073684eac..266e2b0ce9a 100644 --- a/drivers/staging/usbip/stub.h +++ b/drivers/staging/usbip/stub.h @@ -35,7 +35,6 @@ struct stub_device { struct usb_interface *interface; struct usb_device *udev; - struct list_head list; struct usbip_device ud; __u32 devid; @@ -87,6 +86,7 @@ struct bus_id_priv { char status; int interf_count; struct stub_device *sdev; + struct usb_device *udev; char shutdown_busid; }; @@ -94,7 +94,7 @@ struct bus_id_priv { extern struct kmem_cache *stub_priv_cache; /* stub_dev.c */ -extern struct usb_driver stub_driver; +extern struct usb_device_driver stub_driver; /* stub_main.c */ struct bus_id_priv *get_busid_priv(const char *busid); diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 03420e25d9c..51d0c718873 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -18,6 +18,7 @@ */ #include <linux/device.h> +#include <linux/file.h> #include <linux/kthread.h> #include <linux/module.h> @@ -55,8 +56,8 @@ MODULE_DEVICE_TABLE(usb, stub_table); * usbip_status shows the status of usbip-host as long as this driver is bound * to the target device. */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t usbip_status_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct stub_device *sdev = dev_get_drvdata(dev); int status; @@ -66,13 +67,13 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, return -ENODEV; } - spin_lock(&sdev->ud.lock); + spin_lock_irq(&sdev->ud.lock); status = sdev->ud.status; - spin_unlock(&sdev->ud.lock); + spin_unlock_irq(&sdev->ud.lock); return snprintf(buf, PAGE_SIZE, "%d\n", status); } -static DEVICE_ATTR(usbip_status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR_RO(usbip_status); /* * usbip_sockfd gets a socket descriptor of an established TCP connection that @@ -85,55 +86,63 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, struct stub_device *sdev = dev_get_drvdata(dev); int sockfd = 0; struct socket *socket; + int rv; if (!sdev) { dev_err(dev, "sdev is null\n"); return -ENODEV; } - sscanf(buf, "%d", &sockfd); + rv = sscanf(buf, "%d", &sockfd); + if (rv != 1) + return -EINVAL; if (sockfd != -1) { + int err; + dev_info(dev, "stub up\n"); - spin_lock(&sdev->ud.lock); + spin_lock_irq(&sdev->ud.lock); if (sdev->ud.status != SDEV_ST_AVAILABLE) { dev_err(dev, "not ready\n"); - spin_unlock(&sdev->ud.lock); - return -EINVAL; + goto err; } - socket = sockfd_to_socket(sockfd); - if (!socket) { - spin_unlock(&sdev->ud.lock); - return -EINVAL; - } + socket = sockfd_lookup(sockfd, &err); + if (!socket) + goto err; + sdev->ud.tcp_socket = socket; - spin_unlock(&sdev->ud.lock); + spin_unlock_irq(&sdev->ud.lock); - sdev->ud.tcp_rx = kthread_run(stub_rx_loop, &sdev->ud, "stub_rx"); - sdev->ud.tcp_tx = kthread_run(stub_tx_loop, &sdev->ud, "stub_tx"); + sdev->ud.tcp_rx = kthread_get_run(stub_rx_loop, &sdev->ud, + "stub_rx"); + sdev->ud.tcp_tx = kthread_get_run(stub_tx_loop, &sdev->ud, + "stub_tx"); - spin_lock(&sdev->ud.lock); + spin_lock_irq(&sdev->ud.lock); sdev->ud.status = SDEV_ST_USED; - spin_unlock(&sdev->ud.lock); + spin_unlock_irq(&sdev->ud.lock); } else { dev_info(dev, "stub down\n"); - spin_lock(&sdev->ud.lock); - if (sdev->ud.status != SDEV_ST_USED) { - spin_unlock(&sdev->ud.lock); - return -EINVAL; - } - spin_unlock(&sdev->ud.lock); + spin_lock_irq(&sdev->ud.lock); + if (sdev->ud.status != SDEV_ST_USED) + goto err; + + spin_unlock_irq(&sdev->ud.lock); usbip_event_add(&sdev->ud, SDEV_EVENT_DOWN); } return count; + +err: + spin_unlock_irq(&sdev->ud.lock); + return -EINVAL; } static DEVICE_ATTR(usbip_sockfd, S_IWUSR, NULL, store_sockfd); @@ -187,10 +196,14 @@ static void stub_shutdown_connection(struct usbip_device *ud) } /* 1. stop threads */ - if (ud->tcp_rx && !task_is_dead(ud->tcp_rx)) - kthread_stop(ud->tcp_rx); - if (ud->tcp_tx && !task_is_dead(ud->tcp_tx)) - kthread_stop(ud->tcp_tx); + if (ud->tcp_rx) { + kthread_stop_put(ud->tcp_rx); + ud->tcp_rx = NULL; + } + if (ud->tcp_tx) { + kthread_stop_put(ud->tcp_tx); + ud->tcp_tx = NULL; + } /* * 2. close the socket @@ -199,7 +212,7 @@ static void stub_shutdown_connection(struct usbip_device *ud) * not touch NULL socket. */ if (ud->tcp_socket) { - sock_release(ud->tcp_socket); + sockfd_put(ud->tcp_socket); ud->tcp_socket = NULL; } @@ -236,9 +249,9 @@ static void stub_device_reset(struct usbip_device *ud) ret = usb_lock_device_for_reset(udev, sdev->interface); if (ret < 0) { dev_err(&udev->dev, "lock for reset\n"); - spin_lock(&ud->lock); + spin_lock_irq(&ud->lock); ud->status = SDEV_ST_ERROR; - spin_unlock(&ud->lock); + spin_unlock_irq(&ud->lock); return; } @@ -246,7 +259,7 @@ static void stub_device_reset(struct usbip_device *ud) ret = usb_reset_device(udev); usb_unlock_device(udev); - spin_lock(&ud->lock); + spin_lock_irq(&ud->lock); if (ret) { dev_err(&udev->dev, "device reset\n"); ud->status = SDEV_ST_ERROR; @@ -254,14 +267,14 @@ static void stub_device_reset(struct usbip_device *ud) dev_info(&udev->dev, "device reset\n"); ud->status = SDEV_ST_AVAILABLE; } - spin_unlock(&ud->lock); + spin_unlock_irq(&ud->lock); } static void stub_device_unusable(struct usbip_device *ud) { - spin_lock(&ud->lock); + spin_lock_irq(&ud->lock); ud->status = SDEV_ST_ERROR; - spin_unlock(&ud->lock); + spin_unlock_irq(&ud->lock); } /** @@ -270,23 +283,19 @@ static void stub_device_unusable(struct usbip_device *ud) * * Allocates and initializes a new stub_device struct. */ -static struct stub_device *stub_device_alloc(struct usb_device *udev, - struct usb_interface *interface) +static struct stub_device *stub_device_alloc(struct usb_device *udev) { struct stub_device *sdev; - int busnum = interface_to_busnum(interface); - int devnum = interface_to_devnum(interface); + int busnum = udev->bus->busnum; + int devnum = udev->devnum; - dev_dbg(&interface->dev, "allocating stub device"); + dev_dbg(&udev->dev, "allocating stub device"); /* yes, it's a new device */ sdev = kzalloc(sizeof(struct stub_device), GFP_KERNEL); - if (!sdev) { - dev_err(&interface->dev, "no memory for stub_device\n"); + if (!sdev) return NULL; - } - sdev->interface = usb_get_intf(interface); sdev->udev = usb_get_dev(udev); /* @@ -297,7 +306,6 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev, sdev->devid = (busnum << 16) | devnum; sdev->ud.side = USBIP_STUB; sdev->ud.status = SDEV_ST_AVAILABLE; - /* sdev->ud.lock = SPIN_LOCK_UNLOCKED; */ spin_lock_init(&sdev->ud.lock); sdev->ud.tcp_socket = NULL; @@ -306,7 +314,6 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev, INIT_LIST_HEAD(&sdev->priv_free); INIT_LIST_HEAD(&sdev->unlink_free); INIT_LIST_HEAD(&sdev->unlink_tx); - /* sdev->priv_lock = SPIN_LOCK_UNLOCKED; */ spin_lock_init(&sdev->priv_lock); init_waitqueue_head(&sdev->tx_waitq); @@ -317,49 +324,33 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev, usbip_start_eh(&sdev->ud); - dev_dbg(&interface->dev, "register new interface\n"); + dev_dbg(&udev->dev, "register new device\n"); return sdev; } -static int stub_device_free(struct stub_device *sdev) +static void stub_device_free(struct stub_device *sdev) { - if (!sdev) - return -EINVAL; - kfree(sdev); - pr_debug("kfree udev ok\n"); - - return 0; } -/* - * If a usb device has multiple active interfaces, this driver is bound to all - * the active interfaces. However, usbip exports *a* usb device (i.e., not *an* - * active interface). Currently, a userland program must ensure that it - * looks at the usbip's sysfs entries of only the first active interface. - * - * TODO: use "struct usb_device_driver" to bind a usb device. - * However, it seems it is not fully supported in mainline kernel yet - * (2.6.19.2). - */ -static int stub_probe(struct usb_interface *interface, - const struct usb_device_id *id) +static int stub_probe(struct usb_device *udev) { - struct usb_device *udev = interface_to_usbdev(interface); struct stub_device *sdev = NULL; - const char *udev_busid = dev_name(interface->dev.parent); + const char *udev_busid = dev_name(&udev->dev); int err = 0; struct bus_id_priv *busid_priv; + int rc; - dev_dbg(&interface->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter\n"); /* check we should claim or not by busid_table */ busid_priv = get_busid_priv(udev_busid); if (!busid_priv || (busid_priv->status == STUB_BUSID_REMOV) || (busid_priv->status == STUB_BUSID_OTHER)) { - dev_info(&interface->dev, "%s is not in match_busid table... " - "skip!\n", udev_busid); + dev_info(&udev->dev, + "%s is not in match_busid table... skip!\n", + udev_busid); /* * Return value should be ENODEV or ENOXIO to continue trying @@ -376,62 +367,48 @@ static int stub_probe(struct usb_interface *interface, } if (!strcmp(udev->bus->bus_name, "vhci_hcd")) { - dev_dbg(&udev->dev, "%s is attached on vhci_hcd... skip!\n", - udev_busid); - return -ENODEV; - } - - if (busid_priv->status == STUB_BUSID_ALLOC) { - sdev = busid_priv->sdev; - if (!sdev) - return -ENODEV; - - busid_priv->interf_count++; - dev_info(&interface->dev, "usbip-host: register new interface " - "(bus %u dev %u ifn %u)\n", - udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); - - /* set private data to usb_interface */ - usb_set_intfdata(interface, sdev); - - err = stub_add_files(&interface->dev); - if (err) { - dev_err(&interface->dev, "stub_add_files for %s\n", - udev_busid); - usb_set_intfdata(interface, NULL); - busid_priv->interf_count--; - return err; - } + dev_dbg(&udev->dev, + "%s is attached on vhci_hcd... skip!\n", + udev_busid); - usb_get_intf(interface); - return 0; + return -ENODEV; } /* ok, this is my device */ - sdev = stub_device_alloc(udev, interface); + sdev = stub_device_alloc(udev); if (!sdev) return -ENOMEM; - dev_info(&interface->dev, "usbip-host: register new device " - "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, - interface->cur_altsetting->desc.bInterfaceNumber); + dev_info(&udev->dev, + "usbip-host: register new device (bus %u dev %u)\n", + udev->bus->busnum, udev->devnum); - busid_priv->interf_count = 0; busid_priv->shutdown_busid = 0; - /* set private data to usb_interface */ - usb_set_intfdata(interface, sdev); - busid_priv->interf_count++; + /* set private data to usb_device */ + dev_set_drvdata(&udev->dev, sdev); busid_priv->sdev = sdev; + busid_priv->udev = udev; + + /* + * Claim this hub port. + * It doesn't matter what value we pass as owner + * (struct dev_state) as long as it is unique. + */ + rc = usb_hub_claim_port(udev->parent, udev->portnum, + (struct usb_dev_state *) udev); + if (rc) { + dev_dbg(&udev->dev, "unable to claim port\n"); + return rc; + } - err = stub_add_files(&interface->dev); + err = stub_add_files(&udev->dev); if (err) { - dev_err(&interface->dev, "stub_add_files for %s\n", udev_busid); - usb_set_intfdata(interface, NULL); - usb_put_intf(interface); + dev_err(&udev->dev, "stub_add_files for %s\n", udev_busid); + dev_set_drvdata(&udev->dev, NULL); + usb_put_dev(udev); + kthread_stop_put(sdev->ud.eh); - busid_priv->interf_count = 0; busid_priv->sdev = NULL; stub_device_free(sdev); return err; @@ -447,7 +424,7 @@ static void shutdown_busid(struct bus_id_priv *busid_priv) busid_priv->shutdown_busid = 1; usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED); - /* 2. wait for the stop of the event handler */ + /* wait for the stop of the event handler */ usbip_stop_eh(&busid_priv->sdev->ud); } } @@ -456,13 +433,14 @@ static void shutdown_busid(struct bus_id_priv *busid_priv) * called in usb_disconnect() or usb_deregister() * but only if actconfig(active configuration) exists */ -static void stub_disconnect(struct usb_interface *interface) +static void stub_disconnect(struct usb_device *udev) { struct stub_device *sdev; - const char *udev_busid = dev_name(interface->dev.parent); + const char *udev_busid = dev_name(&udev->dev); struct bus_id_priv *busid_priv; + int rc; - dev_dbg(&interface->dev, "Enter\n"); + dev_dbg(&udev->dev, "Enter\n"); busid_priv = get_busid_priv(udev_busid); if (!busid_priv) { @@ -470,45 +448,39 @@ static void stub_disconnect(struct usb_interface *interface) return; } - sdev = usb_get_intfdata(interface); + sdev = dev_get_drvdata(&udev->dev); /* get stub_device */ if (!sdev) { - dev_err(&interface->dev, "could not get device"); - /* BUG(); */ + dev_err(&udev->dev, "could not get device"); return; } - usb_set_intfdata(interface, NULL); + dev_set_drvdata(&udev->dev, NULL); /* - * NOTE: - * rx/tx threads are invoked for each usb_device. + * NOTE: rx/tx threads are invoked for each usb_device. */ - stub_remove_files(&interface->dev); + stub_remove_files(&udev->dev); - /*If usb reset called from event handler*/ - if (busid_priv->sdev->ud.eh == current) { - busid_priv->interf_count--; + /* release port */ + rc = usb_hub_release_port(udev->parent, udev->portnum, + (struct usb_dev_state *) udev); + if (rc) { + dev_dbg(&udev->dev, "unable to release port\n"); return; } - if (busid_priv->interf_count > 1) { - busid_priv->interf_count--; - shutdown_busid(busid_priv); - usb_put_intf(interface); + /* If usb reset is called from event handler */ + if (busid_priv->sdev->ud.eh == current) return; - } - - busid_priv->interf_count = 0; - /* 1. shutdown the current connection */ + /* shutdown the current connection */ shutdown_busid(busid_priv); usb_put_dev(sdev->udev); - usb_put_intf(interface); - /* 3. free sdev */ + /* free sdev */ busid_priv->sdev = NULL; stub_device_free(sdev); @@ -520,28 +492,34 @@ static void stub_disconnect(struct usb_interface *interface) } } -/* - * Presence of pre_reset and post_reset prevents the driver from being unbound - * when the device is being reset - */ +#ifdef CONFIG_PM -int stub_pre_reset(struct usb_interface *interface) +/* These functions need usb_port_suspend and usb_port_resume, + * which reside in drivers/usb/core/usb.h. Skip for now. */ + +static int stub_suspend(struct usb_device *udev, pm_message_t message) { - dev_dbg(&interface->dev, "pre_reset\n"); + dev_dbg(&udev->dev, "stub_suspend\n"); + return 0; } -int stub_post_reset(struct usb_interface *interface) +static int stub_resume(struct usb_device *udev, pm_message_t message) { - dev_dbg(&interface->dev, "post_reset\n"); + dev_dbg(&udev->dev, "stub_resume\n"); + return 0; } -struct usb_driver stub_driver = { +#endif /* CONFIG_PM */ + +struct usb_device_driver stub_driver = { .name = "usbip-host", .probe = stub_probe, .disconnect = stub_disconnect, - .id_table = stub_table, - .pre_reset = stub_pre_reset, - .post_reset = stub_post_reset, +#ifdef CONFIG_PM + .suspend = stub_suspend, + .resume = stub_resume, +#endif + .supports_autosuspend = 0, }; diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c index 705a9e530a1..9c5832abbdf 100644 --- a/drivers/staging/usbip/stub_main.c +++ b/drivers/staging/usbip/stub_main.c @@ -19,6 +19,7 @@ #include <linux/string.h> #include <linux/module.h> +#include <linux/device.h> #include "usbip_common.h" #include "stub.h" @@ -38,11 +39,11 @@ static spinlock_t busid_table_lock; static void init_busid_table(void) { - int i; - + /* + * This also sets the bus_table[i].status to + * STUB_BUSID_OTHER, which is 0. + */ memset(busid_table, 0, sizeof(busid_table)); - for (i = 0; i < MAX_BUSID; i++) - busid_table[i].status = STUB_BUSID_OTHER; spin_lock_init(&busid_table_lock); } @@ -167,26 +168,54 @@ static ssize_t store_match_busid(struct device_driver *dev, const char *buf, strncpy(busid, buf + 4, BUSID_SIZE); if (!strncmp(buf, "add ", 4)) { - if (add_match_busid(busid) < 0) { + if (add_match_busid(busid) < 0) return -ENOMEM; - } else { - pr_debug("add busid %s\n", busid); - return count; - } - } else if (!strncmp(buf, "del ", 4)) { - if (del_match_busid(busid) < 0) { + + pr_debug("add busid %s\n", busid); + return count; + } + + if (!strncmp(buf, "del ", 4)) { + if (del_match_busid(busid) < 0) return -ENODEV; - } else { - pr_debug("del busid %s\n", busid); - return count; - } - } else { - return -EINVAL; + + pr_debug("del busid %s\n", busid); + return count; } + + return -EINVAL; } static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid, store_match_busid); +static ssize_t rebind_store(struct device_driver *dev, const char *buf, + size_t count) +{ + int ret; + int len; + struct bus_id_priv *bid; + + /* buf length should be less that BUSID_SIZE */ + len = strnlen(buf, BUSID_SIZE); + + if (!(len < BUSID_SIZE)) + return -EINVAL; + + bid = get_busid_priv(buf); + if (!bid) + return -ENODEV; + + ret = device_attach(&bid->udev->dev); + if (ret < 0) { + dev_err(&bid->udev->dev, "rebind failed\n"); + return ret; + } + + return count; +} + +static DRIVER_ATTR_WO(rebind); + static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead) { struct stub_priv *priv, *tmp; @@ -254,15 +283,22 @@ static int __init usbip_host_init(void) return -ENOMEM; } - ret = usb_register(&stub_driver); - if (ret < 0) { + ret = usb_register_device_driver(&stub_driver, THIS_MODULE); + if (ret) { pr_err("usb_register failed %d\n", ret); goto err_usb_register; } ret = driver_create_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); - if (ret < 0) { + if (ret) { + pr_err("driver_create_file failed\n"); + goto err_create_file; + } + + ret = driver_create_file(&stub_driver.drvwrap.driver, + &driver_attr_rebind); + if (ret) { pr_err("driver_create_file failed\n"); goto err_create_file; } @@ -271,7 +307,7 @@ static int __init usbip_host_init(void) return ret; err_create_file: - usb_deregister(&stub_driver); + usb_deregister_device_driver(&stub_driver); err_usb_register: kmem_cache_destroy(stub_priv_cache); return ret; @@ -282,11 +318,14 @@ static void __exit usbip_host_exit(void) driver_remove_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); + driver_remove_file(&stub_driver.drvwrap.driver, + &driver_attr_rebind); + /* * deregister() calls stub_disconnect() for all devices. Device * specific data is cleared in stub_disconnect(). */ - usb_deregister(&stub_driver); + usb_deregister_device_driver(&stub_driver); kmem_cache_destroy(stub_priv_cache); } diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 27ac363d1cf..e0b6d6b4272 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -102,11 +102,13 @@ static int tweak_clear_halt_cmd(struct urb *urb) ret = usb_clear_halt(urb->dev, target_pipe); if (ret < 0) - dev_err(&urb->dev->dev, "usb_clear_halt error: devnum %d endp " - "%d ret %d\n", urb->dev->devnum, target_endp, ret); + dev_err(&urb->dev->dev, + "usb_clear_halt error: devnum %d endp %d ret %d\n", + urb->dev->devnum, target_endp, ret); else - dev_info(&urb->dev->dev, "usb_clear_halt done: devnum %d endp " - "%d\n", urb->dev->devnum, target_endp); + dev_info(&urb->dev->dev, + "usb_clear_halt done: devnum %d endp %d\n", + urb->dev->devnum, target_endp); return ret; } @@ -127,44 +129,33 @@ static int tweak_set_interface_cmd(struct urb *urb) ret = usb_set_interface(urb->dev, interface, alternate); if (ret < 0) - dev_err(&urb->dev->dev, "usb_set_interface error: inf %u alt " - "%u ret %d\n", interface, alternate, ret); + dev_err(&urb->dev->dev, + "usb_set_interface error: inf %u alt %u ret %d\n", + interface, alternate, ret); else - dev_info(&urb->dev->dev, "usb_set_interface done: inf %u alt " - "%u\n", interface, alternate); + dev_info(&urb->dev->dev, + "usb_set_interface done: inf %u alt %u\n", + interface, alternate); return ret; } static int tweak_set_configuration_cmd(struct urb *urb) { + struct stub_priv *priv = (struct stub_priv *) urb->context; + struct stub_device *sdev = priv->sdev; struct usb_ctrlrequest *req; __u16 config; + int err; req = (struct usb_ctrlrequest *) urb->setup_packet; config = le16_to_cpu(req->wValue); - /* - * I have never seen a multi-config device. Very rare. - * For most devices, this will be called to choose a default - * configuration only once in an initialization phase. - * - * set_configuration may change a device configuration and its device - * drivers will be unbound and assigned for a new device configuration. - * This means this usbip driver will be also unbound when called, then - * eventually reassigned to the device as far as driver matching - * condition is kept. - * - * Unfortunatelly, an existing usbip connection will be dropped - * due to this driver unbinding. So, skip here. - * A user may need to set a special configuration value before - * exporting the device. - */ - dev_info(&urb->dev->dev, "usb_set_configuration %d to %s... skip!\n", - config, dev_name(&urb->dev->dev)); - + err = usb_set_configuration(sdev->udev, config); + if (err && err != -ENODEV) + dev_err(&sdev->udev->dev, "can't set config #%d, error %d\n", + config, err); return 0; - /* return usb_driver_set_configuration(urb->dev, config); */ } static int tweak_reset_device_cmd(struct urb *urb) @@ -229,61 +220,61 @@ static void tweak_special_requests(struct urb *urb) static int stub_recv_cmd_unlink(struct stub_device *sdev, struct usbip_header *pdu) { + int ret; unsigned long flags; - struct stub_priv *priv; spin_lock_irqsave(&sdev->priv_lock, flags); list_for_each_entry(priv, &sdev->priv_init, list) { - if (priv->seqnum == pdu->u.cmd_unlink.seqnum) { - int ret; - - dev_info(&priv->urb->dev->dev, "unlink urb %p\n", - priv->urb); - - /* - * This matched urb is not completed yet (i.e., be in - * flight in usb hcd hardware/driver). Now we are - * cancelling it. The unlinking flag means that we are - * now not going to return the normal result pdu of a - * submission request, but going to return a result pdu - * of the unlink request. - */ - priv->unlinking = 1; - - /* - * In the case that unlinking flag is on, prev->seqnum - * is changed from the seqnum of the cancelling urb to - * the seqnum of the unlink request. This will be used - * to make the result pdu of the unlink request. - */ - priv->seqnum = pdu->base.seqnum; - - spin_unlock_irqrestore(&sdev->priv_lock, flags); - - /* - * usb_unlink_urb() is now out of spinlocking to avoid - * spinlock recursion since stub_complete() is - * sometimes called in this context but not in the - * interrupt context. If stub_complete() is executed - * before we call usb_unlink_urb(), usb_unlink_urb() - * will return an error value. In this case, stub_tx - * will return the result pdu of this unlink request - * though submission is completed and actual unlinking - * is not executed. OK? - */ - /* In the above case, urb->status is not -ECONNRESET, - * so a driver in a client host will know the failure - * of the unlink request ? - */ - ret = usb_unlink_urb(priv->urb); - if (ret != -EINPROGRESS) - dev_err(&priv->urb->dev->dev, - "failed to unlink a urb %p, ret %d\n", - priv->urb, ret); - return 0; - } + if (priv->seqnum != pdu->u.cmd_unlink.seqnum) + continue; + + dev_info(&priv->urb->dev->dev, "unlink urb %p\n", + priv->urb); + + /* + * This matched urb is not completed yet (i.e., be in + * flight in usb hcd hardware/driver). Now we are + * cancelling it. The unlinking flag means that we are + * now not going to return the normal result pdu of a + * submission request, but going to return a result pdu + * of the unlink request. + */ + priv->unlinking = 1; + + /* + * In the case that unlinking flag is on, prev->seqnum + * is changed from the seqnum of the cancelling urb to + * the seqnum of the unlink request. This will be used + * to make the result pdu of the unlink request. + */ + priv->seqnum = pdu->base.seqnum; + + spin_unlock_irqrestore(&sdev->priv_lock, flags); + + /* + * usb_unlink_urb() is now out of spinlocking to avoid + * spinlock recursion since stub_complete() is + * sometimes called in this context but not in the + * interrupt context. If stub_complete() is executed + * before we call usb_unlink_urb(), usb_unlink_urb() + * will return an error value. In this case, stub_tx + * will return the result pdu of this unlink request + * though submission is completed and actual unlinking + * is not executed. OK? + */ + /* In the above case, urb->status is not -ECONNRESET, + * so a driver in a client host will know the failure + * of the unlink request ? + */ + ret = usb_unlink_urb(priv->urb); + if (ret != -EINPROGRESS) + dev_err(&priv->urb->dev->dev, + "failed to unlink a urb %p, ret %d\n", + priv->urb, ret); + + return 0; } usbip_dbg_stub_rx("seqnum %d is not pending\n", @@ -308,12 +299,12 @@ static int valid_request(struct stub_device *sdev, struct usbip_header *pdu) int valid = 0; if (pdu->base.devid == sdev->devid) { - spin_lock(&ud->lock); + spin_lock_irq(&ud->lock); if (ud->status == SDEV_ST_USED) { /* A request is valid. */ valid = 1; } - spin_unlock(&ud->lock); + spin_unlock_irq(&ud->lock); } return valid; @@ -367,15 +358,6 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) } epd = &ep->desc; -#if 0 - /* epnum 0 is always control */ - if (epnum == 0) { - if (dir == USBIP_DIR_OUT) - return usb_sndctrlpipe(udev, 0); - else - return usb_rcvctrlpipe(udev, 0); - } -#endif if (usb_endpoint_xfer_control(epd)) { if (dir == USBIP_DIR_OUT) return usb_sndctrlpipe(udev, epnum); @@ -489,19 +471,18 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, return; } - /* set priv->urb->transfer_buffer */ + /* allocate urb transfer buffer, if needed */ if (pdu->u.cmd_submit.transfer_buffer_length > 0) { priv->urb->transfer_buffer = kzalloc(pdu->u.cmd_submit.transfer_buffer_length, GFP_KERNEL); if (!priv->urb->transfer_buffer) { - dev_err(&sdev->interface->dev, "malloc x_buff\n"); usbip_event_add(ud, SDEV_EVENT_ERROR_MALLOC); return; } } - /* set priv->urb->setup_packet */ + /* copy urb setup packet */ priv->urb->setup_packet = kmemdup(&pdu->u.cmd_submit.setup, 8, GFP_KERNEL); if (!priv->urb->setup_packet) { @@ -557,13 +538,13 @@ static void stub_rx_pdu(struct usbip_device *ud) int ret; struct usbip_header pdu; struct stub_device *sdev = container_of(ud, struct stub_device, ud); - struct device *dev = &sdev->interface->dev; + struct device *dev = &sdev->udev->dev; usbip_dbg_stub_rx("Enter\n"); memset(&pdu, 0, sizeof(pdu)); - /* 1. receive a pdu header */ + /* receive a pdu header */ ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); if (ret != sizeof(pdu)) { dev_err(dev, "recv a header, %d\n", ret); diff --git a/drivers/staging/usbip/stub_tx.c b/drivers/staging/usbip/stub_tx.c index 023fda305be..dbcabc9dbe0 100644 --- a/drivers/staging/usbip/stub_tx.c +++ b/drivers/staging/usbip/stub_tx.c @@ -42,7 +42,6 @@ void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum, unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC); if (!unlink) { - dev_err(&sdev->interface->dev, "alloc stub_unlink\n"); usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC); return; } @@ -75,12 +74,12 @@ void stub_complete(struct urb *urb) /* OK */ break; case -ENOENT: - dev_info(&urb->dev->dev, "stopped by a call to usb_kill_urb() " - "because of cleaning up a virtual connection\n"); + dev_info(&urb->dev->dev, + "stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n"); return; case -ECONNRESET: - dev_info(&urb->dev->dev, "unlinked by a call to " - "usb_unlink_urb()\n"); + dev_info(&urb->dev->dev, + "unlinked by a call to usb_unlink_urb()\n"); break; case -EPIPE: dev_info(&urb->dev->dev, "endpoint %d is stalled\n", @@ -90,8 +89,9 @@ void stub_complete(struct urb *urb) dev_info(&urb->dev->dev, "device removed?\n"); break; default: - dev_info(&urb->dev->dev, "urb completion with non-zero status " - "%d\n", urb->status); + dev_info(&urb->dev->dev, + "urb completion with non-zero status %d\n", + urb->status); break; } @@ -166,7 +166,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) int ret; struct urb *urb = priv->urb; struct usbip_header pdu_header; - void *iso_buffer = NULL; + struct usbip_iso_packet_descriptor *iso_buffer = NULL; struct kvec *iov = NULL; int iovnum = 0; @@ -179,7 +179,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) else iovnum = 2; - iov = kzalloc(iovnum * sizeof(struct kvec), GFP_KERNEL); + iov = kcalloc(iovnum, sizeof(struct kvec), GFP_KERNEL); if (!iov) { usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_MALLOC); @@ -192,7 +192,6 @@ static int stub_send_ret_submit(struct stub_device *sdev) setup_ret_submit_pdu(&pdu_header, urb); usbip_dbg_stub_tx("setup txdata seqnum: %d urb: %p\n", pdu_header.base.seqnum, urb); - /*usbip_dump_header(pdu_header);*/ usbip_header_correct_endian(&pdu_header, 1); iov[iovnum].iov_base = &pdu_header; @@ -219,6 +218,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) */ int i; + for (i = 0; i < urb->number_of_packets; i++) { iov[iovnum].iov_base = urb->transfer_buffer + urb->iso_frame_desc[i].offset; @@ -230,8 +230,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) if (txsize != sizeof(pdu_header) + urb->actual_length) { dev_err(&sdev->interface->dev, - "actual length of urb %d does not " - "match iso packet sizes %zu\n", + "actual length of urb %d does not match iso packet sizes %zu\n", urb->actual_length, txsize-sizeof(pdu_header)); kfree(iov); diff --git a/drivers/staging/usbip/uapi/usbip.h b/drivers/staging/usbip/uapi/usbip.h new file mode 100644 index 00000000000..fa5db30ede3 --- /dev/null +++ b/drivers/staging/usbip/uapi/usbip.h @@ -0,0 +1,26 @@ +/* + * usbip.h + * + * USBIP uapi defines and function prototypes etc. +*/ + +#ifndef _UAPI_LINUX_USBIP_H +#define _UAPI_LINUX_USBIP_H + +/* usbip device status - exported in usbip device sysfs status */ +enum usbip_device_status { + /* sdev is available. */ + SDEV_ST_AVAILABLE = 0x01, + /* sdev is now used. */ + SDEV_ST_USED, + /* sdev is unusable because of a fatal error. */ + SDEV_ST_ERROR, + + /* vdev does not connect a remote device. */ + VDEV_ST_NULL, + /* vdev is used, but the USB address is not assigned yet */ + VDEV_ST_NOTASSIGNED, + VDEV_ST_USED, + VDEV_ST_ERROR +}; +#endif /* _UAPI_LINUX_USBIP_H */ diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index d93e7f1f797..facaaf003f1 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -22,7 +22,9 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <net/sock.h> #include "usbip_common.h" @@ -36,24 +38,28 @@ unsigned long usbip_debug_flag = 0xffffffff; unsigned long usbip_debug_flag; #endif EXPORT_SYMBOL_GPL(usbip_debug_flag); +module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)"); /* FIXME */ struct device_attribute dev_attr_usbip_debug; EXPORT_SYMBOL_GPL(dev_attr_usbip_debug); -static ssize_t show_flag(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t usbip_debug_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%lx\n", usbip_debug_flag); } -static ssize_t store_flag(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t usbip_debug_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { - sscanf(buf, "%lx", &usbip_debug_flag); + if (sscanf(buf, "%lx", &usbip_debug_flag) != 1) + return -EINVAL; return count; } -DEVICE_ATTR(usbip_debug, (S_IRUGO | S_IWUSR), show_flag, store_flag); +DEVICE_ATTR_RW(usbip_debug); static void usbip_dump_buffer(char *buff, int bufflen) { @@ -94,26 +100,8 @@ static void usbip_dump_usb_device(struct usb_device *udev) struct device *dev = &udev->dev; int i; - dev_dbg(dev, " devnum(%d) devpath(%s) ", - udev->devnum, udev->devpath); - - switch (udev->speed) { - case USB_SPEED_HIGH: - pr_debug("SPD_HIGH "); - break; - case USB_SPEED_FULL: - pr_debug("SPD_FULL "); - break; - case USB_SPEED_LOW: - pr_debug("SPD_LOW "); - break; - case USB_SPEED_UNKNOWN: - pr_debug("SPD_UNKNOWN "); - break; - default: - pr_debug("SPD_ERROR "); - break; - } + dev_dbg(dev, " devnum(%d) devpath(%s) usb speed(%s)", + udev->devnum, udev->devpath, usb_speed_string(udev->speed)); pr_debug("tt %p, ttport %d\n", udev->tt, udev->ttport); @@ -150,15 +138,15 @@ static void usbip_dump_usb_device(struct usb_device *udev) dev_dbg(dev, "parent %p, bus %p\n", udev->parent, udev->bus); - dev_dbg(dev, "descriptor %p, config %p, actconfig %p, " - "rawdescriptors %p\n", &udev->descriptor, udev->config, + dev_dbg(dev, + "descriptor %p, config %p, actconfig %p, rawdescriptors %p\n", + &udev->descriptor, udev->config, udev->actconfig, udev->rawdescriptors); dev_dbg(dev, "have_langid %d, string_langid %d\n", udev->have_langid, udev->string_langid); - dev_dbg(dev, "maxchild %d, children %p\n", - udev->maxchild, udev->children); + dev_dbg(dev, "maxchild %d\n", udev->maxchild); } static void usbip_dump_request_type(__u8 rt) @@ -190,8 +178,8 @@ static void usbip_dump_usb_ctrlrequest(struct usb_ctrlrequest *cmd) } pr_debug(" "); - pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) " - "wLength(%04X) ", cmd->bRequestType, cmd->bRequest, + pr_debug("bRequestType(%02X) bRequest(%02X) wValue(%04X) wIndex(%04X) wLength(%04X) ", + cmd->bRequestType, cmd->bRequest, cmd->wValue, cmd->wIndex, cmd->wLength); pr_debug("\n "); @@ -302,8 +290,7 @@ void usbip_dump_header(struct usbip_header *pdu) switch (pdu->base.command) { case USBIP_CMD_SUBMIT: - pr_debug("USBIP_CMD_SUBMIT: " - "x_flags %u x_len %u sf %u #p %d iv %d\n", + pr_debug("USBIP_CMD_SUBMIT: x_flags %u x_len %u sf %u #p %d iv %d\n", pdu->u.cmd_submit.transfer_flags, pdu->u.cmd_submit.transfer_buffer_length, pdu->u.cmd_submit.start_frame, @@ -362,7 +349,6 @@ int usbip_recv(struct socket *sock, void *buf, int size) msg.msg_namelen = 0; msg.msg_control = NULL; msg.msg_controllen = 0; - msg.msg_namelen = 0; msg.msg_flags = MSG_NOSIGNAL; result = kernel_recvmsg(sock, &msg, &iov, 1, size, MSG_WAITALL); @@ -386,7 +372,7 @@ int usbip_recv(struct socket *sock, void *buf, int size) pr_debug("receiving....\n"); usbip_dump_buffer(bp, osize); pr_debug("received, osize %d ret %d size %d total %d\n", - osize, result, size, total); + osize, result, size, total); } return total; @@ -396,29 +382,6 @@ err: } EXPORT_SYMBOL_GPL(usbip_recv); -struct socket *sockfd_to_socket(unsigned int sockfd) -{ - struct socket *socket; - struct file *file; - struct inode *inode; - - file = fget(sockfd); - if (!file) { - pr_err("invalid sockfd\n"); - return NULL; - } - - inode = file->f_dentry->d_inode; - - if (!inode || !S_ISSOCK(inode->i_mode)) - return NULL; - - socket = SOCKET_I(inode); - - return socket; -} -EXPORT_SYMBOL_GPL(sockfd_to_socket); - /* there may be more cases to tweak the flags. */ static unsigned int tweak_transfer_flags(unsigned int flags) { @@ -436,7 +399,6 @@ static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, * will be discussed when usbip is ported to other operating systems. */ if (pack) { - /* vhci_tx.c */ spdu->transfer_flags = tweak_transfer_flags(urb->transfer_flags); spdu->transfer_buffer_length = urb->transfer_buffer_length; @@ -444,9 +406,7 @@ static void usbip_pack_cmd_submit(struct usbip_header *pdu, struct urb *urb, spdu->number_of_packets = urb->number_of_packets; spdu->interval = urb->interval; } else { - /* stub_rx.c */ urb->transfer_flags = spdu->transfer_flags; - urb->transfer_buffer_length = spdu->transfer_buffer_length; urb->start_frame = spdu->start_frame; urb->number_of_packets = spdu->number_of_packets; @@ -460,16 +420,12 @@ static void usbip_pack_ret_submit(struct usbip_header *pdu, struct urb *urb, struct usbip_header_ret_submit *rpdu = &pdu->u.ret_submit; if (pack) { - /* stub_tx.c */ - rpdu->status = urb->status; rpdu->actual_length = urb->actual_length; rpdu->start_frame = urb->start_frame; rpdu->number_of_packets = urb->number_of_packets; rpdu->error_count = urb->error_count; } else { - /* vhci_rx.c */ - urb->status = rpdu->status; urb->actual_length = rpdu->actual_length; urb->start_frame = rpdu->start_frame; @@ -636,28 +592,26 @@ static void usbip_pack_iso(struct usbip_iso_packet_descriptor *iso, } /* must free buffer */ -void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen) +struct usbip_iso_packet_descriptor* +usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen) { - void *buff; struct usbip_iso_packet_descriptor *iso; int np = urb->number_of_packets; ssize_t size = np * sizeof(*iso); int i; - buff = kzalloc(size, GFP_KERNEL); - if (!buff) + iso = kzalloc(size, GFP_KERNEL); + if (!iso) return NULL; for (i = 0; i < np; i++) { - iso = buff + (i * sizeof(*iso)); - - usbip_pack_iso(iso, &urb->iso_frame_desc[i], 1); - usbip_iso_packet_correct_endian(iso, 1); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 1); + usbip_iso_packet_correct_endian(&iso[i], 1); } *bufflen = size; - return buff; + return iso; } EXPORT_SYMBOL_GPL(usbip_alloc_iso_desc_pdu); @@ -676,11 +630,8 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) return 0; /* my Bluetooth dongle gets ISO URBs which are np = 0 */ - if (np == 0) { - /* pr_info("iso np == 0\n"); */ - /* usbip_dump_urb(urb); */ + if (np == 0) return 0; - } buff = kzalloc(size, GFP_KERNEL); if (!buff) @@ -700,11 +651,10 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) return -EPIPE; } + iso = (struct usbip_iso_packet_descriptor *) buff; for (i = 0; i < np; i++) { - iso = buff + (i * sizeof(*iso)); - - usbip_iso_packet_correct_endian(iso, 0); - usbip_pack_iso(iso, &urb->iso_frame_desc[i], 0); + usbip_iso_packet_correct_endian(&iso[i], 0); + usbip_pack_iso(&iso[i], &urb->iso_frame_desc[i], 0); total_length += urb->iso_frame_desc[i].actual_length; } @@ -712,8 +662,7 @@ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb) if (total_length != urb->actual_length) { dev_err(&urb->dev->dev, - "total length of iso packets %d not equal to actual " - "length of buffer %d\n", + "total length of iso packets %d not equal to actual length of buffer %d\n", total_length, urb->actual_length); if (ud->side == USBIP_STUB) @@ -735,26 +684,25 @@ EXPORT_SYMBOL_GPL(usbip_recv_iso); * buffer and iso packets need to be stored and be in propeper endian in urb * before calling this function */ -int usbip_pad_iso(struct usbip_device *ud, struct urb *urb) +void usbip_pad_iso(struct usbip_device *ud, struct urb *urb) { int np = urb->number_of_packets; int i; - int ret; int actualoffset = urb->actual_length; if (!usb_pipeisoc(urb->pipe)) - return 0; + return; /* if no packets or length of data is 0, then nothing to unpack */ if (np == 0 || urb->actual_length == 0) - return 0; + return; /* * if actual_length is transfer_buffer_length then no padding is * present. - */ + */ if (urb->actual_length == urb->transfer_buffer_length) - return 0; + return; /* * loop over all packets from last to first (to prevent overwritting @@ -766,8 +714,6 @@ int usbip_pad_iso(struct usbip_device *ud, struct urb *urb) urb->transfer_buffer + actualoffset, urb->iso_frame_desc[i].actual_length); } - - return ret; } EXPORT_SYMBOL_GPL(usbip_pad_iso); @@ -778,14 +724,12 @@ int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb) int size; if (ud->side == USBIP_STUB) { - /* stub_rx.c */ /* the direction of urb must be OUT. */ if (usb_pipein(urb->pipe)) return 0; size = urb->transfer_buffer_length; } else { - /* vhci_rx.c */ /* the direction of urb must be IN. */ if (usb_pipeout(urb->pipe)) return 0; diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index b8f8c48b8a7..4da3866a037 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -29,6 +29,7 @@ #include <linux/types.h> #include <linux/usb.h> #include <linux/wait.h> +#include "uapi/usbip.h" #define USBIP_VERSION "1.0.0" @@ -235,22 +236,6 @@ enum usbip_side { USBIP_STUB, }; -enum usbip_status { - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - /* event handler */ #define USBIP_EH_SHUTDOWN (1 << 0) #define USBIP_EH_BYE (1 << 1) @@ -271,7 +256,7 @@ enum usbip_status { /* a common structure for stub_device and vhci_device */ struct usbip_device { enum usbip_side side; - enum usbip_status status; + enum usbip_device_status status; /* lock for status */ spinlock_t lock; @@ -292,21 +277,39 @@ struct usbip_device { } eh_ops; }; +#define kthread_get_run(threadfn, data, namefmt, ...) \ +({ \ + struct task_struct *__k \ + = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ + if (!IS_ERR(__k)) { \ + get_task_struct(__k); \ + wake_up_process(__k); \ + } \ + __k; \ +}) + +#define kthread_stop_put(k) \ + do { \ + kthread_stop(k); \ + put_task_struct(k); \ + } while (0) + /* usbip_common.c */ void usbip_dump_urb(struct urb *purb); void usbip_dump_header(struct usbip_header *pdu); int usbip_recv(struct socket *sock, void *buf, int size); -struct socket *sockfd_to_socket(unsigned int sockfd); void usbip_pack_pdu(struct usbip_header *pdu, struct urb *urb, int cmd, int pack); void usbip_header_correct_endian(struct usbip_header *pdu, int send); -void *usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); +struct usbip_iso_packet_descriptor* +usbip_alloc_iso_desc_pdu(struct urb *urb, ssize_t *bufflen); + /* some members of urb must be substituted before. */ int usbip_recv_iso(struct usbip_device *ud, struct urb *urb); -int usbip_pad_iso(struct usbip_device *ud, struct urb *urb); +void usbip_pad_iso(struct usbip_device *ud, struct urb *urb); int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb); /* usbip_event.c */ @@ -318,12 +321,14 @@ int usbip_event_happened(struct usbip_device *ud); static inline int interface_to_busnum(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); + return udev->bus->busnum; } static inline int interface_to_devnum(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); + return udev->devnum; } diff --git a/drivers/staging/usbip/usbip_event.c b/drivers/staging/usbip/usbip_event.c index d332a34ddb6..64933b993d7 100644 --- a/drivers/staging/usbip/usbip_event.c +++ b/drivers/staging/usbip/usbip_event.c @@ -85,7 +85,7 @@ int usbip_start_eh(struct usbip_device *ud) ud->eh = kthread_run(event_handler_loop, ud, "usbip_eh"); if (IS_ERR(ud->eh)) { - pr_warning("Unable to start control thread\n"); + pr_warn("Unable to start control thread\n"); return PTR_ERR(ud->eh); } @@ -105,10 +105,12 @@ EXPORT_SYMBOL_GPL(usbip_stop_eh); void usbip_event_add(struct usbip_device *ud, unsigned long event) { - spin_lock(&ud->lock); + unsigned long flags; + + spin_lock_irqsave(&ud->lock, flags); ud->event |= event; wake_up(&ud->eh_waitq); - spin_unlock(&ud->lock); + spin_unlock_irqrestore(&ud->lock, flags); } EXPORT_SYMBOL_GPL(usbip_event_add); diff --git a/drivers/staging/usbip/usbip_protocol.txt b/drivers/staging/usbip/usbip_protocol.txt index 0f102081e86..16b6fe27284 100644 --- a/drivers/staging/usbip/usbip_protocol.txt +++ b/drivers/staging/usbip/usbip_protocol.txt @@ -27,7 +27,7 @@ Once the client knows the list of exported USB devices it may decide to use one of them. First the client opens a TCP/IP connection towards the server and sends an OP_REQ_IMPORT packet. The server replies with OP_REP_IMPORT. If the import was successful the TCP/IP connection remains open and will be used -to trasfer the URB traffic between the client and the server. The client may +to transfer the URB traffic between the client and the server. The client may send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively. diff --git a/drivers/staging/usbip/userspace/.gitignore b/drivers/staging/usbip/userspace/.gitignore new file mode 100644 index 00000000000..9aad9e30a8b --- /dev/null +++ b/drivers/staging/usbip/userspace/.gitignore @@ -0,0 +1,28 @@ +Makefile +Makefile.in +aclocal.m4 +autom4te.cache/ +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +libsrc/Makefile +libsrc/Makefile.in +libtool +ltmain.sh +missing +src/Makefile +src/Makefile.in +stamp-h1 +libsrc/libusbip.la +libsrc/libusbip_la-names.lo +libsrc/libusbip_la-usbip_common.lo +libsrc/libusbip_la-usbip_host_driver.lo +libsrc/libusbip_la-vhci_driver.lo +src/usbip +src/usbipd diff --git a/drivers/staging/usbip/userspace/Makefile.am b/drivers/staging/usbip/userspace/Makefile.am index 9ab19499fe0..66f8bf038c9 100644 --- a/drivers/staging/usbip/userspace/Makefile.am +++ b/drivers/staging/usbip/userspace/Makefile.am @@ -3,4 +3,4 @@ includedir = @includedir@/usbip include_HEADERS := $(addprefix libsrc/, \ usbip_common.h vhci_driver.h usbip_host_driver.h) -dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8 usbip_bind_driver.8) +dist_man_MANS := $(addprefix doc/, usbip.8 usbipd.8) diff --git a/drivers/staging/usbip/userspace/README b/drivers/staging/usbip/userspace/README index 63cd1071905..831f49fea3c 100644 --- a/drivers/staging/usbip/userspace/README +++ b/drivers/staging/usbip/userspace/README @@ -9,18 +9,20 @@ - USB/IP device drivers Found in the staging directory of the Linux kernel. - - sysfsutils >= 2.0.0 - sysfsutils library + - libudev >= 2.0 + libudev library - libwrap0-dev tcp wrapper library - gcc >= 4.0 - - libglib2.0-dev >= 2.6.0 - - libtool, automake >= 1.9, autoconf >= 2.5.0, pkg-config +[Optional] + - hwdata + Contains USB device identification data. + [Install] 0. Generate configuration scripts. @@ -56,7 +58,7 @@ client:# usbip list --remote <host> - List exported USB devices on the <host>. - client:# usbip attach --host <host> --busid 1-2 + client:# usbip attach --remote <host> --busid 1-2 - Connect the remote USB device. client:# usbip port @@ -165,7 +167,7 @@ exportable on the host. Attach a remote USB device: - deux:# usbip attach --host 10.0.0.3 --busid 1-1 + deux:# usbip attach --remote 10.0.0.3 --busid 1-1 port 0 attached Show the devices attached to this client: @@ -193,7 +195,6 @@ Detach the imported device: - Shutdown firewall. - usbip now uses TCP port 3240. - Disable SELinux. - - If possible, compile your kernel with CONFIG_USB_DEBUG flag and try again. - Check the kernel and daemon messages. diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac index bf5cf49cb55..607d05c5ccf 100644 --- a/drivers/staging/usbip/userspace/configure.ac +++ b/drivers/staging/usbip/userspace/configure.ac @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) -AC_INIT([usbip-utils], [1.1.1], [linux-usb@vger.kernel.org]) +AC_INIT([usbip-utils], [2.0], [linux-usb@vger.kernel.org]) AC_DEFINE([USBIP_VERSION], [0x00000111], [binary-coded decimal version number]) CURRENT=0 @@ -44,11 +44,11 @@ AC_FUNC_REALLOC AC_CHECK_FUNCS([memset mkdir regcomp socket strchr strerror strstr dnl strtoul]) -AC_CHECK_HEADER([sysfs/libsysfs.h], - [AC_CHECK_LIB([sysfs], [sysfs_open_directory_list], - [LIBS="$LIBS -lsysfs"], - [AC_MSG_ERROR([Missing sysfs2 library!])])], - [AC_MSG_ERROR([Missing /usr/include/sysfs/libsysfs.h])]) +AC_CHECK_HEADER([libudev.h], + [AC_CHECK_LIB([udev], [udev_new], + [LIBS="$LIBS -ludev"], + [AC_MSG_ERROR([Missing udev library!])])], + [AC_MSG_ERROR([Missing /usr/include/libudev.h])]) # Checks for libwrap library. AC_MSG_CHECKING([whether to use the libwrap (TCP wrappers) library]) @@ -56,11 +56,11 @@ AC_ARG_WITH([tcp-wrappers], [AS_HELP_STRING([--with-tcp-wrappers], [use the libwrap (TCP wrappers) library])], dnl [ACTION-IF-GIVEN] - [saved_LIBS="$LIBS" - if test "$withval" = "yes"; then + [if test "$withval" = "yes"; then AC_MSG_RESULT([yes]) AC_MSG_CHECKING([for hosts_access in -lwrap]) - LIBS="-lwrap $LIBS" + saved_LIBS="$LIBS" + LIBS="-lwrap $saved_LIBS" AC_TRY_LINK( [int hosts_access(); int allow_severity, deny_severity;], [hosts_access()], @@ -69,9 +69,8 @@ AC_ARG_WITH([tcp-wrappers], [use tcp wrapper]) wrap_LIB="-lwrap"], [AC_MSG_RESULT([not found]); exit 1]) else - AC_MSG_RESULT([no]) - fi - LIBS="$saved_LIBS"], + AC_MSG_RESULT([no]); + fi], dnl [ACTION-IF-NOT-GIVEN] [AC_MSG_RESULT([(default)]) AC_MSG_CHECKING([for hosts_access in -lwrap]) @@ -91,10 +90,22 @@ AC_ARG_WITH([usbids-dir], [USBIDS_DIR=$withval], [USBIDS_DIR="/usr/share/hwdata/"]) AC_SUBST([USBIDS_DIR]) -GLIB2_REQUIRED=2.6.0 -PKG_CHECK_MODULES([PACKAGE], [glib-2.0 >= $GLIB2_REQUIRED]) -AC_SUBST([PACKAGE_CFLAGS]) -AC_SUBST([PACKAGE_LIBS]) +# use _FORTIFY_SOURCE +AC_MSG_CHECKING([whether to use fortify]) +AC_ARG_WITH([fortify], + [AS_HELP_STRING([--with-fortify], + [use _FORTIFY_SROUCE option when compiling)])], + dnl [ACTION-IF-GIVEN] + [if test "$withval" = "yes"; then + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -D_FORTIFY_SOURCE -O" + else + AC_MSG_RESULT([no]) + CFLAGS="$CFLAGS -U_FORTIFY_SOURCE" + fi + ], + dnl [ACTION-IF-NOT-GIVEN] + [AC_MSG_RESULT([default])]) AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile]) AC_OUTPUT diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8 index 1653bb2cd7d..a6097be25d2 100644 --- a/drivers/staging/usbip/userspace/doc/usbip.8 +++ b/drivers/staging/usbip/userspace/doc/usbip.8 @@ -3,69 +3,93 @@ usbip \- manage USB/IP devices .SH SYNOPSIS .B usbip -[\fIoptions\fR] +[\fIoptions\fR] <\fIcommand\fR> <\fIargs\fR> .SH DESCRIPTION -Devices exported by USB/IP servers can be listed, attached and -detached using this program. +On a USB/IP server, devices can be listed, bound, and unbound using +this program. On a USB/IP client, devices exported by USB/IP servers +can be listed, attached and detached. .SH OPTIONS .HP -\fB\-a\fR, \fB\-\-attach\fR <host> <bus_id> +\fB\-\-debug\fR .IP -Attach a remote USB device. +Print debugging information. +.PP + +.HP +\fB\-\-log\fR +.IP +Log to syslog. +.PP + +.HP +\fB\-\-tcp-port PORT\fR +.IP +Connect to PORT on remote host (used for attach and list --remote). +.PP + +.SH COMMANDS +.HP +\fBversion\fR +.IP +Show version and exit. .PP .HP -\fB\-x\fR, \fB\-\-attachall\fR <host> +\fBhelp\fR [\fIcommand\fR] .IP -Attach all remote USB devices on the specific host. +Print the program help message, or help on a specific command, and +then exit. .PP .HP -\fB\-d\fR, \fB\-\-detach\fR <ports> +\fBattach\fR \-\-remote=<\fIhost\fR> \-\-busid=<\fIbus_id\fR> +.IP +Attach a remote USB device. +.PP + +.HP +\fBdetach\fR \-\-port=<\fIport\fR> .IP Detach an imported USB device. .PP .HP -\fB\-l\fR, \fB\-\-list\fR <hosts> +\fBbind\fR \-\-busid=<\fIbusid\fR> .IP -List exported USB devices. +Make a device exportable. .PP .HP -\fB\-p\fR, \fB\-\-port\fR +\fBunbind\fR \-\-busid=<\fIbusid\fR> .IP -List virtual USB port status. +Stop exporting a device so it can be used by a local driver. .PP .HP -\fB\-D\fR, \fB\-\-debug\fR +\fBlist\fR \-\-remote=<\fIhost\fR> .IP -Print debugging information. +List USB devices exported by a remote host. .PP .HP -\fB\-v\fR, \fB\-\-version\fR +\fBlist\fR \-\-local .IP -Show version. +List local USB devices. .PP + .SH EXAMPLES - client:# usbip --list server + client:# usbip list --remote=server - List exportable usb devices on the server. - client:# usbip --attach server 1-2 + client:# usbip attach --remote=server --busid=1-2 - Connect the remote USB device. - client:# usbip --port - - Show virtual port status. - - client:# usbip --detach 0 + client:# usbip detach --port=0 - Detach the usb device. .SH "SEE ALSO" -\fBusbipd\fP\fB(8)\fB\fP, -\fBusbip_attach_driver\fP\fB(8)\fB\fP +\fBusbipd\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 b/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 deleted file mode 100644 index d43bbd6be93..00000000000 --- a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 +++ /dev/null @@ -1,42 +0,0 @@ -.TH USBIP_BIND_DRIVER "8" "February 2009" "usbip" "System Administration Utilities" -.SH NAME -usbip_bind_driver \- change driver binding for USB/IP - -.SH SYNOPSIS -.B usbip_bind_driver -[\fIoptions\fR] - -.SH DESCRIPTION -Driver bindings for USB devices can be changed using -this program. It is used to export and unexport USB -devices over USB/IP. - -.SH OPTIONS -.TP -\fB\-u\fR, \fB\-\-usbip\fR <busid> -Make a device exportable -.TP -\fB\-o\fR, \fB\-\-other\fR <busid> -Use a device by a local driver -.TP -\fB\-l\fR, \fB\-\-list\fR -Print usb devices and their drivers -.TP -\fB\-L\fR, \fB\-\-list2\fR -Print usb devices and their drivers in parseable mode - -.SH EXAMPLES - - server:# usbip_bind_driver --list - - List driver assignments for usb devices. - - server:# usbip_bind_driver --usbip 1-2 - - Bind usbip-host.ko to the device of busid 1-2. - - A usb device 1-2 is now exportable to other hosts! - - server:# usbip_bind_driver --other 1-2 - - Shutdown exporting and use the device locally. - -.SH "SEE ALSO" -\fBusbip\fP\fB(8)\fB\fP, -\fBusbipd\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8 index 006559f1df2..ac4635db3f0 100644 --- a/drivers/staging/usbip/userspace/doc/usbipd.8 +++ b/drivers/staging/usbip/userspace/doc/usbipd.8 @@ -10,14 +10,26 @@ usbipd \- USB/IP server daemon provides USB/IP clients access to exported USB devices. Devices have to explicitly be exported using -.B usbip_bind_driver +.B usbip bind before usbipd makes them available to other hosts. The daemon accepts connections from USB/IP clients -on TCP port 3240. +on TCP port 3240 by default. .SH OPTIONS .HP +\fB\-4\fR, \fB\-\-ipv4\fR +.IP +Bind to IPv4. Default is both. +.PP + +.HP +\fB\-6\fR, \fB\-\-ipv6\fR +.IP +Bind to IPv6. Default is both. +.PP + +.HP \fB\-D\fR, \fB\-\-daemon\fR .IP Run as a daemon process. @@ -30,6 +42,24 @@ Print debugging information. .PP .HP +\fB\-PFILE\fR, \fB\-\-pid FILE\fR +.IP +Write process id to FILE. +.br +If no FILE specified, use /var/run/usbipd.pid +.PP + +\fB\-tPORT\fR, \fB\-\-tcp\-port PORT\fR +.IP +Listen on TCP/IP port PORT. +.PP + +\fB\-h\fR, \fB\-\-help\fR +.IP +Print the program help message and exit. +.PP + +.HP \fB\-v\fR, \fB\-\-version\fR .IP Show version. @@ -48,15 +78,14 @@ USB/IP client can connect and use exported devices. server:# usbipd -D - Start usbip daemon. - server:# usbip_bind_driver --list + server:# usbip list --local - List driver assignments for usb devices. - server:# usbip_bind_driver --usbip 1-2 + server:# usbip bind --busid=1-2 - Bind usbip-host.ko to the device of busid 1-2. - A usb device 1-2 is now exportable to other hosts! - - Use 'usbip_bind_driver --other 1-2' when you want to shutdown exporting and use the device locally. + - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally. .SH "SEE ALSO" -\fBusbip\fP\fB(8)\fB\fP, -\fBusbip_attach_driver\fP\fB(8)\fB\fP +\fBusbip\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/userspace/libsrc/Makefile.am b/drivers/staging/usbip/userspace/libsrc/Makefile.am index 4921189e026..7c8f8a4d54e 100644 --- a/drivers/staging/usbip/userspace/libsrc/Makefile.am +++ b/drivers/staging/usbip/userspace/libsrc/Makefile.am @@ -4,4 +4,5 @@ libusbip_la_LDFLAGS = -version-info @LIBUSBIP_VERSION@ lib_LTLIBRARIES := libusbip.la libusbip_la_SOURCES := names.c names.h usbip_host_driver.c usbip_host_driver.h \ - usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h + usbip_common.c usbip_common.h vhci_driver.c vhci_driver.h \ + sysfs_utils.c sysfs_utils.h diff --git a/drivers/staging/usbip/userspace/libsrc/list.h b/drivers/staging/usbip/userspace/libsrc/list.h new file mode 100644 index 00000000000..8d0c936e184 --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/list.h @@ -0,0 +1,136 @@ +#ifndef _LIST_H +#define _LIST_H + +/* Stripped down implementation of linked list taken + * from the Linux Kernel. + */ + +/* + * Simple doubly linked list implementation. + * + * Some of the internal functions ("__xxx") are useful when + * manipulating whole lists rather than single entries, as + * sometimes we already know the next/prev entries and we can + * generate better code by using them directly rather than + * using the generic single-entry routines. + */ + +struct list_head { + struct list_head *next, *prev; +}; + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define LIST_HEAD(name) \ + struct list_head name = LIST_HEAD_INIT(name) + +static inline void INIT_LIST_HEAD(struct list_head *list) +{ + list->next = list; + list->prev = list; +} + +/* + * Insert a new entry between two known consecutive entries. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +/** + * list_add - add a new entry + * @new: new entry to be added + * @head: list head to add it after + * + * Insert a new entry after the specified head. + * This is good for implementing stacks. + */ +static inline void list_add(struct list_head *new, struct list_head *head) +{ + __list_add(new, head, head->next); +} + +/* + * Delete a list entry by making the prev/next entries + * point to each other. + * + * This is only for internal list manipulation where we know + * the prev/next entries already! + */ +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +#define POISON_POINTER_DELTA 0 +#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) + +/** + * list_del - deletes entry from list. + * @entry: the element to delete from the list. + * Note: list_empty() on entry does not return true after this, the entry is + * in an undefined state. + */ +static inline void __list_del_entry(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); + entry->next = LIST_POISON1; + entry->prev = LIST_POISON2; +} + +/** + * list_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_struct within the struct. + */ +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) +/** + * list_for_each - iterate over a list + * @pos: the &struct list_head to use as a loop cursor. + * @head: the head for your list. + */ +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/** + * list_for_each_safe - iterate over a list safe against removal of list entry + * @pos: the &struct list_head to use as a loop cursor. + * @n: another &struct list_head to use as temporary storage + * @head: the head for your list. + */ +#define list_for_each_safe(pos, n, head) \ + for (pos = (head)->next, n = pos->next; pos != (head); \ + pos = n, n = pos->next) + +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +/** + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + * + */ +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#endif diff --git a/drivers/staging/usbip/userspace/libsrc/names.c b/drivers/staging/usbip/userspace/libsrc/names.c index b4de18b4bb9..81ff8522405 100644 --- a/drivers/staging/usbip/userspace/libsrc/names.c +++ b/drivers/staging/usbip/userspace/libsrc/names.c @@ -1,4 +1,3 @@ -/*****************************************************************************/ /* * names.c -- USB name database manipulation routines * @@ -19,15 +18,14 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * + * + * + * + * Copyright (C) 2005 Takahiro Hirofuchi + * - names_deinit() is added. + * */ -/* - * Copyright (C) 2005 Takahiro Hirofuchi - * - names_deinit() is added. - */ - -/*****************************************************************************/ - #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -39,11 +37,8 @@ #include <stdio.h> #include <ctype.h> - #include "names.h" - - -/* ---------------------------------------------------------------------- */ +#include "usbip_common.h" struct vendor { struct vendor *next; @@ -75,19 +70,12 @@ struct protocol { char name[1]; }; -struct audioterminal { - struct audioterminal *next; - u_int16_t termt; - char name[1]; -}; - struct genericstrtable { - struct genericstrtable *next; - unsigned int num; - char name[1]; + struct genericstrtable *next; + unsigned int num; + char name[1]; }; -/* ---------------------------------------------------------------------- */ #define HASH1 0x10 #define HASH2 0x02 @@ -103,74 +91,12 @@ static unsigned int hashnum(unsigned int num) return num & (HASHSZ-1); } -/* ---------------------------------------------------------------------- */ static struct vendor *vendors[HASHSZ] = { NULL, }; static struct product *products[HASHSZ] = { NULL, }; static struct class *classes[HASHSZ] = { NULL, }; static struct subclass *subclasses[HASHSZ] = { NULL, }; static struct protocol *protocols[HASHSZ] = { NULL, }; -static struct audioterminal *audioterminals[HASHSZ] = { NULL, }; -static struct genericstrtable *hiddescriptors[HASHSZ] = { NULL, }; -static struct genericstrtable *reports[HASHSZ] = { NULL, }; -static struct genericstrtable *huts[HASHSZ] = { NULL, }; -static struct genericstrtable *biass[HASHSZ] = { NULL, }; -static struct genericstrtable *physdess[HASHSZ] = { NULL, }; -static struct genericstrtable *hutus[HASHSZ] = { NULL, }; -static struct genericstrtable *langids[HASHSZ] = { NULL, }; -static struct genericstrtable *countrycodes[HASHSZ] = { NULL, }; - -/* ---------------------------------------------------------------------- */ - -static const char *names_genericstrtable(struct genericstrtable *t[HASHSZ], unsigned int index) -{ - struct genericstrtable *h; - - for (h = t[hashnum(index)]; h; h = h->next) - if (h->num == index) - return h->name; - return NULL; -} - -const char *names_hid(u_int8_t hidd) -{ - return names_genericstrtable(hiddescriptors, hidd); -} - -const char *names_reporttag(u_int8_t rt) -{ - return names_genericstrtable(reports, rt); -} - -const char *names_huts(unsigned int data) -{ - return names_genericstrtable(huts, data); -} - -const char *names_hutus(unsigned int data) -{ - return names_genericstrtable(hutus, data); -} - -const char *names_langid(u_int16_t langid) -{ - return names_genericstrtable(langids, langid); -} - -const char *names_physdes(u_int8_t ph) -{ - return names_genericstrtable(physdess, ph); -} - -const char *names_bias(u_int8_t b) -{ - return names_genericstrtable(biass, b); -} - -const char *names_countrycode(unsigned int countrycode) -{ - return names_genericstrtable(countrycodes, countrycode); -} const char *names_vendor(u_int16_t vendorid) { @@ -216,51 +142,41 @@ const char *names_subclass(u_int8_t classid, u_int8_t subclassid) return NULL; } -const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid) +const char *names_protocol(u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid) { struct protocol *p; - p = protocols[hashnum((classid << 16) | (subclassid << 8) | protocolid)]; + p = protocols[hashnum((classid << 16) | (subclassid << 8) + | protocolid)]; for (; p; p = p->next) - if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid) + if (p->classid == classid && p->subclassid == subclassid && + p->protocolid == protocolid) return p->name; return NULL; } -const char *names_audioterminal(u_int16_t termt) -{ - struct audioterminal *at; - - at = audioterminals[hashnum(termt)]; - for (; at; at = at->next) - if (at->termt == termt) - return at->name; - return NULL; -} - -/* ---------------------------------------------------------------------- */ /* add a cleanup function by takahiro */ - struct pool { struct pool *next; void *mem; }; -static struct pool *pool_head = NULL; +static struct pool *pool_head; static void *my_malloc(size_t size) { struct pool *p; p = calloc(1, sizeof(struct pool)); - if (!p) { - free(p); + if (!p) return NULL; - } p->mem = calloc(1, size); - if (!p->mem) + if (!p->mem) { + free(p); return NULL; + } p->next = pool_head; pool_head = p; @@ -287,8 +203,6 @@ void names_free(void) } } -/* ---------------------------------------------------------------------- */ - static int new_vendor(const char *name, u_int16_t vendorid) { struct vendor *v; @@ -308,7 +222,8 @@ static int new_vendor(const char *name, u_int16_t vendorid) return 0; } -static int new_product(const char *name, u_int16_t vendorid, u_int16_t productid) +static int new_product(const char *name, u_int16_t vendorid, + u_int16_t productid) { struct product *p; unsigned int h = hashnum((vendorid << 16) | productid); @@ -367,14 +282,17 @@ static int new_subclass(const char *name, u_int8_t classid, u_int8_t subclassid) return 0; } -static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid) +static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid) { struct protocol *p; - unsigned int h = hashnum((classid << 16) | (subclassid << 8) | protocolid); + unsigned int h = hashnum((classid << 16) | (subclassid << 8) + | protocolid); p = protocols[h]; for (; p; p = p->next) - if (p->classid == classid && p->subclassid == subclassid && p->protocolid == protocolid) + if (p->classid == classid && p->subclassid == subclassid + && p->protocolid == protocolid) return -1; p = my_malloc(sizeof(struct protocol) + strlen(name)); if (!p) @@ -388,253 +306,84 @@ static int new_protocol(const char *name, u_int8_t classid, u_int8_t subclassid, return 0; } -static int new_audioterminal(const char *name, u_int16_t termt) -{ - struct audioterminal *at; - unsigned int h = hashnum(termt); - - at = audioterminals[h]; - for (; at; at = at->next) - if (at->termt == termt) - return -1; - at = my_malloc(sizeof(struct audioterminal) + strlen(name)); - if (!at) - return -1; - strcpy(at->name, name); - at->termt = termt; - at->next = audioterminals[h]; - audioterminals[h] = at; - return 0; -} - -static int new_genericstrtable(struct genericstrtable *t[HASHSZ], const char *name, unsigned int index) -{ - struct genericstrtable *g; - unsigned int h = hashnum(index); - - for (g = t[h]; g; g = g->next) - if (g->num == index) - return -1; - g = my_malloc(sizeof(struct genericstrtable) + strlen(name)); - if (!g) - return -1; - strcpy(g->name, name); - g->num = index; - g->next = t[h]; - t[h] = g; - return 0; -} - -static int new_hid(const char *name, u_int8_t hidd) -{ - return new_genericstrtable(hiddescriptors, name, hidd); -} - -static int new_reporttag(const char *name, u_int8_t rt) -{ - return new_genericstrtable(reports, name, rt); -} - -static int new_huts(const char *name, unsigned int data) -{ - return new_genericstrtable(huts, name, data); -} - -static int new_hutus(const char *name, unsigned int data) -{ - return new_genericstrtable(hutus, name, data); -} - -static int new_langid(const char *name, u_int16_t langid) -{ - return new_genericstrtable(langids, name, langid); -} - -static int new_physdes(const char *name, u_int8_t ph) -{ - return new_genericstrtable(physdess, name, ph); -} -static int new_bias(const char *name, u_int8_t b) -{ - return new_genericstrtable(biass, name, b); -} - -static int new_countrycode(const char *name, unsigned int countrycode) -{ - return new_genericstrtable(countrycodes, name, countrycode); -} - -/* ---------------------------------------------------------------------- */ - -#define DBG(x) - static void parse(FILE *f) { char buf[512], *cp; unsigned int linectr = 0; - int lastvendor = -1, lastclass = -1, lastsubclass = -1, lasthut=-1, lastlang=-1; + int lastvendor = -1; + int lastclass = -1; + int lastsubclass = -1; + int lasthut = -1; + int lastlang = -1; unsigned int u; while (fgets(buf, sizeof(buf), f)) { linectr++; /* remove line ends */ - if ((cp = strchr(buf, 13))) + cp = strchr(buf, '\r'); + if (cp) *cp = 0; - if ((cp = strchr(buf, 10))) + cp = strchr(buf, '\n'); + if (cp) *cp = 0; if (buf[0] == '#' || !buf[0]) continue; cp = buf; - if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && buf[3] == 'S' && buf[4] == 'D' && - buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ buf[7] == ' ') { - cp = buf + 8; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid Physdes type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid Physdes type at line %u\n", linectr); - continue; - } - if (new_physdes(cp, u)) - fprintf(stderr, "Duplicate Physdes type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u physdes type %02x %s\n", linectr, u, cp)); - continue; - - } - if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { - cp = buf + 4; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid PHY type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid PHY type at line %u\n", linectr); - continue; - } - if (new_physdes(cp, u)) - fprintf(stderr, "Duplicate PHY type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u PHY type %02x %s\n", linectr, u, cp)); - continue; - - } - if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { - cp = buf + 5; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid BIAS type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid BIAS type at line %u\n", linectr); - continue; - } - if (new_bias(cp, u)) - fprintf(stderr, "Duplicate BIAS type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u BIAS type %02x %s\n", linectr, u, cp)); - continue; - - } - if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { - cp = buf+2; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid LANGID spec at line %u\n", linectr); - continue; - } - if (new_langid(cp, u)) - fprintf(stderr, "Duplicate LANGID spec at line %u language-id %04x %s\n", linectr, u, cp); - DBG(printf("line %5u LANGID %02x %s\n", linectr, u, cp)); - lasthut = lastclass = lastvendor = lastsubclass = -1; - lastlang = u; - continue; - } + if (buf[0] == 'P' && buf[1] == 'H' && buf[2] == 'Y' && + buf[3] == 'S' && buf[4] == 'D' && + buf[5] == 'E' && buf[6] == 'S' && /*isspace(buf[7])*/ + buf[7] == ' ') { + continue; + } + if (buf[0] == 'P' && buf[1] == 'H' && + buf[2] == 'Y' && /*isspace(buf[3])*/ buf[3] == ' ') { + continue; + } + if (buf[0] == 'B' && buf[1] == 'I' && buf[2] == 'A' && + buf[3] == 'S' && /*isspace(buf[4])*/ buf[4] == ' ') { + continue; + } + if (buf[0] == 'L' && /*isspace(buf[1])*/ buf[1] == ' ') { + lasthut = lastclass = lastvendor = lastsubclass = -1; + /* + * set 1 as pseudo-id to indicate that the parser is + * in a `L' section. + */ + lastlang = 1; + continue; + } if (buf[0] == 'C' && /*isspace(buf[1])*/ buf[1] == ' ') { /* class spec */ cp = buf+2; while (isspace(*cp)) cp++; if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid class spec at line %u\n", linectr); + err("Invalid class spec at line %u", linectr); continue; } u = strtoul(cp, &cp, 16); while (isspace(*cp)) cp++; if (!*cp) { - fprintf(stderr, "Invalid class spec at line %u\n", linectr); + err("Invalid class spec at line %u", linectr); continue; } if (new_class(cp, u)) - fprintf(stderr, "Duplicate class spec at line %u class %04x %s\n", linectr, u, cp); - DBG(printf("line %5u class %02x %s\n", linectr, u, cp)); + err("Duplicate class spec at line %u class %04x %s", + linectr, u, cp); + dbg("line %5u class %02x %s", linectr, u, cp); lasthut = lastlang = lastvendor = lastsubclass = -1; lastclass = u; continue; } if (buf[0] == 'A' && buf[1] == 'T' && isspace(buf[2])) { /* audio terminal type spec */ - cp = buf+3; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid audio terminal type at line %u\n", linectr); - continue; - } - if (new_audioterminal(cp, u)) - fprintf(stderr, "Duplicate audio terminal type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u audio terminal type %02x %s\n", linectr, u, cp)); continue; } - if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' && isspace(buf[3])) { + if (buf[0] == 'H' && buf[1] == 'C' && buf[2] == 'C' + && isspace(buf[3])) { /* HID Descriptor bCountryCode */ - cp = buf+3; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid HID country code at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 10); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid HID country code at line %u\n", linectr); - continue; - } - if (new_countrycode(cp, u)) - fprintf(stderr, "Duplicate HID country code at line %u country %02u %s\n", linectr, u, cp); - DBG(printf("line %5u keyboard country code %02u %s\n", linectr, u, cp)); - continue; + continue; } if (isxdigit(*cp)) { /* vendor */ @@ -642,12 +391,13 @@ static void parse(FILE *f) while (isspace(*cp)) cp++; if (!*cp) { - fprintf(stderr, "Invalid vendor spec at line %u\n", linectr); + err("Invalid vendor spec at line %u", linectr); continue; } if (new_vendor(cp, u)) - fprintf(stderr, "Duplicate vendor spec at line %u vendor %04x %s\n", linectr, u, cp); - DBG(printf("line %5u vendor %04x %s\n", linectr, u, cp)); + err("Duplicate vendor spec at line %u vendor %04x %s", + linectr, u, cp); + dbg("line %5u vendor %04x %s", linectr, u, cp); lastvendor = u; lasthut = lastlang = lastclass = lastsubclass = -1; continue; @@ -658,33 +408,37 @@ static void parse(FILE *f) while (isspace(*cp)) cp++; if (!*cp) { - fprintf(stderr, "Invalid product/subclass spec at line %u\n", linectr); + err("Invalid product/subclass spec at line %u", + linectr); continue; } if (lastvendor != -1) { if (new_product(cp, lastvendor, u)) - fprintf(stderr, "Duplicate product spec at line %u product %04x:%04x %s\n", linectr, lastvendor, u, cp); - DBG(printf("line %5u product %04x:%04x %s\n", linectr, lastvendor, u, cp)); + err("Duplicate product spec at line %u product %04x:%04x %s", + linectr, lastvendor, u, cp); + dbg("line %5u product %04x:%04x %s", linectr, + lastvendor, u, cp); continue; } if (lastclass != -1) { if (new_subclass(cp, lastclass, u)) - fprintf(stderr, "Duplicate subclass spec at line %u class %02x:%02x %s\n", linectr, lastclass, u, cp); - DBG(printf("line %5u subclass %02x:%02x %s\n", linectr, lastclass, u, cp)); + err("Duplicate subclass spec at line %u class %02x:%02x %s", + linectr, lastclass, u, cp); + dbg("line %5u subclass %02x:%02x %s", linectr, + lastclass, u, cp); lastsubclass = u; continue; } if (lasthut != -1) { - if (new_hutus(cp, (lasthut << 16)+u)) - fprintf(stderr, "Duplicate HUT Usage Spec at line %u\n", linectr); + /* do not store hut */ continue; } if (lastlang != -1) { - if (new_langid(cp, lastlang+(u<<10))) - fprintf(stderr, "Duplicate LANGID Usage Spec at line %u\n", linectr); - continue; - } - fprintf(stderr, "Product/Subclass spec without prior Vendor/Class spec at line %u\n", linectr); + /* do not store langid */ + continue; + } + err("Product/Subclass spec without prior Vendor/Class spec at line %u", + linectr); continue; } if (buf[0] == '\t' && buf[1] == '\t' && isxdigit(buf[2])) { @@ -693,100 +447,57 @@ static void parse(FILE *f) while (isspace(*cp)) cp++; if (!*cp) { - fprintf(stderr, "Invalid protocol spec at line %u\n", linectr); + err("Invalid protocol spec at line %u", + linectr); continue; } if (lastclass != -1 && lastsubclass != -1) { - if (new_protocol(cp, lastclass, lastsubclass, u)) - fprintf(stderr, "Duplicate protocol spec at line %u class %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp); - DBG(printf("line %5u protocol %02x:%02x:%02x %s\n", linectr, lastclass, lastsubclass, u, cp)); + if (new_protocol(cp, lastclass, lastsubclass, + u)) + err("Duplicate protocol spec at line %u class %02x:%02x:%02x %s", + linectr, lastclass, lastsubclass, + u, cp); + dbg("line %5u protocol %02x:%02x:%02x %s", + linectr, lastclass, lastsubclass, u, cp); continue; } - fprintf(stderr, "Protocol spec without prior Class and Subclass spec at line %u\n", linectr); + err("Protocol spec without prior Class and Subclass spec at line %u", + linectr); continue; } - if (buf[0] == 'H' && buf[1] == 'I' && buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { - cp = buf + 4; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid HID type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid HID type at line %u\n", linectr); - continue; - } - if (new_hid(cp, u)) - fprintf(stderr, "Duplicate HID type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u HID type %02x %s\n", linectr, u, cp)); - continue; - + if (buf[0] == 'H' && buf[1] == 'I' && + buf[2] == 'D' && /*isspace(buf[3])*/ buf[3] == ' ') { + continue; } - if (buf[0] == 'H' && buf[1] == 'U' && buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { - cp = buf + 4; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid HUT type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid HUT type at line %u\n", linectr); - continue; - } - if (new_huts(cp, u)) - fprintf(stderr, "Duplicate HUT type spec at line %u terminal type %04x %s\n", linectr, u, cp); + if (buf[0] == 'H' && buf[1] == 'U' && + buf[2] == 'T' && /*isspace(buf[3])*/ buf[3] == ' ') { lastlang = lastclass = lastvendor = lastsubclass = -1; - lasthut = u; - DBG(printf("line %5u HUT type %02x %s\n", linectr, u, cp)); - continue; - - } - if (buf[0] == 'R' && buf[1] == ' ') { - cp = buf + 2; - while (isspace(*cp)) - cp++; - if (!isxdigit(*cp)) { - fprintf(stderr, "Invalid Report type at line %u\n", linectr); - continue; - } - u = strtoul(cp, &cp, 16); - while (isspace(*cp)) - cp++; - if (!*cp) { - fprintf(stderr, "Invalid Report type at line %u\n", linectr); - continue; - } - if (new_reporttag(cp, u)) - fprintf(stderr, "Duplicate Report type spec at line %u terminal type %04x %s\n", linectr, u, cp); - DBG(printf("line %5u Report type %02x %s\n", linectr, u, cp)); - continue; - - } - if (buf[0] == 'V' && buf[1] == 'T') { - /* add here */ + /* + * set 1 as pseudo-id to indicate that the parser is + * in a `HUT' section. + */ + lasthut = 1; continue; } - fprintf(stderr, "Unknown line at line %u\n", linectr); + if (buf[0] == 'R' && buf[1] == ' ') + continue; + + if (buf[0] == 'V' && buf[1] == 'T') + continue; + + err("Unknown line at line %u", linectr); } } -/* ---------------------------------------------------------------------- */ int names_init(char *n) { FILE *f; - if (!(f = fopen(n, "r"))) { + f = fopen(n, "r"); + if (!f) return errno; - } + parse(f); fclose(f); return 0; diff --git a/drivers/staging/usbip/userspace/libsrc/names.h b/drivers/staging/usbip/userspace/libsrc/names.h index 3a269fecc02..680926512de 100644 --- a/drivers/staging/usbip/userspace/libsrc/names.h +++ b/drivers/staging/usbip/userspace/libsrc/names.h @@ -1,5 +1,3 @@ -/*****************************************************************************/ - /* * names.h -- USB name database manipulation routines * @@ -20,38 +18,24 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * - */ - -/* + * * Copyright (C) 2005 Takahiro Hirofuchi * - names_free() is added. */ -/*****************************************************************************/ - #ifndef _NAMES_H #define _NAMES_H #include <sys/types.h> -/* ---------------------------------------------------------------------- */ - +/* used by usbip_common.c */ extern const char *names_vendor(u_int16_t vendorid); extern const char *names_product(u_int16_t vendorid, u_int16_t productid); extern const char *names_class(u_int8_t classid); extern const char *names_subclass(u_int8_t classid, u_int8_t subclassid); -extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, u_int8_t protocolid); -extern const char *names_audioterminal(u_int16_t termt); -extern const char *names_hid(u_int8_t hidd); -extern const char *names_reporttag(u_int8_t rt); -extern const char *names_huts(unsigned int data); -extern const char *names_hutus(unsigned int data); -extern const char *names_langid(u_int16_t langid); -extern const char *names_physdes(u_int8_t ph); -extern const char *names_bias(u_int8_t b); -extern const char *names_countrycode(unsigned int countrycode); +extern const char *names_protocol(u_int8_t classid, u_int8_t subclassid, + u_int8_t protocolid); extern int names_init(char *n); extern void names_free(void); -/* ---------------------------------------------------------------------- */ #endif /* _NAMES_H */ diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c new file mode 100644 index 00000000000..36ac88ece0b --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.c @@ -0,0 +1,31 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#include "sysfs_utils.h" +#include "usbip_common.h" + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len) +{ + int fd; + int length; + + fd = open(attr_path, O_WRONLY); + if (fd < 0) { + dbg("error opening attribute %s", attr_path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dbg("error writing to attribute %s", attr_path); + close(fd); + return -1; + } + + close(fd); + + return 0; +} diff --git a/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h new file mode 100644 index 00000000000..32ac1d105d1 --- /dev/null +++ b/drivers/staging/usbip/userspace/libsrc/sysfs_utils.h @@ -0,0 +1,8 @@ + +#ifndef __SYSFS_UTILS_H +#define __SYSFS_UTILS_H + +int write_sysfs_attribute(const char *attr_path, const char *new_value, + size_t len); + +#endif diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.c b/drivers/staging/usbip/userspace/libsrc/usbip_common.c index 154b4b1103e..ac73710473d 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_common.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.c @@ -2,15 +2,18 @@ * Copyright (C) 2005-2007 Takahiro Hirofuchi */ +#include <libudev.h> #include "usbip_common.h" #include "names.h" #undef PROGNAME #define PROGNAME "libusbip" -int usbip_use_syslog = 0; -int usbip_use_stderr = 0; -int usbip_use_debug = 0; +int usbip_use_syslog; +int usbip_use_stderr; +int usbip_use_debug; + +extern struct udev *udev_context; struct speed_string { int num; @@ -23,6 +26,8 @@ static const struct speed_string speed_strings[] = { { USB_SPEED_LOW, "1.5", "Low Speed(1.5Mbps)" }, { USB_SPEED_FULL, "12", "Full Speed(12Mbps)" }, { USB_SPEED_HIGH, "480", "High Speed(480Mbps)" }, + { USB_SPEED_WIRELESS, "53.3-480", "Wireless"}, + { USB_SPEED_SUPER, "5000", "Super Speed(5000Mbps)" }, { 0, NULL, NULL } }; @@ -44,7 +49,7 @@ static struct portst_string portst_strings[] = { const char *usbip_status_string(int32_t status) { - for (int i=0; portst_strings[i].desc != NULL; i++) + for (int i = 0; portst_strings[i].desc != NULL; i++) if (portst_strings[i].num == status) return portst_strings[i].desc; @@ -53,7 +58,7 @@ const char *usbip_status_string(int32_t status) const char *usbip_speed_string(int num) { - for (int i=0; speed_strings[i].speed != NULL; i++) + for (int i = 0; speed_strings[i].speed != NULL; i++) if (speed_strings[i].num == num) return speed_strings[i].desc; @@ -70,6 +75,7 @@ const char *usbip_speed_string(int num) void dump_usb_interface(struct usbip_usb_interface *uinf) { char buff[100]; + usbip_names_get_class(buff, sizeof(buff), uinf->bInterfaceClass, uinf->bInterfaceSubClass, @@ -81,7 +87,6 @@ void dump_usb_device(struct usbip_usb_device *udev) { char buff[100]; - dbg("%-20s = %s", "path", udev->path); dbg("%-20s = %s", "busid", udev->busid); @@ -109,84 +114,75 @@ void dump_usb_device(struct usbip_usb_device *udev) } -int read_attr_value(struct sysfs_device *dev, const char *name, const char *format) +int read_attr_value(struct udev_device *dev, const char *name, + const char *format) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + const char *attr; int num = 0; int ret; - snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, name); - - attr = sysfs_open_attribute(attrpath); + attr = udev_device_get_sysattr_value(dev, name); if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); - return 0; - } - - ret = sysfs_read_attribute(attr); - if (ret < 0) { - dbg("sysfs_read_attribute failed"); + err("udev_device_get_sysattr_value failed"); goto err; } - ret = sscanf(attr->value, format, &num); + /* The client chooses the device configuration + * when attaching it so right after being bound + * to usbip-host on the server the device will + * have no configuration. + * Therefore, attributes such as bConfigurationValue + * and bNumInterfaces will not exist and sscanf will + * fail. Check for these cases and don't treat them + * as errors. + */ + + ret = sscanf(attr, format, &num); if (ret < 1) { - dbg("sscanf failed"); - goto err; + if (strcmp(name, "bConfigurationValue") && + strcmp(name, "bNumInterfaces")) { + err("sscanf failed for attribute %s", name); + goto err; + } } err: - sysfs_close_attribute(attr); return num; } -int read_attr_speed(struct sysfs_device *dev) +int read_attr_speed(struct udev_device *dev) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; - char speed[100]; - int ret; - - snprintf(attrpath, sizeof(attrpath), "%s/%s", dev->path, "speed"); + const char *speed; - attr = sysfs_open_attribute(attrpath); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); - return 0; - } - - ret = sysfs_read_attribute(attr); - if (ret < 0) { - dbg("sysfs_read_attribute failed"); - goto err; - } - - ret = sscanf(attr->value, "%s\n", speed); - if (ret < 1) { - dbg("sscanf failed"); + speed = udev_device_get_sysattr_value(dev, "speed"); + if (!speed) { + err("udev_device_get_sysattr_value failed"); goto err; } -err: - sysfs_close_attribute(attr); - for (int i=0; speed_strings[i].speed != NULL; i++) { + for (int i = 0; speed_strings[i].speed != NULL; i++) { if (!strcmp(speed, speed_strings[i].speed)) return speed_strings[i].num; } +err: + return USB_SPEED_UNKNOWN; } -#define READ_ATTR(object, type, dev, name, format)\ - do { (object)->name = (type) read_attr_value(dev, to_string(name), format); } while (0) +#define READ_ATTR(object, type, dev, name, format) \ + do { \ + (object)->name = (type) read_attr_value(dev, to_string(name), \ + format); \ + } while (0) -int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev) +int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev) { uint32_t busnum, devnum; + const char *path, *name; READ_ATTR(udev, uint8_t, sdev, bDeviceClass, "%02x\n"); READ_ATTR(udev, uint8_t, sdev, bDeviceSubClass, "%02x\n"); @@ -203,10 +199,13 @@ int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev) READ_ATTR(udev, uint8_t, sdev, devnum, "%d\n"); udev->speed = read_attr_speed(sdev); - strncpy(udev->path, sdev->path, SYSFS_PATH_MAX); - strncpy(udev->busid, sdev->name, SYSFS_BUS_ID_SIZE); + path = udev_device_get_syspath(sdev); + name = udev_device_get_sysname(sdev); - sscanf(sdev->name, "%u-%u", &busnum, &devnum); + strncpy(udev->path, path, SYSFS_PATH_MAX); + strncpy(udev->busid, name, SYSFS_BUS_ID_SIZE); + + sscanf(name, "%u-%u", &busnum, &devnum); udev->busnum = busnum; return 0; @@ -216,13 +215,13 @@ int read_usb_interface(struct usbip_usb_device *udev, int i, struct usbip_usb_interface *uinf) { char busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *sif; + struct udev_device *sif; sprintf(busid, "%s:%d.%d", udev->busid, udev->bConfigurationValue, i); - sif = sysfs_open_device("usb", busid); + sif = udev_device_new_from_subsystem_sysname(udev_context, "usb", busid); if (!sif) { - dbg("sysfs_open_device(\"usb\", \"%s\") failed", busid); + err("udev_device_new_from_subsystem_sysname %s failed", busid); return -1; } @@ -230,8 +229,6 @@ int read_usb_interface(struct usbip_usb_device *udev, int i, READ_ATTR(uinf, uint8_t, sif, bInterfaceSubClass, "%02x\n"); READ_ATTR(uinf, uint8_t, sif, bInterfaceProtocol, "%02x\n"); - sysfs_close_device(sif); - return 0; } @@ -240,12 +237,13 @@ int usbip_names_init(char *f) return names_init(f); } -void usbip_names_free() +void usbip_names_free(void) { names_free(); } -void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product) +void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, + uint16_t product) { const char *prod, *vend; @@ -261,7 +259,8 @@ void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t snprintf(buff, size, "%s : %s (%04x:%04x)", vend, prod, vendor, product); } -void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol) +void usbip_names_get_class(char *buff, size_t size, uint8_t class, + uint8_t subclass, uint8_t protocol) { const char *c, *s, *p; diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h index eedefbd12ea..5a0e95edf4d 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_common.h +++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.h @@ -5,7 +5,7 @@ #ifndef __USBIP_COMMON_H #define __USBIP_COMMON_H -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <stdint.h> #include <stdio.h> @@ -14,6 +14,8 @@ #include <syslog.h> #include <unistd.h> +#include <linux/usb/ch9.h> +#include "../../uapi/usbip.h" #ifndef USBIDS_FILE #define USBIDS_FILE "/usr/share/hwdata/usb.ids" @@ -28,6 +30,15 @@ #define USBIP_HOST_DRV_NAME "usbip-host" #define USBIP_VHCI_DRV_NAME "vhci_hcd" +/* sysfs constants */ +#define SYSFS_MNT_PATH "/sys" +#define SYSFS_BUS_NAME "bus" +#define SYSFS_BUS_TYPE "usb" +#define SYSFS_DRIVERS_NAME "drivers" + +#define SYSFS_PATH_MAX 256 +#define SYSFS_BUS_ID_SIZE 32 + extern int usbip_use_syslog; extern int usbip_use_stderr; extern int usbip_use_debug ; @@ -36,7 +47,7 @@ extern int usbip_use_debug ; #define pr_fmt(fmt) "%s: %s: " fmt "\n", PROGNAME #define dbg_fmt(fmt) pr_fmt("%s:%d:[%s] " fmt), "debug", \ - __FILE__, __LINE__, __FUNCTION__ + __FILE__, __LINE__, __func__ #define err(fmt, args...) \ do { \ @@ -76,30 +87,6 @@ extern int usbip_use_debug ; abort(); \ } while (0) -enum usb_device_speed { - USB_SPEED_UNKNOWN = 0, /* enumerating */ - USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */ - USB_SPEED_HIGH, /* usb 2.0 */ - USB_SPEED_VARIABLE /* wireless (usb 2.5) */ -}; - -/* FIXME: how to sync with drivers/usbip_common.h ? */ -enum usbip_device_status{ - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - struct usbip_usb_interface { uint8_t bInterfaceClass; uint8_t bInterfaceSubClass; @@ -131,8 +118,9 @@ struct usbip_usb_device { void dump_usb_interface(struct usbip_usb_interface *); void dump_usb_device(struct usbip_usb_device *); -int read_usb_device(struct sysfs_device *sdev, struct usbip_usb_device *udev); -int read_attr_value(struct sysfs_device *dev, const char *name, const char *format); +int read_usb_device(struct udev_device *sdev, struct usbip_usb_device *udev); +int read_attr_value(struct udev_device *dev, const char *name, + const char *format); int read_usb_interface(struct usbip_usb_device *udev, int i, struct usbip_usb_interface *uinf); @@ -141,7 +129,9 @@ const char *usbip_status_string(int32_t status); int usbip_names_init(char *); void usbip_names_free(void); -void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, uint16_t product); -void usbip_names_get_class(char *buff, size_t size, uint8_t class, uint8_t subclass, uint8_t protocol); +void usbip_names_get_product(char *buff, size_t size, uint16_t vendor, + uint16_t product); +void usbip_names_get_class(char *buff, size_t size, uint8_t class, + uint8_t subclass, uint8_t protocol); #endif /* __USBIP_COMMON_H */ diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c index 71a449cf50d..92caef7474c 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c @@ -18,102 +18,65 @@ #include <sys/types.h> #include <sys/stat.h> +#include <fcntl.h> #include <errno.h> #include <unistd.h> +#include <libudev.h> + #include "usbip_common.h" #include "usbip_host_driver.h" +#include "list.h" +#include "sysfs_utils.h" #undef PROGNAME #define PROGNAME "libusbip" struct usbip_host_driver *host_driver; +struct udev *udev_context; -#define SYSFS_OPEN_RETRIES 100 - -/* only the first interface value is true! */ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) { - char attrpath[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + char status_attr_path[SYSFS_PATH_MAX]; + int fd; + int length; + char status; int value = 0; - int rc; - struct stat s; - int retries = SYSFS_OPEN_RETRIES; - - /* This access is racy! - * - * Just after detach, our driver removes the sysfs - * files and recreates them. - * - * We may try and fail to open the usbip_status of - * an exported device in the (short) window where - * it has been removed and not yet recreated. - * - * This is a bug in the interface. Nothing we can do - * except work around it here by polling for the sysfs - * usbip_status to reappear. - */ - - snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status", - udev->path, udev->busid, udev->bConfigurationValue, 0); - - while (retries > 0) { - if (stat(attrpath, &s) == 0) - break; - - if (errno != ENOENT) { - dbg("stat failed: %s", attrpath); - return -1; - } - - usleep(10000); /* 10ms */ - retries--; - } - if (retries == 0) - dbg("usbip_status not ready after %d retries", - SYSFS_OPEN_RETRIES); - else if (retries < SYSFS_OPEN_RETRIES) - dbg("warning: usbip_status ready after %d retries", - SYSFS_OPEN_RETRIES - retries); + snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status", + udev->path); - attr = sysfs_open_attribute(attrpath); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attrpath); + if ((fd = open(status_attr_path, O_RDONLY)) < 0) { + err("error opening attribute %s", status_attr_path); return -1; } - rc = sysfs_read_attribute(attr); - if (rc) { - dbg("sysfs_read_attribute failed: %s", attrpath); - sysfs_close_attribute(attr); + length = read(fd, &status, 1); + if (length < 0) { + err("error reading attribute %s", status_attr_path); + close(fd); return -1; } - value = atoi(attr->value); - - sysfs_close_attribute(attr); + value = atoi(&status); return value; } -static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) +static +struct usbip_exported_device *usbip_exported_device_new(const char *sdevpath) { struct usbip_exported_device *edev = NULL; + struct usbip_exported_device *edev_old; size_t size; int i; - edev = calloc(1, sizeof(*edev)); - if (!edev) { - dbg("calloc failed"); - return NULL; - } + edev = calloc(1, sizeof(struct usbip_exported_device)); - edev->sudev = sysfs_open_device_path(sdevpath); + edev->sudev = udev_device_new_from_syspath(udev_context, sdevpath); if (!edev->sudev) { - dbg("sysfs_open_device_path failed: %s", sdevpath); + err("udev_device_new_from_syspath: %s", sdevpath); goto err; } @@ -124,11 +87,13 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) goto err; /* reallocate buffer to include usb interface data */ - size = sizeof(*edev) + edev->udev.bNumInterfaces * + size = sizeof(struct usbip_exported_device) + edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); + edev_old = edev; edev = realloc(edev, size); if (!edev) { + edev = edev_old; dbg("realloc failed"); goto err; } @@ -138,160 +103,91 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) return edev; err: - if (edev && edev->sudev) - sysfs_close_device(edev->sudev); + if (edev->sudev) + udev_device_unref(edev->sudev); if (edev) free(edev); return NULL; } -static int check_new(struct dlist *dlist, struct sysfs_device *target) -{ - struct sysfs_device *dev; - - dlist_for_each_data(dlist, dev, struct sysfs_device) { - if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE)) - /* device found and is not new */ - return 0; - } - return 1; -} - -static void delete_nothing(void *unused_data) -{ - /* - * NOTE: Do not delete anything, but the container will be deleted. - */ - (void) unused_data; -} - static int refresh_exported_devices(void) { - /* sysfs_device of usb_interface */ - struct sysfs_device *suintf; - struct dlist *suintf_list; - /* sysfs_device of usb_device */ - struct sysfs_device *sudev; - struct dlist *sudev_list; struct usbip_exported_device *edev; - - sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), - delete_nothing); - - suintf_list = sysfs_get_driver_devices(host_driver->sysfs_driver); - if (!suintf_list) { - /* - * Not an error condition. There are simply no devices bound to - * the driver yet. - */ - dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be " - "exportable!"); - return 0; - } - - /* collect unique USB devices (not interfaces) */ - dlist_for_each_data(suintf_list, suintf, struct sysfs_device) { - /* get usb device of this usb interface */ - sudev = sysfs_get_device_parent(suintf); - if (!sudev) { - dbg("sysfs_get_device_parent failed: %s", suintf->name); + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + const char *path; + const char *driver; + + enumerate = udev_enumerate_new(udev_context); + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + udev_list_entry_foreach(dev_list_entry, devices) { + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev_context, path); + if (dev == NULL) continue; - } - - if (check_new(sudev_list, sudev)) { - /* insert item at head of list */ - dlist_unshift(sudev_list, sudev); - } - } - dlist_for_each_data(sudev_list, sudev, struct sysfs_device) { - edev = usbip_exported_device_new(sudev->path); - if (!edev) { - dbg("usbip_exported_device_new failed"); - continue; + /* Check whether device uses usbip-host driver. */ + driver = udev_device_get_driver(dev); + if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { + edev = usbip_exported_device_new(path); + if (!edev) { + dbg("usbip_exported_device_new failed"); + continue; + } + + list_add(&edev->node, &host_driver->edev_list); + host_driver->ndevs++; } - - dlist_unshift(host_driver->edev_list, edev); - host_driver->ndevs++; } - dlist_destroy(sudev_list); - return 0; } -static struct sysfs_driver *open_sysfs_host_driver(void) +static void usbip_exported_device_destroy(void) { - char bus_type[] = "usb"; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char host_drv_path[SYSFS_PATH_MAX]; - struct sysfs_driver *host_drv; - int rc; - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - dbg("sysfs_get_mnt_path failed"); - return NULL; - } - - snprintf(host_drv_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, - USBIP_HOST_DRV_NAME); + struct list_head *i, *tmp; + struct usbip_exported_device *edev; - host_drv = sysfs_open_driver_path(host_drv_path); - if (!host_drv) { - dbg("sysfs_open_driver_path failed"); - return NULL; + list_for_each_safe(i, tmp, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); + list_del(i); + free(edev); } - - return host_drv; -} - -static void usbip_exported_device_delete(void *dev) -{ - struct usbip_exported_device *edev = dev; - sysfs_close_device(edev->sudev); - free(dev); } int usbip_host_driver_open(void) { int rc; - host_driver = calloc(1, sizeof(*host_driver)); - if (!host_driver) { - dbg("calloc failed"); + udev_context = udev_new(); + if (!udev_context) { + err("udev_new failed"); return -1; } - host_driver->ndevs = 0; - host_driver->edev_list = - dlist_new_with_delete(sizeof(struct usbip_exported_device), - usbip_exported_device_delete); - if (!host_driver->edev_list) { - dbg("dlist_new_with_delete failed"); - goto err_free_host_driver; - } + host_driver = calloc(1, sizeof(*host_driver)); - host_driver->sysfs_driver = open_sysfs_host_driver(); - if (!host_driver->sysfs_driver) - goto err_destroy_edev_list; + host_driver->ndevs = 0; + INIT_LIST_HEAD(&host_driver->edev_list); rc = refresh_exported_devices(); if (rc < 0) - goto err_close_sysfs_driver; + goto err_free_host_driver; return 0; -err_close_sysfs_driver: - sysfs_close_driver(host_driver->sysfs_driver); -err_destroy_edev_list: - dlist_destroy(host_driver->edev_list); err_free_host_driver: free(host_driver); host_driver = NULL; + udev_unref(udev_context); + return -1; } @@ -300,30 +196,22 @@ void usbip_host_driver_close(void) if (!host_driver) return; - if (host_driver->edev_list) - dlist_destroy(host_driver->edev_list); - if (host_driver->sysfs_driver) - sysfs_close_driver(host_driver->sysfs_driver); + usbip_exported_device_destroy(); free(host_driver); host_driver = NULL; + + udev_unref(udev_context); } int usbip_host_refresh_device_list(void) { int rc; - if (host_driver->edev_list) - dlist_destroy(host_driver->edev_list); + usbip_exported_device_destroy(); host_driver->ndevs = 0; - host_driver->edev_list = - dlist_new_with_delete(sizeof(struct usbip_exported_device), - usbip_exported_device_delete); - if (!host_driver->edev_list) { - dbg("dlist_new_with_delete failed"); - return -1; - } + INIT_LIST_HEAD(&host_driver->edev_list); rc = refresh_exported_devices(); if (rc < 0) @@ -335,8 +223,7 @@ int usbip_host_refresh_device_list(void) int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) { char attr_name[] = "usbip_sockfd"; - char attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *attr; + char sockfd_attr_path[SYSFS_PATH_MAX]; char sockfd_buff[30]; int ret; @@ -356,41 +243,32 @@ int usbip_host_export_device(struct usbip_exported_device *edev, int sockfd) } /* only the first interface is true */ - snprintf(attr_path, sizeof(attr_path), "%s/%s:%d.%d/%s", - edev->udev.path, edev->udev.busid, - edev->udev.bConfigurationValue, 0, attr_name); - - attr = sysfs_open_attribute(attr_path); - if (!attr) { - dbg("sysfs_open_attribute failed: %s", attr_path); - return -1; - } + snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s", + edev->udev.path, attr_name); snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd); - dbg("write: %s", sockfd_buff); - ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff)); + ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff, + strlen(sockfd_buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed: sockfd %s to %s", - sockfd_buff, attr_path); - goto err_write_sockfd; + err("write_sysfs_attribute failed: sockfd %s to %s", + sockfd_buff, sockfd_attr_path); + return ret; } - dbg("connect: %s", edev->udev.busid); - -err_write_sockfd: - sysfs_close_attribute(attr); + info("connect: %s", edev->udev.busid); return ret; } struct usbip_exported_device *usbip_host_get_device(int num) { + struct list_head *i; struct usbip_exported_device *edev; - struct dlist *dlist = host_driver->edev_list; int cnt = 0; - dlist_for_each_data(dlist, edev, struct usbip_exported_device) { + list_for_each(i, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); if (num == cnt) return edev; else diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h index 34fd14cbfc4..2a31f855c61 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.h @@ -21,18 +21,19 @@ #include <stdint.h> #include "usbip_common.h" +#include "list.h" struct usbip_host_driver { int ndevs; - struct sysfs_driver *sysfs_driver; /* list of exported device */ - struct dlist *edev_list; + struct list_head edev_list; }; struct usbip_exported_device { - struct sysfs_device *sudev; + struct udev_device *sudev; int32_t status; struct usbip_usb_device udev; + struct list_head node; struct usbip_usb_interface uinf[]; }; diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c index 269787751b2..ad920477353 100644 --- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c @@ -4,41 +4,30 @@ #include "usbip_common.h" #include "vhci_driver.h" +#include <limits.h> +#include <netdb.h> +#include <libudev.h> +#include "sysfs_utils.h" #undef PROGNAME #define PROGNAME "libusbip" struct usbip_vhci_driver *vhci_driver; +struct udev *udev_context; -static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid) +static struct usbip_imported_device * +imported_device_init(struct usbip_imported_device *idev, char *busid) { - struct sysfs_device *sudev; + struct udev_device *sudev; - sudev = sysfs_open_device("usb", busid); + sudev = udev_device_new_from_subsystem_sysname(udev_context, + "usb", busid); if (!sudev) { - dbg("sysfs_open_device failed: %s", busid); + dbg("udev_device_new_from_subsystem_sysname failed: %s", busid); goto err; } read_usb_device(sudev, &idev->udev); - sysfs_close_device(sudev); - - /* add class devices of this imported device */ - struct usbip_class_device *cdev; - dlist_for_each_data(vhci_driver->cdev_list, cdev, - struct usbip_class_device) { - if (!strncmp(cdev->dev_path, idev->udev.path, - strlen(idev->udev.path))) { - struct usbip_class_device *new_cdev; - - /* alloc and copy because dlist is linked from only one list */ - new_cdev = calloc(1, sizeof(*new_cdev)); - if (!new_cdev) - goto err; - - memcpy(new_cdev, cdev, sizeof(*new_cdev)); - dlist_unshift(idev->cdev_list, (void*) new_cdev); - } - } + udev_device_unref(sudev); return idev; @@ -48,7 +37,7 @@ err: -static int parse_status(char *value) +static int parse_status(const char *value) { int ret = 0; char *c; @@ -59,14 +48,17 @@ static int parse_status(char *value) /* skip a header line */ - c = strchr(value, '\n') + 1; + c = strchr(value, '\n'); + if (!c) + return -1; + c++; while (*c != '\0') { int port, status, speed, devid; unsigned long socket; char lbusid[SYSFS_BUS_ID_SIZE]; - ret = sscanf(c, "%d %d %d %x %lx %s\n", + ret = sscanf(c, "%d %d %d %x %lx %31s\n", &port, &status, &speed, &devid, &socket, lbusid); @@ -92,13 +84,8 @@ static int parse_status(char *value) idev->busnum = (devid >> 16); idev->devnum = (devid & 0x0000ffff); - idev->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!idev->cdev_list) { - dbg("dlist_new failed"); - return -1; - } - - if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) { + if (idev->status != VDEV_ST_NULL + && idev->status != VDEV_ST_NOTASSIGNED) { idev = imported_device_init(idev, lbusid); if (!idev) { dbg("imported_device_init failed"); @@ -109,7 +96,10 @@ static int parse_status(char *value) /* go to the next line */ - c = strchr(c, '\n') + 1; + c = strchr(c, '\n'); + if (!c) + break; + c++; } dbg("exit"); @@ -117,237 +107,133 @@ static int parse_status(char *value) return 0; } - -static int check_usbip_device(struct sysfs_class_device *cdev) -{ - char class_path[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */ - char dev_path[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */ - int ret; - struct usbip_class_device *usbip_cdev; - - snprintf(class_path, sizeof(class_path), "%s/device", cdev->path); - - ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path)); - if (ret == 0) { - if (!strncmp(dev_path, vhci_driver->hc_device->path, - strlen(vhci_driver->hc_device->path))) { - /* found usbip device */ - usbip_cdev = calloc(1, sizeof(*usbip_cdev)); - if (!usbip_cdev) { - dbg("calloc failed"); - return -1; - } - dlist_unshift(vhci_driver->cdev_list, usbip_cdev); - strncpy(usbip_cdev->class_path, class_path, - sizeof(usbip_cdev->class_path)); - strncpy(usbip_cdev->dev_path, dev_path, - sizeof(usbip_cdev->dev_path)); - dbg("found: %s %s", class_path, dev_path); - } - } - - return 0; -} - - -static int search_class_for_usbip_device(char *cname) -{ - struct sysfs_class *class; - struct dlist *cdev_list; - struct sysfs_class_device *cdev; - int ret = 0; - - class = sysfs_open_class(cname); - if (!class) { - dbg("sysfs_open_class failed"); - return -1; - } - - dbg("class: %s", class->name); - - cdev_list = sysfs_get_class_devices(class); - if (!cdev_list) - /* nothing */ - goto out; - - dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) { - dbg("cdev: %s", cdev->name); - ret = check_usbip_device(cdev); - if (ret < 0) - goto out; - } - -out: - sysfs_close_class(class); - - return ret; -} - - -static int refresh_class_device_list(void) -{ - int ret; - struct dlist *cname_list; - char *cname; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char class_path[SYSFS_PATH_MAX]; - - ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (ret < 0) { - dbg("sysfs_get_mnt_path failed"); - return -1; - } - - snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath, - SYSFS_CLASS_NAME); - - /* search under /sys/class */ - cname_list = sysfs_open_directory_list(class_path); - if (!cname_list) { - dbg("sysfs_open_directory failed"); - return -1; - } - - dlist_for_each_data(cname_list, cname, char) { - ret = search_class_for_usbip_device(cname); - if (ret < 0) { - sysfs_close_list(cname_list); - return -1; - } - } - - sysfs_close_list(cname_list); - - /* seach under /sys/block */ - ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME); - if (ret < 0) - return -1; - - return 0; -} - - static int refresh_imported_device_list(void) { - struct sysfs_attribute *attr_status; + const char *attr_status; - - attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); + attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, + "status"); if (!attr_status) { - dbg("sysfs_get_device_attr(\"status\") failed: %s", - vhci_driver->hc_device->name); + err("udev_device_get_sysattr_value failed"); return -1; } - dbg("name: %s path: %s len: %d method: %d value: %s", - attr_status->name, attr_status->path, attr_status->len, - attr_status->method, attr_status->value); - - return parse_status(attr_status->value); + return parse_status(attr_status); } static int get_nports(void) { char *c; int nports = 0; - struct sysfs_attribute *attr_status; + const char *attr_status; - attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status"); + attr_status = udev_device_get_sysattr_value(vhci_driver->hc_device, + "status"); if (!attr_status) { - dbg("sysfs_get_device_attr(\"status\") failed: %s", - vhci_driver->hc_device->name); + err("udev_device_get_sysattr_value failed"); return -1; } - dbg("name: %s path: %s len: %d method: %d value: %s", - attr_status->name, attr_status->path, attr_status->len, - attr_status->method, attr_status->value); - /* skip a header line */ - c = strchr(attr_status->value, '\n') + 1; + c = strchr(attr_status, '\n'); + if (!c) + return 0; + c++; while (*c != '\0') { /* go to the next line */ - c = strchr(c, '\n') + 1; + c = strchr(c, '\n'); + if (!c) + return nports; + c++; nports += 1; } return nports; } -static int get_hc_busid(char *sysfs_mntpath, char *hc_busid) +/* + * Read the given port's record. + * + * To avoid buffer overflow we will read the entire line and + * validate each part's size. The initial buffer is padded by 4 to + * accommodate the 2 spaces, 1 newline and an additional character + * which is needed to properly validate the 3rd part without it being + * truncated to an acceptable length. + */ +static int read_record(int rhport, char *host, unsigned long host_len, + char *port, unsigned long port_len, char *busid) { - struct sysfs_driver *sdriver; - char sdriver_path[SYSFS_PATH_MAX]; - - struct sysfs_device *hc_dev; - struct dlist *hc_devs; - - int found = 0; - - snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/%s/%s/%s", sysfs_mntpath, - SYSFS_BUS_NAME, USBIP_VHCI_BUS_TYPE, SYSFS_DRIVERS_NAME, - USBIP_VHCI_DRV_NAME); + int part; + FILE *file; + char path[PATH_MAX+1]; + char *buffer, *start, *end; + char delim[] = {' ', ' ', '\n'}; + int max_len[] = {(int)host_len, (int)port_len, SYSFS_BUS_ID_SIZE}; + size_t buffer_len = host_len + port_len + SYSFS_BUS_ID_SIZE + 4; + + buffer = malloc(buffer_len); + if (!buffer) + return -1; - sdriver = sysfs_open_driver_path(sdriver_path); - if (!sdriver) { - dbg("sysfs_open_driver_path failed: %s", sdriver_path); - dbg("make sure " USBIP_CORE_MOD_NAME ".ko and " - USBIP_VHCI_DRV_NAME ".ko are loaded!"); - return -1; - } + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); - hc_devs = sysfs_get_driver_devices(sdriver); - if (!hc_devs) { - dbg("sysfs_get_driver failed"); - goto err; + file = fopen(path, "r"); + if (!file) { + err("fopen"); + free(buffer); + return -1; } - /* assume only one vhci_hcd */ - dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) { - strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE); - found = 1; + if (fgets(buffer, buffer_len, file) == NULL) { + err("fgets"); + free(buffer); + fclose(file); + return -1; + } + fclose(file); + + /* validate the length of each of the 3 parts */ + start = buffer; + for (part = 0; part < 3; part++) { + end = strchr(start, delim[part]); + if (end == NULL || (end - start) > max_len[part]) { + free(buffer); + return -1; + } + start = end + 1; } -err: - sysfs_close_driver(sdriver); + if (sscanf(buffer, "%s %s %s\n", host, port, busid) != 3) { + err("sscanf"); + free(buffer); + return -1; + } - if (found) - return 0; + free(buffer); - dbg("%s not found", hc_busid); - return -1; + return 0; } - /* ---------------------------------------------------------------------- */ int usbip_vhci_driver_open(void) { - int ret; - char hc_busid[SYSFS_BUS_ID_SIZE]; - - vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver)); - if (!vhci_driver) { - dbg("calloc failed"); + udev_context = udev_new(); + if (!udev_context) { + err("udev_new failed"); return -1; } - ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX); - if (ret < 0) { - dbg("sysfs_get_mnt_path failed"); - goto err; - } - - ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid); - if (ret < 0) - goto err; + vhci_driver = calloc(1, sizeof(struct usbip_vhci_driver)); /* will be freed in usbip_driver_close() */ - vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE, - hc_busid); + vhci_driver->hc_device = + udev_device_new_from_subsystem_sysname(udev_context, + USBIP_VHCI_BUS_TYPE, + USBIP_VHCI_DRV_NAME); if (!vhci_driver->hc_device) { - dbg("sysfs_open_device failed"); + err("udev_device_new_from_subsystem_sysname failed"); goto err; } @@ -355,85 +241,48 @@ int usbip_vhci_driver_open(void) dbg("available ports: %d", vhci_driver->nports); - vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!vhci_driver->cdev_list) - goto err; - - if (refresh_class_device_list()) - goto err; - if (refresh_imported_device_list()) goto err; - return 0; - err: - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - if (vhci_driver->hc_device) - sysfs_close_device(vhci_driver->hc_device); + udev_device_unref(vhci_driver->hc_device); + if (vhci_driver) free(vhci_driver); vhci_driver = NULL; + + udev_unref(udev_context); + return -1; } -void usbip_vhci_driver_close() +void usbip_vhci_driver_close(void) { if (!vhci_driver) return; - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } + udev_device_unref(vhci_driver->hc_device); - if (vhci_driver->hc_device) - sysfs_close_device(vhci_driver->hc_device); free(vhci_driver); vhci_driver = NULL; + + udev_unref(udev_context); } int usbip_vhci_refresh_device_list(void) { - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } - - vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device)); - if (!vhci_driver->cdev_list) - goto err; - - if (refresh_class_device_list()) - goto err; if (refresh_imported_device_list()) goto err; return 0; err: - if (vhci_driver->cdev_list) - dlist_destroy(vhci_driver->cdev_list); - - for (int i = 0; i < vhci_driver->nports; i++) { - if (vhci_driver->idev[i].cdev_list) - dlist_destroy(vhci_driver->idev[i].cdev_list); - } - dbg("failed to refresh device list"); return -1; } @@ -451,24 +300,24 @@ int usbip_vhci_get_free_port(void) int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, uint32_t speed) { - struct sysfs_attribute *attr_attach; char buff[200]; /* what size should be ? */ + char attach_attr_path[SYSFS_PATH_MAX]; + char attr_attach[] = "attach"; + const char *path; int ret; - attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach"); - if (!attr_attach) { - dbg("sysfs_get_device_attr(\"attach\") failed: %s", - vhci_driver->hc_device->name); - return -1; - } - - snprintf(buff, sizeof(buff), "%u %u %u %u", + snprintf(buff, sizeof(buff), "%u %d %u %u", port, sockfd, devid, speed); dbg("writing: %s", buff); - ret = sysfs_write_attribute(attr_attach, buff, strlen(buff)); + path = udev_device_get_syspath(vhci_driver->hc_device); + snprintf(attach_attr_path, sizeof(attach_attr_path), "%s/%s", + path, attr_attach); + dbg("attach attribute path: %s", attach_attr_path); + + ret = write_sysfs_attribute(attach_attr_path, buff, strlen(buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed"); + dbg("write_sysfs_attribute failed"); return -1; } @@ -493,23 +342,23 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, int usbip_vhci_detach_device(uint8_t port) { - struct sysfs_attribute *attr_detach; + char detach_attr_path[SYSFS_PATH_MAX]; + char attr_detach[] = "detach"; char buff[200]; /* what size should be ? */ + const char *path; int ret; - attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach"); - if (!attr_detach) { - dbg("sysfs_get_device_attr(\"detach\") failed: %s", - vhci_driver->hc_device->name); - return -1; - } - snprintf(buff, sizeof(buff), "%u", port); dbg("writing: %s", buff); - ret = sysfs_write_attribute(attr_detach, buff, strlen(buff)); + path = udev_device_get_syspath(vhci_driver->hc_device); + snprintf(detach_attr_path, sizeof(detach_attr_path), "%s/%s", + path, attr_detach); + dbg("detach attribute path: %s", detach_attr_path); + + ret = write_sysfs_attribute(detach_attr_path, buff, strlen(buff)); if (ret < 0) { - dbg("sysfs_write_attribute failed"); + dbg("write_sysfs_attribute failed"); return -1; } @@ -517,3 +366,46 @@ int usbip_vhci_detach_device(uint8_t port) return 0; } + +int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev) +{ + char product_name[100]; + char host[NI_MAXHOST] = "unknown host"; + char serv[NI_MAXSERV] = "unknown port"; + char remote_busid[SYSFS_BUS_ID_SIZE]; + int ret; + int read_record_error = 0; + + if (idev->status == VDEV_ST_NULL || idev->status == VDEV_ST_NOTASSIGNED) + return 0; + + ret = read_record(idev->port, host, sizeof(host), serv, sizeof(serv), + remote_busid); + if (ret) { + err("read_record"); + read_record_error = 1; + } + + printf("Port %02d: <%s> at %s\n", idev->port, + usbip_status_string(idev->status), + usbip_speed_string(idev->udev.speed)); + + usbip_names_get_product(product_name, sizeof(product_name), + idev->udev.idVendor, idev->udev.idProduct); + + printf(" %s\n", product_name); + + if (!read_record_error) { + printf("%10s -> usbip://%s:%s/%s\n", idev->udev.busid, + host, serv, remote_busid); + printf("%10s -> remote bus/dev %03d/%03d\n", " ", + idev->busnum, idev->devnum); + } else { + printf("%10s -> unknown host, remote port and remote busid\n", + idev->udev.busid); + printf("%10s -> remote bus/dev %03d/%03d\n", " ", + idev->busnum, idev->devnum); + } + + return 0; +} diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h index 89949aa7c31..fa2316cf2ca 100644 --- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.h +++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.h @@ -5,7 +5,7 @@ #ifndef __VHCI_DRIVER_H #define __VHCI_DRIVER_H -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <stdint.h> #include "usbip_common.h" @@ -13,11 +13,6 @@ #define USBIP_VHCI_BUS_TYPE "platform" #define MAXNPORT 128 -struct usbip_class_device { - char class_path[SYSFS_PATH_MAX]; - char dev_path[SYSFS_PATH_MAX]; -}; - struct usbip_imported_device { uint8_t port; uint32_t status; @@ -28,18 +23,13 @@ struct usbip_imported_device { uint8_t devnum; /* usbip_class_device list */ - struct dlist *cdev_list; struct usbip_usb_device udev; }; struct usbip_vhci_driver { - char sysfs_mntpath[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd */ - struct sysfs_device *hc_device; - - /* usbip_class_device list */ - struct dlist *cdev_list; + struct udev_device *hc_device; int nports; struct usbip_imported_device idev[MAXNPORT]; @@ -64,4 +54,6 @@ int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum, int usbip_vhci_detach_device(uint8_t port); +int usbip_vhci_imported_device_dump(struct usbip_imported_device *idev); + #endif /* __VHCI_DRIVER_H */ diff --git a/drivers/staging/usbip/userspace/src/Makefile.am b/drivers/staging/usbip/userspace/src/Makefile.am index 3f09f6ad39f..e81a4ebadef 100644 --- a/drivers/staging/usbip/userspace/src/Makefile.am +++ b/drivers/staging/usbip/userspace/src/Makefile.am @@ -1,11 +1,11 @@ AM_CPPFLAGS = -I$(top_srcdir)/libsrc -DUSBIDS_FILE='"@USBIDS_DIR@/usb.ids"' -AM_CFLAGS = @EXTRA_CFLAGS@ @PACKAGE_CFLAGS@ -LDADD = $(top_builddir)/libsrc/libusbip.la @PACKAGE_LIBS@ +AM_CFLAGS = @EXTRA_CFLAGS@ +LDADD = $(top_builddir)/libsrc/libusbip.la sbin_PROGRAMS := usbip usbipd -usbip_SOURCES := usbip.c utils.c usbip_network.c \ +usbip_SOURCES := usbip.h utils.h usbip.c utils.c usbip_network.c \ usbip_attach.c usbip_detach.c usbip_list.c \ - usbip_bind.c usbip_unbind.c + usbip_bind.c usbip_unbind.c usbip_port.c -usbipd_SOURCES := usbipd.c usbip_network.c +usbipd_SOURCES := usbip_network.h usbipd.c usbip_network.c diff --git a/drivers/staging/usbip/userspace/src/usbip.c b/drivers/staging/usbip/userspace/src/usbip.c index fff4b768e70..d7599d94352 100644 --- a/drivers/staging/usbip/userspace/src/usbip.c +++ b/drivers/staging/usbip/userspace/src/usbip.c @@ -26,6 +26,7 @@ #include <syslog.h> #include "usbip_common.h" +#include "usbip_network.h" #include "usbip.h" static int usbip_help(int argc, char *argv[]); @@ -34,7 +35,7 @@ static int usbip_version(int argc, char *argv[]); static const char usbip_version_string[] = PACKAGE_STRING; static const char usbip_usage_string[] = - "usbip [--debug] [--log] [version]\n" + "usbip [--debug] [--log] [--tcp-port PORT] [version]\n" " [help] <command> <args>\n"; static void usbip_usage(void) @@ -92,6 +93,12 @@ static const struct command cmds[] = { .help = "Unbind device from " USBIP_HOST_DRV_NAME ".ko", .usage = usbip_unbind_usage }, + { + .name = "port", + .fn = usbip_port_show, + .help = "Show imported USB devices", + .usage = NULL + }, { NULL, NULL, NULL, NULL } }; @@ -138,9 +145,10 @@ static int run_command(const struct command *cmd, int argc, char *argv[]) int main(int argc, char *argv[]) { static const struct option opts[] = { - { "debug", no_argument, NULL, 'd' }, - { "log", no_argument, NULL, 'l' }, - { NULL, 0, NULL, 0 } + { "debug", no_argument, NULL, 'd' }, + { "log", no_argument, NULL, 'l' }, + { "tcp-port", required_argument, NULL, 't' }, + { NULL, 0, NULL, 0 } }; char *cmd; @@ -150,7 +158,7 @@ int main(int argc, char *argv[]) usbip_use_stderr = 1; opterr = 0; for (;;) { - opt = getopt_long(argc, argv, "+d", opts, NULL); + opt = getopt_long(argc, argv, "+dlt:", opts, NULL); if (opt == -1) break; @@ -163,6 +171,9 @@ int main(int argc, char *argv[]) usbip_use_syslog = 1; openlog("", LOG_PID, LOG_USER); break; + case 't': + usbip_setup_port_number(optarg); + break; case '?': printf("usbip: invalid option\n"); default: diff --git a/drivers/staging/usbip/userspace/src/usbip.h b/drivers/staging/usbip/userspace/src/usbip.h index 14d4a475b68..84fe66a9d8a 100644 --- a/drivers/staging/usbip/userspace/src/usbip.h +++ b/drivers/staging/usbip/userspace/src/usbip.h @@ -29,6 +29,7 @@ int usbip_detach(int argc, char *argv[]); int usbip_list(int argc, char *argv[]); int usbip_bind(int argc, char *argv[]); int usbip_unbind(int argc, char *argv[]); +int usbip_port_show(int argc, char *argv[]); void usbip_attach_usage(void); void usbip_detach_usage(void); diff --git a/drivers/staging/usbip/userspace/src/usbip_attach.c b/drivers/staging/usbip/userspace/src/usbip_attach.c index bdf61c0fe69..d58a14dfc09 100644 --- a/drivers/staging/usbip/userspace/src/usbip_attach.c +++ b/drivers/staging/usbip/userspace/src/usbip_attach.c @@ -17,7 +17,6 @@ */ #include <sys/stat.h> -#include <sysfs/libsysfs.h> #include <limits.h> #include <stdint.h> @@ -27,6 +26,7 @@ #include <fcntl.h> #include <getopt.h> #include <unistd.h> +#include <errno.h> #include "vhci_driver.h" #include "usbip_common.h" @@ -35,7 +35,7 @@ static const char usbip_attach_usage_string[] = "usbip attach <args>\n" - " -h, --host=<host> The machine with exported USB devices\n" + " -r, --remote=<host> The machine with exported USB devices\n" " -b, --busid=<busid> Busid of the device on <host>\n"; void usbip_attach_usage(void) @@ -52,8 +52,19 @@ static int record_connection(char *host, char *port, char *busid, int rhport) int ret; ret = mkdir(VHCI_STATE_PATH, 0700); - if (ret < 0) - return -1; + if (ret < 0) { + /* if VHCI_STATE_PATH exists, then it better be a directory */ + if (errno == EEXIST) { + struct stat s; + + ret = stat(VHCI_STATE_PATH, &s); + if (ret < 0) + return -1; + if (!(s.st_mode & S_IFDIR)) + return -1; + } else + return -1; + } snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", rhport); @@ -133,7 +144,7 @@ static int query_import_device(int sockfd, char *busid) return -1; } - /* recieve a reply */ + /* receive a reply */ rc = usbip_net_recv_op_common(sockfd, &code); if (rc < 0) { err("recv op_common"); @@ -164,7 +175,7 @@ static int attach_device(char *host, char *busid) int rc; int rhport; - sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + sockfd = usbip_net_tcp_connect(host, usbip_port_string); if (sockfd < 0) { err("tcp connect"); return -1; @@ -178,7 +189,7 @@ static int attach_device(char *host, char *busid) close(sockfd); - rc = record_connection(host, USBIP_PORT_STRING, busid, rhport); + rc = record_connection(host, usbip_port_string, busid, rhport); if (rc < 0) { err("record connection"); return -1; @@ -190,9 +201,9 @@ static int attach_device(char *host, char *busid) int usbip_attach(int argc, char *argv[]) { static const struct option opts[] = { - { "host", required_argument, NULL, 'h' }, - { "busid", required_argument, NULL, 'b' }, - { NULL, 0, NULL, 0 } + { "remote", required_argument, NULL, 'r' }, + { "busid", required_argument, NULL, 'b' }, + { NULL, 0, NULL, 0 } }; char *host = NULL; char *busid = NULL; @@ -200,13 +211,13 @@ int usbip_attach(int argc, char *argv[]) int ret = -1; for (;;) { - opt = getopt_long(argc, argv, "h:b:", opts, NULL); + opt = getopt_long(argc, argv, "r:b:", opts, NULL); if (opt == -1) break; switch (opt) { - case 'h': + case 'r': host = optarg; break; case 'b': diff --git a/drivers/staging/usbip/userspace/src/usbip_bind.c b/drivers/staging/usbip/userspace/src/usbip_bind.c index 9ecaf6e574d..fa46141ae68 100644 --- a/drivers/staging/usbip/userspace/src/usbip_bind.c +++ b/drivers/staging/usbip/userspace/src/usbip_bind.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdio.h> @@ -28,6 +28,7 @@ #include "usbip_common.h" #include "utils.h" #include "usbip.h" +#include "sysfs_utils.h" enum unbind_status { UNBIND_ST_OK, @@ -48,167 +49,92 @@ void usbip_bind_usage(void) /* call at unbound state */ static int bind_usbip(char *busid) { - char bus_type[] = "usb"; char attr_name[] = "bind"; - char sysfs_mntpath[SYSFS_PATH_MAX]; char bind_attr_path[SYSFS_PATH_MAX]; - char intf_busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *busid_dev; - struct sysfs_attribute *bind_attr; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bNumIntfs; - int i, failed = 0; - int rc, ret = -1; - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; - } + int rc = -1; snprintf(bind_attr_path, sizeof(bind_attr_path), "%s/%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, - USBIP_HOST_DRV_NAME, attr_name); - - bind_attr = sysfs_open_attribute(bind_attr_path); - if (!bind_attr) { - dbg("problem getting bind attribute: %s", strerror(errno)); - return -1; - } + SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, + SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); - busid_dev = sysfs_open_device(bus_type, busid); - if (!busid_dev) { - dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); - goto err_close_bind_attr; - } - - bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); - bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); - - if (!bConfValue || !bNumIntfs) { - dbg("problem getting device attributes: %s", + rc = write_sysfs_attribute(bind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error binding device %s to driver: %s", busid, strerror(errno)); - goto err_close_busid_dev; - } - - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, - bConfValue->value, i); - - rc = sysfs_write_attribute(bind_attr, intf_busid, - SYSFS_BUS_ID_SIZE); - if (rc < 0) { - dbg("bind driver at %s failed", intf_busid); - failed = 1; - } + return -1; } - if (!failed) - ret = 0; - -err_close_busid_dev: - sysfs_close_device(busid_dev); -err_close_bind_attr: - sysfs_close_attribute(bind_attr); - - return ret; + return 0; } /* buggy driver may cause dead lock */ static int unbind_other(char *busid) { - char bus_type[] = "usb"; - char intf_busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_device *busid_dev; - struct sysfs_device *intf_dev; - struct sysfs_driver *intf_drv; - struct sysfs_attribute *unbind_attr; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bDevClass; - struct sysfs_attribute *bNumIntfs; - int i, rc; enum unbind_status status = UNBIND_ST_OK; - busid_dev = sysfs_open_device(bus_type, busid); - if (!busid_dev) { - dbg("sysfs_open_device %s failed: %s", busid, strerror(errno)); - return -1; + char attr_name[] = "unbind"; + char unbind_attr_path[SYSFS_PATH_MAX]; + int rc = -1; + + struct udev *udev; + struct udev_device *dev; + const char *driver; + const char *bDevClass; + + /* Create libudev context. */ + udev = udev_new(); + + /* Get the device. */ + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + dbg("unable to find device with bus ID %s", busid); + goto err_close_busid_dev; } - bConfValue = sysfs_get_device_attr(busid_dev, "bConfigurationValue"); - bDevClass = sysfs_get_device_attr(busid_dev, "bDeviceClass"); - bNumIntfs = sysfs_get_device_attr(busid_dev, "bNumInterfaces"); - if (!bConfValue || !bDevClass || !bNumIntfs) { - dbg("problem getting device attributes: %s", - strerror(errno)); + /* Check what kind of device it is. */ + bDevClass = udev_device_get_sysattr_value(dev, "bDeviceClass"); + if (!bDevClass) { + dbg("unable to get bDevClass device attribute"); goto err_close_busid_dev; } - if (!strncmp(bDevClass->value, "09", bDevClass->len)) { + if (!strncmp(bDevClass, "09", strlen(bDevClass))) { dbg("skip unbinding of hub"); goto err_close_busid_dev; } - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(intf_busid, SYSFS_BUS_ID_SIZE, "%s:%.1s.%d", busid, - bConfValue->value, i); - intf_dev = sysfs_open_device(bus_type, intf_busid); - if (!intf_dev) { - dbg("could not open interface device: %s", - strerror(errno)); - goto err_close_busid_dev; - } - - dbg("%s -> %s", intf_dev->name, intf_dev->driver_name); - - if (!strncmp("unknown", intf_dev->driver_name, SYSFS_NAME_LEN)) - /* unbound interface */ - continue; - - if (!strncmp(USBIP_HOST_DRV_NAME, intf_dev->driver_name, - SYSFS_NAME_LEN)) { - /* already bound to usbip-host */ - status = UNBIND_ST_USBIP_HOST; - continue; - } - - /* unbinding */ - intf_drv = sysfs_open_driver(bus_type, intf_dev->driver_name); - if (!intf_drv) { - dbg("could not open interface driver on %s: %s", - intf_dev->name, strerror(errno)); - goto err_close_intf_dev; - } + /* Get the device driver. */ + driver = udev_device_get_driver(dev); + if (!driver) { + /* No driver bound to this device. */ + goto out; + } - unbind_attr = sysfs_get_driver_attr(intf_drv, "unbind"); - if (!unbind_attr) { - dbg("problem getting interface driver attribute: %s", - strerror(errno)); - goto err_close_intf_drv; - } + if (!strncmp(USBIP_HOST_DRV_NAME, driver, + strlen(USBIP_HOST_DRV_NAME))) { + /* Already bound to usbip-host. */ + status = UNBIND_ST_USBIP_HOST; + goto out; + } - rc = sysfs_write_attribute(unbind_attr, intf_dev->bus_id, - SYSFS_BUS_ID_SIZE); - if (rc < 0) { - /* NOTE: why keep unbinding other interfaces? */ - dbg("unbind driver at %s failed", intf_dev->bus_id); - status = UNBIND_ST_FAILED; - } + /* Unbind device from driver. */ + snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, SYSFS_BUS_TYPE, + SYSFS_DRIVERS_NAME, driver, attr_name); - sysfs_close_driver(intf_drv); - sysfs_close_device(intf_dev); + rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error unbinding device %s from driver", busid); + goto err_close_busid_dev; } goto out; -err_close_intf_drv: - sysfs_close_driver(intf_drv); -err_close_intf_dev: - sysfs_close_device(intf_dev); err_close_busid_dev: status = UNBIND_ST_FAILED; out: - sysfs_close_device(busid_dev); + udev_device_unref(dev); + udev_unref(udev); return status; } @@ -216,6 +142,17 @@ out: static int bind_device(char *busid) { int rc; + struct udev *udev; + struct udev_device *dev; + + /* Check whether the device with this bus ID exists. */ + udev = udev_new(); + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + err("device with the specified bus ID does not exist"); + return -1; + } + udev_unref(udev); rc = unbind_other(busid); if (rc == UNBIND_ST_FAILED) { @@ -240,7 +177,7 @@ static int bind_device(char *busid) return -1; } - printf("bind device on busid %s: complete\n", busid); + info("bind device on busid %s: complete", busid); return 0; } diff --git a/drivers/staging/usbip/userspace/src/usbip_detach.c b/drivers/staging/usbip/userspace/src/usbip_detach.c index 89bf3c195c2..05c6d15856e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_detach.c +++ b/drivers/staging/usbip/userspace/src/usbip_detach.c @@ -16,9 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> - #include <ctype.h> +#include <limits.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -46,8 +45,9 @@ static int detach_port(char *port) { int ret; uint8_t portnum; + char path[PATH_MAX+1]; - for (unsigned int i=0; i < strlen(port); i++) + for (unsigned int i = 0; i < strlen(port); i++) if (!isdigit(port[i])) { err("invalid port %s", port); return -1; @@ -57,6 +57,13 @@ static int detach_port(char *port) portnum = atoi(port); + /* remove the port state file */ + + snprintf(path, PATH_MAX, VHCI_STATE_PATH"/port%d", portnum); + + remove(path); + rmdir(VHCI_STATE_PATH); + ret = usbip_vhci_driver_open(); if (ret < 0) { err("open vhci_driver"); diff --git a/drivers/staging/usbip/userspace/src/usbip_list.c b/drivers/staging/usbip/userspace/src/usbip_list.c index ed30d910e03..d5ce34a410e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_list.c +++ b/drivers/staging/usbip/userspace/src/usbip_list.c @@ -17,7 +17,7 @@ */ #include <sys/types.h> -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdbool.h> @@ -54,7 +54,7 @@ static int get_exported_devices(char *host, int sockfd) struct usbip_usb_device udev; struct usbip_usb_interface uintf; unsigned int i; - int j, rc; + int rc, j; rc = usbip_net_send_op_common(sockfd, OP_REQ_DEVLIST, 0); if (rc < 0) { @@ -107,19 +107,20 @@ static int get_exported_devices(char *host, int sockfd) for (j = 0; j < udev.bNumInterfaces; j++) { rc = usbip_net_recv(sockfd, &uintf, sizeof(uintf)); if (rc < 0) { - dbg("usbip_net_recv failed: usbip_usb_intf[%d]", - j); + err("usbip_net_recv failed: usbip_usb_intf[%d]", + j); return -1; } usbip_net_pack_usb_interface(0, &uintf); usbip_names_get_class(class_name, sizeof(class_name), - uintf.bInterfaceClass, - uintf.bInterfaceSubClass, - uintf.bInterfaceProtocol); + uintf.bInterfaceClass, + uintf.bInterfaceSubClass, + uintf.bInterfaceProtocol); printf("%11s: %2d - %s\n", "", j, class_name); } + printf("\n"); } @@ -131,13 +132,13 @@ static int list_exported_devices(char *host) int rc; int sockfd; - sockfd = usbip_net_tcp_connect(host, USBIP_PORT_STRING); + sockfd = usbip_net_tcp_connect(host, usbip_port_string); if (sockfd < 0) { err("could not connect to %s:%s: %s", host, - USBIP_PORT_STRING, gai_strerror(sockfd)); + usbip_port_string, gai_strerror(sockfd)); return -1; } - dbg("connected to %s:%s", host, USBIP_PORT_STRING); + dbg("connected to %s:%s", host, usbip_port_string); rc = get_exported_devices(host, sockfd); if (rc < 0) { @@ -150,8 +151,8 @@ static int list_exported_devices(char *host) return 0; } -static void print_device(char *busid, char *vendor, char *product, - bool parsable) +static void print_device(const char *busid, const char *vendor, + const char *product, bool parsable) { if (parsable) printf("busid=%s#usbid=%.4s:%.4s#", busid, vendor, product); @@ -159,100 +160,79 @@ static void print_device(char *busid, char *vendor, char *product, printf(" - busid %s (%.4s:%.4s)\n", busid, vendor, product); } -static void print_interface(char *busid, char *driver, bool parsable) +static void print_product_name(char *product_name, bool parsable) { - if (parsable) - printf("%s=%s#", busid, driver); - else - printf("%9s%s -> %s\n", "", busid, driver); -} - -static int is_device(void *x) -{ - struct sysfs_attribute *devpath; - struct sysfs_device *dev = x; - int ret = 0; - - devpath = sysfs_get_device_attr(dev, "devpath"); - if (devpath && *devpath->value != '0') - ret = 1; - - return ret; -} - -static int devcmp(void *a, void *b) -{ - return strcmp(a, b); + if (!parsable) + printf(" %s\n", product_name); } static int list_devices(bool parsable) { - char bus_type[] = "usb"; - char busid[SYSFS_BUS_ID_SIZE]; - struct sysfs_bus *ubus; - struct sysfs_device *dev; - struct sysfs_device *intf; - struct sysfs_attribute *idVendor; - struct sysfs_attribute *idProduct; - struct sysfs_attribute *bConfValue; - struct sysfs_attribute *bNumIntfs; - struct dlist *devlist; - int i; + struct udev *udev; + struct udev_enumerate *enumerate; + struct udev_list_entry *devices, *dev_list_entry; + struct udev_device *dev; + const char *path; + const char *idVendor; + const char *idProduct; + const char *bConfValue; + const char *bNumIntfs; + const char *busid; + char product_name[128]; int ret = -1; - ubus = sysfs_open_bus(bus_type); - if (!ubus) { - err("could not open %s bus: %s", bus_type, strerror(errno)); - return -1; - } - - devlist = sysfs_get_bus_devices(ubus); - if (!devlist) { - err("could not get %s bus devices: %s", bus_type, - strerror(errno)); - goto err_out; - } - - /* remove interfaces and root hubs from device list */ - dlist_filter_sort(devlist, is_device, devcmp); - - if (!parsable) { - printf("Local USB devices\n"); - printf("=================\n"); - } - dlist_for_each_data(devlist, dev, struct sysfs_device) { - idVendor = sysfs_get_device_attr(dev, "idVendor"); - idProduct = sysfs_get_device_attr(dev, "idProduct"); - bConfValue = sysfs_get_device_attr(dev, "bConfigurationValue"); - bNumIntfs = sysfs_get_device_attr(dev, "bNumInterfaces"); + /* Create libudev context. */ + udev = udev_new(); + + /* Create libudev device enumeration. */ + enumerate = udev_enumerate_new(udev); + + /* Take only USB devices that are not hubs and do not have + * the bInterfaceNumber attribute, i.e. are not interfaces. + */ + udev_enumerate_add_match_subsystem(enumerate, "usb"); + udev_enumerate_add_nomatch_sysattr(enumerate, "bDeviceClass", "09"); + udev_enumerate_add_nomatch_sysattr(enumerate, "bInterfaceNumber", NULL); + udev_enumerate_scan_devices(enumerate); + + devices = udev_enumerate_get_list_entry(enumerate); + + /* Show information about each device. */ + udev_list_entry_foreach(dev_list_entry, devices) { + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + + /* Get device information. */ + idVendor = udev_device_get_sysattr_value(dev, "idVendor"); + idProduct = udev_device_get_sysattr_value(dev, "idProduct"); + bConfValue = udev_device_get_sysattr_value(dev, "bConfigurationValue"); + bNumIntfs = udev_device_get_sysattr_value(dev, "bNumInterfaces"); + busid = udev_device_get_sysname(dev); if (!idVendor || !idProduct || !bConfValue || !bNumIntfs) { err("problem getting device attributes: %s", strerror(errno)); goto err_out; } - print_device(dev->bus_id, idVendor->value, idProduct->value, - parsable); - - for (i = 0; i < atoi(bNumIntfs->value); i++) { - snprintf(busid, sizeof(busid), "%s:%.1s.%d", - dev->bus_id, bConfValue->value, i); - intf = sysfs_open_device(bus_type, busid); - if (!intf) { - err("could not open device interface: %s", - strerror(errno)); - goto err_out; - } - print_interface(busid, intf->driver_name, parsable); - sysfs_close_device(intf); - } + /* Get product name. */ + usbip_names_get_product(product_name, sizeof(product_name), + strtol(idVendor, NULL, 16), + strtol(idProduct, NULL, 16)); + + /* Print information. */ + print_device(busid, idVendor, idProduct, parsable); + print_product_name(product_name, parsable); + printf("\n"); + + udev_device_unref(dev); } ret = 0; err_out: - sysfs_close_bus(ubus); + udev_enumerate_unref(enumerate); + udev_unref(udev); return ret; } diff --git a/drivers/staging/usbip/userspace/src/usbip_network.c b/drivers/staging/usbip/userspace/src/usbip_network.c index 1a84dd37e12..b4c37e76a6e 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.c +++ b/drivers/staging/usbip/userspace/src/usbip_network.c @@ -25,9 +25,43 @@ #include <netinet/tcp.h> #include <unistd.h> +#ifdef HAVE_LIBWRAP +#include <tcpd.h> +#endif + #include "usbip_common.h" #include "usbip_network.h" +int usbip_port = 3240; +char *usbip_port_string = "3240"; + +void usbip_setup_port_number(char *arg) +{ + dbg("parsing port arg '%s'", arg); + char *end; + unsigned long int port = strtoul(arg, &end, 10); + + if (end == arg) { + err("port: could not parse '%s' as a decimal integer", arg); + return; + } + + if (*end != '\0') { + err("port: garbage at end of '%s'", arg); + return; + } + + if (port > UINT16_MAX) { + err("port: %s too high (max=%d)", + arg, UINT16_MAX); + return; + } + + usbip_port = port; + usbip_port_string = arg; + info("using port %d (\"%s\")", usbip_port, usbip_port_string); +} + void usbip_net_pack_uint32_t(int pack, uint32_t *num) { uint32_t i; @@ -56,7 +90,7 @@ void usbip_net_pack_usb_device(int pack, struct usbip_usb_device *udev) { usbip_net_pack_uint32_t(pack, &udev->busnum); usbip_net_pack_uint32_t(pack, &udev->devnum); - usbip_net_pack_uint32_t(pack, &udev->speed ); + usbip_net_pack_uint32_t(pack, &udev->speed); usbip_net_pack_uint16_t(pack, &udev->idVendor); usbip_net_pack_uint16_t(pack, &udev->idProduct); @@ -209,6 +243,18 @@ int usbip_net_set_keepalive(int sockfd) return ret; } +int usbip_net_set_v6only(int sockfd) +{ + const int val = 1; + int ret; + + ret = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); + if (ret < 0) + dbg("setsockopt: IPV6_V6ONLY"); + + return ret; +} + /* * IPv6 Ready */ @@ -248,10 +294,10 @@ int usbip_net_tcp_connect(char *hostname, char *service) close(sockfd); } + freeaddrinfo(res); + if (!rp) return EAI_SYSTEM; - freeaddrinfo(res); - return sockfd; } diff --git a/drivers/staging/usbip/userspace/src/usbip_network.h b/drivers/staging/usbip/userspace/src/usbip_network.h index 2d1e070fb7b..c1e875cf107 100644 --- a/drivers/staging/usbip/userspace/src/usbip_network.h +++ b/drivers/staging/usbip/userspace/src/usbip_network.h @@ -10,12 +10,12 @@ #endif #include <sys/types.h> -#include <sysfs/libsysfs.h> #include <stdint.h> -#define USBIP_PORT 3240 -#define USBIP_PORT_STRING "3240" +extern int usbip_port; +extern char *usbip_port_string; +void usbip_setup_port_number(char *arg); /* ---------------------------------------------------------------------- */ /* Common header for all the kinds of PDUs. */ @@ -35,8 +35,8 @@ struct op_common { #define PACK_OP_COMMON(pack, op_common) do {\ usbip_net_pack_uint16_t(pack, &(op_common)->version);\ - usbip_net_pack_uint16_t(pack, &(op_common)->code );\ - usbip_net_pack_uint32_t(pack, &(op_common)->status );\ + usbip_net_pack_uint16_t(pack, &(op_common)->code);\ + usbip_net_pack_uint32_t(pack, &(op_common)->status);\ } while (0) /* ---------------------------------------------------------------------- */ @@ -179,6 +179,7 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code); int usbip_net_set_reuseaddr(int sockfd); int usbip_net_set_nodelay(int sockfd); int usbip_net_set_keepalive(int sockfd); +int usbip_net_set_v6only(int sockfd); int usbip_net_tcp_connect(char *hostname, char *port); #endif /* __USBIP_NETWORK_H */ diff --git a/drivers/staging/usbip/userspace/src/usbip_port.c b/drivers/staging/usbip/userspace/src/usbip_port.c new file mode 100644 index 00000000000..a2e884fd922 --- /dev/null +++ b/drivers/staging/usbip/userspace/src/usbip_port.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 matt mooney <mfm@muteddisk.com> + * 2005-2007 Takahiro Hirofuchi + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vhci_driver.h" +#include "usbip_common.h" + +static int list_imported_devices(void) +{ + int i; + struct usbip_imported_device *idev; + int ret; + + ret = usbip_vhci_driver_open(); + if (ret < 0) { + err("open vhci_driver"); + return -1; + } + + printf("Imported USB devices\n"); + printf("====================\n"); + + for (i = 0; i < vhci_driver->nports; i++) { + idev = &vhci_driver->idev[i]; + + if (usbip_vhci_imported_device_dump(idev) < 0) + ret = -1; + } + + usbip_vhci_driver_close(); + + return ret; + +} + +int usbip_port_show(__attribute__((unused)) int argc, + __attribute__((unused)) char *argv[]) +{ + int ret; + + ret = list_imported_devices(); + if (ret < 0) + err("list imported devices"); + + return ret; +} diff --git a/drivers/staging/usbip/userspace/src/usbip_unbind.c b/drivers/staging/usbip/userspace/src/usbip_unbind.c index d5a9ab6af2a..a4a496c9cba 100644 --- a/drivers/staging/usbip/userspace/src/usbip_unbind.c +++ b/drivers/staging/usbip/userspace/src/usbip_unbind.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> +#include <libudev.h> #include <errno.h> #include <stdio.h> @@ -27,6 +27,7 @@ #include "usbip_common.h" #include "utils.h" #include "usbip.h" +#include "sysfs_utils.h" static const char usbip_unbind_usage_string[] = "usbip unbind <args>\n" @@ -41,115 +42,69 @@ void usbip_unbind_usage(void) static int unbind_device(char *busid) { char bus_type[] = "usb"; - struct sysfs_driver *usbip_host_drv; - struct sysfs_device *dev; - struct dlist *devlist; - int verified = 0; int rc, ret = -1; - char attr_name[] = "bConfigurationValue"; - char sysfs_mntpath[SYSFS_PATH_MAX]; - char busid_attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *busid_attr; - char *val = NULL; - int len; - - /* verify the busid device is using usbip-host */ - usbip_host_drv = sysfs_open_driver(bus_type, USBIP_HOST_DRV_NAME); - if (!usbip_host_drv) { - err("could not open %s driver: %s", USBIP_HOST_DRV_NAME, - strerror(errno)); - return -1; - } + char unbind_attr_name[] = "unbind"; + char unbind_attr_path[SYSFS_PATH_MAX]; + char rebind_attr_name[] = "rebind"; + char rebind_attr_path[SYSFS_PATH_MAX]; - devlist = sysfs_get_driver_devices(usbip_host_drv); - if (!devlist) { - err("%s is not in use by any devices", USBIP_HOST_DRV_NAME); - goto err_close_usbip_host_drv; - } + struct udev *udev; + struct udev_device *dev; + const char *driver; - dlist_for_each_data(devlist, dev, struct sysfs_device) { - if (!strncmp(busid, dev->name, strlen(busid)) && - !strncmp(dev->driver_name, USBIP_HOST_DRV_NAME, - strlen(USBIP_HOST_DRV_NAME))) { - verified = 1; - break; - } - } + /* Create libudev context. */ + udev = udev_new(); - if (!verified) { - err("device on busid %s is not using %s", busid, - USBIP_HOST_DRV_NAME); - goto err_close_usbip_host_drv; + /* Check whether the device with this bus ID exists. */ + dev = udev_device_new_from_subsystem_sysname(udev, "usb", busid); + if (!dev) { + err("device with the specified bus ID does not exist"); + goto err_close_udev; } - /* - * NOTE: A read and write of an attribute value of the device busid - * refers to must be done to start probing. That way a rebind of the - * default driver for the device occurs. - * - * This seems very hackish and adds a lot of pointless code. I think it - * should be done in the kernel by the driver after del_match_busid is - * finished! - */ - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; + /* Check whether the device is using usbip-host driver. */ + driver = udev_device_get_driver(dev); + if (!driver || strcmp(driver, "usbip-host")) { + err("device is not bound to usbip-host driver"); + goto err_close_udev; } - snprintf(busid_attr_path, sizeof(busid_attr_path), "%s/%s/%s/%s/%s/%s", - sysfs_mntpath, SYSFS_BUS_NAME, bus_type, SYSFS_DEVICES_NAME, - busid, attr_name); + /* Unbind device from driver. */ + snprintf(unbind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, + USBIP_HOST_DRV_NAME, unbind_attr_name); - /* read a device attribute */ - busid_attr = sysfs_open_attribute(busid_attr_path); - if (!busid_attr) { - err("could not open %s/%s: %s", busid, attr_name, - strerror(errno)); - return -1; - } - - if (sysfs_read_attribute(busid_attr) < 0) { - err("problem reading attribute: %s", strerror(errno)); - goto err_out; + rc = write_sysfs_attribute(unbind_attr_path, busid, strlen(busid)); + if (rc < 0) { + err("error unbinding device %s from driver", busid); + goto err_close_udev; } - len = busid_attr->len; - val = malloc(len); - *val = *busid_attr->value; - sysfs_close_attribute(busid_attr); - - /* notify driver of unbind */ + /* Notify driver of unbind. */ rc = modify_match_busid(busid, 0); if (rc < 0) { err("unable to unbind device on %s", busid); - goto err_out; + goto err_close_udev; } - /* write the device attribute */ - busid_attr = sysfs_open_attribute(busid_attr_path); - if (!busid_attr) { - err("could not open %s/%s: %s", busid, attr_name, - strerror(errno)); - return -1; - } + /* Trigger new probing. */ + snprintf(rebind_attr_path, sizeof(unbind_attr_path), "%s/%s/%s/%s/%s/%s", + SYSFS_MNT_PATH, SYSFS_BUS_NAME, bus_type, SYSFS_DRIVERS_NAME, + USBIP_HOST_DRV_NAME, rebind_attr_name); - rc = sysfs_write_attribute(busid_attr, val, len); + rc = write_sysfs_attribute(rebind_attr_path, busid, strlen(busid)); if (rc < 0) { - err("problem writing attribute: %s", strerror(errno)); - goto err_out; + err("error rebinding"); + goto err_close_udev; } - sysfs_close_attribute(busid_attr); ret = 0; - printf("unbind device on busid %s: complete\n", busid); + info("unbind device on busid %s: complete", busid); -err_out: - free(val); -err_close_usbip_host_drv: - sysfs_close_driver(usbip_host_drv); +err_close_udev: + udev_device_unref(dev); + udev_unref(udev); return ret; } diff --git a/drivers/staging/usbip/userspace/src/usbipd.c b/drivers/staging/usbip/userspace/src/usbipd.c index 8668a8092d4..2f87f2d348b 100644 --- a/drivers/staging/usbip/userspace/src/usbipd.c +++ b/drivers/staging/usbip/userspace/src/usbipd.c @@ -20,6 +20,7 @@ #include "../config.h" #endif +#define _GNU_SOURCE #include <errno.h> #include <unistd.h> #include <netdb.h> @@ -35,36 +36,52 @@ #include <tcpd.h> #endif -#define _GNU_SOURCE #include <getopt.h> -#include <glib.h> #include <signal.h> +#include <poll.h> #include "usbip_host_driver.h" #include "usbip_common.h" #include "usbip_network.h" +#include "list.h" #undef PROGNAME #define PROGNAME "usbipd" #define MAXSOCKFD 20 -GMainLoop *main_loop; +#define MAIN_LOOP_TIMEOUT 10 + +#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid" static const char usbip_version_string[] = PACKAGE_STRING; static const char usbipd_help_string[] = - "usage: usbipd [options] \n" - " -D, --daemon \n" - " Run as a daemon process. \n" - " \n" - " -d, --debug \n" - " Print debugging information. \n" - " \n" - " -h, --help \n" - " Print this help. \n" - " \n" - " -v, --version \n" - " Show version. \n"; + "usage: usbipd [options]\n" + "\n" + " -4, --ipv4\n" + " Bind to IPv4. Default is both.\n" + "\n" + " -6, --ipv6\n" + " Bind to IPv6. Default is both.\n" + "\n" + " -D, --daemon\n" + " Run as a daemon process.\n" + "\n" + " -d, --debug\n" + " Print debugging information.\n" + "\n" + " -PFILE, --pid FILE\n" + " Write process id to FILE.\n" + " If no FILE specified, use " DEFAULT_PID_FILE "\n" + "\n" + " -tPORT, --tcp-port PORT\n" + " Listen on TCP/IP port PORT.\n" + "\n" + " -h, --help\n" + " Print this help.\n" + "\n" + " -v, --version\n" + " Show version.\n"; static void usbipd_help(void) { @@ -77,6 +94,7 @@ static int recv_request_import(int sockfd) struct op_common reply; struct usbip_exported_device *edev; struct usbip_usb_device pdu_udev; + struct list_head *i; int found = 0; int error = 0; int rc; @@ -91,8 +109,8 @@ static int recv_request_import(int sockfd) } PACK_OP_IMPORT_REQUEST(0, &req); - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(i, &host_driver->edev_list) { + edev = list_entry(i, struct usbip_exported_device, node); if (!strncmp(req.busid, edev->udev.busid, SYSFS_BUS_ID_SIZE)) { info("found requested device: %s", req.busid); found = 1; @@ -145,13 +163,12 @@ static int send_reply_devlist(int connfd) struct usbip_usb_device pdu_udev; struct usbip_usb_interface pdu_uinf; struct op_devlist_reply reply; - int i; - int rc; + struct list_head *j; + int rc, i; reply.ndev = 0; /* number of exported devices */ - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(j, &host_driver->edev_list) { reply.ndev += 1; } info("exportable devices: %d", reply.ndev); @@ -169,8 +186,8 @@ static int send_reply_devlist(int connfd) return -1; } - dlist_for_each_data(host_driver->edev_list, edev, - struct usbip_exported_device) { + list_for_each(j, &host_driver->edev_list) { + edev = list_entry(j, struct usbip_exported_device, node); dump_usb_device(&edev->udev); memcpy(&pdu_udev, &edev->udev, sizeof(pdu_udev)); usbip_net_pack_usb_device(1, &pdu_udev); @@ -187,9 +204,9 @@ static int send_reply_devlist(int connfd) usbip_net_pack_usb_interface(1, &pdu_uinf); rc = usbip_net_send(connfd, &pdu_uinf, - sizeof(pdu_uinf)); + sizeof(pdu_uinf)); if (rc < 0) { - dbg("usbip_net_send failed: pdu_uinf"); + err("usbip_net_send failed: pdu_uinf"); return -1; } } @@ -286,13 +303,13 @@ static int do_accept(int listenfd) memset(&ss, 0, sizeof(ss)); - connfd = accept(listenfd, (struct sockaddr *) &ss, &len); + connfd = accept(listenfd, (struct sockaddr *)&ss, &len); if (connfd < 0) { err("failed to accept connection"); return -1; } - rc = getnameinfo((struct sockaddr *) &ss, len, host, sizeof(host), + rc = getnameinfo((struct sockaddr *)&ss, len, host, sizeof(host), port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); if (rc) err("getnameinfo: %s", gai_strerror(rc)); @@ -310,89 +327,94 @@ static int do_accept(int listenfd) return connfd; } -gboolean process_request(GIOChannel *gio, GIOCondition condition, - gpointer unused_data) +int process_request(int listenfd) { - int listenfd; + pid_t childpid; int connfd; - (void) unused_data; - - if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { - err("unknown condition"); - BUG(); - } - - if (condition & G_IO_IN) { - listenfd = g_io_channel_unix_get_fd(gio); - connfd = do_accept(listenfd); - if (connfd < 0) - return TRUE; - + connfd = do_accept(listenfd); + if (connfd < 0) + return -1; + childpid = fork(); + if (childpid == 0) { + close(listenfd); recv_pdu(connfd); - close(connfd); + exit(0); } - - return TRUE; + close(connfd); + return 0; } -static void log_addrinfo(struct addrinfo *ai) +static void addrinfo_to_text(struct addrinfo *ai, char buf[], + const size_t buf_size) { char hbuf[NI_MAXHOST]; char sbuf[NI_MAXSERV]; int rc; + buf[0] = '\0'; + rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); if (rc) err("getnameinfo: %s", gai_strerror(rc)); - info("listening on %s:%s", hbuf, sbuf); + snprintf(buf, buf_size, "%s:%s", hbuf, sbuf); } -static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[]) +static int listen_all_addrinfo(struct addrinfo *ai_head, int sockfdlist[], + int maxsockfd) { struct addrinfo *ai; int ret, nsockfd = 0; - - for (ai = ai_head; ai && nsockfd < MAXSOCKFD; ai = ai->ai_next) { - sockfdlist[nsockfd] = socket(ai->ai_family, ai->ai_socktype, - ai->ai_protocol); - if (sockfdlist[nsockfd] < 0) + const size_t ai_buf_size = NI_MAXHOST + NI_MAXSERV + 2; + char ai_buf[ai_buf_size]; + + for (ai = ai_head; ai && nsockfd < maxsockfd; ai = ai->ai_next) { + int sock; + + addrinfo_to_text(ai, ai_buf, ai_buf_size); + dbg("opening %s", ai_buf); + sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock < 0) { + err("socket: %s: %d (%s)", + ai_buf, errno, strerror(errno)); continue; + } - usbip_net_set_reuseaddr(sockfdlist[nsockfd]); - usbip_net_set_nodelay(sockfdlist[nsockfd]); + usbip_net_set_reuseaddr(sock); + usbip_net_set_nodelay(sock); + /* We use seperate sockets for IPv4 and IPv6 + * (see do_standalone_mode()) */ + usbip_net_set_v6only(sock); - if (sockfdlist[nsockfd] >= FD_SETSIZE) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + if (sock >= FD_SETSIZE) { + err("FD_SETSIZE: %s: sock=%d, max=%d", + ai_buf, sock, FD_SETSIZE); + close(sock); continue; } - ret = bind(sockfdlist[nsockfd], ai->ai_addr, ai->ai_addrlen); + ret = bind(sock, ai->ai_addr, ai->ai_addrlen); if (ret < 0) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + err("bind: %s: %d (%s)", + ai_buf, errno, strerror(errno)); + close(sock); continue; } - ret = listen(sockfdlist[nsockfd], SOMAXCONN); + ret = listen(sock, SOMAXCONN); if (ret < 0) { - close(sockfdlist[nsockfd]); - sockfdlist[nsockfd] = -1; + err("listen: %s: %d (%s)", + ai_buf, errno, strerror(errno)); + close(sock); continue; } - log_addrinfo(ai); - nsockfd++; + info("listening on %s", ai_buf); + sockfdlist[nsockfd++] = sock; } - if (nsockfd == 0) - return -1; - - dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); - return nsockfd; } @@ -406,9 +428,9 @@ static struct addrinfo *do_getaddrinfo(char *host, int ai_family) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - rc = getaddrinfo(host, USBIP_PORT_STRING, &hints, &ai_head); + rc = getaddrinfo(host, usbip_port_string, &hints, &ai_head); if (rc) { - err("failed to get a network address %s: %s", USBIP_PORT_STRING, + err("failed to get a network address %s: %s", usbip_port_string, gai_strerror(rc)); return NULL; } @@ -418,10 +440,7 @@ static struct addrinfo *do_getaddrinfo(char *host, int ai_family) static void signal_handler(int i) { - dbg("received signal: code %d", i); - - if (main_loop) - g_main_loop_quit(main_loop); + dbg("received '%s' signal", strsignal(i)); } static void set_signal(void) @@ -433,17 +452,46 @@ static void set_signal(void) sigemptyset(&act.sa_mask); sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); + act.sa_handler = SIG_IGN; + sigaction(SIGCLD, &act, NULL); +} + +static const char *pid_file; + +static void write_pid_file(void) +{ + if (pid_file) { + dbg("creating pid file %s", pid_file); + FILE *fp; + + fp = fopen(pid_file, "w"); + if (!fp) { + err("pid_file: %s: %d (%s)", + pid_file, errno, strerror(errno)); + return; + } + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } +} + +static void remove_pid_file(void) +{ + if (pid_file) { + dbg("removing pid file %s", pid_file); + unlink(pid_file); + } } -static int do_standalone_mode(gboolean daemonize) +static int do_standalone_mode(int daemonize, int ipv4, int ipv6) { struct addrinfo *ai_head; int sockfdlist[MAXSOCKFD]; - int nsockfd; - int i; - - if (usbip_names_init(USBIDS_FILE)) - err("failed to open %s", USBIDS_FILE); + int nsockfd, family; + int i, terminate; + struct pollfd *fds; + struct timespec timeout; + sigset_t sigmask; if (usbip_host_driver_open()) { err("please load " USBIP_CORE_MOD_NAME ".ko and " @@ -452,43 +500,83 @@ static int do_standalone_mode(gboolean daemonize) } if (daemonize) { - if (daemon(0,0) < 0) { + if (daemon(0, 0) < 0) { err("daemonizing failed: %s", strerror(errno)); + usbip_host_driver_close(); return -1; } - + umask(0); usbip_use_syslog = 1; } set_signal(); - - ai_head = do_getaddrinfo(NULL, PF_UNSPEC); - if (!ai_head) - return -1; + write_pid_file(); info("starting " PROGNAME " (%s)", usbip_version_string); - nsockfd = listen_all_addrinfo(ai_head, sockfdlist); + /* + * To suppress warnings on systems with bindv6only disabled + * (default), we use seperate sockets for IPv6 and IPv4 and set + * IPV6_V6ONLY on the IPv6 sockets. + */ + if (ipv4 && ipv6) + family = AF_UNSPEC; + else if (ipv4) + family = AF_INET; + else + family = AF_INET6; + + ai_head = do_getaddrinfo(NULL, family); + if (!ai_head) { + usbip_host_driver_close(); + return -1; + } + nsockfd = listen_all_addrinfo(ai_head, sockfdlist, + sizeof(sockfdlist) / sizeof(*sockfdlist)); + freeaddrinfo(ai_head); if (nsockfd <= 0) { err("failed to open a listening socket"); + usbip_host_driver_close(); return -1; } - for (i = 0; i < nsockfd; i++) { - GIOChannel *gio; + dbg("listening on %d address%s", nsockfd, (nsockfd == 1) ? "" : "es"); - gio = g_io_channel_unix_new(sockfdlist[i]); - g_io_add_watch(gio, (G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL), - process_request, NULL); + fds = calloc(nsockfd, sizeof(struct pollfd)); + for (i = 0; i < nsockfd; i++) { + fds[i].fd = sockfdlist[i]; + fds[i].events = POLLIN; + } + timeout.tv_sec = MAIN_LOOP_TIMEOUT; + timeout.tv_nsec = 0; + + sigfillset(&sigmask); + sigdelset(&sigmask, SIGTERM); + sigdelset(&sigmask, SIGINT); + + terminate = 0; + while (!terminate) { + int r; + + r = ppoll(fds, nsockfd, &timeout, &sigmask); + if (r < 0) { + dbg("%s", strerror(errno)); + terminate = 1; + } else if (r) { + for (i = 0; i < nsockfd; i++) { + if (fds[i].revents & POLLIN) { + dbg("read event on fd[%d]=%d", + i, sockfdlist[i]); + process_request(sockfdlist[i]); + } + } + } else { + dbg("heartbeat timeout on ppoll()"); + } } - - main_loop = g_main_loop_new(FALSE, FALSE); - g_main_loop_run(main_loop); info("shutting down " PROGNAME); - - freeaddrinfo(ai_head); + free(fds); usbip_host_driver_close(); - usbip_names_free(); return 0; } @@ -496,11 +584,16 @@ static int do_standalone_mode(gboolean daemonize) int main(int argc, char *argv[]) { static const struct option longopts[] = { - { "daemon", no_argument, NULL, 'D' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'v' }, - { NULL, 0, NULL, 0 } + { "ipv4", no_argument, NULL, '4' }, + { "ipv6", no_argument, NULL, '6' }, + { "daemon", no_argument, NULL, 'D' }, + { "daemon", no_argument, NULL, 'D' }, + { "debug", no_argument, NULL, 'd' }, + { "pid", optional_argument, NULL, 'P' }, + { "tcp-port", required_argument, NULL, 't' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { NULL, 0, NULL, 0 } }; enum { @@ -509,9 +602,12 @@ int main(int argc, char *argv[]) cmd_version } cmd; - gboolean daemonize = FALSE; + int daemonize = 0; + int ipv4 = 0, ipv6 = 0; int opt, rc = -1; + pid_file = NULL; + usbip_use_stderr = 1; usbip_use_syslog = 0; @@ -520,14 +616,20 @@ int main(int argc, char *argv[]) cmd = cmd_standalone_mode; for (;;) { - opt = getopt_long(argc, argv, "Ddhv", longopts, NULL); + opt = getopt_long(argc, argv, "46DdP::t:hv", longopts, NULL); if (opt == -1) break; switch (opt) { + case '4': + ipv4 = 1; + break; + case '6': + ipv6 = 1; + break; case 'D': - daemonize = TRUE; + daemonize = 1; break; case 'd': usbip_use_debug = 1; @@ -535,6 +637,12 @@ int main(int argc, char *argv[]) case 'h': cmd = cmd_help; break; + case 'P': + pid_file = optarg ? optarg : DEFAULT_PID_FILE; + break; + case 't': + usbip_setup_port_number(optarg); + break; case 'v': cmd = cmd_version; break; @@ -545,9 +653,13 @@ int main(int argc, char *argv[]) } } + if (!ipv4 && !ipv6) + ipv4 = ipv6 = 1; + switch (cmd) { case cmd_standalone_mode: - rc = do_standalone_mode(daemonize); + rc = do_standalone_mode(daemonize, ipv4, ipv6); + remove_pid_file(); break; case cmd_version: printf(PROGNAME " (%s)\n", usbip_version_string); diff --git a/drivers/staging/usbip/userspace/src/utils.c b/drivers/staging/usbip/userspace/src/utils.c index 2d4966e6289..2b3d6d23501 100644 --- a/drivers/staging/usbip/userspace/src/utils.c +++ b/drivers/staging/usbip/userspace/src/utils.c @@ -16,61 +16,37 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sysfs/libsysfs.h> - #include <errno.h> #include <stdio.h> #include <string.h> #include "usbip_common.h" #include "utils.h" +#include "sysfs_utils.h" int modify_match_busid(char *busid, int add) { - char bus_type[] = "usb"; char attr_name[] = "match_busid"; - char buff[SYSFS_BUS_ID_SIZE + 4]; - char sysfs_mntpath[SYSFS_PATH_MAX]; + char command[SYSFS_BUS_ID_SIZE + 4]; char match_busid_attr_path[SYSFS_PATH_MAX]; - struct sysfs_attribute *match_busid_attr; - int rc, ret = 0; - - if (strnlen(busid, SYSFS_BUS_ID_SIZE) > SYSFS_BUS_ID_SIZE - 1) { - dbg("busid is too long"); - return -1; - } - - rc = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX); - if (rc < 0) { - err("sysfs must be mounted: %s", strerror(errno)); - return -1; - } + int rc; snprintf(match_busid_attr_path, sizeof(match_busid_attr_path), - "%s/%s/%s/%s/%s/%s", sysfs_mntpath, SYSFS_BUS_NAME, bus_type, - SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, attr_name); - - match_busid_attr = sysfs_open_attribute(match_busid_attr_path); - if (!match_busid_attr) { - dbg("problem getting match_busid attribute: %s", - strerror(errno)); - return -1; - } + "%s/%s/%s/%s/%s/%s", SYSFS_MNT_PATH, SYSFS_BUS_NAME, + SYSFS_BUS_TYPE, SYSFS_DRIVERS_NAME, USBIP_HOST_DRV_NAME, + attr_name); if (add) - snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); + snprintf(command, SYSFS_BUS_ID_SIZE + 4, "add %s", busid); else - snprintf(buff, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); + snprintf(command, SYSFS_BUS_ID_SIZE + 4, "del %s", busid); - dbg("write \"%s\" to %s", buff, match_busid_attr->path); - - rc = sysfs_write_attribute(match_busid_attr, buff, sizeof(buff)); + rc = write_sysfs_attribute(match_busid_attr_path, command, + sizeof(command)); if (rc < 0) { dbg("failed to write match_busid: %s", strerror(errno)); - ret = -1; + return -1; } - sysfs_close_attribute(match_busid_attr); - - return ret; + return 0; } diff --git a/drivers/staging/usbip/vhci.h b/drivers/staging/usbip/vhci.h index 88b32981cf1..a863a98a91c 100644 --- a/drivers/staging/usbip/vhci.h +++ b/drivers/staging/usbip/vhci.h @@ -71,12 +71,7 @@ struct vhci_unlink { unsigned long unlink_seqnum; }; -/* - * The number of ports is less than 16 ? - * USB_MAXCHILDREN is statically defined to 16 in usb.h. Its maximum value - * would be 31 because the event_bits[1] of struct usb_hub is defined as - * unsigned long in hub.h - */ +/* Number of supported ports. Value has an upperbound of USB_MAXCHILDREN */ #define VHCI_NPORTS 8 /* for usb_bus.hcpriv */ @@ -100,11 +95,9 @@ struct vhci_hcd { extern struct vhci_hcd *the_controller; extern const struct attribute_group dev_attr_group; -#define hardware (&the_controller->pdev.dev) /* vhci_hcd.c */ void rh_port_connect(int rhport, enum usb_device_speed speed); -void rh_port_disconnect(int rhport); /* vhci_rx.c */ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum); diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 2ee97e2095b..0007d30e45b 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -18,6 +18,7 @@ */ #include <linux/init.h> +#include <linux/file.h> #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/module.h> @@ -120,11 +121,9 @@ static void dump_port_status_diff(u32 prev_status, u32 new_status) void rh_port_connect(int rhport, enum usb_device_speed speed) { - unsigned long flags; - usbip_dbg_vhci_rh("rh_port_connect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); the_controller->port_status[rhport] |= USB_PORT_STAT_CONNECTION | (1 << USB_PORT_FEAT_C_CONNECTION); @@ -140,33 +139,22 @@ void rh_port_connect(int rhport, enum usb_device_speed speed) break; } - /* spin_lock(&the_controller->vdev[rhport].ud.lock); - * the_controller->vdev[rhport].ud.status = VDEV_CONNECT; - * spin_unlock(&the_controller->vdev[rhport].ud.lock); */ - - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); } -void rh_port_disconnect(int rhport) +static void rh_port_disconnect(int rhport) { - unsigned long flags; - usbip_dbg_vhci_rh("rh_port_disconnect %d\n", rhport); - spin_lock_irqsave(&the_controller->lock, flags); - /* stop_activity(dum, driver); */ + spin_lock(&the_controller->lock); + the_controller->port_status[rhport] &= ~USB_PORT_STAT_CONNECTION; the_controller->port_status[rhport] |= (1 << USB_PORT_FEAT_C_CONNECTION); - /* not yet complete the disconnection - * spin_lock(&vdev->ud.lock); - * vdev->ud.status = VHC_ST_DISCONNECT; - * spin_unlock(&vdev->ud.lock); */ - - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_poll_rh_status(vhci_to_hcd(the_controller)); } @@ -178,44 +166,31 @@ void rh_port_disconnect(int rhport) | USB_PORT_STAT_C_RESET) << 16) /* - * This function is almostly the same as dummy_hcd.c:dummy_hub_status() without - * suspend/resume support. But, it is modified to provide multiple ports. + * Returns 0 if the status hasn't changed, or the number of bytes in buf. + * Ports are 0-indexed from the HCD point of view, + * and 1-indexed from the USB core pointer of view. * * @buf: a bitmap to show which port status has been changed. - * bit 0: reserved or used for another purpose? + * bit 0: reserved * bit 1: the status of port 0 has been changed. * bit 2: the status of port 1 has been changed. * ... - * bit 7: the status of port 6 has been changed. - * bit 8: the status of port 7 has been changed. - * ... - * bit 15: the status of port 14 has been changed. - * - * So, the maximum number of ports is 31 ( port 0 to port 30) ? - * - * The return value is the actual transferred length in byte. If nothing has - * been changed, return 0. In the case that the number of ports is less than or - * equal to 6 (VHCI_NPORTS==7), return 1. - * */ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) { struct vhci_hcd *vhci; - unsigned long flags; - int retval = 0; - - /* the enough buffer is allocated according to USB_MAXCHILDREN */ - unsigned long *event_bits = (unsigned long *) buf; + int retval; int rhport; int changed = 0; - *event_bits = 0; + retval = DIV_ROUND_UP(VHCI_NPORTS + 1, 8); + memset(buf, 0, retval); vhci = hcd_to_vhci(hcd); - spin_lock_irqsave(&vhci->lock, flags); + spin_lock(&vhci->lock); if (!HCD_HW_ACCESSIBLE(hcd)) { - usbip_dbg_vhci_rh("hw accessible flag in on?\n"); + usbip_dbg_vhci_rh("hw accessible flag not on?\n"); goto done; } @@ -223,36 +198,27 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { if ((vhci->port_status[rhport] & PORT_C_MASK)) { /* The status of a port has been changed, */ - usbip_dbg_vhci_rh("port %d is changed\n", rhport); + usbip_dbg_vhci_rh("port %d status changed\n", rhport); - *event_bits |= 1 << (rhport + 1); + buf[(rhport + 1) / 8] |= 1 << (rhport + 1) % 8; changed = 1; } } - pr_info("changed %d\n", changed); - - if (hcd->state == HC_STATE_SUSPENDED) + if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1)) usb_hcd_resume_root_hub(hcd); - if (changed) - retval = 1 + (VHCI_NPORTS / 8); - else - retval = 0; - done: - spin_unlock_irqrestore(&vhci->lock, flags); - return retval; + spin_unlock(&vhci->lock); + return changed ? retval : 0; } -/* See hub_configure in hub.c */ static inline void hub_descriptor(struct usb_hub_descriptor *desc) { memset(desc, 0, sizeof(*desc)); desc->bDescriptorType = 0x29; desc->bDescLength = 9; - desc->wHubCharacteristics = (__force __u16) - (__constant_cpu_to_le16(0x0001)); + desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001)); desc->bNbrPorts = VHCI_NPORTS; desc->u.hs.DeviceRemovable[0] = 0xff; desc->u.hs.DeviceRemovable[1] = 0xff; @@ -263,7 +229,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, { struct vhci_hcd *dum; int retval = 0; - unsigned long flags; int rhport; u32 prev_port_status[VHCI_NPORTS]; @@ -283,7 +248,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, dum = hcd_to_vhci(hcd); - spin_lock_irqsave(&dum->lock, flags); + spin_lock(&dum->lock); /* store old status and compare now and old later */ if (usbip_dbg_flag_vhci_rh) { @@ -306,16 +271,14 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } break; case USB_PORT_FEAT_POWER: - usbip_dbg_vhci_rh(" ClearPortFeature: " - "USB_PORT_FEAT_POWER\n"); + usbip_dbg_vhci_rh( + " ClearPortFeature: USB_PORT_FEAT_POWER\n"); dum->port_status[rhport] = 0; - /* dum->address = 0; */ - /* dum->hdev = 0; */ dum->resuming = 0; break; case USB_PORT_FEAT_C_RESET: - usbip_dbg_vhci_rh(" ClearPortFeature: " - "USB_PORT_FEAT_C_RESET\n"); + usbip_dbg_vhci_rh( + " ClearPortFeature: USB_PORT_FEAT_C_RESET\n"); switch (dum->vdev[rhport].speed) { case USB_SPEED_HIGH: dum->port_status[rhport] |= @@ -350,11 +313,11 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, retval = -EPIPE; } - /* we do no care of resume. */ + /* we do not care about resume. */ /* whoever resets or resumes must GetPortStatus to * complete it!! - * */ + */ if (dum->resuming && time_after(jiffies, dum->re_timeout)) { dum->port_status[rhport] |= (1 << USB_PORT_FEAT_C_SUSPEND); @@ -362,11 +325,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, ~(1 << USB_PORT_FEAT_SUSPEND); dum->resuming = 0; dum->re_timeout = 0; - /* if (dum->driver && dum->driver->resume) { - * spin_unlock (&dum->lock); - * dum->driver->resume (&dum->gadget); - * spin_lock (&dum->lock); - * } */ } if ((dum->port_status[rhport] & (1 << USB_PORT_FEAT_RESET)) != @@ -379,39 +337,17 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, if (dum->vdev[rhport].ud.status == VDEV_ST_NOTASSIGNED) { - usbip_dbg_vhci_rh(" enable rhport %d " - "(status %u)\n", - rhport, - dum->vdev[rhport].ud.status); + usbip_dbg_vhci_rh( + " enable rhport %d (status %u)\n", + rhport, + dum->vdev[rhport].ud.status); dum->port_status[rhport] |= USB_PORT_STAT_ENABLE; } -#if 0 - if (dum->driver) { - dum->port_status[rhport] |= - USB_PORT_STAT_ENABLE; - /* give it the best speed we agree on */ - dum->gadget.speed = dum->driver->speed; - dum->gadget.ep0->maxpacket = 64; - switch (dum->gadget.speed) { - case USB_SPEED_HIGH: - dum->port_status[rhport] |= - USB_PORT_STAT_HIGH_SPEED; - break; - case USB_SPEED_LOW: - dum->gadget.ep0->maxpacket = 8; - dum->port_status[rhport] |= - USB_PORT_STAT_LOW_SPEED; - break; - default: - dum->gadget.speed = USB_SPEED_FULL; - break; - } - } -#endif } - ((u16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); - ((u16 *) buf)[1] = cpu_to_le16(dum->port_status[rhport] >> 16); + ((__le16 *) buf)[0] = cpu_to_le16(dum->port_status[rhport]); + ((__le16 *) buf)[1] = + cpu_to_le16(dum->port_status[rhport] >> 16); usbip_dbg_vhci_rh(" GetPortStatus bye %x %x\n", ((u16 *)buf)[0], ((u16 *)buf)[1]); @@ -423,34 +359,18 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, case SetPortFeature: switch (wValue) { case USB_PORT_FEAT_SUSPEND: - usbip_dbg_vhci_rh(" SetPortFeature: " - "USB_PORT_FEAT_SUSPEND\n"); -#if 0 - dum->port_status[rhport] |= - (1 << USB_PORT_FEAT_SUSPEND); - if (dum->driver->suspend) { - spin_unlock(&dum->lock); - dum->driver->suspend(&dum->gadget); - spin_lock(&dum->lock); - } -#endif + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_SUSPEND\n"); break; case USB_PORT_FEAT_RESET: - usbip_dbg_vhci_rh(" SetPortFeature: " - "USB_PORT_FEAT_RESET\n"); + usbip_dbg_vhci_rh( + " SetPortFeature: USB_PORT_FEAT_RESET\n"); /* if it's already running, disconnect first */ if (dum->port_status[rhport] & USB_PORT_STAT_ENABLE) { dum->port_status[rhport] &= ~(USB_PORT_STAT_ENABLE | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); -#if 0 - if (dum->driver) { - dev_dbg(hardware, "disconnect\n"); - stop_activity(dum, dum->driver); - } -#endif - /* FIXME test that code path! */ } /* 50msec reset signaling */ @@ -467,9 +387,6 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: pr_err("default: no such request\n"); - /* dev_dbg (hardware, - * "hub control req%04x v%04x i%04x l%d\n", - * typeReq, wValue, wIndex, wLength); */ /* "protocol stall" on error */ retval = -EPIPE; @@ -485,7 +402,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, } usbip_dbg_vhci_rh(" bye\n"); - spin_unlock_irqrestore(&dum->lock, flags); + spin_unlock(&dum->lock); return retval; } @@ -508,25 +425,20 @@ static void vhci_tx_urb(struct urb *urb) { struct vhci_device *vdev = get_vdev(urb->dev); struct vhci_priv *priv; - unsigned long flag; if (!vdev) { pr_err("could not get virtual device"); - /* BUG(); */ return; } priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC); - - spin_lock_irqsave(&vdev->priv_lock, flag); - if (!priv) { - dev_err(&urb->dev->dev, "malloc vhci_priv\n"); - spin_unlock_irqrestore(&vdev->priv_lock, flag); usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); return; } + spin_lock(&vdev->priv_lock); + priv->seqnum = atomic_inc_return(&the_controller->seqnum); if (priv->seqnum == 0xffff) dev_info(&urb->dev->dev, "seqnum max\n"); @@ -539,7 +451,7 @@ static void vhci_tx_urb(struct urb *urb) list_add_tail(&priv->list, &vdev->priv_tx); wake_up(&vdev->waitq_tx); - spin_unlock_irqrestore(&vdev->priv_lock, flag); + spin_unlock(&vdev->priv_lock); } static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, @@ -547,7 +459,6 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, { struct device *dev = &urb->dev->dev; int ret = 0; - unsigned long flags; struct vhci_device *vdev; usbip_dbg_vhci_hc("enter, usb_hcd %p urb %p mem_flags %d\n", @@ -556,11 +467,11 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, /* patch to usb_sg_init() is in 2.5.60 */ BUG_ON(!urb->transfer_buffer && urb->transfer_buffer_length); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); if (urb->status != -EINPROGRESS) { dev_err(dev, "URB already unlinked!, status %d\n", urb->status); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); return urb->status; } @@ -572,7 +483,7 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, vdev->ud.status == VDEV_ST_ERROR) { dev_err(dev, "enqueue for inactive port %d\n", vdev->rhport); spin_unlock(&vdev->ud.lock); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); return -ENODEV; } spin_unlock(&vdev->ud.lock); @@ -624,10 +535,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, goto no_need_xmit; case USB_REQ_GET_DESCRIPTOR: - if (ctrlreq->wValue == (USB_DT_DEVICE << 8)) - usbip_dbg_vhci_hc("Not yet?: " - "Get_Descriptor to device 0 " - "(get max pipe size)\n"); + if (ctrlreq->wValue == cpu_to_le16(USB_DT_DEVICE << 8)) + usbip_dbg_vhci_hc( + "Not yet?:Get_Descriptor to device 0 (get max pipe size)\n"); if (vdev->udev) usb_put_dev(vdev->udev); @@ -636,8 +546,9 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, default: /* NOT REACHED */ - dev_err(dev, "invalid request to devnum 0 bRequest %u, " - "wValue %u\n", ctrlreq->bRequest, + dev_err(dev, + "invalid request to devnum 0 bRequest %u, wValue %u\n", + ctrlreq->bRequest, ctrlreq->wValue); ret = -EINVAL; goto no_need_xmit; @@ -647,14 +558,14 @@ static int vhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, out: vhci_tx_urb(urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); return 0; no_need_xmit: usb_hcd_unlink_urb_from_ep(hcd, urb); no_need_unlink: - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); return ret; } @@ -707,27 +618,27 @@ no_need_unlink: */ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { - unsigned long flags; struct vhci_priv *priv; struct vhci_device *vdev; pr_info("dequeue a urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); priv = urb->hcpriv; if (!priv) { /* URB was never linked! or will be soon given back by * vhci_rx. */ - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); return 0; } { int ret = 0; + ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret) { - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); return ret; } } @@ -737,16 +648,14 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) if (!vdev->ud.tcp_socket) { /* tcp connection is closed */ - unsigned long flags2; - - spin_lock_irqsave(&vdev->priv_lock, flags2); + spin_lock(&vdev->priv_lock); pr_info("device %p seems to be disconnected\n", vdev); list_del(&priv->list); kfree(priv); urb->hcpriv = NULL; - spin_unlock_irqrestore(&vdev->priv_lock, flags2); + spin_unlock(&vdev->priv_lock); /* * If tcp connection is alive, we have sent CMD_UNLINK. @@ -757,24 +666,22 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); } else { /* tcp connection is alive */ - unsigned long flags2; struct vhci_unlink *unlink; - spin_lock_irqsave(&vdev->priv_lock, flags2); + spin_lock(&vdev->priv_lock); /* setup CMD_UNLINK pdu */ unlink = kzalloc(sizeof(struct vhci_unlink), GFP_ATOMIC); if (!unlink) { - pr_err("malloc vhci_unlink\n"); - spin_unlock_irqrestore(&vdev->priv_lock, flags2); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&vdev->priv_lock); + spin_unlock(&the_controller->lock); usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); return -ENOMEM; } @@ -792,10 +699,10 @@ static int vhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) list_add_tail(&unlink->list, &vdev->unlink_tx); wake_up(&vdev->waitq_tx); - spin_unlock_irqrestore(&vdev->priv_lock, flags2); + spin_unlock(&vdev->priv_lock); } - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usbip_dbg_vhci_hc("leave\n"); return 0; @@ -805,6 +712,7 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) { struct vhci_unlink *unlink, *tmp; + spin_lock(&the_controller->lock); spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { @@ -813,9 +721,12 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) kfree(unlink); } - list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { + while (!list_empty(&vdev->unlink_rx)) { struct urb *urb; + unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink, + list); + /* give back URB of unanswered unlink request */ pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum); @@ -830,18 +741,24 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) urb->status = -ENODEV; - spin_lock(&the_controller->lock); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); + + list_del(&unlink->list); + + spin_unlock(&vdev->priv_lock); spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); - list_del(&unlink->list); + spin_lock(&the_controller->lock); + spin_lock(&vdev->priv_lock); + kfree(unlink); } spin_unlock(&vdev->priv_lock); + spin_unlock(&the_controller->lock); } /* @@ -859,17 +776,20 @@ static void vhci_shutdown_connection(struct usbip_device *ud) kernel_sock_shutdown(ud->tcp_socket, SHUT_RDWR); } - /* kill threads related to this sdev, if v.c. exists */ - if (vdev->ud.tcp_rx && !task_is_dead(vdev->ud.tcp_rx)) - kthread_stop(vdev->ud.tcp_rx); - if (vdev->ud.tcp_tx && !task_is_dead(vdev->ud.tcp_tx)) - kthread_stop(vdev->ud.tcp_tx); - + /* kill threads related to this sdev */ + if (vdev->ud.tcp_rx) { + kthread_stop_put(vdev->ud.tcp_rx); + vdev->ud.tcp_rx = NULL; + } + if (vdev->ud.tcp_tx) { + kthread_stop_put(vdev->ud.tcp_tx); + vdev->ud.tcp_tx = NULL; + } pr_info("stop threads\n"); /* active connection is closed */ - if (vdev->ud.tcp_socket != NULL) { - sock_release(vdev->ud.tcp_socket); + if (vdev->ud.tcp_socket) { + sockfd_put(vdev->ud.tcp_socket); vdev->ud.tcp_socket = NULL; } pr_info("release socket\n"); @@ -884,11 +804,11 @@ static void vhci_shutdown_connection(struct usbip_device *ud) * disable endpoints. pending urbs are unlinked(dequeued). * * NOTE: After calling rh_port_disconnect(), the USB device drivers of a - * deteched device should release used urbs in a cleanup function(i.e. + * detached device should release used urbs in a cleanup function (i.e. * xxx_disconnect()). Therefore, vhci_hcd does not need to release * pushed urbs and their private data in this function. * - * NOTE: vhci_dequeue() must be considered carefully. When shutdowning + * NOTE: vhci_dequeue() must be considered carefully. When shutting down * a connection, vhci_shutdown_connection() expects vhci_dequeue() * gives back pushed urbs and frees their private data by request of * the cleanup function of a USB driver. When unlinking a urb with an @@ -915,7 +835,10 @@ static void vhci_device_reset(struct usbip_device *ud) usb_put_dev(vdev->udev); vdev->udev = NULL; - ud->tcp_socket = NULL; + if (ud->tcp_socket) { + sockfd_put(ud->tcp_socket); + ud->tcp_socket = NULL; + } ud->status = VDEV_ST_NULL; spin_unlock(&ud->lock); @@ -934,14 +857,12 @@ static void vhci_device_init(struct vhci_device *vdev) vdev->ud.side = USBIP_VHCI; vdev->ud.status = VDEV_ST_NULL; - /* vdev->ud.lock = SPIN_LOCK_UNLOCKED; */ spin_lock_init(&vdev->ud.lock); INIT_LIST_HEAD(&vdev->priv_rx); INIT_LIST_HEAD(&vdev->priv_tx); INIT_LIST_HEAD(&vdev->unlink_tx); INIT_LIST_HEAD(&vdev->unlink_rx); - /* vdev->priv_lock = SPIN_LOCK_UNLOCKED; */ spin_lock_init(&vdev->priv_lock); init_waitqueue_head(&vdev->waitq_tx); @@ -965,6 +886,7 @@ static int vhci_start(struct usb_hcd *hcd) for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; + vhci_device_init(vdev); vdev->rhport = rhport; } @@ -973,7 +895,6 @@ static int vhci_start(struct usb_hcd *hcd) spin_lock_init(&vhci->lock); hcd->power_budget = 0; /* no limit */ - hcd->state = HC_STATE_RUNNING; hcd->uses_new_polling = 1; /* vhci_hcd is now ready to be controlled through sysfs */ @@ -997,7 +918,7 @@ static void vhci_stop(struct usb_hcd *hcd) sysfs_remove_group(&vhci_dev(vhci)->kobj, &dev_attr_group); /* 2. shutdown all the ports of vhci_hcd */ - for (rhport = 0 ; rhport < VHCI_NPORTS; rhport++) { + for (rhport = 0; rhport < VHCI_NPORTS; rhport++) { struct vhci_device *vdev = &vhci->vdev[rhport]; usbip_event_add(&vdev->ud, VDEV_EVENT_REMOVED); @@ -1020,11 +941,9 @@ static int vhci_bus_suspend(struct usb_hcd *hcd) dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); - spin_lock_irq(&vhci->lock); - /* vhci->rh_state = DUMMY_RH_SUSPENDED; - * set_link_state(vhci); */ + spin_lock(&vhci->lock); hcd->state = HC_STATE_SUSPENDED; - spin_unlock_irq(&vhci->lock); + spin_unlock(&vhci->lock); return 0; } @@ -1036,17 +955,12 @@ static int vhci_bus_resume(struct usb_hcd *hcd) dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__); - spin_lock_irq(&vhci->lock); - if (!HCD_HW_ACCESSIBLE(hcd)) { + spin_lock(&vhci->lock); + if (!HCD_HW_ACCESSIBLE(hcd)) rc = -ESHUTDOWN; - } else { - /* vhci->rh_state = DUMMY_RH_RUNNING; - * set_link_state(vhci); - * if (!list_empty(&vhci->urbp_list)) - * mod_timer(&vhci->timer, jiffies); */ + else hcd->state = HC_STATE_RUNNING; - } - spin_unlock_irq(&vhci->lock); + spin_unlock(&vhci->lock); return rc; } @@ -1085,12 +999,6 @@ static int vhci_hcd_probe(struct platform_device *pdev) usbip_dbg_vhci_hc("name %s id %d\n", pdev->name, pdev->id); - /* will be removed */ - if (pdev->dev.dma_mask) { - dev_info(&pdev->dev, "vhci_hcd DMA not supported\n"); - return -EINVAL; - } - /* * Allocate and initialize hcd. * Our private data is also allocated automatically. @@ -1163,8 +1071,9 @@ static int vhci_hcd_suspend(struct platform_device *pdev, pm_message_t state) spin_unlock(&the_controller->lock); if (connected > 0) { - dev_info(&pdev->dev, "We have %d active connection%s. Do not " - "suspend.\n", connected, (connected == 1 ? "" : "s")); + dev_info(&pdev->dev, + "We have %d active connection%s. Do not suspend.\n", + connected, (connected == 1 ? "" : "s")); ret = -EBUSY; } else { dev_info(&pdev->dev, "suspend vhci_hcd"); @@ -1196,11 +1105,11 @@ static int vhci_hcd_resume(struct platform_device *pdev) static struct platform_driver vhci_driver = { .probe = vhci_hcd_probe, - .remove = __devexit_p(vhci_hcd_remove), + .remove = vhci_hcd_remove, .suspend = vhci_hcd_suspend, .resume = vhci_hcd_resume, .driver = { - .name = (char *) driver_name, + .name = driver_name, .owner = THIS_MODULE, }, }; @@ -1217,10 +1126,9 @@ static void the_pdev_release(struct device *dev) static struct platform_device the_pdev = { /* should be the same name as driver_name */ - .name = (char *) driver_name, + .name = driver_name, .id = -1, .dev = { - /* .driver = &vhci_driver, */ .release = the_pdev_release, }, }; @@ -1233,11 +1141,11 @@ static int __init vhci_hcd_init(void) return -ENODEV; ret = platform_driver_register(&vhci_driver); - if (ret < 0) + if (ret) goto err_driver_register; ret = platform_device_register(&the_pdev); - if (ret < 0) + if (ret) goto err_platform_device_register; pr_info(DRIVER_DESC " v" USBIP_VERSION "\n"); diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 3f511b47563..d07fcb5ee93 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -31,33 +31,37 @@ struct urb *pickup_urb_and_free_priv(struct vhci_device *vdev, __u32 seqnum) int status; list_for_each_entry_safe(priv, tmp, &vdev->priv_rx, list) { - if (priv->seqnum == seqnum) { - urb = priv->urb; - status = urb->status; - - usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n", - urb, priv, seqnum); - - /* TODO: fix logic here to improve indent situtation */ - if (status != -EINPROGRESS) { - if (status == -ENOENT || - status == -ECONNRESET) - dev_info(&urb->dev->dev, - "urb %p was unlinked " - "%ssynchronuously.\n", urb, - status == -ENOENT ? "" : "a"); - else - dev_info(&urb->dev->dev, - "urb %p may be in a error, " - "status %d\n", urb, status); - } - - list_del(&priv->list); - kfree(priv); - urb->hcpriv = NULL; - + if (priv->seqnum != seqnum) + continue; + + urb = priv->urb; + status = urb->status; + + usbip_dbg_vhci_rx("find urb %p vurb %p seqnum %u\n", + urb, priv, seqnum); + + switch (status) { + case -ENOENT: + /* fall through */ + case -ECONNRESET: + dev_info(&urb->dev->dev, + "urb %p was unlinked %ssynchronuously.\n", urb, + status == -ENOENT ? "" : "a"); + break; + case -EINPROGRESS: + /* no info output */ break; + default: + dev_info(&urb->dev->dev, + "urb %p may be in a error, status %d\n", urb, + status); } + + list_del(&priv->list); + kfree(priv); + urb->hcpriv = NULL; + + break; } return urb; @@ -68,7 +72,6 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, { struct usbip_device *ud = &vdev->ud; struct urb *urb; - unsigned long flags; spin_lock(&vdev->priv_lock); urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); @@ -94,17 +97,16 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, return; /* restore the padding in iso packets */ - if (usbip_pad_iso(ud, urb) < 0) - return; + usbip_pad_iso(ud, urb); if (usbip_dbg_flag_vhci_rx) usbip_dump_urb(urb); usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); @@ -142,7 +144,6 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, { struct vhci_unlink *unlink; struct urb *urb; - unsigned long flags; usbip_dump_header(pdu); @@ -163,18 +164,18 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, * already received the result of its submit result and gave * back the URB. */ - pr_info("the urb (seqnum %d) was already given backed\n", + pr_info("the urb (seqnum %d) was already given back\n", pdu->base.seqnum); } else { usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - /* If unlink is succeed, status is -ECONNRESET */ + /* If unlink is successful, status is -ECONNRESET */ urb->status = pdu->u.ret_unlink.status; pr_info("urb->status %d\n", urb->status); - spin_lock_irqsave(&the_controller->lock, flags); + spin_lock(&the_controller->lock); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock_irqrestore(&the_controller->lock, flags); + spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); @@ -205,7 +206,7 @@ static void vhci_rx_pdu(struct usbip_device *ud) memset(&pdu, 0, sizeof(pdu)); - /* 1. receive a pdu header */ + /* receive a pdu header */ ret = usbip_recv(ud->tcp_socket, &pdu, sizeof(pdu)); if (ret < 0) { if (ret == -ECONNRESET) diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 0cd039bb5fd..211f43f67ea 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -18,6 +18,7 @@ */ #include <linux/kthread.h> +#include <linux/file.h> #include <linux/net.h> #include "usbip_common.h" @@ -26,7 +27,7 @@ /* TODO: refine locking ?*/ /* Sysfs entry to show port status */ -static ssize_t show_status(struct device *dev, struct device_attribute *attr, +static ssize_t status_show(struct device *dev, struct device_attribute *attr, char *out) { char *s = out; @@ -46,8 +47,8 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, * up /proc/net/{tcp,tcp6}. Also, a userland program may remember a * port number and its peer IP address. */ - out += sprintf(out, "prt sta spd bus dev socket " - "local_busid\n"); + out += sprintf(out, + "prt sta spd bus dev socket local_busid\n"); for (i = 0; i < VHCI_NPORTS; i++) { struct vhci_device *vdev = port_to_vdev(i); @@ -73,7 +74,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *attr, return out - s; } -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR_RO(status); /* Sysfs entry to shutdown a virtual connection */ static int vhci_port_disconnect(__u32 rhport) @@ -113,7 +114,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, int err; __u32 rhport = 0; - sscanf(buf, "%u", &rhport); + if (sscanf(buf, "%u", &rhport) != 1) + return -EINVAL; /* check rhport */ if (rhport >= VHCI_NPORTS) { @@ -148,7 +150,8 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) case USB_SPEED_WIRELESS: break; default: - pr_err("speed %d\n", speed); + pr_err("Failed attach request for unsupported USB speed: %s\n", + usb_speed_string(speed)); return -EINVAL; } @@ -173,6 +176,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, struct socket *socket; int sockfd = 0; __u32 rhport = 0, devid = 0, speed = 0; + int err; /* * @rhport: port number of vhci_hcd @@ -180,7 +184,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ - sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed); + if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) + return -EINVAL; usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", rhport, sockfd, devid, speed); @@ -189,8 +194,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, if (valid_args(rhport, speed) < 0) return -EINVAL; - /* check sockfd */ - socket = sockfd_to_socket(sockfd); + /* Extract socket from fd. */ + socket = sockfd_lookup(sockfd, &err); if (!socket) return -EINVAL; @@ -206,12 +211,15 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, spin_unlock(&vdev->ud.lock); spin_unlock(&the_controller->lock); + sockfd_put(socket); + dev_err(dev, "port %d already used\n", rhport); return -EINVAL; } - dev_info(dev, "rhport(%u) sockfd(%d) devid(%u) speed(%u)\n", - rhport, sockfd, devid, speed); + dev_info(dev, + "rhport(%u) sockfd(%d) devid(%u) speed(%u) speed_str(%s)\n", + rhport, sockfd, devid, speed, usb_speed_string(speed)); vdev->devid = devid; vdev->speed = speed; @@ -222,8 +230,8 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, spin_unlock(&the_controller->lock); /* end the lock */ - vdev->ud.tcp_rx = kthread_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); - vdev->ud.tcp_tx = kthread_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); + vdev->ud.tcp_rx = kthread_get_run(vhci_rx_loop, &vdev->ud, "vhci_rx"); + vdev->ud.tcp_tx = kthread_get_run(vhci_tx_loop, &vdev->ud, "vhci_tx"); rh_port_connect(rhport, speed); diff --git a/drivers/staging/usbip/vhci_tx.c b/drivers/staging/usbip/vhci_tx.c index 9b437e7ef1a..409fd99f325 100644 --- a/drivers/staging/usbip/vhci_tx.c +++ b/drivers/staging/usbip/vhci_tx.c @@ -46,18 +46,17 @@ static void setup_cmd_submit_pdu(struct usbip_header *pdup, struct urb *urb) static struct vhci_priv *dequeue_from_priv_tx(struct vhci_device *vdev) { - unsigned long flags; struct vhci_priv *priv, *tmp; - spin_lock_irqsave(&vdev->priv_lock, flags); + spin_lock(&vdev->priv_lock); list_for_each_entry_safe(priv, tmp, &vdev->priv_tx, list) { list_move_tail(&priv->list, &vdev->priv_rx); - spin_unlock_irqrestore(&vdev->priv_lock, flags); + spin_unlock(&vdev->priv_lock); return priv; } - spin_unlock_irqrestore(&vdev->priv_lock, flags); + spin_unlock(&vdev->priv_lock); return NULL; } @@ -76,7 +75,7 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev) int ret; struct urb *urb = priv->urb; struct usbip_header pdu_header; - void *iso_buffer = NULL; + struct usbip_iso_packet_descriptor *iso_buffer = NULL; txsize = 0; memset(&pdu_header, 0, sizeof(pdu_header)); @@ -136,18 +135,17 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev) static struct vhci_unlink *dequeue_from_unlink_tx(struct vhci_device *vdev) { - unsigned long flags; struct vhci_unlink *unlink, *tmp; - spin_lock_irqsave(&vdev->priv_lock, flags); + spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { list_move_tail(&unlink->list, &vdev->unlink_rx); - spin_unlock_irqrestore(&vdev->priv_lock, flags); + spin_unlock(&vdev->priv_lock); return unlink; } - spin_unlock_irqrestore(&vdev->priv_lock, flags); + spin_unlock(&vdev->priv_lock); return NULL; } |
