Add missing newlines to some uses of dev_<level> messages
[safe/jmp/linux-2.6] / drivers / usb / misc / ldusb.c
index 7e93ac9..8208496 100644 (file)
  * V0.1  (mh) Initial version
  * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint)
  * V0.12 (mh) Added kmalloc check for string buffer
+ * V0.13 (mh) Added support for LD X-Ray and Machine Test System
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 #include <asm/uaccess.h>
 #include <linux/input.h>
 
 /* Define these values to match your devices */
 #define USB_VENDOR_ID_LD               0x0f11  /* USB Vendor ID of LD Didactic GmbH */
-#define USB_DEVICE_ID_CASSY            0x1000  /* USB Product ID for all CASSY-S modules */
-#define USB_DEVICE_ID_POCKETCASSY      0x1010  /* USB Product ID for Pocket-CASSY */
-#define USB_DEVICE_ID_MOBILECASSY      0x1020  /* USB Product ID for Mobile-CASSY */
-#define USB_DEVICE_ID_JWM              0x1080  /* USB Product ID for Joule and Wattmeter */
-#define USB_DEVICE_ID_DMMP             0x1081  /* USB Product ID for Digital Multimeter P (reserved) */
-#define USB_DEVICE_ID_UMIP             0x1090  /* USB Product ID for UMI P */
-#define USB_DEVICE_ID_VIDEOCOM         0x1200  /* USB Product ID for VideoCom */
-#define USB_DEVICE_ID_COM3LAB          0x2000  /* USB Product ID for COM3LAB */
-#define USB_DEVICE_ID_TELEPORT         0x2010  /* USB Product ID for Terminal Adapter */
-#define USB_DEVICE_ID_NETWORKANALYSER  0x2020  /* USB Product ID for Network Analyser */
-#define USB_DEVICE_ID_POWERCONTROL     0x2030  /* USB Product ID for Controlling device for Power Electronics */
+#define USB_DEVICE_ID_LD_CASSY         0x1000  /* USB Product ID of CASSY-S */
+#define USB_DEVICE_ID_LD_POCKETCASSY   0x1010  /* USB Product ID of Pocket-CASSY */
+#define USB_DEVICE_ID_LD_MOBILECASSY   0x1020  /* USB Product ID of Mobile-CASSY */
+#define USB_DEVICE_ID_LD_JWM           0x1080  /* USB Product ID of Joule and Wattmeter */
+#define USB_DEVICE_ID_LD_DMMP          0x1081  /* USB Product ID of Digital Multimeter P (reserved) */
+#define USB_DEVICE_ID_LD_UMIP          0x1090  /* USB Product ID of UMI P */
+#define USB_DEVICE_ID_LD_XRAY1         0x1100  /* USB Product ID of X-Ray Apparatus */
+#define USB_DEVICE_ID_LD_XRAY2         0x1101  /* USB Product ID of X-Ray Apparatus */
+#define USB_DEVICE_ID_LD_VIDEOCOM      0x1200  /* USB Product ID of VideoCom */
+#define USB_DEVICE_ID_LD_COM3LAB       0x2000  /* USB Product ID of COM3LAB */
+#define USB_DEVICE_ID_LD_TELEPORT      0x2010  /* USB Product ID of Terminal Adapter */
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020        /* USB Product ID of Network Analyser */
+#define USB_DEVICE_ID_LD_POWERCONTROL  0x2030  /* USB Product ID of Converter Control Unit */
+#define USB_DEVICE_ID_LD_MACHINETEST   0x2040  /* USB Product ID of Machine Test System */
 
 #define USB_VENDOR_ID_VERNIER          0x08f7
 #define USB_DEVICE_ID_VERNIER_LABPRO   0x0001
@@ -58,6 +62,8 @@
 #define USB_DEVICE_ID_VERNIER_SKIP     0x0003
 #define USB_DEVICE_ID_VERNIER_CYCLOPS  0x0004
 
