diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-05 14:18:03 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-05 14:18:03 -0700 |
commit | e9563355ac1175dd3440dc2ea5c28b27ed51a283 (patch) | |
tree | 8546d55832714b5d19ba4c7799266918ca04882e /drivers/staging/usbip | |
parent | cdd854bc42b5e6c79bbbc40c6600d995ffe6e747 (diff) | |
parent | b12d1995f650e92f26184afd28e6cf40bf64467a (diff) | |
download | lwn-e9563355ac1175dd3440dc2ea5c28b27ed51a283.tar.gz lwn-e9563355ac1175dd3440dc2ea5c28b27ed51a283.zip |
Staging: Merge staging-next into Linus's tree
Conflicts:
drivers/staging/Kconfig
drivers/staging/batman-adv/bat_sysfs.c
drivers/staging/batman-adv/device.c
drivers/staging/batman-adv/hard-interface.c
drivers/staging/cx25821/cx25821-audups11.c
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/usbip')
-rw-r--r-- | drivers/staging/usbip/stub.h | 17 | ||||
-rw-r--r-- | drivers/staging/usbip/stub_dev.c | 101 | ||||
-rw-r--r-- | drivers/staging/usbip/stub_main.c | 65 | ||||
-rw-r--r-- | drivers/staging/usbip/stub_rx.c | 101 | ||||
-rw-r--r-- | drivers/staging/usbip/usbip_common.h | 2 |
5 files changed, 220 insertions, 66 deletions
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h index 022d0649ac5e..30dbfb6d16f2 100644 --- a/drivers/staging/usbip/stub.h +++ b/drivers/staging/usbip/stub.h @@ -25,6 +25,11 @@ #include <linux/module.h> #include <linux/net.h> +#define STUB_BUSID_OTHER 0 +#define STUB_BUSID_REMOV 1 +#define STUB_BUSID_ADDED 2 +#define STUB_BUSID_ALLOC 3 + struct stub_device { struct usb_interface *interface; struct list_head list; @@ -72,6 +77,14 @@ struct stub_unlink { __u32 status; }; +#define BUSID_SIZE 20 +struct bus_id_priv { + char name[BUSID_SIZE]; + char status; + int interf_count; + struct stub_device *sdev; + char shutdown_busid; +}; extern struct kmem_cache *stub_priv_cache; @@ -91,5 +104,7 @@ void stub_rx_loop(struct usbip_task *); void stub_enqueue_ret_unlink(struct stub_device *, __u32, __u32); /* stub_main.c */ -int match_busid(const char *busid); +struct bus_id_priv *get_busid_priv(const char *busid); +int del_match_busid(char *busid); + void stub_device_cleanup_urbs(struct stub_device *sdev); diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 3f95605427a7..b6b753a49346 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -393,11 +393,14 @@ static int stub_probe(struct usb_interface *interface, struct stub_device *sdev = NULL; const char *udev_busid = dev_name(interface->dev.parent); int err = 0; + struct bus_id_priv *busid_priv; dev_dbg(&interface->dev, "Enter\n"); /* check we should claim or not by busid_table */ - if (match_busid(udev_busid)) { + 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, "this device %s is not in match_busid table. skip!\n", udev_busid); @@ -422,28 +425,80 @@ static int stub_probe(struct usb_interface *interface, return -ENODEV; } + + if (busid_priv->status == STUB_BUSID_ALLOC) { + busid_priv->interf_count++; + sdev = busid_priv->sdev; + if (!sdev) + return -ENODEV; + + dev_info(&interface->dev, + "USB/IP Stub: register a 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, "create sysfs files for %s\n", + udev_busid); + usb_set_intfdata(interface, NULL); + busid_priv->interf_count--; + + return err; + } + + return 0; + } + /* ok. this is my device. */ sdev = stub_device_alloc(interface); if (!sdev) return -ENOMEM; - dev_info(&interface->dev, "USB/IP Stub: register a new interface " + dev_info(&interface->dev, "USB/IP Stub: register a new device " "(bus %u dev %u ifn %u)\n", udev->bus->busnum, udev->devnum, interface->cur_altsetting->desc.bInterfaceNumber); + 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++; + + busid_priv->sdev = sdev; err = stub_add_files(&interface->dev); if (err) { dev_err(&interface->dev, "create sysfs files for %s\n", udev_busid); + usb_set_intfdata(interface, NULL); + busid_priv->interf_count = 0; + + busid_priv->sdev = NULL; + stub_device_free(sdev); return err; } + busid_priv->status = STUB_BUSID_ALLOC; return 0; } +static void shutdown_busid(struct bus_id_priv *busid_priv) +{ + if (busid_priv->sdev && !busid_priv->shutdown_busid) { + busid_priv->shutdown_busid = 1; + usbip_event_add(&busid_priv->sdev->ud, SDEV_EVENT_REMOVED); + + /* 2. wait for the stop of the event handler */ + usbip_stop_eh(&busid_priv->sdev->ud); + } + +} + /* * called in usb_disconnect() or usb_deregister() @@ -451,10 +506,21 @@ static int stub_probe(struct usb_interface *interface, */ static void stub_disconnect(struct usb_interface *interface) { - struct stub_device *sdev = usb_get_intfdata(interface); + struct stub_device *sdev; + const char *udev_busid = dev_name(interface->dev.parent); + struct bus_id_priv *busid_priv; + + busid_priv = get_busid_priv(udev_busid); usbip_udbg("Enter\n"); + if (!busid_priv) { + BUG(); + return; + } + + sdev = usb_get_intfdata(interface); + /* get stub_device */ if (!sdev) { err(" could not get device from inteface data"); @@ -464,22 +530,39 @@ static void stub_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); - /* * NOTE: * rx/tx threads are invoked for each usb_device. */ stub_remove_files(&interface->dev); - /* 1. shutdown the current connection */ - usbip_event_add(&sdev->ud, SDEV_EVENT_REMOVED); + /*If usb reset called from event handler*/ + if (busid_priv->sdev->ud.eh.thread == current) { + busid_priv->interf_count--; + return; + } + + if (busid_priv->interf_count > 1) { + busid_priv->interf_count--; + shutdown_busid(busid_priv); + return; + } + + busid_priv->interf_count = 0; - /* 2. wait for the stop of the event handler */ - usbip_stop_eh(&sdev->ud); + + /* 1. shutdown the current connection */ + shutdown_busid(busid_priv); /* 3. free sdev */ + busid_priv->sdev = NULL; stub_device_free(sdev); - + if (busid_priv->status == STUB_BUSID_ALLOC) { + busid_priv->status = STUB_BUSID_ADDED; + } else { + busid_priv->status = STUB_BUSID_OTHER; + del_match_busid((char *)udev_busid); + } usbip_udbg("bye\n"); } diff --git a/drivers/staging/usbip/stub_main.c b/drivers/staging/usbip/stub_main.c index 6665cefe573b..f3a40968aae2 100644 --- a/drivers/staging/usbip/stub_main.c +++ b/drivers/staging/usbip/stub_main.c @@ -41,8 +41,7 @@ struct kmem_cache *stub_priv_cache; * remote host. */ #define MAX_BUSID 16 -#define BUSID_SIZE 20 -static char busid_table[MAX_BUSID][BUSID_SIZE]; +static struct bus_id_priv busid_table[MAX_BUSID]; static spinlock_t busid_table_lock; @@ -53,8 +52,8 @@ int match_busid(const char *busid) spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) - if (busid_table[i][0]) - if (!strncmp(busid_table[i], busid, BUSID_SIZE)) { + if (busid_table[i].name[0]) + if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { /* already registerd */ spin_unlock(&busid_table_lock); return 0; @@ -65,6 +64,25 @@ int match_busid(const char *busid) return 1; } +struct bus_id_priv *get_busid_priv(const char *busid) +{ + int i; + + spin_lock(&busid_table_lock); + + for (i = 0; i < MAX_BUSID; i++) + if (busid_table[i].name[0]) + if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { + /* already registerd */ + spin_unlock(&busid_table_lock); + return &(busid_table[i]); + } + + spin_unlock(&busid_table_lock); + + return NULL; +} + static ssize_t show_match_busid(struct device_driver *drv, char *buf) { int i; @@ -73,8 +91,8 @@ static ssize_t show_match_busid(struct device_driver *drv, char *buf) spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) - if (busid_table[i][0]) - out += sprintf(out, "%s ", busid_table[i]); + if (busid_table[i].name[0]) + out += sprintf(out, "%s ", busid_table[i].name); spin_unlock(&busid_table_lock); @@ -93,8 +111,11 @@ static int add_match_busid(char *busid) spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) - if (!busid_table[i][0]) { - strncpy(busid_table[i], busid, BUSID_SIZE); + if (!busid_table[i].name[0]) { + strncpy(busid_table[i].name, busid, BUSID_SIZE); + if ((busid_table[i].status != STUB_BUSID_ALLOC) && + (busid_table[i].status != STUB_BUSID_REMOV)) + busid_table[i].status = STUB_BUSID_ADDED; spin_unlock(&busid_table_lock); return 0; } @@ -104,16 +125,21 @@ static int add_match_busid(char *busid) return -1; } -static int del_match_busid(char *busid) +int del_match_busid(char *busid) { int i; spin_lock(&busid_table_lock); for (i = 0; i < MAX_BUSID; i++) - if (!strncmp(busid_table[i], busid, BUSID_SIZE)) { + if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) { /* found */ - memset(busid_table[i], 0, BUSID_SIZE); + if (busid_table[i].status == STUB_BUSID_OTHER) + memset(busid_table[i].name, 0, BUSID_SIZE); + if ((busid_table[i].status != STUB_BUSID_OTHER) && + (busid_table[i].status != STUB_BUSID_ADDED)) { + busid_table[i].status = STUB_BUSID_REMOV; + } spin_unlock(&busid_table_lock); return 0; } @@ -122,6 +148,20 @@ static int del_match_busid(char *busid) return -1; } +static void init_busid_table(void) +{ + int i; + + + for (i = 0; i < MAX_BUSID; i++) { + memset(busid_table[i].name, 0, BUSID_SIZE); + busid_table[i].status = STUB_BUSID_OTHER; + busid_table[i].interf_count = 0; + busid_table[i].sdev = NULL; + busid_table[i].shutdown_busid = 0; + } + spin_lock_init(&busid_table_lock); +} static ssize_t store_match_busid(struct device_driver *dev, const char *buf, size_t count) @@ -261,8 +301,7 @@ static int __init usb_stub_init(void) printk(KERN_INFO KBUILD_MODNAME ":" DRIVER_DESC ":" DRIVER_VERSION "\n"); - memset(busid_table, 0, sizeof(busid_table)); - spin_lock_init(&busid_table_lock); + init_busid_table(); ret = driver_create_file(&stub_driver.drvwrap.driver, &driver_attr_match_busid); diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 5972ae70e381..3de6fd2539dc 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -362,54 +362,16 @@ static struct stub_priv *stub_priv_alloc(struct stub_device *sdev, return priv; } - -static struct usb_host_endpoint *get_ep_from_epnum(struct usb_device *udev, - int epnum0) -{ - struct usb_host_config *config; - int i = 0, j = 0; - struct usb_host_endpoint *ep = NULL; - int epnum; - int found = 0; - - if (epnum0 == 0) - return &udev->ep0; - - config = udev->actconfig; - if (!config) - return NULL; - - for (i = 0; i < config->desc.bNumInterfaces; i++) { - struct usb_host_interface *setting; - - setting = config->interface[i]->cur_altsetting; - - for (j = 0; j < setting->desc.bNumEndpoints; j++) { - ep = &setting->endpoint[j]; - epnum = (ep->desc.bEndpointAddress & 0x7f); - - if (epnum == epnum0) { - /* usbip_uinfo("found epnum %d\n", epnum0);*/ - found = 1; - break; - } - } - } - - if (found) - return ep; - else - return NULL; -} - - static int get_pipe(struct stub_device *sdev, int epnum, int dir) { struct usb_device *udev = interface_to_usbdev(sdev->interface); struct usb_host_endpoint *ep; struct usb_endpoint_descriptor *epd = NULL; - ep = get_ep_from_epnum(udev, epnum); + if (dir == USBIP_DIR_IN) + ep = udev->ep_in[epnum & 0x7f]; + else + ep = udev->ep_out[epnum & 0x7f]; if (!ep) { dev_err(&sdev->interface->dev, "no such endpoint?, %d\n", epnum); @@ -462,6 +424,60 @@ static int get_pipe(struct stub_device *sdev, int epnum, int dir) return 0; } +static void masking_bogus_flags(struct urb *urb) +{ + int xfertype; + struct usb_device *dev; + struct usb_host_endpoint *ep; + int is_out; + unsigned int allowed; + + if (!urb || urb->hcpriv || !urb->complete) + return; + dev = urb->dev; + if ((!dev) || (dev->state < USB_STATE_UNAUTHENTICATED)) + return; + + ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out) + [usb_pipeendpoint(urb->pipe)]; + if (!ep) + return; + + xfertype = usb_endpoint_type(&ep->desc); + if (xfertype == USB_ENDPOINT_XFER_CONTROL) { + struct usb_ctrlrequest *setup = + (struct usb_ctrlrequest *) urb->setup_packet; + + if (!setup) + return; + is_out = !(setup->bRequestType & USB_DIR_IN) || + !setup->wLength; + } else { + is_out = usb_endpoint_dir_out(&ep->desc); + } + + /* enforce simple/standard policy */ + allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | + URB_DIR_MASK | URB_FREE_BUFFER); + switch (xfertype) { + case USB_ENDPOINT_XFER_BULK: + if (is_out) + allowed |= URB_ZERO_PACKET; + /* FALLTHROUGH */ + case USB_ENDPOINT_XFER_CONTROL: + allowed |= URB_NO_FSBR; /* only affects UHCI */ + /* FALLTHROUGH */ + default: /* all non-iso endpoints */ + if (!is_out) + allowed |= URB_SHORT_NOT_OK; + break; + case USB_ENDPOINT_XFER_ISOC: + allowed |= URB_ISO_ASAP; + break; + } + urb->transfer_flags &= allowed; +} + static void stub_recv_cmd_submit(struct stub_device *sdev, struct usbip_header *pdu) { @@ -528,6 +544,7 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, /* no need to submit an intercepted request, but harmless? */ tweak_special_requests(priv->urb); + masking_bogus_flags(priv->urb); /* urb is now ready to submit */ ret = usb_submit_urb(priv->urb, GFP_KERNEL); diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index e1bbd1287e28..d280e234e067 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -172,7 +172,7 @@ struct usbip_header_basic { #define USBIP_RET_UNLINK 0x0004 __u32 command; - /* sequencial number which identifies requests. + /* sequential number which identifies requests. * incremented per connections */ __u32 seqnum; |