aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/usbip
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@suse.de>2010-08-05 14:18:03 -0700
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-05 14:18:03 -0700
commite9563355ac1175dd3440dc2ea5c28b27ed51a283 (patch)
tree8546d55832714b5d19ba4c7799266918ca04882e /drivers/staging/usbip
parentcdd854bc42b5e6c79bbbc40c6600d995ffe6e747 (diff)
parentb12d1995f650e92f26184afd28e6cf40bf64467a (diff)
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.h17
-rw-r--r--drivers/staging/usbip/stub_dev.c101
-rw-r--r--drivers/staging/usbip/stub_main.c65
-rw-r--r--drivers/staging/usbip/stub_rx.c101
-rw-r--r--drivers/staging/usbip/usbip_common.h2
5 files changed, 220 insertions, 66 deletions
diff --git a/drivers/staging/usbip/stub.h b/drivers/staging/usbip/stub.h
index 022d0649ac5..30dbfb6d16f 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 3f95605427a..b6b753a4934 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 6665cefe573..f3a40968aae 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 5972ae70e38..3de6fd2539d 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 e1bbd1287e2..d280e234e06 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;