/** * usb_tranzport_disconnect * * Called by the usb core when the device is removed from the system. */ static void usb_tranzport_disconnect(struct usb_interface *intf) { struct usb_tranzport *dev; int minor; mutex_lock(&disconnect_mutex); dev = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); down(&dev->sem); minor = intf->minor; /* give back our minor */ usb_deregister_dev(intf, &usb_tranzport_class); /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { up(&dev->sem); usb_tranzport_delete(dev); } else { dev->intf = NULL; up(&dev->sem); } mutex_unlock(&disconnect_mutex); dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n", (minor - USB_TRANZPORT_MINOR_BASE)); }
/** * usb_tranzport_release */ static int usb_tranzport_release(struct inode *inode, struct file *file) { struct usb_tranzport *dev; int retval = 0; dev = file->private_data; if (dev == NULL) { retval = -ENODEV; goto exit; } if (mutex_lock_interruptible(&dev->mtx)) { retval = -ERESTARTSYS; goto exit; } if (dev->open_count != 1) { retval = -ENODEV; goto unlock_exit; } if (dev->intf == NULL) { /* the device was unplugged before the file was released */ mutex_unlock(&dev->mtx); /* unlock here as usb_tranzport_delete frees dev */ usb_tranzport_delete(dev); retval = -ENODEV; goto exit; } /* wait until write transfer is finished */ if (dev->interrupt_out_busy) wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); usb_tranzport_abort_transfers(dev); dev->open_count = 0; unlock_exit: mutex_unlock(&dev->mtx); exit: return retval; }
/** * usb_tranzport_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */ static int usb_tranzport_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(intf); struct usb_tranzport *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int i; int true_size; int retval = -ENOMEM; /* allocate memory for our device state and intialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { dev_err(&intf->dev, "Out of memory\n"); goto exit; } init_MUTEX(&dev->sem); dev->intf = intf; init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); iface_desc = intf->cur_altsetting; /* set up the endpoint information */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint)) dev->interrupt_in_endpoint = endpoint; if (usb_endpoint_is_int_out(endpoint)) dev->interrupt_out_endpoint = endpoint; } if (dev->interrupt_in_endpoint == NULL) { dev_err(&intf->dev, "Interrupt in endpoint not found\n"); goto error; } if (dev->interrupt_out_endpoint == NULL) dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); if (dev->interrupt_in_endpoint_size != 8) dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n"); if(ring_buffer_size == 0) { ring_buffer_size = RING_BUFFER_SIZE; } true_size = min(ring_buffer_size,RING_BUFFER_SIZE); /* FIXME - there are more usb_alloc routines for dma correctness. Needed? */ dev->ring_buffer = kmalloc((true_size*sizeof(struct tranzport_cmd))+8, GFP_KERNEL); if (!dev->ring_buffer) { dev_err(&intf->dev, "Couldn't allocate ring_buffer of size %d\n",true_size); goto error; } dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); if (!dev->interrupt_in_buffer) { dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) { dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); goto error; } dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : udev->descriptor.bMaxPacketSize0; if (dev->interrupt_out_endpoint_size !=8) dev_warn(&intf->dev, "Interrupt out endpoint size is not 8!)\n"); dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) { dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); goto error; } dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; if (dev->interrupt_out_endpoint) dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; /* we can register the device now, as it is ready */ usb_set_intfdata(intf, dev); retval = usb_register_dev(intf, &usb_tranzport_class); if (retval) { /* something prevented us from registering this driver */ dev_err(&intf->dev, "Not able to get a minor for this device.\n"); usb_set_intfdata(intf, NULL); goto error; } if((retval = device_create_file(&intf->dev, &dev_attr_LightRecord))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackrec))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightTrackmute))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightTracksolo))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightAnysolo))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightLoop))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_LightPunch))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_wheel))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_event))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_dump_state))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_compress_wheel))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_enable))) goto error; if((retval = device_create_file(&intf->dev, &dev_attr_offline))) goto error; /* let the user know what node this device is now attached to */ dev_info(&intf->dev, "Tranzport Device #%d now attached to major %d minor %d\n", (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, intf->minor); exit: return retval; error: usb_tranzport_delete(dev); return retval; }