usb-skeleton: don't submit URBs after disconnection
This patch (as712b) is a slight revision of one submitted earlier. It fixes the usb-skeleton example driver so that it won't try to submit URBs after skel_disconnect() has returned. This could cause errors, if the driver was unbound and then a different driver was bound to the device. It also fixes a couple of small bugs in the skel_write() routine. The revised patch uses a slightly different test, suggested by Dave Brownell, for determining whether to free a transfer buffer. It's a little clearer than the earlier version. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
349710c3a7
commit
121e287cb5
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* USB Skeleton driver - 2.0
|
* USB Skeleton driver - 2.1
|
||||||
*
|
*
|
||||||
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
|
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
|
||||||
*
|
*
|
||||||
@ -8,8 +8,7 @@
|
|||||||
* published by the Free Software Foundation, version 2.
|
* published by the Free Software Foundation, version 2.
|
||||||
*
|
*
|
||||||
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
|
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
|
||||||
* but has been rewritten to be easy to read and use, as no locks are now
|
* but has been rewritten to be easier to read and use.
|
||||||
* needed anymore.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -21,6 +20,7 @@
|
|||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
|
|
||||||
/* Define these values to match your devices */
|
/* Define these values to match your devices */
|
||||||
@ -52,6 +52,7 @@ struct usb_skel {
|
|||||||
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
|
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
|
||||||
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
|
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
|
||||||
struct kref kref;
|
struct kref kref;
|
||||||
|
struct mutex io_mutex; /* synchronize I/O with disconnect */
|
||||||
};
|
};
|
||||||
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
|
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
|
||||||
|
|
||||||
@ -120,6 +121,12 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *
|
|||||||
|
|
||||||
dev = (struct usb_skel *)file->private_data;
|
dev = (struct usb_skel *)file->private_data;
|
||||||
|
|
||||||
|
mutex_lock(&dev->io_mutex);
|
||||||
|
if (!dev->interface) { /* disconnect() was called */
|
||||||
|
retval = -ENODEV;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
/* do a blocking bulk read to get data from the device */
|
/* do a blocking bulk read to get data from the device */
|
||||||
retval = usb_bulk_msg(dev->udev,
|
retval = usb_bulk_msg(dev->udev,
|
||||||
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
|
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
|
||||||
@ -135,6 +142,8 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *
|
|||||||
retval = bytes_read;
|
retval = bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mutex_unlock(&dev->io_mutex);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +188,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&dev->io_mutex);
|
||||||
|
if (!dev->interface) { /* disconnect() was called */
|
||||||
|
retval = -ENODEV;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
/* create a urb, and a buffer for it, and copy the data to the urb */
|
/* create a urb, and a buffer for it, and copy the data to the urb */
|
||||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!urb) {
|
if (!urb) {
|
||||||
@ -213,13 +228,18 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
|
|||||||
/* release our reference to this urb, the USB core will eventually free it entirely */
|
/* release our reference to this urb, the USB core will eventually free it entirely */
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
|
|
||||||
exit:
|
mutex_unlock(&dev->io_mutex);
|
||||||
return writesize;
|
return writesize;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
if (urb) {
|
||||||
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
|
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
|
}
|
||||||
|
mutex_unlock(&dev->io_mutex);
|
||||||
up(&dev->limit_sem);
|
up(&dev->limit_sem);
|
||||||
|
|
||||||
|
exit:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,6 +278,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
|
|||||||
}
|
}
|
||||||
kref_init(&dev->kref);
|
kref_init(&dev->kref);
|
||||||
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
|
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
|
||||||
|
mutex_init(&dev->io_mutex);
|
||||||
|
|
||||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||||
dev->interface = interface;
|
dev->interface = interface;
|
||||||
@ -334,6 +355,11 @@ static void skel_disconnect(struct usb_interface *interface)
|
|||||||
/* give back our minor */
|
/* give back our minor */
|
||||||
usb_deregister_dev(interface, &skel_class);
|
usb_deregister_dev(interface, &skel_class);
|
||||||
|
|
||||||
|
/* prevent more I/O from starting */
|
||||||
|
mutex_lock(&dev->io_mutex);
|
||||||
|
dev->interface = NULL;
|
||||||
|
mutex_unlock(&dev->io_mutex);
|
||||||
|
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
|
|
||||||
/* decrement our usage count */
|
/* decrement our usage count */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user