Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 121e287c authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman
Browse files

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 349710c3
Loading
Loading
Loading
Loading
+33 −7
Original line number Original line Diff line number Diff line
/*
/*
 * 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 */