1*03270634SSteven Haigh /* 2*03270634SSteven Haigh * adutux - driver for ADU devices from Ontrak Control Systems 3*03270634SSteven Haigh * This is an experimental driver. Use at your own risk. 4*03270634SSteven Haigh * This driver is not supported by Ontrak Control Systems. 5*03270634SSteven Haigh * 6*03270634SSteven Haigh * Copyright (c) 2003 John Homppi (SCO, leave this notice here) 7*03270634SSteven Haigh * 8*03270634SSteven Haigh * This program is free software; you can redistribute it and/or 9*03270634SSteven Haigh * modify it under the terms of the GNU General Public License as 10*03270634SSteven Haigh * published by the Free Software Foundation; either version 2 of 11*03270634SSteven Haigh * the License, or (at your option) any later version. 12*03270634SSteven Haigh * 13*03270634SSteven Haigh * derived from the Lego USB Tower driver 0.56: 14*03270634SSteven Haigh * Copyright (c) 2003 David Glance <davidgsf@sourceforge.net> 15*03270634SSteven Haigh * 2001 Juergen Stuber <stuber@loria.fr> 16*03270634SSteven Haigh * that was derived from USB Skeleton driver - 0.5 17*03270634SSteven Haigh * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) 18*03270634SSteven Haigh * 19*03270634SSteven Haigh */ 20*03270634SSteven Haigh 21*03270634SSteven Haigh #include <linux/kernel.h> 22*03270634SSteven Haigh #include <linux/errno.h> 23*03270634SSteven Haigh #include <linux/init.h> 24*03270634SSteven Haigh #include <linux/slab.h> 25*03270634SSteven Haigh #include <linux/module.h> 26*03270634SSteven Haigh #include <linux/usb.h> 27*03270634SSteven Haigh #include <asm/uaccess.h> 28*03270634SSteven Haigh 29*03270634SSteven Haigh #ifdef CONFIG_USB_DEBUG 30*03270634SSteven Haigh static int debug = 5; 31*03270634SSteven Haigh #else 32*03270634SSteven Haigh static int debug = 1; 33*03270634SSteven Haigh #endif 34*03270634SSteven Haigh 35*03270634SSteven Haigh /* Use our own dbg macro */ 36*03270634SSteven Haigh #undef dbg 37*03270634SSteven Haigh #define dbg(lvl, format, arg...) \ 38*03270634SSteven Haigh do { \ 39*03270634SSteven Haigh if (debug >= lvl) \ 40*03270634SSteven Haigh printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \ 41*03270634SSteven Haigh } while (0) 42*03270634SSteven Haigh 43*03270634SSteven Haigh 44*03270634SSteven Haigh /* Version Information */ 45*03270634SSteven Haigh #define DRIVER_VERSION "v0.0.13" 46*03270634SSteven Haigh #define DRIVER_AUTHOR "John Homppi" 47*03270634SSteven Haigh #define DRIVER_DESC "adutux (see www.ontrak.net)" 48*03270634SSteven Haigh 49*03270634SSteven Haigh /* Module parameters */ 50*03270634SSteven Haigh module_param(debug, int, S_IRUGO | S_IWUSR); 51*03270634SSteven Haigh MODULE_PARM_DESC(debug, "Debug enabled or not"); 52*03270634SSteven Haigh 53*03270634SSteven Haigh /* Define these values to match your device */ 54*03270634SSteven Haigh #define ADU_VENDOR_ID 0x0a07 55*03270634SSteven Haigh #define ADU_PRODUCT_ID 0x0064 56*03270634SSteven Haigh 57*03270634SSteven Haigh /* table of devices that work with this driver */ 58*03270634SSteven Haigh static struct usb_device_id device_table [] = { 59*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */ 60*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */ 61*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */ 62*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) }, /* ADU200 */ 63*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) }, /* ADU208 */ 64*03270634SSteven Haigh { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) }, /* ADU218 */ 65*03270634SSteven Haigh { }/* Terminating entry */ 66*03270634SSteven Haigh }; 67*03270634SSteven Haigh 68*03270634SSteven Haigh MODULE_DEVICE_TABLE(usb, device_table); 69*03270634SSteven Haigh 70*03270634SSteven Haigh #ifdef CONFIG_USB_DYNAMIC_MINORS 71*03270634SSteven Haigh #define ADU_MINOR_BASE 0 72*03270634SSteven Haigh #else 73*03270634SSteven Haigh #define ADU_MINOR_BASE 67 74*03270634SSteven Haigh #endif 75*03270634SSteven Haigh 76*03270634SSteven Haigh /* we can have up to this number of device plugged in at once */ 77*03270634SSteven Haigh #define MAX_DEVICES 16 78*03270634SSteven Haigh 79*03270634SSteven Haigh #define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */ 80*03270634SSteven Haigh 81*03270634SSteven Haigh /* Structure to hold all of our device specific stuff */ 82*03270634SSteven Haigh struct adu_device { 83*03270634SSteven Haigh struct semaphore sem; /* locks this structure */ 84*03270634SSteven Haigh struct usb_device* udev; /* save off the usb device pointer */ 85*03270634SSteven Haigh struct usb_interface* interface; 86*03270634SSteven Haigh unsigned char minor; /* the starting minor number for this device */ 87*03270634SSteven Haigh char serial_number[8]; 88*03270634SSteven Haigh 89*03270634SSteven Haigh int open_count; /* number of times this port has been opened */ 90*03270634SSteven Haigh 91*03270634SSteven Haigh char* read_buffer_primary; 92*03270634SSteven Haigh int read_buffer_length; 93*03270634SSteven Haigh char* read_buffer_secondary; 94*03270634SSteven Haigh int secondary_head; 95*03270634SSteven Haigh int secondary_tail; 96*03270634SSteven Haigh spinlock_t buflock; 97*03270634SSteven Haigh 98*03270634SSteven Haigh wait_queue_head_t read_wait; 99*03270634SSteven Haigh wait_queue_head_t write_wait; 100*03270634SSteven Haigh 101*03270634SSteven Haigh char* interrupt_in_buffer; 102*03270634SSteven Haigh struct usb_endpoint_descriptor* interrupt_in_endpoint; 103*03270634SSteven Haigh struct urb* interrupt_in_urb; 104*03270634SSteven Haigh int read_urb_finished; 105*03270634SSteven Haigh 106*03270634SSteven Haigh char* interrupt_out_buffer; 107*03270634SSteven Haigh struct usb_endpoint_descriptor* interrupt_out_endpoint; 108*03270634SSteven Haigh struct urb* interrupt_out_urb; 109*03270634SSteven Haigh }; 110*03270634SSteven Haigh 111*03270634SSteven Haigh /* prevent races between open() and disconnect */ 112*03270634SSteven Haigh static DEFINE_MUTEX(disconnect_mutex); 113*03270634SSteven Haigh static struct usb_driver adu_driver; 114*03270634SSteven Haigh 115*03270634SSteven Haigh static void adu_debug_data(int level, const char *function, int size, 116*03270634SSteven Haigh const unsigned char *data) 117*03270634SSteven Haigh { 118*03270634SSteven Haigh int i; 119*03270634SSteven Haigh 120*03270634SSteven Haigh if (debug < level) 121*03270634SSteven Haigh return; 122*03270634SSteven Haigh 123*03270634SSteven Haigh printk(KERN_DEBUG __FILE__": %s - length = %d, data = ", 124*03270634SSteven Haigh function, size); 125*03270634SSteven Haigh for (i = 0; i < size; ++i) 126*03270634SSteven Haigh printk("%.2x ", data[i]); 127*03270634SSteven Haigh printk("\n"); 128*03270634SSteven Haigh } 129*03270634SSteven Haigh 130*03270634SSteven Haigh /** 131*03270634SSteven Haigh * adu_abort_transfers 132*03270634SSteven Haigh * aborts transfers and frees associated data structures 133*03270634SSteven Haigh */ 134*03270634SSteven Haigh static void adu_abort_transfers(struct adu_device *dev) 135*03270634SSteven Haigh { 136*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 137*03270634SSteven Haigh 138*03270634SSteven Haigh if (dev == NULL) { 139*03270634SSteven Haigh dbg(1," %s : dev is null", __FUNCTION__); 140*03270634SSteven Haigh goto exit; 141*03270634SSteven Haigh } 142*03270634SSteven Haigh 143*03270634SSteven Haigh if (dev->udev == NULL) { 144*03270634SSteven Haigh dbg(1," %s : udev is null", __FUNCTION__); 145*03270634SSteven Haigh goto exit; 146*03270634SSteven Haigh } 147*03270634SSteven Haigh 148*03270634SSteven Haigh dbg(2," %s : udev state %d", __FUNCTION__, dev->udev->state); 149*03270634SSteven Haigh if (dev->udev->state == USB_STATE_NOTATTACHED) { 150*03270634SSteven Haigh dbg(1," %s : udev is not attached", __FUNCTION__); 151*03270634SSteven Haigh goto exit; 152*03270634SSteven Haigh } 153*03270634SSteven Haigh 154*03270634SSteven Haigh /* shutdown transfer */ 155*03270634SSteven Haigh usb_unlink_urb(dev->interrupt_in_urb); 156*03270634SSteven Haigh usb_unlink_urb(dev->interrupt_out_urb); 157*03270634SSteven Haigh 158*03270634SSteven Haigh exit: 159*03270634SSteven Haigh dbg(2," %s : leave", __FUNCTION__); 160*03270634SSteven Haigh } 161*03270634SSteven Haigh 162*03270634SSteven Haigh static void adu_delete(struct adu_device *dev) 163*03270634SSteven Haigh { 164*03270634SSteven Haigh dbg(2, "%s enter", __FUNCTION__); 165*03270634SSteven Haigh 166*03270634SSteven Haigh adu_abort_transfers(dev); 167*03270634SSteven Haigh 168*03270634SSteven Haigh /* free data structures */ 169*03270634SSteven Haigh usb_free_urb(dev->interrupt_in_urb); 170*03270634SSteven Haigh usb_free_urb(dev->interrupt_out_urb); 171*03270634SSteven Haigh kfree(dev->read_buffer_primary); 172*03270634SSteven Haigh kfree(dev->read_buffer_secondary); 173*03270634SSteven Haigh kfree(dev->interrupt_in_buffer); 174*03270634SSteven Haigh kfree(dev->interrupt_out_buffer); 175*03270634SSteven Haigh kfree(dev); 176*03270634SSteven Haigh 177*03270634SSteven Haigh dbg(2, "%s : leave", __FUNCTION__); 178*03270634SSteven Haigh } 179*03270634SSteven Haigh 180*03270634SSteven Haigh static void adu_interrupt_in_callback(struct urb *urb, struct pt_regs *regs) 181*03270634SSteven Haigh { 182*03270634SSteven Haigh struct adu_device *dev = urb->context; 183*03270634SSteven Haigh 184*03270634SSteven Haigh dbg(4," %s : enter, status %d", __FUNCTION__, urb->status); 185*03270634SSteven Haigh adu_debug_data(5, __FUNCTION__, urb->actual_length, 186*03270634SSteven Haigh urb->transfer_buffer); 187*03270634SSteven Haigh 188*03270634SSteven Haigh spin_lock(&dev->buflock); 189*03270634SSteven Haigh 190*03270634SSteven Haigh if (urb->status != 0) { 191*03270634SSteven Haigh if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) { 192*03270634SSteven Haigh dbg(1," %s : nonzero status received: %d", 193*03270634SSteven Haigh __FUNCTION__, urb->status); 194*03270634SSteven Haigh } 195*03270634SSteven Haigh goto exit; 196*03270634SSteven Haigh } 197*03270634SSteven Haigh 198*03270634SSteven Haigh if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) { 199*03270634SSteven Haigh if (dev->read_buffer_length < 200*03270634SSteven Haigh (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) - 201*03270634SSteven Haigh (urb->actual_length)) { 202*03270634SSteven Haigh memcpy (dev->read_buffer_primary + 203*03270634SSteven Haigh dev->read_buffer_length, 204*03270634SSteven Haigh dev->interrupt_in_buffer, urb->actual_length); 205*03270634SSteven Haigh 206*03270634SSteven Haigh dev->read_buffer_length += urb->actual_length; 207*03270634SSteven Haigh dbg(2," %s reading %d ", __FUNCTION__, 208*03270634SSteven Haigh urb->actual_length); 209*03270634SSteven Haigh } else { 210*03270634SSteven Haigh dbg(1," %s : read_buffer overflow", __FUNCTION__); 211*03270634SSteven Haigh } 212*03270634SSteven Haigh } 213*03270634SSteven Haigh 214*03270634SSteven Haigh exit: 215*03270634SSteven Haigh dev->read_urb_finished = 1; 216*03270634SSteven Haigh spin_unlock(&dev->buflock); 217*03270634SSteven Haigh /* always wake up so we recover from errors */ 218*03270634SSteven Haigh wake_up_interruptible(&dev->read_wait); 219*03270634SSteven Haigh adu_debug_data(5, __FUNCTION__, urb->actual_length, 220*03270634SSteven Haigh urb->transfer_buffer); 221*03270634SSteven Haigh dbg(4," %s : leave, status %d", __FUNCTION__, urb->status); 222*03270634SSteven Haigh } 223*03270634SSteven Haigh 224*03270634SSteven Haigh static void adu_interrupt_out_callback(struct urb *urb, struct pt_regs *regs) 225*03270634SSteven Haigh { 226*03270634SSteven Haigh struct adu_device *dev = urb->context; 227*03270634SSteven Haigh 228*03270634SSteven Haigh dbg(4," %s : enter, status %d", __FUNCTION__, urb->status); 229*03270634SSteven Haigh adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer); 230*03270634SSteven Haigh 231*03270634SSteven Haigh if (urb->status != 0) { 232*03270634SSteven Haigh if ((urb->status != -ENOENT) && 233*03270634SSteven Haigh (urb->status != -ECONNRESET)) { 234*03270634SSteven Haigh dbg(1, " %s :nonzero status received: %d", 235*03270634SSteven Haigh __FUNCTION__, urb->status); 236*03270634SSteven Haigh } 237*03270634SSteven Haigh goto exit; 238*03270634SSteven Haigh } 239*03270634SSteven Haigh 240*03270634SSteven Haigh wake_up_interruptible(&dev->write_wait); 241*03270634SSteven Haigh exit: 242*03270634SSteven Haigh 243*03270634SSteven Haigh adu_debug_data(5, __FUNCTION__, urb->actual_length, 244*03270634SSteven Haigh urb->transfer_buffer); 245*03270634SSteven Haigh dbg(4," %s : leave, status %d", __FUNCTION__, urb->status); 246*03270634SSteven Haigh } 247*03270634SSteven Haigh 248*03270634SSteven Haigh static int adu_open(struct inode *inode, struct file *file) 249*03270634SSteven Haigh { 250*03270634SSteven Haigh struct adu_device *dev = NULL; 251*03270634SSteven Haigh struct usb_interface *interface; 252*03270634SSteven Haigh int subminor; 253*03270634SSteven Haigh int retval = 0; 254*03270634SSteven Haigh 255*03270634SSteven Haigh dbg(2,"%s : enter", __FUNCTION__); 256*03270634SSteven Haigh 257*03270634SSteven Haigh subminor = iminor(inode); 258*03270634SSteven Haigh 259*03270634SSteven Haigh mutex_lock(&disconnect_mutex); 260*03270634SSteven Haigh 261*03270634SSteven Haigh interface = usb_find_interface(&adu_driver, subminor); 262*03270634SSteven Haigh if (!interface) { 263*03270634SSteven Haigh err("%s - error, can't find device for minor %d", 264*03270634SSteven Haigh __FUNCTION__, subminor); 265*03270634SSteven Haigh retval = -ENODEV; 266*03270634SSteven Haigh goto exit_no_device; 267*03270634SSteven Haigh } 268*03270634SSteven Haigh 269*03270634SSteven Haigh dev = usb_get_intfdata(interface); 270*03270634SSteven Haigh if (!dev) { 271*03270634SSteven Haigh retval = -ENODEV; 272*03270634SSteven Haigh goto exit_no_device; 273*03270634SSteven Haigh } 274*03270634SSteven Haigh 275*03270634SSteven Haigh /* lock this device */ 276*03270634SSteven Haigh if ((retval = down_interruptible(&dev->sem))) { 277*03270634SSteven Haigh dbg(2, "%s : sem down failed", __FUNCTION__); 278*03270634SSteven Haigh goto exit_no_device; 279*03270634SSteven Haigh } 280*03270634SSteven Haigh 281*03270634SSteven Haigh /* increment our usage count for the device */ 282*03270634SSteven Haigh ++dev->open_count; 283*03270634SSteven Haigh dbg(2,"%s : open count %d", __FUNCTION__, dev->open_count); 284*03270634SSteven Haigh 285*03270634SSteven Haigh /* save device in the file's private structure */ 286*03270634SSteven Haigh file->private_data = dev; 287*03270634SSteven Haigh 288*03270634SSteven Haigh /* initialize in direction */ 289*03270634SSteven Haigh dev->read_buffer_length = 0; 290*03270634SSteven Haigh 291*03270634SSteven Haigh /* fixup first read by having urb waiting for it */ 292*03270634SSteven Haigh usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, 293*03270634SSteven Haigh usb_rcvintpipe(dev->udev, 294*03270634SSteven Haigh dev->interrupt_in_endpoint->bEndpointAddress), 295*03270634SSteven Haigh dev->interrupt_in_buffer, 296*03270634SSteven Haigh le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), 297*03270634SSteven Haigh adu_interrupt_in_callback, dev, 298*03270634SSteven Haigh dev->interrupt_in_endpoint->bInterval); 299*03270634SSteven Haigh /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ 300*03270634SSteven Haigh dev->read_urb_finished = 0; 301*03270634SSteven Haigh usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); 302*03270634SSteven Haigh /* we ignore failure */ 303*03270634SSteven Haigh /* end of fixup for first read */ 304*03270634SSteven Haigh 305*03270634SSteven Haigh up(&dev->sem); 306*03270634SSteven Haigh 307*03270634SSteven Haigh exit_no_device: 308*03270634SSteven Haigh mutex_unlock(&disconnect_mutex); 309*03270634SSteven Haigh dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval); 310*03270634SSteven Haigh 311*03270634SSteven Haigh return retval; 312*03270634SSteven Haigh } 313*03270634SSteven Haigh 314*03270634SSteven Haigh static int adu_release_internal(struct adu_device *dev) 315*03270634SSteven Haigh { 316*03270634SSteven Haigh int retval = 0; 317*03270634SSteven Haigh 318*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 319*03270634SSteven Haigh 320*03270634SSteven Haigh if (dev->udev == NULL) { 321*03270634SSteven Haigh /* the device was unplugged before the file was released */ 322*03270634SSteven Haigh adu_delete(dev); 323*03270634SSteven Haigh goto exit; 324*03270634SSteven Haigh } 325*03270634SSteven Haigh 326*03270634SSteven Haigh /* decrement our usage count for the device */ 327*03270634SSteven Haigh --dev->open_count; 328*03270634SSteven Haigh dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); 329*03270634SSteven Haigh if (dev->open_count <= 0) { 330*03270634SSteven Haigh adu_abort_transfers(dev); 331*03270634SSteven Haigh dev->open_count = 0; 332*03270634SSteven Haigh } 333*03270634SSteven Haigh 334*03270634SSteven Haigh exit: 335*03270634SSteven Haigh dbg(2," %s : leave", __FUNCTION__); 336*03270634SSteven Haigh return retval; 337*03270634SSteven Haigh } 338*03270634SSteven Haigh 339*03270634SSteven Haigh static int adu_release(struct inode *inode, struct file *file) 340*03270634SSteven Haigh { 341*03270634SSteven Haigh struct adu_device *dev = NULL; 342*03270634SSteven Haigh int retval = 0; 343*03270634SSteven Haigh 344*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 345*03270634SSteven Haigh 346*03270634SSteven Haigh if (file == NULL) { 347*03270634SSteven Haigh dbg(1," %s : file is NULL", __FUNCTION__); 348*03270634SSteven Haigh retval = -ENODEV; 349*03270634SSteven Haigh goto exit; 350*03270634SSteven Haigh } 351*03270634SSteven Haigh 352*03270634SSteven Haigh dev = file->private_data; 353*03270634SSteven Haigh 354*03270634SSteven Haigh if (dev == NULL) { 355*03270634SSteven Haigh dbg(1," %s : object is NULL", __FUNCTION__); 356*03270634SSteven Haigh retval = -ENODEV; 357*03270634SSteven Haigh goto exit; 358*03270634SSteven Haigh } 359*03270634SSteven Haigh 360*03270634SSteven Haigh /* lock our device */ 361*03270634SSteven Haigh down(&dev->sem); /* not interruptible */ 362*03270634SSteven Haigh 363*03270634SSteven Haigh if (dev->open_count <= 0) { 364*03270634SSteven Haigh dbg(1," %s : device not opened", __FUNCTION__); 365*03270634SSteven Haigh retval = -ENODEV; 366*03270634SSteven Haigh goto exit; 367*03270634SSteven Haigh } 368*03270634SSteven Haigh 369*03270634SSteven Haigh /* do the work */ 370*03270634SSteven Haigh retval = adu_release_internal(dev); 371*03270634SSteven Haigh 372*03270634SSteven Haigh exit: 373*03270634SSteven Haigh up(&dev->sem); 374*03270634SSteven Haigh dbg(2," %s : leave, return value %d", __FUNCTION__, retval); 375*03270634SSteven Haigh return retval; 376*03270634SSteven Haigh } 377*03270634SSteven Haigh 378*03270634SSteven Haigh static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, 379*03270634SSteven Haigh loff_t *ppos) 380*03270634SSteven Haigh { 381*03270634SSteven Haigh struct adu_device *dev; 382*03270634SSteven Haigh size_t bytes_read = 0; 383*03270634SSteven Haigh size_t bytes_to_read = count; 384*03270634SSteven Haigh int i; 385*03270634SSteven Haigh int retval = 0; 386*03270634SSteven Haigh int timeout = 0; 387*03270634SSteven Haigh int should_submit = 0; 388*03270634SSteven Haigh unsigned long flags; 389*03270634SSteven Haigh DECLARE_WAITQUEUE(wait, current); 390*03270634SSteven Haigh 391*03270634SSteven Haigh dbg(2," %s : enter, count = %Zd, file=%p", __FUNCTION__, count, file); 392*03270634SSteven Haigh 393*03270634SSteven Haigh dev = file->private_data; 394*03270634SSteven Haigh dbg(2," %s : dev=%p", __FUNCTION__, dev); 395*03270634SSteven Haigh /* lock this object */ 396*03270634SSteven Haigh if (down_interruptible(&dev->sem)) 397*03270634SSteven Haigh return -ERESTARTSYS; 398*03270634SSteven Haigh 399*03270634SSteven Haigh /* verify that the device wasn't unplugged */ 400*03270634SSteven Haigh if (dev->udev == NULL || dev->minor == 0) { 401*03270634SSteven Haigh retval = -ENODEV; 402*03270634SSteven Haigh err("No device or device unplugged %d", retval); 403*03270634SSteven Haigh goto exit; 404*03270634SSteven Haigh } 405*03270634SSteven Haigh 406*03270634SSteven Haigh /* verify that some data was requested */ 407*03270634SSteven Haigh if (count == 0) { 408*03270634SSteven Haigh dbg(1," %s : read request of 0 bytes", __FUNCTION__); 409*03270634SSteven Haigh goto exit; 410*03270634SSteven Haigh } 411*03270634SSteven Haigh 412*03270634SSteven Haigh timeout = COMMAND_TIMEOUT; 413*03270634SSteven Haigh dbg(2," %s : about to start looping", __FUNCTION__); 414*03270634SSteven Haigh while (bytes_to_read) { 415*03270634SSteven Haigh int data_in_secondary = dev->secondary_tail - dev->secondary_head; 416*03270634SSteven Haigh dbg(2," %s : while, data_in_secondary=%d, status=%d", 417*03270634SSteven Haigh __FUNCTION__, data_in_secondary, 418*03270634SSteven Haigh dev->interrupt_in_urb->status); 419*03270634SSteven Haigh 420*03270634SSteven Haigh if (data_in_secondary) { 421*03270634SSteven Haigh /* drain secondary buffer */ 422*03270634SSteven Haigh int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary; 423*03270634SSteven Haigh i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount); 424*03270634SSteven Haigh if (i < 0) { 425*03270634SSteven Haigh retval = -EFAULT; 426*03270634SSteven Haigh goto exit; 427*03270634SSteven Haigh } 428*03270634SSteven Haigh dev->secondary_head += (amount - i); 429*03270634SSteven Haigh bytes_read += (amount - i); 430*03270634SSteven Haigh bytes_to_read -= (amount - i); 431*03270634SSteven Haigh if (i) { 432*03270634SSteven Haigh retval = bytes_read ? bytes_read : -EFAULT; 433*03270634SSteven Haigh goto exit; 434*03270634SSteven Haigh } 435*03270634SSteven Haigh } else { 436*03270634SSteven Haigh /* we check the primary buffer */ 437*03270634SSteven Haigh spin_lock_irqsave (&dev->buflock, flags); 438*03270634SSteven Haigh if (dev->read_buffer_length) { 439*03270634SSteven Haigh /* we secure access to the primary */ 440*03270634SSteven Haigh char *tmp; 441*03270634SSteven Haigh dbg(2," %s : swap, read_buffer_length = %d", 442*03270634SSteven Haigh __FUNCTION__, dev->read_buffer_length); 443*03270634SSteven Haigh tmp = dev->read_buffer_secondary; 444*03270634SSteven Haigh dev->read_buffer_secondary = dev->read_buffer_primary; 445*03270634SSteven Haigh dev->read_buffer_primary = tmp; 446*03270634SSteven Haigh dev->secondary_head = 0; 447*03270634SSteven Haigh dev->secondary_tail = dev->read_buffer_length; 448*03270634SSteven Haigh dev->read_buffer_length = 0; 449*03270634SSteven Haigh spin_unlock_irqrestore(&dev->buflock, flags); 450*03270634SSteven Haigh /* we have a free buffer so use it */ 451*03270634SSteven Haigh should_submit = 1; 452*03270634SSteven Haigh } else { 453*03270634SSteven Haigh /* even the primary was empty - we may need to do IO */ 454*03270634SSteven Haigh if (dev->interrupt_in_urb->status == -EINPROGRESS) { 455*03270634SSteven Haigh /* somebody is doing IO */ 456*03270634SSteven Haigh spin_unlock_irqrestore(&dev->buflock, flags); 457*03270634SSteven Haigh dbg(2," %s : submitted already", __FUNCTION__); 458*03270634SSteven Haigh } else { 459*03270634SSteven Haigh /* we must initiate input */ 460*03270634SSteven Haigh dbg(2," %s : initiate input", __FUNCTION__); 461*03270634SSteven Haigh dev->read_urb_finished = 0; 462*03270634SSteven Haigh 463*03270634SSteven Haigh usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, 464*03270634SSteven Haigh usb_rcvintpipe(dev->udev, 465*03270634SSteven Haigh dev->interrupt_in_endpoint->bEndpointAddress), 466*03270634SSteven Haigh dev->interrupt_in_buffer, 467*03270634SSteven Haigh le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), 468*03270634SSteven Haigh adu_interrupt_in_callback, 469*03270634SSteven Haigh dev, 470*03270634SSteven Haigh dev->interrupt_in_endpoint->bInterval); 471*03270634SSteven Haigh retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); 472*03270634SSteven Haigh if (!retval) { 473*03270634SSteven Haigh spin_unlock_irqrestore(&dev->buflock, flags); 474*03270634SSteven Haigh dbg(2," %s : submitted OK", __FUNCTION__); 475*03270634SSteven Haigh } else { 476*03270634SSteven Haigh if (retval == -ENOMEM) { 477*03270634SSteven Haigh retval = bytes_read ? bytes_read : -ENOMEM; 478*03270634SSteven Haigh } 479*03270634SSteven Haigh spin_unlock_irqrestore(&dev->buflock, flags); 480*03270634SSteven Haigh dbg(2," %s : submit failed", __FUNCTION__); 481*03270634SSteven Haigh goto exit; 482*03270634SSteven Haigh } 483*03270634SSteven Haigh } 484*03270634SSteven Haigh 485*03270634SSteven Haigh /* we wait for I/O to complete */ 486*03270634SSteven Haigh set_current_state(TASK_INTERRUPTIBLE); 487*03270634SSteven Haigh add_wait_queue(&dev->read_wait, &wait); 488*03270634SSteven Haigh if (!dev->read_urb_finished) 489*03270634SSteven Haigh timeout = schedule_timeout(COMMAND_TIMEOUT); 490*03270634SSteven Haigh else 491*03270634SSteven Haigh set_current_state(TASK_RUNNING); 492*03270634SSteven Haigh remove_wait_queue(&dev->read_wait, &wait); 493*03270634SSteven Haigh 494*03270634SSteven Haigh if (timeout <= 0) { 495*03270634SSteven Haigh dbg(2," %s : timeout", __FUNCTION__); 496*03270634SSteven Haigh retval = bytes_read ? bytes_read : -ETIMEDOUT; 497*03270634SSteven Haigh goto exit; 498*03270634SSteven Haigh } 499*03270634SSteven Haigh 500*03270634SSteven Haigh if (signal_pending(current)) { 501*03270634SSteven Haigh dbg(2," %s : signal pending", __FUNCTION__); 502*03270634SSteven Haigh retval = bytes_read ? bytes_read : -EINTR; 503*03270634SSteven Haigh goto exit; 504*03270634SSteven Haigh } 505*03270634SSteven Haigh } 506*03270634SSteven Haigh } 507*03270634SSteven Haigh } 508*03270634SSteven Haigh 509*03270634SSteven Haigh retval = bytes_read; 510*03270634SSteven Haigh /* if the primary buffer is empty then use it */ 511*03270634SSteven Haigh if (should_submit && !dev->interrupt_in_urb->status==-EINPROGRESS) { 512*03270634SSteven Haigh usb_fill_int_urb(dev->interrupt_in_urb,dev->udev, 513*03270634SSteven Haigh usb_rcvintpipe(dev->udev, 514*03270634SSteven Haigh dev->interrupt_in_endpoint->bEndpointAddress), 515*03270634SSteven Haigh dev->interrupt_in_buffer, 516*03270634SSteven Haigh le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize), 517*03270634SSteven Haigh adu_interrupt_in_callback, 518*03270634SSteven Haigh dev, 519*03270634SSteven Haigh dev->interrupt_in_endpoint->bInterval); 520*03270634SSteven Haigh /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ 521*03270634SSteven Haigh dev->read_urb_finished = 0; 522*03270634SSteven Haigh usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); 523*03270634SSteven Haigh /* we ignore failure */ 524*03270634SSteven Haigh } 525*03270634SSteven Haigh 526*03270634SSteven Haigh exit: 527*03270634SSteven Haigh /* unlock the device */ 528*03270634SSteven Haigh up(&dev->sem); 529*03270634SSteven Haigh 530*03270634SSteven Haigh dbg(2," %s : leave, return value %d", __FUNCTION__, retval); 531*03270634SSteven Haigh return retval; 532*03270634SSteven Haigh } 533*03270634SSteven Haigh 534*03270634SSteven Haigh static ssize_t adu_write(struct file *file, const __user char *buffer, 535*03270634SSteven Haigh size_t count, loff_t *ppos) 536*03270634SSteven Haigh { 537*03270634SSteven Haigh struct adu_device *dev; 538*03270634SSteven Haigh size_t bytes_written = 0; 539*03270634SSteven Haigh size_t bytes_to_write; 540*03270634SSteven Haigh size_t buffer_size; 541*03270634SSteven Haigh int retval = 0; 542*03270634SSteven Haigh int timeout = 0; 543*03270634SSteven Haigh 544*03270634SSteven Haigh dbg(2," %s : enter, count = %Zd", __FUNCTION__, count); 545*03270634SSteven Haigh 546*03270634SSteven Haigh dev = file->private_data; 547*03270634SSteven Haigh 548*03270634SSteven Haigh /* lock this object */ 549*03270634SSteven Haigh down_interruptible(&dev->sem); 550*03270634SSteven Haigh 551*03270634SSteven Haigh /* verify that the device wasn't unplugged */ 552*03270634SSteven Haigh if (dev->udev == NULL || dev->minor == 0) { 553*03270634SSteven Haigh retval = -ENODEV; 554*03270634SSteven Haigh err("No device or device unplugged %d", retval); 555*03270634SSteven Haigh goto exit; 556*03270634SSteven Haigh } 557*03270634SSteven Haigh 558*03270634SSteven Haigh /* verify that we actually have some data to write */ 559*03270634SSteven Haigh if (count == 0) { 560*03270634SSteven Haigh dbg(1," %s : write request of 0 bytes", __FUNCTION__); 561*03270634SSteven Haigh goto exit; 562*03270634SSteven Haigh } 563*03270634SSteven Haigh 564*03270634SSteven Haigh 565*03270634SSteven Haigh while (count > 0) { 566*03270634SSteven Haigh if (dev->interrupt_out_urb->status == -EINPROGRESS) { 567*03270634SSteven Haigh timeout = COMMAND_TIMEOUT; 568*03270634SSteven Haigh 569*03270634SSteven Haigh while (timeout > 0) { 570*03270634SSteven Haigh if (signal_pending(current)) { 571*03270634SSteven Haigh dbg(1," %s : interrupted", __FUNCTION__); 572*03270634SSteven Haigh retval = -EINTR; 573*03270634SSteven Haigh goto exit; 574*03270634SSteven Haigh } 575*03270634SSteven Haigh up(&dev->sem); 576*03270634SSteven Haigh timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout); 577*03270634SSteven Haigh down_interruptible(&dev->sem); 578*03270634SSteven Haigh if (timeout > 0) { 579*03270634SSteven Haigh break; 580*03270634SSteven Haigh } 581*03270634SSteven Haigh dbg(1," %s : interrupted timeout: %d", __FUNCTION__, timeout); 582*03270634SSteven Haigh } 583*03270634SSteven Haigh 584*03270634SSteven Haigh 585*03270634SSteven Haigh dbg(1," %s : final timeout: %d", __FUNCTION__, timeout); 586*03270634SSteven Haigh 587*03270634SSteven Haigh if (timeout == 0) { 588*03270634SSteven Haigh dbg(1, "%s - command timed out.", __FUNCTION__); 589*03270634SSteven Haigh retval = -ETIMEDOUT; 590*03270634SSteven Haigh goto exit; 591*03270634SSteven Haigh } 592*03270634SSteven Haigh 593*03270634SSteven Haigh dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count); 594*03270634SSteven Haigh 595*03270634SSteven Haigh } else { 596*03270634SSteven Haigh dbg(4," %s : sending, count = %Zd", __FUNCTION__, count); 597*03270634SSteven Haigh 598*03270634SSteven Haigh /* write the data into interrupt_out_buffer from userspace */ 599*03270634SSteven Haigh buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize); 600*03270634SSteven Haigh bytes_to_write = count > buffer_size ? buffer_size : count; 601*03270634SSteven Haigh dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd", 602*03270634SSteven Haigh __FUNCTION__, buffer_size, count, bytes_to_write); 603*03270634SSteven Haigh 604*03270634SSteven Haigh if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) { 605*03270634SSteven Haigh retval = -EFAULT; 606*03270634SSteven Haigh goto exit; 607*03270634SSteven Haigh } 608*03270634SSteven Haigh 609*03270634SSteven Haigh /* send off the urb */ 610*03270634SSteven Haigh usb_fill_int_urb( 611*03270634SSteven Haigh dev->interrupt_out_urb, 612*03270634SSteven Haigh dev->udev, 613*03270634SSteven Haigh usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress), 614*03270634SSteven Haigh dev->interrupt_out_buffer, 615*03270634SSteven Haigh bytes_to_write, 616*03270634SSteven Haigh adu_interrupt_out_callback, 617*03270634SSteven Haigh dev, 618*03270634SSteven Haigh dev->interrupt_in_endpoint->bInterval); 619*03270634SSteven Haigh /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */ 620*03270634SSteven Haigh dev->interrupt_out_urb->actual_length = bytes_to_write; 621*03270634SSteven Haigh retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); 622*03270634SSteven Haigh if (retval < 0) { 623*03270634SSteven Haigh err("Couldn't submit interrupt_out_urb %d", retval); 624*03270634SSteven Haigh goto exit; 625*03270634SSteven Haigh } 626*03270634SSteven Haigh 627*03270634SSteven Haigh buffer += bytes_to_write; 628*03270634SSteven Haigh count -= bytes_to_write; 629*03270634SSteven Haigh 630*03270634SSteven Haigh bytes_written += bytes_to_write; 631*03270634SSteven Haigh } 632*03270634SSteven Haigh } 633*03270634SSteven Haigh 634*03270634SSteven Haigh retval = bytes_written; 635*03270634SSteven Haigh 636*03270634SSteven Haigh exit: 637*03270634SSteven Haigh /* unlock the device */ 638*03270634SSteven Haigh up(&dev->sem); 639*03270634SSteven Haigh 640*03270634SSteven Haigh dbg(2," %s : leave, return value %d", __FUNCTION__, retval); 641*03270634SSteven Haigh 642*03270634SSteven Haigh return retval; 643*03270634SSteven Haigh } 644*03270634SSteven Haigh 645*03270634SSteven Haigh /* file operations needed when we register this driver */ 646*03270634SSteven Haigh static struct file_operations adu_fops = { 647*03270634SSteven Haigh .owner = THIS_MODULE, 648*03270634SSteven Haigh .read = adu_read, 649*03270634SSteven Haigh .write = adu_write, 650*03270634SSteven Haigh .open = adu_open, 651*03270634SSteven Haigh .release = adu_release, 652*03270634SSteven Haigh }; 653*03270634SSteven Haigh 654*03270634SSteven Haigh /* 655*03270634SSteven Haigh * usb class driver info in order to get a minor number from the usb core, 656*03270634SSteven Haigh * and to have the device registered with devfs and the driver core 657*03270634SSteven Haigh */ 658*03270634SSteven Haigh static struct usb_class_driver adu_class = { 659*03270634SSteven Haigh .name = "usb/adutux%d", 660*03270634SSteven Haigh .fops = &adu_fops, 661*03270634SSteven Haigh .minor_base = ADU_MINOR_BASE, 662*03270634SSteven Haigh }; 663*03270634SSteven Haigh 664*03270634SSteven Haigh /** 665*03270634SSteven Haigh * adu_probe 666*03270634SSteven Haigh * 667*03270634SSteven Haigh * Called by the usb core when a new device is connected that it thinks 668*03270634SSteven Haigh * this driver might be interested in. 669*03270634SSteven Haigh */ 670*03270634SSteven Haigh static int adu_probe(struct usb_interface *interface, 671*03270634SSteven Haigh const struct usb_device_id *id) 672*03270634SSteven Haigh { 673*03270634SSteven Haigh struct usb_device *udev = interface_to_usbdev(interface); 674*03270634SSteven Haigh struct adu_device *dev = NULL; 675*03270634SSteven Haigh struct usb_host_interface *iface_desc; 676*03270634SSteven Haigh struct usb_endpoint_descriptor *endpoint; 677*03270634SSteven Haigh int retval = -ENODEV; 678*03270634SSteven Haigh int in_end_size; 679*03270634SSteven Haigh int out_end_size; 680*03270634SSteven Haigh int i; 681*03270634SSteven Haigh 682*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 683*03270634SSteven Haigh 684*03270634SSteven Haigh if (udev == NULL) { 685*03270634SSteven Haigh dev_err(&interface->dev, "udev is NULL.\n"); 686*03270634SSteven Haigh goto exit; 687*03270634SSteven Haigh } 688*03270634SSteven Haigh 689*03270634SSteven Haigh /* allocate memory for our device state and intialize it */ 690*03270634SSteven Haigh dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); 691*03270634SSteven Haigh if (dev == NULL) { 692*03270634SSteven Haigh dev_err(&interface->dev, "Out of memory\n"); 693*03270634SSteven Haigh retval = -ENOMEM; 694*03270634SSteven Haigh goto exit; 695*03270634SSteven Haigh } 696*03270634SSteven Haigh 697*03270634SSteven Haigh init_MUTEX(&dev->sem); 698*03270634SSteven Haigh spin_lock_init(&dev->buflock); 699*03270634SSteven Haigh dev->udev = udev; 700*03270634SSteven Haigh init_waitqueue_head(&dev->read_wait); 701*03270634SSteven Haigh init_waitqueue_head(&dev->write_wait); 702*03270634SSteven Haigh 703*03270634SSteven Haigh iface_desc = &interface->altsetting[0]; 704*03270634SSteven Haigh 705*03270634SSteven Haigh /* set up the endpoint information */ 706*03270634SSteven Haigh for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { 707*03270634SSteven Haigh endpoint = &iface_desc->endpoint[i].desc; 708*03270634SSteven Haigh 709*03270634SSteven Haigh if (usb_endpoint_is_int_in(endpoint)) 710*03270634SSteven Haigh dev->interrupt_in_endpoint = endpoint; 711*03270634SSteven Haigh 712*03270634SSteven Haigh if (usb_endpoint_is_int_out(endpoint)) 713*03270634SSteven Haigh dev->interrupt_out_endpoint = endpoint; 714*03270634SSteven Haigh } 715*03270634SSteven Haigh if (dev->interrupt_in_endpoint == NULL) { 716*03270634SSteven Haigh dev_err(&interface->dev, "interrupt in endpoint not found\n"); 717*03270634SSteven Haigh goto error; 718*03270634SSteven Haigh } 719*03270634SSteven Haigh if (dev->interrupt_out_endpoint == NULL) { 720*03270634SSteven Haigh dev_err(&interface->dev, "interrupt out endpoint not found\n"); 721*03270634SSteven Haigh goto error; 722*03270634SSteven Haigh } 723*03270634SSteven Haigh 724*03270634SSteven Haigh in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); 725*03270634SSteven Haigh out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize); 726*03270634SSteven Haigh 727*03270634SSteven Haigh dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL); 728*03270634SSteven Haigh if (!dev->read_buffer_primary) { 729*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n"); 730*03270634SSteven Haigh retval = -ENOMEM; 731*03270634SSteven Haigh goto error; 732*03270634SSteven Haigh } 733*03270634SSteven Haigh 734*03270634SSteven Haigh /* debug code prime the buffer */ 735*03270634SSteven Haigh memset(dev->read_buffer_primary, 'a', in_end_size); 736*03270634SSteven Haigh memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size); 737*03270634SSteven Haigh memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size); 738*03270634SSteven Haigh memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size); 739*03270634SSteven Haigh 740*03270634SSteven Haigh dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL); 741*03270634SSteven Haigh if (!dev->read_buffer_secondary) { 742*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n"); 743*03270634SSteven Haigh retval = -ENOMEM; 744*03270634SSteven Haigh goto error; 745*03270634SSteven Haigh } 746*03270634SSteven Haigh 747*03270634SSteven Haigh /* debug code prime the buffer */ 748*03270634SSteven Haigh memset(dev->read_buffer_secondary, 'e', in_end_size); 749*03270634SSteven Haigh memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size); 750*03270634SSteven Haigh memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size); 751*03270634SSteven Haigh memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size); 752*03270634SSteven Haigh 753*03270634SSteven Haigh dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL); 754*03270634SSteven Haigh if (!dev->interrupt_in_buffer) { 755*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n"); 756*03270634SSteven Haigh goto error; 757*03270634SSteven Haigh } 758*03270634SSteven Haigh 759*03270634SSteven Haigh /* debug code prime the buffer */ 760*03270634SSteven Haigh memset(dev->interrupt_in_buffer, 'i', in_end_size); 761*03270634SSteven Haigh 762*03270634SSteven Haigh dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); 763*03270634SSteven Haigh if (!dev->interrupt_in_urb) { 764*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); 765*03270634SSteven Haigh goto error; 766*03270634SSteven Haigh } 767*03270634SSteven Haigh dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); 768*03270634SSteven Haigh if (!dev->interrupt_out_buffer) { 769*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n"); 770*03270634SSteven Haigh goto error; 771*03270634SSteven Haigh } 772*03270634SSteven Haigh dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); 773*03270634SSteven Haigh if (!dev->interrupt_out_urb) { 774*03270634SSteven Haigh dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n"); 775*03270634SSteven Haigh goto error; 776*03270634SSteven Haigh } 777*03270634SSteven Haigh 778*03270634SSteven Haigh if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number, 779*03270634SSteven Haigh sizeof(dev->serial_number))) { 780*03270634SSteven Haigh dev_err(&interface->dev, "Could not retrieve serial number\n"); 781*03270634SSteven Haigh goto error; 782*03270634SSteven Haigh } 783*03270634SSteven Haigh dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number); 784*03270634SSteven Haigh 785*03270634SSteven Haigh /* we can register the device now, as it is ready */ 786*03270634SSteven Haigh usb_set_intfdata(interface, dev); 787*03270634SSteven Haigh 788*03270634SSteven Haigh retval = usb_register_dev(interface, &adu_class); 789*03270634SSteven Haigh 790*03270634SSteven Haigh if (retval) { 791*03270634SSteven Haigh /* something prevented us from registering this driver */ 792*03270634SSteven Haigh dev_err(&interface->dev, "Not able to get a minor for this device.\n"); 793*03270634SSteven Haigh usb_set_intfdata(interface, NULL); 794*03270634SSteven Haigh goto error; 795*03270634SSteven Haigh } 796*03270634SSteven Haigh 797*03270634SSteven Haigh dev->minor = interface->minor; 798*03270634SSteven Haigh 799*03270634SSteven Haigh /* let the user know what node this device is now attached to */ 800*03270634SSteven Haigh dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d", 801*03270634SSteven Haigh udev->descriptor.idProduct, dev->serial_number, 802*03270634SSteven Haigh (dev->minor - ADU_MINOR_BASE)); 803*03270634SSteven Haigh exit: 804*03270634SSteven Haigh dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev); 805*03270634SSteven Haigh 806*03270634SSteven Haigh return retval; 807*03270634SSteven Haigh 808*03270634SSteven Haigh error: 809*03270634SSteven Haigh adu_delete(dev); 810*03270634SSteven Haigh return retval; 811*03270634SSteven Haigh } 812*03270634SSteven Haigh 813*03270634SSteven Haigh /** 814*03270634SSteven Haigh * adu_disconnect 815*03270634SSteven Haigh * 816*03270634SSteven Haigh * Called by the usb core when the device is removed from the system. 817*03270634SSteven Haigh */ 818*03270634SSteven Haigh static void adu_disconnect(struct usb_interface *interface) 819*03270634SSteven Haigh { 820*03270634SSteven Haigh struct adu_device *dev; 821*03270634SSteven Haigh int minor; 822*03270634SSteven Haigh 823*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 824*03270634SSteven Haigh 825*03270634SSteven Haigh mutex_lock(&disconnect_mutex); /* not interruptible */ 826*03270634SSteven Haigh 827*03270634SSteven Haigh dev = usb_get_intfdata(interface); 828*03270634SSteven Haigh usb_set_intfdata(interface, NULL); 829*03270634SSteven Haigh 830*03270634SSteven Haigh down(&dev->sem); /* not interruptible */ 831*03270634SSteven Haigh 832*03270634SSteven Haigh minor = dev->minor; 833*03270634SSteven Haigh 834*03270634SSteven Haigh /* give back our minor */ 835*03270634SSteven Haigh usb_deregister_dev(interface, &adu_class); 836*03270634SSteven Haigh dev->minor = 0; 837*03270634SSteven Haigh 838*03270634SSteven Haigh /* if the device is not opened, then we clean up right now */ 839*03270634SSteven Haigh dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); 840*03270634SSteven Haigh if (!dev->open_count) { 841*03270634SSteven Haigh up(&dev->sem); 842*03270634SSteven Haigh adu_delete(dev); 843*03270634SSteven Haigh } else { 844*03270634SSteven Haigh dev->udev = NULL; 845*03270634SSteven Haigh up(&dev->sem); 846*03270634SSteven Haigh } 847*03270634SSteven Haigh 848*03270634SSteven Haigh mutex_unlock(&disconnect_mutex); 849*03270634SSteven Haigh 850*03270634SSteven Haigh dev_info(&interface->dev, "ADU device adutux%d now disconnected", 851*03270634SSteven Haigh (minor - ADU_MINOR_BASE)); 852*03270634SSteven Haigh 853*03270634SSteven Haigh dbg(2," %s : leave", __FUNCTION__); 854*03270634SSteven Haigh } 855*03270634SSteven Haigh 856*03270634SSteven Haigh /* usb specific object needed to register this driver with the usb subsystem */ 857*03270634SSteven Haigh static struct usb_driver adu_driver = { 858*03270634SSteven Haigh .name = "adutux", 859*03270634SSteven Haigh .probe = adu_probe, 860*03270634SSteven Haigh .disconnect = adu_disconnect, 861*03270634SSteven Haigh .id_table = device_table, 862*03270634SSteven Haigh }; 863*03270634SSteven Haigh 864*03270634SSteven Haigh static int __init adu_init(void) 865*03270634SSteven Haigh { 866*03270634SSteven Haigh int result; 867*03270634SSteven Haigh 868*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 869*03270634SSteven Haigh 870*03270634SSteven Haigh /* register this driver with the USB subsystem */ 871*03270634SSteven Haigh result = usb_register(&adu_driver); 872*03270634SSteven Haigh if (result < 0) { 873*03270634SSteven Haigh err("usb_register failed for the "__FILE__" driver. " 874*03270634SSteven Haigh "Error number %d", result); 875*03270634SSteven Haigh goto exit; 876*03270634SSteven Haigh } 877*03270634SSteven Haigh 878*03270634SSteven Haigh info("adutux " DRIVER_DESC " " DRIVER_VERSION); 879*03270634SSteven Haigh info("adutux is an experimental driver. Use at your own risk"); 880*03270634SSteven Haigh 881*03270634SSteven Haigh exit: 882*03270634SSteven Haigh dbg(2," %s : leave, return value %d", __FUNCTION__, result); 883*03270634SSteven Haigh 884*03270634SSteven Haigh return result; 885*03270634SSteven Haigh } 886*03270634SSteven Haigh 887*03270634SSteven Haigh static void __exit adu_exit(void) 888*03270634SSteven Haigh { 889*03270634SSteven Haigh dbg(2," %s : enter", __FUNCTION__); 890*03270634SSteven Haigh /* deregister this driver with the USB subsystem */ 891*03270634SSteven Haigh usb_deregister(&adu_driver); 892*03270634SSteven Haigh dbg(2," %s : leave", __FUNCTION__); 893*03270634SSteven Haigh } 894*03270634SSteven Haigh 895*03270634SSteven Haigh module_init(adu_init); 896*03270634SSteven Haigh module_exit(adu_exit); 897*03270634SSteven Haigh 898*03270634SSteven Haigh MODULE_AUTHOR(DRIVER_AUTHOR); 899*03270634SSteven Haigh MODULE_DESCRIPTION(DRIVER_DESC); 900*03270634SSteven Haigh MODULE_LICENSE("GPL"); 901