/** * adu_disconnect * * Called by the usb core when the device is removed from the system. */ static void adu_disconnect(struct usb_interface *interface) { struct adu_device *dev; int minor; dbg(2," %s : enter", __func__); dev = usb_get_intfdata(interface); mutex_lock(&dev->mtx); /* not interruptible */ dev->udev = NULL; /* poison */ minor = dev->minor; usb_deregister_dev(interface, &adu_class); mutex_unlock(&dev->mtx); mutex_lock(&adutux_mutex); usb_set_intfdata(interface, NULL); /* if the device is not opened, then we clean up right now */ dbg(2," %s : open count %d", __func__, dev->open_count); if (!dev->open_count) adu_delete(dev); mutex_unlock(&adutux_mutex); dev_info(&interface->dev, "ADU device adutux%d now disconnected\n", (minor - ADU_MINOR_BASE)); dbg(2," %s : leave", __func__); }
static int adu_release(struct inode *inode, struct file *file) { struct adu_device *dev = NULL; int retval = 0; dbg(2," %s : enter", __FUNCTION__); if (file == NULL) { dbg(1," %s : file is NULL", __FUNCTION__); retval = -ENODEV; goto exit; } dev = file->private_data; if (dev == NULL) { dbg(1," %s : object is NULL", __FUNCTION__); retval = -ENODEV; goto exit; } /* lock our device */ mutex_lock(&dev->mtx); /* not interruptible */ if (dev->open_count <= 0) { dbg(1," %s : device not opened", __FUNCTION__); retval = -ENODEV; goto exit; } if (dev->udev == NULL) { /* the device was unplugged before the file was released */ mutex_unlock(&dev->mtx); adu_delete(dev); dev = NULL; } else { /* do the work */ retval = adu_release_internal(dev); } exit: if (dev) mutex_unlock(&dev->mtx); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; }
static int adu_release(struct inode *inode, struct file *file) { struct adu_device *dev; int retval = 0; dbg(2," %s : enter", __func__); if (file == NULL) { dbg(1," %s : file is NULL", __func__); retval = -ENODEV; goto exit; } dev = file->private_data; if (dev == NULL) { dbg(1," %s : object is NULL", __func__); retval = -ENODEV; goto exit; } mutex_lock(&adutux_mutex); /* not interruptible */ if (dev->open_count <= 0) { dbg(1," %s : device not opened", __func__); retval = -ENODEV; goto unlock; } adu_release_internal(dev); if (dev->udev == NULL) { /* the device was unplugged before the file was released */ if (!dev->open_count) /* ... and we're the last user */ adu_delete(dev); } unlock: mutex_unlock(&adutux_mutex); exit: dbg(2," %s : leave, return value %d", __func__, retval); return retval; }
static int adu_release(struct inode *inode, struct file *file) { struct adu_device *dev; int retval = 0; dbg(2," %s : enter", __func__); if (file == NULL) { dbg(1," %s : file is NULL", __func__); retval = -ENODEV; goto exit; } dev = file->private_data; if (dev == NULL) { dbg(1," %s : object is NULL", __func__); retval = -ENODEV; goto exit; } mutex_lock(&adutux_mutex); if (dev->open_count <= 0) { dbg(1," %s : device not opened", __func__); retval = -ENODEV; goto unlock; } adu_release_internal(dev); if (dev->udev == NULL) { if (!dev->open_count) adu_delete(dev); } unlock: mutex_unlock(&adutux_mutex); exit: dbg(2," %s : leave, return value %d", __func__, retval); return retval; }
/** * adu_disconnect * * Called by the usb core when the device is removed from the system. */ static void adu_disconnect(struct usb_interface *interface) { struct adu_device *dev; int minor; dbg(2," %s : enter", __FUNCTION__); mutex_lock(&disconnect_mutex); /* not interruptible */ dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); down(&dev->sem); /* not interruptible */ minor = dev->minor; /* give back our minor */ usb_deregister_dev(interface, &adu_class); dev->minor = 0; /* if the device is not opened, then we clean up right now */ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); if (!dev->open_count) { up(&dev->sem); adu_delete(dev); } else { dev->udev = NULL; up(&dev->sem); } mutex_unlock(&disconnect_mutex); dev_info(&interface->dev, "ADU device adutux%d now disconnected", (minor - ADU_MINOR_BASE)); dbg(2," %s : leave", __FUNCTION__); }
static int adu_release_internal(struct adu_device *dev) { int retval = 0; dbg(2," %s : enter", __FUNCTION__); if (dev->udev == NULL) { /* the device was unplugged before the file was released */ adu_delete(dev); goto exit; } /* decrement our usage count for the device */ --dev->open_count; dbg(2," %s : open count %d", __FUNCTION__, dev->open_count); if (dev->open_count <= 0) { adu_abort_transfers(dev); dev->open_count = 0; } exit: dbg(2," %s : leave", __FUNCTION__); return retval; }
/** * adu_probe * * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */ static int adu_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); struct adu_device *dev = NULL; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int retval = -ENODEV; int in_end_size; int out_end_size; int i; dbg(2," %s : enter", __func__); if (udev == NULL) { dev_err(&interface->dev, "udev is NULL.\n"); goto exit; } /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL); if (dev == NULL) { dev_err(&interface->dev, "Out of memory\n"); retval = -ENOMEM; goto exit; } mutex_init(&dev->mtx); spin_lock_init(&dev->buflock); dev->udev = udev; init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->write_wait); iface_desc = &interface->altsetting[0]; /* 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(&interface->dev, "interrupt in endpoint not found\n"); goto error; } if (dev->interrupt_out_endpoint == NULL) { dev_err(&interface->dev, "interrupt out endpoint not found\n"); goto error; } in_end_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); out_end_size = usb_endpoint_maxp(dev->interrupt_out_endpoint); dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL); if (!dev->read_buffer_primary) { dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n"); retval = -ENOMEM; goto error; } /* debug code prime the buffer */ memset(dev->read_buffer_primary, 'a', in_end_size); memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size); memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size); memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size); dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL); if (!dev->read_buffer_secondary) { dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n"); retval = -ENOMEM; goto error; } /* debug code prime the buffer */ memset(dev->read_buffer_secondary, 'e', in_end_size); memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size); memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size); memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size); dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL); if (!dev->interrupt_in_buffer) { dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n"); goto error; } /* debug code prime the buffer */ memset(dev->interrupt_in_buffer, 'i', in_end_size); dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) { dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n"); goto error; } dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { dev_err(&interface->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(&interface->dev, "Couldn't allocate interrupt_out_urb\n"); goto error; } if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number, sizeof(dev->serial_number))) { dev_err(&interface->dev, "Could not retrieve serial number\n"); goto error; } dbg(2," %s : serial_number=%s", __func__, dev->serial_number); /* we can register the device now, as it is ready */ usb_set_intfdata(interface, dev); retval = usb_register_dev(interface, &adu_class); if (retval) { /* something prevented us from registering this driver */ dev_err(&interface->dev, "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } dev->minor = interface->minor; /* let the user know what node this device is now attached to */ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n", le16_to_cpu(udev->descriptor.idProduct), dev->serial_number, (dev->minor - ADU_MINOR_BASE)); exit: dbg(2," %s : leave, return value %p (dev)", __func__, dev); return retval; error: adu_delete(dev); return retval; }