/* Structure to hold all of our device specific stuff */ struct adu_device { struct mutex mtx; struct usb_device *udev; /* save off the usb device pointer */ struct usb_interface *interface; unsignedint minor; /* the starting minor number for this device */ char serial_number[8];
int open_count; /* number of times this port has been opened */ unsignedlong disconnected:1;
char *read_buffer_primary; int read_buffer_length; char *read_buffer_secondary; int secondary_head; int secondary_tail;
spinlock_t buflock;
exit:
dev->read_urb_finished = 1;
spin_unlock_irqrestore(&dev->buflock, flags); /* always wake up so we recover from errors */
wake_up_interruptible(&dev->read_wait);
}
staticvoid adu_interrupt_out_callback(struct urb *urb)
{ struct adu_device *dev = urb->context; int status = urb->status; unsignedlong flags;
staticint adu_open(struct inode *inode, struct file *file)
{ struct adu_device *dev = NULL; struct usb_interface *interface; int subminor; int retval;
subminor = iminor(inode);
retval = mutex_lock_interruptible(&adutux_mutex); if (retval) goto exit_no_lock;
interface = usb_find_interface(&adu_driver, subminor); if (!interface) {
pr_err("%s - error, can't find device for minor %d\n",
__func__, subminor);
retval = -ENODEV; goto exit_no_device;
}
dev = usb_get_intfdata(interface); if (!dev) {
retval = -ENODEV; goto exit_no_device;
}
/* check that nobody else is using the device */ if (dev->open_count) {
retval = -EBUSY; goto exit_no_device;
}
++dev->open_count;
dev_dbg(&dev->udev->dev, "%s: open count %d\n", __func__,
dev->open_count);
/* save device in the file's private structure */
file->private_data = dev;
/* initialize in direction */
dev->read_buffer_length = 0;
/* fixup first read by having urb waiting for it */
usb_fill_int_urb(dev->interrupt_in_urb, dev->udev,
usb_rcvintpipe(dev->udev,
dev->interrupt_in_endpoint->bEndpointAddress),
dev->interrupt_in_buffer,
usb_endpoint_maxp(dev->interrupt_in_endpoint),
adu_interrupt_in_callback, dev,
dev->interrupt_in_endpoint->bInterval);
dev->read_urb_finished = 0; if (usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL))
dev->read_urb_finished = 1; /* we ignore failure */ /* end of fixup for first read */
/* initialize out direction */
dev->out_urb_finished = 1;
dev = file->private_data; if (dev == NULL) {
retval = -ENODEV; gotoexit;
}
mutex_lock(&adutux_mutex); /* not interruptible */
if (dev->open_count <= 0) {
dev_dbg(&dev->udev->dev, "%s : device not opened\n", __func__);
retval = -ENODEV; goto unlock;
}
adu_release_internal(dev); if (dev->disconnected) { /* 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: return retval;
}
retval = mutex_lock_interruptible(&dev->mtx); if (retval) goto exit_nolock;
/* verify that the device wasn't unplugged */ if (dev->disconnected) {
retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval); gotoexit;
}
/* verify that we actually have some data to write */ if (count == 0) {
dev_dbg(&dev->udev->dev, "%s : write request of 0 bytes\n",
__func__); gotoexit;
}
while (count > 0) {
add_wait_queue(&dev->write_wait, &waita);
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&dev->buflock, flags); if (!dev->out_urb_finished) {
spin_unlock_irqrestore(&dev->buflock, flags);
dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL); if (!dev->interrupt_in_buffer) 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) goto error;
dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) goto error;
dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) 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");
retval = -EIO; goto error;
}
dev_dbg(&interface->dev, "serial_number=%s", 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));
mutex_lock(&dev->mtx); /* not interruptible */
dev->disconnected = 1;
mutex_unlock(&dev->mtx);
/* if the device is not opened, then we clean up right now */ if (!dev->open_count)
adu_delete(dev);
mutex_unlock(&adutux_mutex);
}
/* usb specific object needed to register this driver with the usb subsystem */ staticstruct usb_driver adu_driver = {
.name = "adutux",
.probe = adu_probe,
.disconnect = adu_disconnect,
.id_table = device_table,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.