+#define USB_VENDOR_ID_MICROCHIP                0x04d8
+#define USB_DEVICE_ID_PICDEM           0x000c
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 #define USB_LD_MINOR_BASE      0
 
 /* table of devices that work with this driver */
 static struct usb_device_id ld_usb_table [] = {
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER) },
-       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
        { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
        { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
        { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
        { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+       { USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICDEM) },
        { }                                     /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, ld_usb_table);
-MODULE_VERSION("V0.12");
+MODULE_VERSION("V0.13");
 MODULE_AUTHOR("Michael Hund <mhund@ld-didactic.de>");
 MODULE_DESCRIPTION("LD USB Driver");
 MODULE_LICENSE("GPL");
@@ -155,6 +165,8 @@ struct ld_usb {
        size_t                  interrupt_in_endpoint_size;
        int                     interrupt_in_running;
        int                     interrupt_in_done;
+       int                     buffer_overflow;
+       spinlock_t              rbsl;
 
        char*                   interrupt_out_buffer;
        struct usb_endpoint_descriptor* interrupt_out_endpoint;
@@ -164,9 +176,6 @@ struct ld_usb {
        int                     interrupt_out_busy;
 };
 
-/* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
-
 static struct usb_driver ld_usb_driver;
 
 /**
@@ -205,25 +214,28 @@ static void ld_usb_delete(struct ld_usb *dev)
 /**
  *     ld_usb_interrupt_in_callback
  */
-static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
+static void ld_usb_interrupt_in_callback(struct urb *urb)
 {
        struct ld_usb *dev = urb->context;
        size_t *actual_buffer;
        unsigned int next_ring_head;
+       int status = urb->status;
        int retval;
 
-       if (urb->status) {
-               if (urb->status == -ENOENT ||
-                   urb->status == -ECONNRESET ||
-                   urb->status == -ESHUTDOWN) {
+       if (status) {
+               if (status == -ENOENT ||
+                   status == -ECONNRESET ||
+                   status == -ESHUTDOWN) {
                        goto exit;
                } else {
                        dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-                                __FUNCTION__, urb->status);
+                                __FUNCTION__, status);
+                       spin_lock(&dev->rbsl);
                        goto resubmit; /* maybe we can recover */
                }
        }
 
+       spin_lock(&dev->rbsl);
        if (urb->actual_length > 0) {
                next_ring_head = (dev->ring_head+1) % ring_buffer_size;
                if (next_ring_head != dev->ring_tail) {
@@ -234,21 +246,25 @@ static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
                        dev->ring_head = next_ring_head;
                        dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
                                 __FUNCTION__, urb->actual_length);
-               } else
+               } else {
                        dev_warn(&dev->intf->dev,
                                 "Ring buffer overflow, %d bytes dropped\n",
                                 urb->actual_length);
+                       dev->buffer_overflow = 1;
+               }
        }
 
 resubmit:
        /* resubmit if we're still running */
-       if (dev->interrupt_in_running && dev->intf) {
+       if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) {
                retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
-               if (retval)
+               if (retval) {
                        dev_err(&dev->intf->dev,
                                "usb_submit_urb failed (%d)\n", retval);
+                       dev->buffer_overflow = 1;
+               }
        }
-
+       spin_unlock(&dev->rbsl);
 exit:
        dev->interrupt_in_done = 1;
        wake_up_interruptible(&dev->read_wait);
@@ -257,17 +273,18 @@ exit:
 /**
  *     ld_usb_interrupt_out_callback
  */
-static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs)
+static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
        struct ld_usb *dev = urb->context;
+       int status = urb->status;
 
        /* sync/async unlink faults aren't errors */
-       if (urb->status && !(urb->status == -ENOENT ||
-                            urb->status == -ECONNRESET ||
-                            urb->status == -ESHUTDOWN))
+       if (status && !(status == -ENOENT ||
+                       status == -ECONNRESET ||
+                       status == -ESHUTDOWN))
                dbg_info(&dev->intf->dev,
                         "%s - nonzero write interrupt status received: %d\n",
-                        __FUNCTION__, urb->status);
+                        __FUNCTION__, status);
 
        dev->interrupt_out_busy = 0;
        wake_up_interruptible(&dev->write_wait);
