Staging: usbip: fix multiple interfaces
The stub_probe function instantiates an stub_dev object for all interfaces. Wich causes a problem. The stub_dev object belongs to their own interfaces. This patch creates the sdev object at the first stub_probe call, the other calls associate the interfaces to this. Signed-off-by: Endre Kollar <taxy443@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Родитель
125ed824d3
Коммит
aa5873e962
|
@ -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);
|
||||
|
|
|
@ -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,30 +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, 0);
|
||||
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()
|
||||
|
@ -453,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");
|
||||
|
@ -466,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;
|
||||
}
|
||||
|
||||
/* 2. wait for the stop of the event handler */
|
||||
usbip_stop_eh(&sdev->ud);
|
||||
if (busid_priv->interf_count > 1) {
|
||||
busid_priv->interf_count--;
|
||||
shutdown_busid(busid_priv);
|
||||
return;
|
||||
}
|
||||
|
||||
busid_priv->interf_count = 0;
|
||||
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче