11da177e4SLinus Torvalds /* 2c0704541SLuiz Fernando N. Capitulino * USB Skeleton driver - 2.2 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 71da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License as 81da177e4SLinus Torvalds * published by the Free Software Foundation, version 2. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c 11121e287cSAlan Stern * but has been rewritten to be easier to read and use. 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/errno.h> 171da177e4SLinus Torvalds #include <linux/init.h> 181da177e4SLinus Torvalds #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/module.h> 201da177e4SLinus Torvalds #include <linux/kref.h> 213ae9da1cSGreg Kroah-Hartman #include <linux/uaccess.h> 221da177e4SLinus Torvalds #include <linux/usb.h> 23121e287cSAlan Stern #include <linux/mutex.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds /* Define these values to match your devices */ 271da177e4SLinus Torvalds #define USB_SKEL_VENDOR_ID 0xfff0 281da177e4SLinus Torvalds #define USB_SKEL_PRODUCT_ID 0xfff0 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* table of devices that work with this driver */ 311bd4f29dSNémeth Márton static const struct usb_device_id skel_table[] = { 321da177e4SLinus Torvalds { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, 331da177e4SLinus Torvalds { } /* Terminating entry */ 341da177e4SLinus Torvalds }; 351da177e4SLinus Torvalds MODULE_DEVICE_TABLE(usb, skel_table); 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* Get a minor range for your devices from the usb maintainer */ 391da177e4SLinus Torvalds #define USB_SKEL_MINOR_BASE 192 401da177e4SLinus Torvalds 41ff906518SOliver Neukum /* our private defines. if this grows any larger, use your own .h file */ 42ff906518SOliver Neukum #define MAX_TRANSFER (PAGE_SIZE - 512) 43ba35e02bSOliver Neukum /* MAX_TRANSFER is chosen so that the VM is not stressed by 44ba35e02bSOliver Neukum allocations > PAGE_SIZE and the number of packets in a page 45ba35e02bSOliver Neukum is an integer 512 is the largest possible packet on EHCI */ 46ff906518SOliver Neukum #define WRITES_IN_FLIGHT 8 47ba35e02bSOliver Neukum /* arbitrarily chosen */ 48ff906518SOliver Neukum 491da177e4SLinus Torvalds /* Structure to hold all of our device specific stuff */ 501da177e4SLinus Torvalds struct usb_skel { 51ba35e02bSOliver Neukum struct usb_device *udev; /* the usb device for this device */ 521da177e4SLinus Torvalds struct usb_interface *interface; /* the interface for this device */ 53ff906518SOliver Neukum struct semaphore limit_sem; /* limiting the number of writes in progress */ 54403dfb58SOliver Neukum struct usb_anchor submitted; /* in case we need to retract our submissions */ 55e7389cc9SOliver Neukum struct urb *bulk_in_urb; /* the urb to read data with */ 561da177e4SLinus Torvalds unsigned char *bulk_in_buffer; /* the buffer to receive data */ 571da177e4SLinus Torvalds size_t bulk_in_size; /* the size of the receive buffer */ 58e7389cc9SOliver Neukum size_t bulk_in_filled; /* number of bytes in the buffer */ 59e7389cc9SOliver Neukum size_t bulk_in_copied; /* already copied to user space */ 601da177e4SLinus Torvalds __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ 611da177e4SLinus Torvalds __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ 62403dfb58SOliver Neukum int errors; /* the last request tanked */ 63e7389cc9SOliver Neukum bool ongoing_read; /* a read is going on */ 64403dfb58SOliver Neukum spinlock_t err_lock; /* lock for errors */ 651da177e4SLinus Torvalds struct kref kref; 66121e287cSAlan Stern struct mutex io_mutex; /* synchronize I/O with disconnect */ 67*c79041a4SDu Xing wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ 681da177e4SLinus Torvalds }; 691da177e4SLinus Torvalds #define to_skel_dev(d) container_of(d, struct usb_skel, kref) 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds static struct usb_driver skel_driver; 72403dfb58SOliver Neukum static void skel_draw_down(struct usb_skel *dev); 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds static void skel_delete(struct kref *kref) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds struct usb_skel *dev = to_skel_dev(kref); 771da177e4SLinus Torvalds 78e7389cc9SOliver Neukum usb_free_urb(dev->bulk_in_urb); 791da177e4SLinus Torvalds usb_put_dev(dev->udev); 801da177e4SLinus Torvalds kfree(dev->bulk_in_buffer); 811da177e4SLinus Torvalds kfree(dev); 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds static int skel_open(struct inode *inode, struct file *file) 851da177e4SLinus Torvalds { 861da177e4SLinus Torvalds struct usb_skel *dev; 871da177e4SLinus Torvalds struct usb_interface *interface; 881da177e4SLinus Torvalds int subminor; 891da177e4SLinus Torvalds int retval = 0; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds subminor = iminor(inode); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds interface = usb_find_interface(&skel_driver, subminor); 941da177e4SLinus Torvalds if (!interface) { 954212cd74SGreg Kroah-Hartman pr_err("%s - error, can't find device for minor %d\n", 96441b62c1SHarvey Harrison __func__, subminor); 971da177e4SLinus Torvalds retval = -ENODEV; 981da177e4SLinus Torvalds goto exit; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds dev = usb_get_intfdata(interface); 1021da177e4SLinus Torvalds if (!dev) { 1031da177e4SLinus Torvalds retval = -ENODEV; 1041da177e4SLinus Torvalds goto exit; 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 107e8cebb9cSConstantine Shulyupin retval = usb_autopm_get_interface(interface); 108e8cebb9cSConstantine Shulyupin if (retval) 109e8cebb9cSConstantine Shulyupin goto exit; 110e8cebb9cSConstantine Shulyupin 1111da177e4SLinus Torvalds /* increment our usage count for the device */ 1121da177e4SLinus Torvalds kref_get(&dev->kref); 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* save our object in the file's private structure */ 1151da177e4SLinus Torvalds file->private_data = dev; 1161da177e4SLinus Torvalds 1171da177e4SLinus Torvalds exit: 1181da177e4SLinus Torvalds return retval; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds static int skel_release(struct inode *inode, struct file *file) 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds struct usb_skel *dev; 1241da177e4SLinus Torvalds 125e53e841dSJoe Perches dev = file->private_data; 1261da177e4SLinus Torvalds if (dev == NULL) 1271da177e4SLinus Torvalds return -ENODEV; 1281da177e4SLinus Torvalds 12901d883d4SAlan Stern /* allow the device to be autosuspended */ 13001d883d4SAlan Stern mutex_lock(&dev->io_mutex); 131e28dbb06SMing Lei if (dev->interface) 13201d883d4SAlan Stern usb_autopm_put_interface(dev->interface); 13301d883d4SAlan Stern mutex_unlock(&dev->io_mutex); 13401d883d4SAlan Stern 1351da177e4SLinus Torvalds /* decrement the count on our device */ 1361da177e4SLinus Torvalds kref_put(&dev->kref, skel_delete); 1371da177e4SLinus Torvalds return 0; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 140403dfb58SOliver Neukum static int skel_flush(struct file *file, fl_owner_t id) 141403dfb58SOliver Neukum { 142403dfb58SOliver Neukum struct usb_skel *dev; 143403dfb58SOliver Neukum int res; 144403dfb58SOliver Neukum 145e53e841dSJoe Perches dev = file->private_data; 146403dfb58SOliver Neukum if (dev == NULL) 147403dfb58SOliver Neukum return -ENODEV; 148403dfb58SOliver Neukum 149403dfb58SOliver Neukum /* wait for io to stop */ 150403dfb58SOliver Neukum mutex_lock(&dev->io_mutex); 151403dfb58SOliver Neukum skel_draw_down(dev); 152403dfb58SOliver Neukum 153403dfb58SOliver Neukum /* read out errors, leave subsequent opens a clean slate */ 154403dfb58SOliver Neukum spin_lock_irq(&dev->err_lock); 155403dfb58SOliver Neukum res = dev->errors ? (dev->errors == -EPIPE ? -EPIPE : -EIO) : 0; 156403dfb58SOliver Neukum dev->errors = 0; 157403dfb58SOliver Neukum spin_unlock_irq(&dev->err_lock); 158403dfb58SOliver Neukum 159403dfb58SOliver Neukum mutex_unlock(&dev->io_mutex); 160403dfb58SOliver Neukum 161403dfb58SOliver Neukum return res; 162403dfb58SOliver Neukum } 163403dfb58SOliver Neukum 164e7389cc9SOliver Neukum static void skel_read_bulk_callback(struct urb *urb) 165e7389cc9SOliver Neukum { 166e7389cc9SOliver Neukum struct usb_skel *dev; 167e7389cc9SOliver Neukum 168e7389cc9SOliver Neukum dev = urb->context; 169e7389cc9SOliver Neukum 170e7389cc9SOliver Neukum spin_lock(&dev->err_lock); 171e7389cc9SOliver Neukum /* sync/async unlink faults aren't errors */ 172e7389cc9SOliver Neukum if (urb->status) { 173e7389cc9SOliver Neukum if (!(urb->status == -ENOENT || 174e7389cc9SOliver Neukum urb->status == -ECONNRESET || 175e7389cc9SOliver Neukum urb->status == -ESHUTDOWN)) 1764212cd74SGreg Kroah-Hartman dev_err(&dev->interface->dev, 1774212cd74SGreg Kroah-Hartman "%s - nonzero write bulk status received: %d\n", 178e7389cc9SOliver Neukum __func__, urb->status); 179e7389cc9SOliver Neukum 180e7389cc9SOliver Neukum dev->errors = urb->status; 181e7389cc9SOliver Neukum } else { 182e7389cc9SOliver Neukum dev->bulk_in_filled = urb->actual_length; 183e7389cc9SOliver Neukum } 184e7389cc9SOliver Neukum dev->ongoing_read = 0; 185e7389cc9SOliver Neukum spin_unlock(&dev->err_lock); 186e7389cc9SOliver Neukum 187*c79041a4SDu Xing wake_up_interruptible(&dev->bulk_in_wait); 188e7389cc9SOliver Neukum } 189e7389cc9SOliver Neukum 190e7389cc9SOliver Neukum static int skel_do_read_io(struct usb_skel *dev, size_t count) 191e7389cc9SOliver Neukum { 192e7389cc9SOliver Neukum int rv; 193e7389cc9SOliver Neukum 194e7389cc9SOliver Neukum /* prepare a read */ 195e7389cc9SOliver Neukum usb_fill_bulk_urb(dev->bulk_in_urb, 196e7389cc9SOliver Neukum dev->udev, 197e7389cc9SOliver Neukum usb_rcvbulkpipe(dev->udev, 198e7389cc9SOliver Neukum dev->bulk_in_endpointAddr), 199e7389cc9SOliver Neukum dev->bulk_in_buffer, 200e7389cc9SOliver Neukum min(dev->bulk_in_size, count), 201e7389cc9SOliver Neukum skel_read_bulk_callback, 202e7389cc9SOliver Neukum dev); 203e7389cc9SOliver Neukum /* tell everybody to leave the URB alone */ 204e7389cc9SOliver Neukum spin_lock_irq(&dev->err_lock); 205e7389cc9SOliver Neukum dev->ongoing_read = 1; 206e7389cc9SOliver Neukum spin_unlock_irq(&dev->err_lock); 207e7389cc9SOliver Neukum 208*c79041a4SDu Xing /* submit bulk in urb, which means no data to deliver */ 209*c79041a4SDu Xing dev->bulk_in_filled = 0; 210*c79041a4SDu Xing dev->bulk_in_copied = 0; 211*c79041a4SDu Xing 212e7389cc9SOliver Neukum /* do it */ 213e7389cc9SOliver Neukum rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); 214e7389cc9SOliver Neukum if (rv < 0) { 2154212cd74SGreg Kroah-Hartman dev_err(&dev->interface->dev, 2164212cd74SGreg Kroah-Hartman "%s - failed submitting read urb, error %d\n", 217e7389cc9SOliver Neukum __func__, rv); 218e7389cc9SOliver Neukum rv = (rv == -ENOMEM) ? rv : -EIO; 219e7389cc9SOliver Neukum spin_lock_irq(&dev->err_lock); 220e7389cc9SOliver Neukum dev->ongoing_read = 0; 221e7389cc9SOliver Neukum spin_unlock_irq(&dev->err_lock); 222e7389cc9SOliver Neukum } 223e7389cc9SOliver Neukum 224e7389cc9SOliver Neukum return rv; 225e7389cc9SOliver Neukum } 226e7389cc9SOliver Neukum 2273ae9da1cSGreg Kroah-Hartman static ssize_t skel_read(struct file *file, char *buffer, size_t count, 2283ae9da1cSGreg Kroah-Hartman loff_t *ppos) 2291da177e4SLinus Torvalds { 2301da177e4SLinus Torvalds struct usb_skel *dev; 231e7389cc9SOliver Neukum int rv; 232e7389cc9SOliver Neukum bool ongoing_io; 2331da177e4SLinus Torvalds 234e53e841dSJoe Perches dev = file->private_data; 2351da177e4SLinus Torvalds 236e7389cc9SOliver Neukum /* if we cannot read at all, return EOF */ 237e7389cc9SOliver Neukum if (!dev->bulk_in_urb || !count) 238e7389cc9SOliver Neukum return 0; 239e7389cc9SOliver Neukum 240e7389cc9SOliver Neukum /* no concurrent readers */ 241e7389cc9SOliver Neukum rv = mutex_lock_interruptible(&dev->io_mutex); 242e7389cc9SOliver Neukum if (rv < 0) 243e7389cc9SOliver Neukum return rv; 244e7389cc9SOliver Neukum 245121e287cSAlan Stern if (!dev->interface) { /* disconnect() was called */ 246e7389cc9SOliver Neukum rv = -ENODEV; 247121e287cSAlan Stern goto exit; 248121e287cSAlan Stern } 249121e287cSAlan Stern 250e7389cc9SOliver Neukum /* if IO is under way, we must not touch things */ 251e7389cc9SOliver Neukum retry: 252e7389cc9SOliver Neukum spin_lock_irq(&dev->err_lock); 253e7389cc9SOliver Neukum ongoing_io = dev->ongoing_read; 254e7389cc9SOliver Neukum spin_unlock_irq(&dev->err_lock); 2551da177e4SLinus Torvalds 256e7389cc9SOliver Neukum if (ongoing_io) { 2578cd01664SOliver Neukum /* nonblocking IO shall not wait */ 2588cd01664SOliver Neukum if (file->f_flags & O_NONBLOCK) { 2598cd01664SOliver Neukum rv = -EAGAIN; 2608cd01664SOliver Neukum goto exit; 2618cd01664SOliver Neukum } 262e7389cc9SOliver Neukum /* 263e7389cc9SOliver Neukum * IO may take forever 264e7389cc9SOliver Neukum * hence wait in an interruptible state 265e7389cc9SOliver Neukum */ 266*c79041a4SDu Xing rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read)); 267e7389cc9SOliver Neukum if (rv < 0) 268e7389cc9SOliver Neukum goto exit; 269e7389cc9SOliver Neukum } 270e7389cc9SOliver Neukum 271e7389cc9SOliver Neukum /* errors must be reported */ 2723ae9da1cSGreg Kroah-Hartman rv = dev->errors; 2733ae9da1cSGreg Kroah-Hartman if (rv < 0) { 274e7389cc9SOliver Neukum /* any error is reported once */ 275e7389cc9SOliver Neukum dev->errors = 0; 276e7389cc9SOliver Neukum /* to preserve notifications about reset */ 277e7389cc9SOliver Neukum rv = (rv == -EPIPE) ? rv : -EIO; 278e7389cc9SOliver Neukum /* report it */ 279e7389cc9SOliver Neukum goto exit; 280e7389cc9SOliver Neukum } 281e7389cc9SOliver Neukum 282e7389cc9SOliver Neukum /* 283e7389cc9SOliver Neukum * if the buffer is filled we may satisfy the read 284e7389cc9SOliver Neukum * else we need to start IO 285e7389cc9SOliver Neukum */ 286e7389cc9SOliver Neukum 287e7389cc9SOliver Neukum if (dev->bulk_in_filled) { 288e7389cc9SOliver Neukum /* we had read data */ 289e7389cc9SOliver Neukum size_t available = dev->bulk_in_filled - dev->bulk_in_copied; 290e7389cc9SOliver Neukum size_t chunk = min(available, count); 291e7389cc9SOliver Neukum 292e7389cc9SOliver Neukum if (!available) { 293e7389cc9SOliver Neukum /* 294e7389cc9SOliver Neukum * all data has been used 295e7389cc9SOliver Neukum * actual IO needs to be done 296e7389cc9SOliver Neukum */ 297e7389cc9SOliver Neukum rv = skel_do_read_io(dev, count); 298e7389cc9SOliver Neukum if (rv < 0) 299e7389cc9SOliver Neukum goto exit; 300e7389cc9SOliver Neukum else 301e7389cc9SOliver Neukum goto retry; 302e7389cc9SOliver Neukum } 303e7389cc9SOliver Neukum /* 304e7389cc9SOliver Neukum * data is available 305e7389cc9SOliver Neukum * chunk tells us how much shall be copied 306e7389cc9SOliver Neukum */ 307e7389cc9SOliver Neukum 308e7389cc9SOliver Neukum if (copy_to_user(buffer, 309e7389cc9SOliver Neukum dev->bulk_in_buffer + dev->bulk_in_copied, 310e7389cc9SOliver Neukum chunk)) 311e7389cc9SOliver Neukum rv = -EFAULT; 312e7389cc9SOliver Neukum else 313e7389cc9SOliver Neukum rv = chunk; 314e7389cc9SOliver Neukum 315e7389cc9SOliver Neukum dev->bulk_in_copied += chunk; 316e7389cc9SOliver Neukum 317e7389cc9SOliver Neukum /* 318e7389cc9SOliver Neukum * if we are asked for more than we have, 319e7389cc9SOliver Neukum * we start IO but don't wait 320e7389cc9SOliver Neukum */ 321e7389cc9SOliver Neukum if (available < count) 322e7389cc9SOliver Neukum skel_do_read_io(dev, count - chunk); 323e7389cc9SOliver Neukum } else { 324e7389cc9SOliver Neukum /* no data in the buffer */ 325e7389cc9SOliver Neukum rv = skel_do_read_io(dev, count); 326e7389cc9SOliver Neukum if (rv < 0) 327e7389cc9SOliver Neukum goto exit; 3284de84057SJulia Lawall else if (!(file->f_flags & O_NONBLOCK)) 329e7389cc9SOliver Neukum goto retry; 3308cd01664SOliver Neukum rv = -EAGAIN; 331e7389cc9SOliver Neukum } 332121e287cSAlan Stern exit: 333121e287cSAlan Stern mutex_unlock(&dev->io_mutex); 334e7389cc9SOliver Neukum return rv; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3377d12e780SDavid Howells static void skel_write_bulk_callback(struct urb *urb) 3381da177e4SLinus Torvalds { 3391da177e4SLinus Torvalds struct usb_skel *dev; 3401da177e4SLinus Torvalds 341cdc97792SMing Lei dev = urb->context; 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds /* sync/async unlink faults aren't errors */ 344403dfb58SOliver Neukum if (urb->status) { 345403dfb58SOliver Neukum if (!(urb->status == -ENOENT || 3461da177e4SLinus Torvalds urb->status == -ECONNRESET || 347403dfb58SOliver Neukum urb->status == -ESHUTDOWN)) 3484212cd74SGreg Kroah-Hartman dev_err(&dev->interface->dev, 3494212cd74SGreg Kroah-Hartman "%s - nonzero write bulk status received: %d\n", 350441b62c1SHarvey Harrison __func__, urb->status); 351403dfb58SOliver Neukum 352403dfb58SOliver Neukum spin_lock(&dev->err_lock); 353403dfb58SOliver Neukum dev->errors = urb->status; 354403dfb58SOliver Neukum spin_unlock(&dev->err_lock); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds /* free up our allocated buffer */ 358997ea58eSDaniel Mack usb_free_coherent(urb->dev, urb->transfer_buffer_length, 3591da177e4SLinus Torvalds urb->transfer_buffer, urb->transfer_dma); 360ff906518SOliver Neukum up(&dev->limit_sem); 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds 3633ae9da1cSGreg Kroah-Hartman static ssize_t skel_write(struct file *file, const char *user_buffer, 3643ae9da1cSGreg Kroah-Hartman size_t count, loff_t *ppos) 3651da177e4SLinus Torvalds { 3661da177e4SLinus Torvalds struct usb_skel *dev; 3671da177e4SLinus Torvalds int retval = 0; 3681da177e4SLinus Torvalds struct urb *urb = NULL; 3691da177e4SLinus Torvalds char *buf = NULL; 370c8dd7709SSam Bishop size_t writesize = min(count, (size_t)MAX_TRANSFER); 3711da177e4SLinus Torvalds 372e53e841dSJoe Perches dev = file->private_data; 3731da177e4SLinus Torvalds 3741da177e4SLinus Torvalds /* verify that we actually have some data to write */ 3751da177e4SLinus Torvalds if (count == 0) 3761da177e4SLinus Torvalds goto exit; 3771da177e4SLinus Torvalds 3783ae9da1cSGreg Kroah-Hartman /* 3793ae9da1cSGreg Kroah-Hartman * limit the number of URBs in flight to stop a user from using up all 3803ae9da1cSGreg Kroah-Hartman * RAM 3813ae9da1cSGreg Kroah-Hartman */ 3824de84057SJulia Lawall if (!(file->f_flags & O_NONBLOCK)) { 383c8dd7709SSam Bishop if (down_interruptible(&dev->limit_sem)) { 384c8dd7709SSam Bishop retval = -ERESTARTSYS; 385c8dd7709SSam Bishop goto exit; 386c8dd7709SSam Bishop } 38779819986SOliver Neukum } else { 38879819986SOliver Neukum if (down_trylock(&dev->limit_sem)) { 38979819986SOliver Neukum retval = -EAGAIN; 39079819986SOliver Neukum goto exit; 39179819986SOliver Neukum } 39279819986SOliver Neukum } 393ff906518SOliver Neukum 394403dfb58SOliver Neukum spin_lock_irq(&dev->err_lock); 3953ae9da1cSGreg Kroah-Hartman retval = dev->errors; 3963ae9da1cSGreg Kroah-Hartman if (retval < 0) { 397403dfb58SOliver Neukum /* any error is reported once */ 398403dfb58SOliver Neukum dev->errors = 0; 399403dfb58SOliver Neukum /* to preserve notifications about reset */ 400403dfb58SOliver Neukum retval = (retval == -EPIPE) ? retval : -EIO; 401403dfb58SOliver Neukum } 402403dfb58SOliver Neukum spin_unlock_irq(&dev->err_lock); 403403dfb58SOliver Neukum if (retval < 0) 404403dfb58SOliver Neukum goto error; 405403dfb58SOliver Neukum 4061da177e4SLinus Torvalds /* create a urb, and a buffer for it, and copy the data to the urb */ 4071da177e4SLinus Torvalds urb = usb_alloc_urb(0, GFP_KERNEL); 4081da177e4SLinus Torvalds if (!urb) { 4091da177e4SLinus Torvalds retval = -ENOMEM; 4101da177e4SLinus Torvalds goto error; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 413997ea58eSDaniel Mack buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL, 4143ae9da1cSGreg Kroah-Hartman &urb->transfer_dma); 4151da177e4SLinus Torvalds if (!buf) { 4161da177e4SLinus Torvalds retval = -ENOMEM; 4171da177e4SLinus Torvalds goto error; 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 420ff906518SOliver Neukum if (copy_from_user(buf, user_buffer, writesize)) { 4211da177e4SLinus Torvalds retval = -EFAULT; 4221da177e4SLinus Torvalds goto error; 4231da177e4SLinus Torvalds } 4241da177e4SLinus Torvalds 425ba35e02bSOliver Neukum /* this lock makes sure we don't submit URBs to gone devices */ 426ba35e02bSOliver Neukum mutex_lock(&dev->io_mutex); 427ba35e02bSOliver Neukum if (!dev->interface) { /* disconnect() was called */ 428ba35e02bSOliver Neukum mutex_unlock(&dev->io_mutex); 429ba35e02bSOliver Neukum retval = -ENODEV; 430ba35e02bSOliver Neukum goto error; 431ba35e02bSOliver Neukum } 432ba35e02bSOliver Neukum 4331da177e4SLinus Torvalds /* initialize the urb properly */ 4341da177e4SLinus Torvalds usb_fill_bulk_urb(urb, dev->udev, 4351da177e4SLinus Torvalds usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), 436ff906518SOliver Neukum buf, writesize, skel_write_bulk_callback, dev); 4371da177e4SLinus Torvalds urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; 438403dfb58SOliver Neukum usb_anchor_urb(urb, &dev->submitted); 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds /* send the data out the bulk port */ 4411da177e4SLinus Torvalds retval = usb_submit_urb(urb, GFP_KERNEL); 442ba35e02bSOliver Neukum mutex_unlock(&dev->io_mutex); 4431da177e4SLinus Torvalds if (retval) { 4444212cd74SGreg Kroah-Hartman dev_err(&dev->interface->dev, 4454212cd74SGreg Kroah-Hartman "%s - failed submitting write urb, error %d\n", 4464212cd74SGreg Kroah-Hartman __func__, retval); 447403dfb58SOliver Neukum goto error_unanchor; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4503ae9da1cSGreg Kroah-Hartman /* 4513ae9da1cSGreg Kroah-Hartman * release our reference to this urb, the USB core will eventually free 4523ae9da1cSGreg Kroah-Hartman * it entirely 4533ae9da1cSGreg Kroah-Hartman */ 4541da177e4SLinus Torvalds usb_free_urb(urb); 4551da177e4SLinus Torvalds 456ba35e02bSOliver Neukum 457ff906518SOliver Neukum return writesize; 4581da177e4SLinus Torvalds 459403dfb58SOliver Neukum error_unanchor: 460403dfb58SOliver Neukum usb_unanchor_urb(urb); 4611da177e4SLinus Torvalds error: 462121e287cSAlan Stern if (urb) { 463997ea58eSDaniel Mack usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma); 4641da177e4SLinus Torvalds usb_free_urb(urb); 465121e287cSAlan Stern } 466ff906518SOliver Neukum up(&dev->limit_sem); 467121e287cSAlan Stern 468121e287cSAlan Stern exit: 4691da177e4SLinus Torvalds return retval; 4701da177e4SLinus Torvalds } 4711da177e4SLinus Torvalds 472066202ddSLuiz Fernando N. Capitulino static const struct file_operations skel_fops = { 4731da177e4SLinus Torvalds .owner = THIS_MODULE, 4741da177e4SLinus Torvalds .read = skel_read, 4751da177e4SLinus Torvalds .write = skel_write, 4761da177e4SLinus Torvalds .open = skel_open, 4771da177e4SLinus Torvalds .release = skel_release, 478403dfb58SOliver Neukum .flush = skel_flush, 4796038f373SArnd Bergmann .llseek = noop_llseek, 4801da177e4SLinus Torvalds }; 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds /* 4831da177e4SLinus Torvalds * usb class driver info in order to get a minor number from the usb core, 484595b14cbSGreg Kroah-Hartman * and to have the device registered with the driver core 4851da177e4SLinus Torvalds */ 4861da177e4SLinus Torvalds static struct usb_class_driver skel_class = { 487d6e5bcf4SGreg Kroah-Hartman .name = "skel%d", 4881da177e4SLinus Torvalds .fops = &skel_fops, 4891da177e4SLinus Torvalds .minor_base = USB_SKEL_MINOR_BASE, 4901da177e4SLinus Torvalds }; 4911da177e4SLinus Torvalds 4923ae9da1cSGreg Kroah-Hartman static int skel_probe(struct usb_interface *interface, 4933ae9da1cSGreg Kroah-Hartman const struct usb_device_id *id) 4941da177e4SLinus Torvalds { 495c0704541SLuiz Fernando N. Capitulino struct usb_skel *dev; 4961da177e4SLinus Torvalds struct usb_host_interface *iface_desc; 4971da177e4SLinus Torvalds struct usb_endpoint_descriptor *endpoint; 4981da177e4SLinus Torvalds size_t buffer_size; 4991da177e4SLinus Torvalds int i; 5001da177e4SLinus Torvalds int retval = -ENOMEM; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds /* allocate memory for our device state and initialize it */ 503ff906518SOliver Neukum dev = kzalloc(sizeof(*dev), GFP_KERNEL); 504c0704541SLuiz Fernando N. Capitulino if (!dev) { 5054212cd74SGreg Kroah-Hartman dev_err(&interface->dev, "Out of memory\n"); 5061da177e4SLinus Torvalds goto error; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds kref_init(&dev->kref); 509ff906518SOliver Neukum sema_init(&dev->limit_sem, WRITES_IN_FLIGHT); 510121e287cSAlan Stern mutex_init(&dev->io_mutex); 511403dfb58SOliver Neukum spin_lock_init(&dev->err_lock); 512403dfb58SOliver Neukum init_usb_anchor(&dev->submitted); 513*c79041a4SDu Xing init_waitqueue_head(&dev->bulk_in_wait); 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds dev->udev = usb_get_dev(interface_to_usbdev(interface)); 5161da177e4SLinus Torvalds dev->interface = interface; 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds /* set up the endpoint information */ 5191da177e4SLinus Torvalds /* use only the first bulk-in and bulk-out endpoints */ 5201da177e4SLinus Torvalds iface_desc = interface->cur_altsetting; 5211da177e4SLinus Torvalds for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 5221da177e4SLinus Torvalds endpoint = &iface_desc->endpoint[i].desc; 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds if (!dev->bulk_in_endpointAddr && 525c0704541SLuiz Fernando N. Capitulino usb_endpoint_is_bulk_in(endpoint)) { 5261da177e4SLinus Torvalds /* we found a bulk in endpoint */ 52729cc8897SKuninori Morimoto buffer_size = usb_endpoint_maxp(endpoint); 5281da177e4SLinus Torvalds dev->bulk_in_size = buffer_size; 5291da177e4SLinus Torvalds dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; 5301da177e4SLinus Torvalds dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); 5311da177e4SLinus Torvalds if (!dev->bulk_in_buffer) { 5324212cd74SGreg Kroah-Hartman dev_err(&interface->dev, 5334212cd74SGreg Kroah-Hartman "Could not allocate bulk_in_buffer\n"); 5341da177e4SLinus Torvalds goto error; 5351da177e4SLinus Torvalds } 536e7389cc9SOliver Neukum dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); 537e7389cc9SOliver Neukum if (!dev->bulk_in_urb) { 5384212cd74SGreg Kroah-Hartman dev_err(&interface->dev, 5394212cd74SGreg Kroah-Hartman "Could not allocate bulk_in_urb\n"); 540e7389cc9SOliver Neukum goto error; 541e7389cc9SOliver Neukum } 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds if (!dev->bulk_out_endpointAddr && 545c0704541SLuiz Fernando N. Capitulino usb_endpoint_is_bulk_out(endpoint)) { 5461da177e4SLinus Torvalds /* we found a bulk out endpoint */ 5471da177e4SLinus Torvalds dev->bulk_out_endpointAddr = endpoint->bEndpointAddress; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { 5514212cd74SGreg Kroah-Hartman dev_err(&interface->dev, 5524212cd74SGreg Kroah-Hartman "Could not find both bulk-in and bulk-out endpoints\n"); 5531da177e4SLinus Torvalds goto error; 5541da177e4SLinus Torvalds } 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /* save our data pointer in this interface device */ 5571da177e4SLinus Torvalds usb_set_intfdata(interface, dev); 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /* we can register the device now, as it is ready */ 5601da177e4SLinus Torvalds retval = usb_register_dev(interface, &skel_class); 5611da177e4SLinus Torvalds if (retval) { 5621da177e4SLinus Torvalds /* something prevented us from registering this driver */ 5634212cd74SGreg Kroah-Hartman dev_err(&interface->dev, 5644212cd74SGreg Kroah-Hartman "Not able to get a minor for this device.\n"); 5651da177e4SLinus Torvalds usb_set_intfdata(interface, NULL); 5661da177e4SLinus Torvalds goto error; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* let the user know what node this device is now attached to */ 570a5f5ea23SMatt Kraai dev_info(&interface->dev, 571a5f5ea23SMatt Kraai "USB Skeleton device now attached to USBSkel-%d", 572a5f5ea23SMatt Kraai interface->minor); 5731da177e4SLinus Torvalds return 0; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds error: 5761da177e4SLinus Torvalds if (dev) 577ba35e02bSOliver Neukum /* this frees allocated memory */ 5781da177e4SLinus Torvalds kref_put(&dev->kref, skel_delete); 5791da177e4SLinus Torvalds return retval; 5801da177e4SLinus Torvalds } 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds static void skel_disconnect(struct usb_interface *interface) 5831da177e4SLinus Torvalds { 5841da177e4SLinus Torvalds struct usb_skel *dev; 5851da177e4SLinus Torvalds int minor = interface->minor; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds dev = usb_get_intfdata(interface); 58852a74999SGreg Kroah-Hartman usb_set_intfdata(interface, NULL); 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds /* give back our minor */ 5911da177e4SLinus Torvalds usb_deregister_dev(interface, &skel_class); 5921da177e4SLinus Torvalds 593121e287cSAlan Stern /* prevent more I/O from starting */ 594121e287cSAlan Stern mutex_lock(&dev->io_mutex); 595121e287cSAlan Stern dev->interface = NULL; 596121e287cSAlan Stern mutex_unlock(&dev->io_mutex); 597121e287cSAlan Stern 598e73c7247SOliver Neukum usb_kill_anchored_urbs(&dev->submitted); 599e73c7247SOliver Neukum 6001da177e4SLinus Torvalds /* decrement our usage count */ 6011da177e4SLinus Torvalds kref_put(&dev->kref, skel_delete); 6021da177e4SLinus Torvalds 603a5f5ea23SMatt Kraai dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor); 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 606403dfb58SOliver Neukum static void skel_draw_down(struct usb_skel *dev) 607403dfb58SOliver Neukum { 608403dfb58SOliver Neukum int time; 609403dfb58SOliver Neukum 610403dfb58SOliver Neukum time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000); 611403dfb58SOliver Neukum if (!time) 612403dfb58SOliver Neukum usb_kill_anchored_urbs(&dev->submitted); 613e7389cc9SOliver Neukum usb_kill_urb(dev->bulk_in_urb); 614403dfb58SOliver Neukum } 615403dfb58SOliver Neukum 616758f7e16SOliver Neukum static int skel_suspend(struct usb_interface *intf, pm_message_t message) 617758f7e16SOliver Neukum { 618758f7e16SOliver Neukum struct usb_skel *dev = usb_get_intfdata(intf); 619758f7e16SOliver Neukum 620758f7e16SOliver Neukum if (!dev) 621758f7e16SOliver Neukum return 0; 622758f7e16SOliver Neukum skel_draw_down(dev); 623758f7e16SOliver Neukum return 0; 624758f7e16SOliver Neukum } 625758f7e16SOliver Neukum 626758f7e16SOliver Neukum static int skel_resume(struct usb_interface *intf) 627758f7e16SOliver Neukum { 628758f7e16SOliver Neukum return 0; 629758f7e16SOliver Neukum } 630758f7e16SOliver Neukum 63187d093e2SOliver Neukum static int skel_pre_reset(struct usb_interface *intf) 63287d093e2SOliver Neukum { 63387d093e2SOliver Neukum struct usb_skel *dev = usb_get_intfdata(intf); 63487d093e2SOliver Neukum 63587d093e2SOliver Neukum mutex_lock(&dev->io_mutex); 63687d093e2SOliver Neukum skel_draw_down(dev); 63787d093e2SOliver Neukum 63887d093e2SOliver Neukum return 0; 63987d093e2SOliver Neukum } 64087d093e2SOliver Neukum 64187d093e2SOliver Neukum static int skel_post_reset(struct usb_interface *intf) 64287d093e2SOliver Neukum { 64387d093e2SOliver Neukum struct usb_skel *dev = usb_get_intfdata(intf); 64487d093e2SOliver Neukum 64587d093e2SOliver Neukum /* we are sure no URBs are active - no locking needed */ 64687d093e2SOliver Neukum dev->errors = -EPIPE; 64787d093e2SOliver Neukum mutex_unlock(&dev->io_mutex); 64887d093e2SOliver Neukum 64987d093e2SOliver Neukum return 0; 65087d093e2SOliver Neukum } 65187d093e2SOliver Neukum 6521da177e4SLinus Torvalds static struct usb_driver skel_driver = { 6531da177e4SLinus Torvalds .name = "skeleton", 6541da177e4SLinus Torvalds .probe = skel_probe, 6551da177e4SLinus Torvalds .disconnect = skel_disconnect, 656758f7e16SOliver Neukum .suspend = skel_suspend, 657758f7e16SOliver Neukum .resume = skel_resume, 65887d093e2SOliver Neukum .pre_reset = skel_pre_reset, 65987d093e2SOliver Neukum .post_reset = skel_post_reset, 6601da177e4SLinus Torvalds .id_table = skel_table, 661ba35e02bSOliver Neukum .supports_autosuspend = 1, 6621da177e4SLinus Torvalds }; 6631da177e4SLinus Torvalds 66465db4305SGreg Kroah-Hartman module_usb_driver(skel_driver); 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 667