@@ -280,35 +297,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 {
        struct ld_usb *dev;
        int subminor;
-       int retval = 0;
+       int retval;
        struct usb_interface *interface;
 
        nonseekable_open(inode, file);
        subminor = iminor(inode);
 
-       down(&disconnect_sem);
-
        interface = usb_find_interface(&ld_usb_driver, subminor);
 
        if (!interface) {
                err("%s - error, can't find device for minor %d\n",
                     __FUNCTION__, subminor);
-               retval = -ENODEV;
-               goto unlock_disconnect_exit;
+               return -ENODEV;
        }
 
        dev = usb_get_intfdata(interface);
 
-       if (!dev) {
-               retval = -ENODEV;
-               goto unlock_disconnect_exit;
-       }
+       if (!dev)
+               return -ENODEV;
 
        /* lock this device */
-       if (down_interruptible(&dev->sem)) {
-               retval = -ERESTARTSYS;
-               goto unlock_disconnect_exit;
-       }
+       if (down_interruptible(&dev->sem))
+               return -ERESTARTSYS;
 
        /* allow opening only once */
        if (dev->open_count) {
@@ -320,6 +330,7 @@ static int ld_usb_open(struct inode *inode, struct file *file)
        /* initialize in direction */
        dev->ring_head = 0;
        dev->ring_tail = 0;
+       dev->buffer_overflow = 0;
        usb_fill_int_urb(dev->interrupt_in_urb,
                         interface_to_usbdev(interface),
                         usb_rcvintpipe(interface_to_usbdev(interface),
@@ -347,9 +358,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 unlock_exit:
        up(&dev->sem);
 
-unlock_disconnect_exit:
-       up(&disconnect_sem);
-
        return retval;
 }
 
@@ -429,6 +437,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
        size_t *actual_buffer;
        size_t bytes_to_read;
        int retval = 0;
+       int rv;
 
        dev = file->private_data;
 
@@ -450,7 +459,10 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
        }
 
        /* wait for data */
+       spin_lock_irq(&dev->rbsl);
        if (dev->ring_head == dev->ring_tail) {
+               dev->interrupt_in_done = 0;
+               spin_unlock_irq(&dev->rbsl);
                if (file->f_flags & O_NONBLOCK) {
                        retval = -EAGAIN;
                        goto unlock_exit;
@@ -458,6 +470,8 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
                retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
                if (retval < 0)
                        goto unlock_exit;
+       } else {
+               spin_unlock_irq(&dev->rbsl);
        }
 
        /* actual_buffer contains actual_length + interrupt_in_buffer */
@@ -476,6 +490,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 
        retval = bytes_to_read;
 
+       spin_lock_irq(&dev->rbsl);
+       if (dev->buffer_overflow) {
+               dev->buffer_overflow = 0;
+               spin_unlock_irq(&dev->rbsl);
+               rv = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+               if (rv < 0)
+                       dev->buffer_overflow = 1;
+       } else {
+               spin_unlock_irq(&dev->rbsl);
+       }
+
 unlock_exit:
        /* unlock the device */
        up(&dev->sem);
@@ -582,7 +607,7 @@ exit:
 }
 
 /* file operations needed when we register this driver */
-static struct file_operations ld_usb_fops = {
+static const struct file_operations ld_usb_fops = {
        .owner =        THIS_MODULE,
        .read  =        ld_usb_read,
        .write =        ld_usb_write,
@@ -593,7 +618,7 @@ static struct file_operations ld_usb_fops = {
 
 /*
  * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with devfs and the driver core
+ * and to have the device registered with the driver core
  */
 static struct usb_class_driver ld_usb_class = {
        .name =         "ldusb%d",
@@ -619,21 +644,21 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
 
        /* allocate memory for our device state and intialize it */
 
-       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        if (dev == NULL) {
                dev_err(&intf->dev, "Out of memory\n");
                goto exit;
        }
-       memset(dev, 0x00, sizeof(*dev));
        init_MUTEX(&dev->sem);
+       spin_lock_init(&dev->rbsl);
        dev->intf = intf;
        init_waitqueue_head(&dev->read_wait);
        init_waitqueue_head(&dev->write_wait);
 
        /* workaround for early firmware versions on fast computers */
        if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) &&
-           ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) ||
-            (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) &&
+           ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_LD_CASSY) ||
+            (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_LD_COM3LAB)) &&
            (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) {
                buffer = kmalloc(256, GFP_KERNEL);
                if (buffer == NULL) {
@@ -651,15 +676,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
                endpoint = &iface_desc->endpoint[i].desc;
 
-               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
-                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+               if (usb_endpoint_is_int_in(endpoint))
                        dev->interrupt_in_endpoint = endpoint;
-               }
 
-               if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
-                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+               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");
@@ -734,18 +755,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
        struct ld_usb *dev;
        int minor;
 
-       down(&disconnect_sem);
-
        dev = usb_get_intfdata(intf);
        usb_set_intfdata(intf, NULL);
 
-       down(&dev->sem);
-
        minor = intf->minor;
 
        /* give back our minor */
        usb_deregister_dev(intf, &ld_usb_class);
 
+       down(&dev->sem);
+
        /* if the device is not opened, then we clean up right now */
        if (!dev->open_count) {
                up(&dev->sem);
@@ -755,15 +774,12 @@ static void ld_usb_disconnect(struct usb_interface *intf)
                up(&dev->sem);
        }
 
-       up(&disconnect_sem);
-
        dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
                 (minor - USB_LD_MINOR_BASE));
 }
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver ld_usb_driver = {
-       .owner =        THIS_MODULE,
        .name =         "ldusb",
        .probe =        ld_usb_probe,
        .disconnect =   ld_usb_disconnect,