aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.de>2007-05-25 07:42:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-07-12 19:34:28 -0400
commit403dfb58c3134a339e415fba9f6d45b51c6ee357 (patch)
tree65055125aca69e2e8c0d55a4f5221bd8693cfe7b /drivers/usb
parent51a2f077c44e559841b09de6da605b4d3ae40dad (diff)
USB: usb-skeleton: usb anchor to implement flush
This patch set introduces usb_anchor and uses it to implement all modern APIs in the skeleton driver. - proper error reporting in the skeleton driver - implementation of flush() Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/usb-skeleton.c72
1 files changed, 65 insertions, 7 deletions
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 38f8e4df9dd6..a31fcfd5eda7 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -51,16 +51,20 @@ struct usb_skel {
51 struct usb_device *udev; /* the usb device for this device */ 51 struct usb_device *udev; /* the usb device for this device */
52 struct usb_interface *interface; /* the interface for this device */ 52 struct usb_interface *interface; /* the interface for this device */
53 struct semaphore limit_sem; /* limiting the number of writes in progress */ 53 struct semaphore limit_sem; /* limiting the number of writes in progress */
54 struct usb_anchor submitted; /* in case we need to retract our submissions */
54 unsigned char *bulk_in_buffer; /* the buffer to receive data */ 55 unsigned char *bulk_in_buffer; /* the buffer to receive data */
55 size_t bulk_in_size; /* the size of the receive buffer */ 56 size_t bulk_in_size; /* the size of the receive buffer */
56 __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 57 __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
57 __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 58 __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
59 int errors; /* the last request tanked */
60 spinlock_t err_lock; /* lock for errors */
58 struct kref kref; 61 struct kref kref;
59 struct mutex io_mutex; /* synchronize I/O with disconnect */ 62 struct mutex io_mutex; /* synchronize I/O with disconnect */
60}; 63};
61#define to_skel_dev(d) container_of(d, struct usb_skel, kref) 64#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
62 65
63static struct usb_driver skel_driver; 66static struct usb_driver skel_driver;
67static void skel_draw_down(struct usb_skel *dev);
64 68
65static void skel_delete(struct kref *kref) 69static void skel_delete(struct kref *kref)
66{ 70{
@@ -130,6 +134,30 @@ static int skel_release(struct inode *inode, struct file *file)
130 return 0; 134 return 0;
131} 135}
132 136
137static int skel_flush(struct file *file, fl_owner_t id)
138{
139 struct usb_skel *dev;
140 int res;
141
142 dev = (struct usb_skel *)file->private_data;
143 if (dev == NULL)
144 return -ENODEV;
145
146 /* wait for io to stop */
147 mutex_lock(&dev->io_mutex);
148 skel_draw_down(dev);
149
150 /* read out errors, leave subsequent opens a clean slate */
151 spin_lock_irq(&dev->err_lock);
152 res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0;
153 dev->errors = 0;
154 spin_unlock_irq(&dev->err_lock);
155
156 mutex_unlock(&dev->io_mutex);
157
158 return res;
159}
160
133static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos) 161static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
134{ 162{
135 struct usb_skel *dev; 163 struct usb_skel *dev;
@@ -171,12 +199,16 @@ static void skel_write_bulk_callback(struct urb *urb)
171 dev = (struct usb_skel *)urb->context; 199 dev = (struct usb_skel *)urb->context;
172 200
173 /* sync/async unlink faults aren't errors */ 201 /* sync/async unlink faults aren't errors */
174 if (urb->status && 202 if (urb->status) {
175 !(urb->status == -ENOENT || 203 if(!(urb->status == -ENOENT ||
176 urb->status == -ECONNRESET || 204 urb->status == -ECONNRESET ||
177 urb->status == -ESHUTDOWN)) { 205 urb->status == -ESHUTDOWN))
178 err("%s - nonzero write bulk status received: %d", 206 err("%s - nonzero write bulk status received: %d",
179 __FUNCTION__, urb->status); 207 __FUNCTION__, urb->status);
208
209 spin_lock(&dev->err_lock);
210 dev->errors = urb->status;
211 spin_unlock(&dev->err_lock);
180 } 212 }
181 213
182 /* free up our allocated buffer */ 214 /* free up our allocated buffer */
@@ -205,6 +237,17 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
205 goto exit; 237 goto exit;
206 } 238 }
207 239
240 spin_lock_irq(&dev->err_lock);
241 if ((retval = dev->errors) < 0) {
242 /* any error is reported once */
243 dev->errors = 0;
244 /* to preserve notifications about reset */
245 retval = (retval == -EPIPE) ? retval : -EIO;
246 }
247 spin_unlock_irq(&dev->err_lock);
248 if (retval < 0)
249 goto error;
250
208 /* create a urb, and a buffer for it, and copy the data to the urb */ 251 /* create a urb, and a buffer for it, and copy the data to the urb */
209 urb = usb_alloc_urb(0, GFP_KERNEL); 252 urb = usb_alloc_urb(0, GFP_KERNEL);
210 if (!urb) { 253 if (!urb) {
@@ -236,13 +279,14 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
236 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 279 usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
237 buf, writesize, skel_write_bulk_callback, dev); 280 buf, writesize, skel_write_bulk_callback, dev);
238 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 281 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
282 usb_anchor_urb(urb, &dev->submitted);
239 283
240 /* send the data out the bulk port */ 284 /* send the data out the bulk port */
241 retval = usb_submit_urb(urb, GFP_KERNEL); 285 retval = usb_submit_urb(urb, GFP_KERNEL);
242 mutex_unlock(&dev->io_mutex); 286 mutex_unlock(&dev->io_mutex);
243 if (retval) { 287 if (retval) {
244 err("%s - failed submitting write urb, error %d", __FUNCTION__, retval); 288 err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
245 goto error; 289 goto error_unanchor;
246 } 290 }
247 291
248 /* release our reference to this urb, the USB core will eventually free it entirely */ 292 /* release our reference to this urb, the USB core will eventually free it entirely */
@@ -251,6 +295,8 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
251 295
252 return writesize; 296 return writesize;
253 297
298error_unanchor:
299 usb_unanchor_urb(urb);
254error: 300error:
255 if (urb) { 301 if (urb) {
256 usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma); 302 usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
@@ -268,6 +314,7 @@ static const struct file_operations skel_fops = {
268 .write = skel_write, 314 .write = skel_write,
269 .open = skel_open, 315 .open = skel_open,
270 .release = skel_release, 316 .release = skel_release,
317 .flush = skel_flush,
271}; 318};
272 319
273/* 320/*
@@ -298,6 +345,8 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
298 kref_init(&dev->kref); 345 kref_init(&dev->kref);
299 sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); 346 sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
300 mutex_init(&dev->io_mutex); 347 mutex_init(&dev->io_mutex);
348 spin_lock_init(&dev->err_lock);
349 init_usb_anchor(&dev->submitted);
301 350
302 dev->udev = usb_get_dev(interface_to_usbdev(interface)); 351 dev->udev = usb_get_dev(interface_to_usbdev(interface));
303 dev->interface = interface; 352 dev->interface = interface;
@@ -377,6 +426,15 @@ static void skel_disconnect(struct usb_interface *interface)
377 info("USB Skeleton #%d now disconnected", minor); 426 info("USB Skeleton #%d now disconnected", minor);
378} 427}
379 428
429static void skel_draw_down(struct usb_skel *dev)
430{
431 int time;
432
433 time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
434 if (!time)
435 usb_kill_anchored_urbs(&dev->submitted);
436}
437
380static struct usb_driver skel_driver = { 438static struct usb_driver skel_driver = {
381 .name = "skeleton", 439 .name = "skeleton",
382 .probe = skel_probe, 440 .probe = skel_probe,