diff options
Diffstat (limited to 'drivers/usb/misc')
-rw-r--r-- | drivers/usb/misc/Kconfig | 24 | ||||
-rw-r--r-- | drivers/usb/misc/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/misc/adutux.c | 22 | ||||
-rw-r--r-- | drivers/usb/misc/appledisplay.c | 26 | ||||
-rw-r--r-- | drivers/usb/misc/cypress_cy7c63.c | 6 | ||||
-rw-r--r-- | drivers/usb/misc/cytherm.c | 9 | ||||
-rw-r--r-- | drivers/usb/misc/emi26.c | 17 | ||||
-rw-r--r-- | drivers/usb/misc/emi62.c | 4 | ||||
-rw-r--r-- | drivers/usb/misc/ftdi-elan.c | 10 | ||||
-rw-r--r-- | drivers/usb/misc/idmouse.c | 5 | ||||
-rw-r--r-- | drivers/usb/misc/legousbtower.c | 23 | ||||
-rw-r--r-- | drivers/usb/misc/rio500.c | 11 | ||||
-rw-r--r-- | drivers/usb/misc/trancevibrator.c | 3 | ||||
-rw-r--r-- | drivers/usb/misc/usblcd.c | 13 | ||||
-rw-r--r-- | drivers/usb/misc/usbsevseg.c | 394 | ||||
-rw-r--r-- | drivers/usb/misc/uss720.c | 19 | ||||
-rw-r--r-- | drivers/usb/misc/vstusb.c | 782 |
17 files changed, 1297 insertions, 73 deletions
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 4ea50e0abcb..e463db5d818 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -42,6 +42,15 @@ config USB_ADUTUX To compile this driver as a module, choose M here. The module will be called adutux. +config USB_SEVSEG + tristate "USB 7-Segment LED Display" + depends on USB + help + Say Y here if you have a USB 7-Segment Display by Delcom + + To compile this driver as a module, choose M here: the + module will be called usbsevseg. + config USB_RIO500 tristate "USB Diamond Rio500 support" depends on USB @@ -271,3 +280,18 @@ config USB_ISIGHTFW The firmware for this driver must be extracted from the MacOS driver beforehand. Tools for doing so are available at http://bersace03.free.fr + +config USB_VST + tristate "USB VST driver" + depends on USB + help + This driver is intended for Vernier Software Technologies + bulk usb devices such as their Ocean-Optics spectrometers or + Labquest. + It is a bulk channel driver with configurable read and write + timeouts. + + To compile this driver as a module, choose M here: the + module will be called vstusb. + + diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 45b4e12afb0..1334f7bdd7b 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o +obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o +obj-$(CONFIG_USB_VST) += vstusb.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 965f6eaea6a..7b6922e08ed 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -283,8 +283,8 @@ static int adu_open(struct inode *inode, struct file *file) interface = usb_find_interface(&adu_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "adutux: %s - error, can't find device for " + "minor %d\n", __func__, subminor); retval = -ENODEV; goto exit_no_device; } @@ -416,7 +416,8 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "adutux: No device or device unplugged %d\n", + retval); goto exit; } @@ -576,7 +577,8 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "adutux: No device or device unplugged %d\n", + retval); goto exit; } @@ -645,7 +647,8 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval < 0) { dev->out_urb_finished = 1; - err("Couldn't submit interrupt_out_urb %d", retval); + dev_err(&dev->udev->dev, "Couldn't submit " + "interrupt_out_urb %d\n", retval); goto exit; } @@ -890,13 +893,14 @@ static int __init adu_init(void) /* register this driver with the USB subsystem */ result = usb_register(&adu_driver); if (result < 0) { - err("usb_register failed for the "__FILE__" driver. " - "Error number %d", result); + printk(KERN_ERR "usb_register failed for the "__FILE__ + " driver. Error number %d\n", result); goto exit; } - info("adutux " DRIVER_DESC " " DRIVER_VERSION); - info("adutux is an experimental driver. Use at your own risk"); + printk(KERN_INFO "adutux " DRIVER_DESC " " DRIVER_VERSION "\n"); + printk(KERN_INFO "adutux is an experimental driver. " + "Use at your own risk\n"); exit: dbg(2," %s : leave, return value %d", __func__, result); diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index a076c24a312..1d8e39a557d 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -130,7 +130,8 @@ static void appledisplay_complete(struct urb *urb) exit: retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); if (retval) { - err("%s - usb_submit_urb failed with result %d", + dev_err(&pdata->udev->dev, + "%s - usb_submit_urb failed with result %d\n", __func__, retval); } } @@ -220,7 +221,7 @@ static int appledisplay_probe(struct usb_interface *iface, } } if (!int_in_endpointAddr) { - err("Could not find int-in endpoint"); + dev_err(&iface->dev, "Could not find int-in endpoint\n"); return -EIO; } @@ -228,7 +229,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata = kzalloc(sizeof(struct appledisplay), GFP_KERNEL); if (!pdata) { retval = -ENOMEM; - err("Out of memory"); + dev_err(&iface->dev, "Out of memory\n"); goto error; } @@ -241,8 +242,8 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); if (!pdata->msgdata) { retval = -ENOMEM; - err("appledisplay: Allocating buffer for control messages " - "failed"); + dev_err(&iface->dev, + "Allocating buffer for control messages failed\n"); goto error; } @@ -250,7 +251,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->urb = usb_alloc_urb(0, GFP_KERNEL); if (!pdata->urb) { retval = -ENOMEM; - err("appledisplay: Allocating URB failed"); + dev_err(&iface->dev, "Allocating URB failed\n"); goto error; } @@ -259,7 +260,7 @@ static int appledisplay_probe(struct usb_interface *iface, GFP_KERNEL, &pdata->urb->transfer_dma); if (!pdata->urbdata) { retval = -ENOMEM; - err("appledisplay: Allocating URB buffer failed"); + dev_err(&iface->dev, "Allocating URB buffer failed\n"); goto error; } @@ -270,7 +271,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata, 1); if (usb_submit_urb(pdata->urb, GFP_KERNEL)) { retval = -EIO; - err("appledisplay: Submitting URB failed"); + dev_err(&iface->dev, "Submitting URB failed\n"); goto error; } @@ -280,7 +281,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->bd = backlight_device_register(bl_name, NULL, pdata, &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { - err("appledisplay: Backlight registration failed"); + dev_err(&iface->dev, "Backlight registration failed\n"); goto error; } @@ -291,7 +292,8 @@ static int appledisplay_probe(struct usb_interface *iface, if (brightness < 0) { retval = brightness; - err("appledisplay: Error while getting initial brightness: %d", retval); + dev_err(&iface->dev, + "Error while getting initial brightness: %d\n", retval); goto error; } @@ -314,7 +316,7 @@ error: pdata->urbdata, pdata->urb->transfer_dma); usb_free_urb(pdata->urb); } - if (pdata->bd) + if (pdata->bd && !IS_ERR(pdata->bd)) backlight_device_unregister(pdata->bd); kfree(pdata->msgdata); } @@ -352,7 +354,7 @@ static int __init appledisplay_init(void) { wq = create_singlethread_workqueue("appledisplay"); if (!wq) { - err("Could not create work queue\n"); + printk(KERN_ERR "appledisplay: Could not create work queue\n"); return -ENOMEM; } diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index 937940404b7..5720bfef6a3 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -278,9 +278,9 @@ static int __init cypress_init(void) /* register this driver with the USB subsystem */ result = usb_register(&cypress_driver); - if (result) { - err("Function usb_register failed! Error number: %d\n", result); - } + if (result) + printk(KERN_ERR KBUILD_MODNAME ": usb_register failed! " + "Error number: %d\n", result); return result; } diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 1cd9e7eba93..4fb3c38b924 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -422,13 +422,14 @@ static int __init usb_cytherm_init(void) int result; result = usb_register(&cytherm_driver); - if (result) - { - err("usb_register failed. Error number %d", result); + if (result) { + printk(KERN_ERR KBUILD_MODNAME ": usb_register failed! " + "Error number: %d\n", result); return result; } - info(DRIVER_VERSION ":" DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return 0; } diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index 4b994a0cd27..e762beb5f3c 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -50,7 +50,7 @@ static int emi26_writememory (struct usb_device *dev, int address, unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); if (!buffer) { - err("emi26: kmalloc(%d) failed.", length); + dev_err(&dev->dev, "kmalloc(%d) failed.\n", length); return -ENOMEM; } /* Note: usb_control_msg returns negative value on error or length of the @@ -64,11 +64,11 @@ static int emi26_writememory (struct usb_device *dev, int address, static int emi26_set_reset (struct usb_device *dev, unsigned char reset_bit) { int response; - info("%s - %d", __func__, reset_bit); + dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); /* printk(KERN_DEBUG "%s - %d", __func__, reset_bit); */ response = emi26_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) { - err("emi26: set_reset (%d) failed", reset_bit); + dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit); } return response; } @@ -88,7 +88,8 @@ static int emi26_load_firmware (struct usb_device *dev) buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); if (!buf) { - err( "%s - error loading firmware: error = %d", __func__, -ENOMEM); + dev_err(&dev->dev, "%s - error loading firmware: error = %d\n", + __func__, -ENOMEM); err = -ENOMEM; goto wraperr; } @@ -106,14 +107,16 @@ static int emi26_load_firmware (struct usb_device *dev) &dev->dev); if (err) { nofw: - err( "%s - request_firmware() failed", __func__); + dev_err(&dev->dev, "%s - request_firmware() failed\n", + __func__); goto wraperr; } /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); if (err < 0) { - err( "%s - error loading firmware: error = %d", __func__, err); + dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", + __func__, err); goto wraperr; } @@ -254,7 +257,7 @@ static int emi26_probe(struct usb_interface *intf, const struct usb_device_id *i { struct usb_device *dev = interface_to_usbdev(intf); - info("%s start", __func__); + dev_info(&intf->dev, "%s start\n", __func__); emi26_load_firmware(dev); diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index 5d859ded5bb..602ee05ba9f 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -73,7 +73,7 @@ static int emi62_writememory(struct usb_device *dev, int address, static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit) { int response; - info("%s - %d", __func__, reset_bit); + dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) { @@ -271,7 +271,7 @@ static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *i struct usb_device *dev = interface_to_usbdev(intf); dev_dbg(&intf->dev, "emi62_probe\n"); - info("%s start", __func__); + dev_info(&intf->dev, "%s start\n", __func__); emi62_load_firmware(dev); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 97c28097153..79a7668ef26 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -698,7 +698,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, int retval = usb_bulk_msg(ftdi->udev, usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, msecs_to_jiffies(50)); + &packet_bytes, 50); if (packet_bytes > 2) { ftdi->bulk_in_left = packet_bytes - 2; ftdi->bulk_in_last = 1; @@ -960,7 +960,7 @@ static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) int retval = usb_bulk_msg(ftdi->udev, usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, msecs_to_jiffies(500)); + &packet_bytes, 500); char diag[30 *3 + 4]; char *d = diag; int m = packet_bytes; @@ -1880,7 +1880,7 @@ static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) int retval = usb_bulk_msg(ftdi->udev, usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, msecs_to_jiffies(100)); + &packet_bytes, 100); if (packet_bytes > 2) { char diag[30 *3 + 4]; char *d = diag; @@ -2067,7 +2067,7 @@ static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, msecs_to_jiffies(500)); + &packet_bytes, 500); if (packet_bytes > 2) { char diag[30 *3 + 4]; char *d = diag; @@ -2176,7 +2176,7 @@ static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) int retval = usb_bulk_msg(ftdi->udev, usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, msecs_to_jiffies(1000)); + &packet_bytes, 1000); if (packet_bytes > 2) { char diag[30 *3 + 4]; char *d = diag; diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 4bcf7fb4e5d..6da8887538c 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -403,14 +403,15 @@ static void idmouse_disconnect(struct usb_interface *interface) mutex_unlock(&dev->lock); } - info("%s disconnected", DRIVER_DESC); + dev_info(&interface->dev, "disconnected\n"); } static int __init usb_idmouse_init(void) { int result; - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); /* register this driver with the USB subsystem */ result = usb_register(&idmouse_driver); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 9370326a594..ab0f3226158 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -851,9 +851,8 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dbg(2, "%s: enter", __func__); - if (udev == NULL) { - info ("udev is NULL."); - } + if (udev == NULL) + dev_info(&interface->dev, "udev is NULL.\n"); /* allocate memory for our device state and initialize it */ @@ -954,7 +953,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev->minor = interface->minor; /* let the user know what node this device is now attached to */ - info ("LEGO USB Tower #%d now attached to major %d minor %d", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), USB_MAJOR, dev->minor); + dev_info(&interface->dev, "LEGO USB Tower #%d now attached to major " + "%d minor %d\n", (dev->minor - LEGO_USB_TOWER_MINOR_BASE), + USB_MAJOR, dev->minor); /* get the firmware version and log it */ result = usb_control_msg (udev, @@ -971,10 +972,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device retval = result; goto error; } - info("LEGO USB Tower firmware version is %d.%d build %d", - get_version_reply.major, - get_version_reply.minor, - le16_to_cpu(get_version_reply.build_no)); + dev_info(&interface->dev, "LEGO USB Tower firmware version is %d.%d " + "build %d\n", get_version_reply.major, + get_version_reply.minor, + le16_to_cpu(get_version_reply.build_no)); exit: @@ -1021,7 +1022,8 @@ static void tower_disconnect (struct usb_interface *interface) mutex_unlock(&dev->lock); } - info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE)); + dev_info(&interface->dev, "LEGO USB Tower #%d now disconnected\n", + (minor - LEGO_USB_TOWER_MINOR_BASE)); dbg(2, "%s: leave", __func__); } @@ -1046,7 +1048,8 @@ static int __init lego_usb_tower_init(void) goto exit; } - info(DRIVER_DESC " " DRIVER_VERSION); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); exit: dbg(2, "%s: leave, return value %d", __func__, retval); diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 248a12aacef..deb95bb49fd 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -89,7 +89,7 @@ static int open_rio(struct inode *inode, struct file *file) mutex_unlock(&(rio->lock)); - info("Rio opened."); + dev_info(&rio->rio_dev->dev, "Rio opened.\n"); return 0; } @@ -100,7 +100,7 @@ static int close_rio(struct inode *inode, struct file *file) rio->isopen = 0; - info("Rio closed."); + dev_info(&rio->rio_dev->dev, "Rio closed.\n"); return 0; } @@ -451,7 +451,7 @@ static int probe_rio(struct usb_interface *intf, struct rio_usb_data *rio = &rio_instance; int retval; - info("USB Rio found at address %d", dev->devnum); + dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum); retval = usb_register_dev(intf, &usb_rio_class); if (retval) { @@ -503,7 +503,7 @@ static void disconnect_rio(struct usb_interface *intf) kfree(rio->ibuf); kfree(rio->obuf); - info("USB Rio disconnected."); + dev_info(&intf->dev, "USB Rio disconnected.\n"); rio->present = 0; mutex_unlock(&(rio->lock)); @@ -531,7 +531,8 @@ static int __init usb_rio_init(void) if (retval) goto out; - info(DRIVER_VERSION ":" DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); out: return retval; diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 03368edf3f2..2e14102955c 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -144,7 +144,8 @@ static int __init tv_init(void) return retval; } - info(DRIVER_VERSION ":" DRIVER_DESC); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); return 0; } diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 2db4228fbb0..e0ff9ccd866 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -311,7 +311,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id dev->interface = interface; if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) { - warn(KERN_INFO "USBLCD model not supported."); + dev_warn(&interface->dev, "USBLCD model not supported.\n"); return -ENODEV; } @@ -359,12 +359,13 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id i = le16_to_cpu(dev->udev->descriptor.bcdDevice); - info("USBLCD Version %1d%1d.%1d%1d found at address %d", - (i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF), - dev->udev->devnum); + dev_info(&interface->dev, "USBLCD Version %1d%1d.%1d%1d found " + "at address %d\n", (i & 0xF000)>>12, (i & 0xF00)>>8, + (i & 0xF0)>>4,(i & 0xF), dev->udev->devnum); /* let the user know what node this device is now attached to */ - info("USB LCD device now attached to USBLCD-%d", interface->minor); + dev_info(&interface->dev, "USB LCD device now attached to USBLCD-%d\n", + interface->minor); return 0; error: @@ -413,7 +414,7 @@ static void lcd_disconnect(struct usb_interface *interface) /* decrement our usage count */ kref_put(&dev->kref, lcd_delete); - info("USB LCD #%d now disconnected", minor); + dev_info(&interface->dev, "USB LCD #%d now disconnected\n", minor); } static struct usb_driver lcd_driver = { diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c new file mode 100644 index 00000000000..28a6a3a0953 --- /dev/null +++ b/drivers/usb/misc/usbsevseg.c @@ -0,0 +1,394 @@ +/* + * USB 7 Segment Driver + * + * Copyright (C) 2008 Harrison Metzger <harrisonmetz@gmail.com> + * Based on usbled.c by Greg Kroah-Hartman (greg@kroah.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/usb.h> + + +#define DRIVER_AUTHOR "Harrison Metzger <harrisonmetz@gmail.com>" +#define DRIVER_DESC "USB 7 Segment Driver" + +#define VENDOR_ID 0x0fc5 +#define PRODUCT_ID 0x1227 +#define MAXLEN 6 + +/* table of devices that work with this driver */ +static struct usb_device_id id_table[] = { + { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +/* the different text display modes the device is capable of */ +static char *display_textmodes[] = {"raw", "hex", "ascii", NULL}; + +struct usb_sevsegdev { + struct usb_device *udev; + + u8 powered; + u8 mode_msb; + u8 mode_lsb; + u8 decimals[MAXLEN]; + u8 textmode; + u8 text[MAXLEN]; + u16 textlength; +}; + +/* sysfs_streq can't replace this completely + * If the device was in hex mode, and the user wanted a 0, + * if str commands are used, we would assume the end of string + * so mem commands are used. + */ +inline size_t my_memlen(const char *buf, size_t count) +{ + if (count > 0 && buf[count-1] == '\n') + return count - 1; + else + return count; +} + +static void update_display_powered(struct usb_sevsegdev *mydev) +{ + int rc; + + rc = usb_control_msg(mydev->udev, + usb_sndctrlpipe(mydev->udev, 0), + 0x12, + 0x48, + (80 * 0x100) + 10, /* (power mode) */ + (0x00 * 0x100) + (mydev->powered ? 1 : 0), + NULL, + 0, + 2000); + if (rc < 0) + dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); +} + +static void update_display_mode(struct usb_sevsegdev *mydev) +{ + int rc; + + rc = usb_control_msg(mydev->udev, + usb_sndctrlpipe(mydev->udev, 0), + 0x12, + 0x48, + (82 * 0x100) + 10, /* (set mode) */ + (mydev->mode_msb * 0x100) + mydev->mode_lsb, + NULL, + 0, + 2000); + + if (rc < 0) + dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); +} + +static void update_display_visual(struct usb_sevsegdev *mydev) +{ + int rc; + int i; + unsigned char *buffer; + u8 decimals = 0; + + buffer = kzalloc(MAXLEN, GFP_KERNEL); + if (!buffer) { + dev_err(&mydev->udev->dev, "out of memory\n"); + return; + } + + /* The device is right to left, where as you write left to right */ + for (i = 0; i < mydev->textlength; i++) + buffer[i] = mydev->text[mydev->textlength-1-i]; + + rc = usb_control_msg(mydev->udev, + usb_sndctrlpipe(mydev->udev, 0), + 0x12, + 0x48, + (85 * 0x100) + 10, /* (write text) */ + (0 * 0x100) + mydev->textmode, /* mode */ + buffer, + mydev->textlength, + 2000); + + if (rc < 0) + dev_dbg(&mydev->udev->dev, "write retval = %d\n", rc); + + kfree(buffer); + + /* The device is right to left, where as you write left to right */ + for (i = 0; i < sizeof(mydev->decimals); i++) + decimals |= mydev->decimals[i] << i; + + rc = usb_control_msg(mydev->udev, + usb_sndctrlpipe(mydev->udev, 0), + 0x12, + 0x48, + (86 * 0x100) + 10, /* (set decimal) */ + (0 * 0x100) + decimals, /* decimals */ + NULL, + 0, + 2000); + + if (rc < 0) + dev_dbg(&mydev->udev->dev, "decimal retval = %d\n", rc); +} + +#define MYDEV_ATTR_SIMPLE_UNSIGNED(name, update_fcn) \ +static ssize_t show_attr_##name(struct device *dev, \ + struct device_attribute *attr, char *buf) \ +{ \ + struct usb_interface *intf = to_usb_interface(dev); \ + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ + \ + return sprintf(buf, "%u\n", mydev->name); \ +} \ + \ +static ssize_t set_attr_##name(struct device *dev, \ + struct device_attribute *attr, const char *buf, size_t count) \ +{ \ + struct usb_interface *intf = to_usb_interface(dev); \ + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ + \ + mydev->name = simple_strtoul(buf, NULL, 10); \ + update_fcn(mydev); \ + \ + return count; \ +} \ +static DEVICE_ATTR(name, S_IWUGO | S_IRUGO, show_attr_##name, set_attr_##name); + +static ssize_t show_attr_text(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + + return snprintf(buf, mydev->textlength, "%s\n", mydev->text); +} + +static ssize_t set_attr_text(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + size_t end = my_memlen(buf, count); + + if (end > sizeof(mydev->text)) + return -EINVAL; + + memset(mydev->text, 0, sizeof(mydev->text)); + mydev->textlength = end; + + if (end > 0) + memcpy(mydev->text, buf, end); + + update_display_visual(mydev); + return count; +} + +static DEVICE_ATTR(text, S_IWUGO | S_IRUGO, show_attr_text, set_attr_text); + +static ssize_t show_attr_decimals(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + int i; + int pos; + + for (i = 0; i < sizeof(mydev->decimals); i++) { + pos = sizeof(mydev->decimals) - 1 - i; + if (mydev->decimals[i] == 0) + buf[pos] = '0'; + else if (mydev->decimals[i] == 1) + buf[pos] = '1'; + else + buf[pos] = 'x'; + } + + buf[sizeof(mydev->decimals)] = '\n'; + return sizeof(mydev->decimals) + 1; +} + +static ssize_t set_attr_decimals(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + size_t end = my_memlen(buf, count); + int i; + + if (end > sizeof(mydev->decimals)) + return -EINVAL; + + for (i = 0; i < end; i++) + if (buf[i] != '0' && buf[i] != '1') + return -EINVAL; + + memset(mydev->decimals, 0, sizeof(mydev->decimals)); + for (i = 0; i < end; i++) + if (buf[i] == '1') + mydev->decimals[end-1-i] = 1; + + update_display_visual(mydev); + + return count; +} + +static DEVICE_ATTR(decimals, S_IWUGO | S_IRUGO, + show_attr_decimals, set_attr_decimals); + +static ssize_t show_attr_textmode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + int i; + + buf[0] = 0; + + for (i = 0; display_textmodes[i]; i++) { + if (mydev->textmode == i) { + strcat(buf, " ["); + strcat(buf, display_textmodes[i]); + strcat(buf, "] "); + } else { + strcat(buf, " "); + strcat(buf, display_textmodes[i]); + strcat(buf, " "); + } + } + strcat(buf, "\n"); + + + return strlen(buf); +} + +static ssize_t set_attr_textmode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct usb_interface *intf = to_usb_interface(dev); + struct usb_sevsegdev *mydev = usb_get_intfdata(intf); + int i; + + for (i = 0; display_textmodes[i]; i++) { + if (sysfs_streq(display_textmodes[i], buf)) { + mydev->textmode = i; + update_display_visual(mydev); + return count; + } + } + + return -EINVAL; +} + +static DEVICE_ATTR(textmode, S_IWUGO | S_IRUGO, + show_attr_textmode, set_attr_textmode); + + +MYDEV_ATTR_SIMPLE_UNSIGNED(powered, update_display_powered); +MYDEV_ATTR_SIMPLE_UNSIGNED(mode_msb, update_display_mode); +MYDEV_ATTR_SIMPLE_UNSIGNED(mode_lsb, update_display_mode); + +static struct attribute *dev_attrs[] = { + &dev_attr_powered.attr, + &dev_attr_text.attr, + &dev_attr_textmode.attr, + &dev_attr_decimals.attr, + &dev_attr_mode_msb.attr, + &dev_attr_mode_lsb.attr, + NULL +}; + +static struct attribute_group dev_attr_grp = { + .attrs = dev_attrs, +}; + +static int sevseg_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(interface); + struct usb_sevsegdev *mydev = NULL; + int rc = -ENOMEM; + + mydev = kzalloc(sizeof(struct usb_sevsegdev), GFP_KERNEL); + if (mydev == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + goto error_mem; + } + + mydev->udev = usb_get_dev(udev); + usb_set_intfdata(interface, mydev); + + /*set defaults */ + mydev->textmode = 0x02; /* ascii mode */ + mydev->mode_msb = 0x06; /* 6 characters */ + mydev->mode_lsb = 0x3f; /* scanmode for 6 chars */ + + rc = sysfs_create_group(&interface->dev.kobj, &dev_attr_grp); + if (rc) + goto error; + + dev_info(&interface->dev, "USB 7 Segment device now attached\n"); + return 0; + +error: + usb_set_intfdata(interface, NULL); + usb_put_dev(mydev->udev); + kfree(mydev); +error_mem: + return rc; +} + +static void sevseg_disconnect(struct usb_interface *interface) +{ + struct usb_sevsegdev *mydev; + + mydev = usb_get_intfdata(interface); + sysfs_remove_group(&interface->dev.kobj, &dev_attr_grp); + usb_set_intfdata(interface, NULL); + usb_put_dev(mydev->udev); + kfree(mydev); + dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); +} + +static struct usb_driver sevseg_driver = { + .name = "usbsevseg", + .probe = sevseg_probe, + .disconnect = sevseg_disconnect, + .id_table = id_table, +}; + +static int __init usb_sevseg_init(void) +{ + int rc = 0; + + rc = usb_register(&sevseg_driver); + if (rc) + err("usb_register failed. Error number %d", rc); + return rc; +} + +static void __exit usb_sevseg_exit(void) +{ + usb_deregister(&sevseg_driver); +} + +module_init(usb_sevseg_init); +module_exit(usb_sevseg_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index f1255b0a182..9a6c27a0179 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -228,11 +228,12 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha ret = rq->urb->status; *val = priv->reg[(reg >= 9) ? 0 : regindex[reg]]; if (ret) - warn("get_1284_register: usb error %d", ret); + printk(KERN_WARNING "get_1284_register: " + "usb error %d\n", ret); kref_put(&rq->ref_count, destroy_async); return ret; } - warn("get_1284_register timeout"); + printk(KERN_WARNING "get_1284_register timeout\n"); kill_all_async_requests_priv(priv); return -EIO; } @@ -716,7 +717,7 @@ static int uss720_probe(struct usb_interface *intf, spin_lock_init(&priv->asynclock); INIT_LIST_HEAD(&priv->asynclist); if (!(pp = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &parport_uss720_ops))) { - warn("could not register parport"); + printk(KERN_WARNING "uss720: could not register parport\n"); goto probe_abort; } @@ -800,10 +801,14 @@ static int __init uss720_init(void) if (retval) goto out; - info(DRIVER_VERSION ":" DRIVER_DESC); - info("NOTE: this is a special purpose driver to allow nonstandard"); - info("protocols (eg. bitbang) over USS720 usb to parallel cables"); - info("If you just want to connect to a printer, use usblp instead"); + printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" + DRIVER_DESC "\n"); + printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose " + "driver to allow nonstandard\n"); + printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over " + "USS720 usb to parallel cables\n"); + printk(KERN_INFO KBUILD_MODNAME ": If you just want to connect to a " + "printer, use usblp instead\n"); out: return retval; } diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c new file mode 100644 index 00000000000..8648470c81c --- /dev/null +++ b/drivers/usb/misc/vstusb.c @@ -0,0 +1,782 @@ +/***************************************************************************** + * File: drivers/usb/misc/vstusb.c + * + * Purpose: Support for the bulk USB Vernier Spectrophotometers + * + * Author: Johnnie Peters + * Axian Consulting + * Beaverton, OR, USA 97005 + * + * Modified by: EQware Engineering, Inc. + * Oregon City, OR, USA 97045 + * + * Copyright: 2007, 2008 + * Vernier Software & Technology + * Beaverton, OR, USA 97005 + * + * Web: www.vernier.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + *****************************************************************************/ +#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 <linux/uaccess.h> +#include <linux/usb.h> + +#include <linux/usb/vstusb.h> + +#define DRIVER_VERSION "VST USB Driver Version 1.5" +#define DRIVER_DESC "Vernier Software Technology Bulk USB Driver" + +#ifdef CONFIG_USB_DYNAMIC_MINORS + #define VSTUSB_MINOR_BASE 0 +#else + #define VSTUSB_MINOR_BASE 199 +#endif + +#define USB_VENDOR_OCEANOPTICS 0x2457 +#define USB_VENDOR_VERNIER 0x08F7 /* Vernier Software & Technology */ + +#define USB_PRODUCT_USB2000 0x1002 +#define USB_PRODUCT_ADC1000_FW 0x1003 /* firmware download (renumerates) */ +#define USB_PRODUCT_ADC1000 0x1004 +#define USB_PRODUCT_HR2000_FW 0x1009 /* firmware download (renumerates) */ +#define USB_PRODUCT_HR2000 0x100A +#define USB_PRODUCT_HR4000_FW 0x1011 /* firmware download (renumerates) */ +#define USB_PRODUCT_HR4000 0x1012 +#define USB_PRODUCT_USB650 0x1014 /* "Red Tide" */ +#define USB_PRODUCT_QE65000 0x1018 +#define USB_PRODUCT_USB4000 0x1022 +#define USB_PRODUCT_USB325 0x1024 /* "Vernier Spectrometer" */ + +#define USB_PRODUCT_LABPRO 0x0001 +#define USB_PRODUCT_LABQUEST 0x0005 + +#define VST_MAXBUFFER (64*1024) + +static struct usb_device_id id_table[] = { + { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)}, + { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)}, + { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)}, + { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)}, + { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)}, + { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)}, + { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)}, + {}, +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +struct vstusb_device { + struct kref kref; + struct mutex lock; + struct usb_device *usb_dev; + char present; + char isopen; + struct usb_anchor submitted; + int rd_pipe; + int rd_timeout_ms; + int wr_pipe; + int wr_timeout_ms; +}; +#define to_vst_dev(d) container_of(d, struct vstusb_device, kref) + +static struct usb_driver vstusb_driver; + +static void vstusb_delete(struct kref *kref) +{ + struct vstusb_device *vstdev = to_vst_dev(kref); + + usb_put_dev(vstdev->usb_dev); + kfree(vstdev); +} + +static int vstusb_open(struct inode *inode, struct file *file) +{ + struct vstusb_device *vstdev; + struct usb_interface *interface; + + interface = usb_find_interface(&vstusb_driver, iminor(inode)); + + if (!interface) { + printk(KERN_ERR KBUILD_MODNAME + ": %s - error, can't find device for minor %d\n", + __func__, iminor(inode)); + return -ENODEV; + } + + vstdev = usb_get_intfdata(interface); + + if (!vstdev) + return -ENODEV; + + /* lock this device */ + mutex_lock(&vstdev->lock); + + /* can only open one time */ + if ((!vstdev->present) || (vstdev->isopen)) { + mutex_unlock(&vstdev->lock); + return -EBUSY; + } + + /* increment our usage count */ + kref_get(&vstdev->kref); + + vstdev->isopen = 1; + + /* save device in the file's private structure */ + file->private_data = vstdev; + + dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__); + + mutex_unlock(&vstdev->lock); + + return 0; +} + +static int vstusb_release(struct inode *inode, struct file *file) +{ + struct vstusb_device *vstdev; + + vstdev = file->private_data; + + if (vstdev == NULL) + return -ENODEV; + + mutex_lock(&vstdev->lock); + + vstdev->isopen = 0; + + dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__); + + mutex_unlock(&vstdev->lock); + + kref_put(&vstdev->kref, vstusb_delete); + + return 0; +} + +static void usb_api_blocking_completion(struct urb *urb) +{ + struct completion *completeit = urb->context; + + complete(completeit); +} + +static int vstusb_fill_and_send_urb(struct urb *urb, + struct usb_device *usb_dev, + unsigned int pipe, void *data, + unsigned int len, struct completion *done) +{ + struct usb_host_endpoint *ep; + struct usb_host_endpoint **hostep; + unsigned int pipend; + + int status; + + hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out; + pipend = usb_pipeendpoint(pipe); + ep = hostep[pipend]; + + if (!ep || (len == 0)) + return -EINVAL; + + if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) + == USB_ENDPOINT_XFER_INT) { + pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30); + usb_fill_int_urb(urb, usb_dev, pipe, data, len, + (usb_complete_t)usb_api_blocking_completion, + NULL, ep->desc.bInterval); + } else + usb_fill_bulk_urb(urb, usb_dev, pipe, data, len, + (usb_complete_t)usb_api_blocking_completion, + NULL); + + init_completion(done); + urb->context = done; + urb->actual_length = 0; + status = usb_submit_urb(urb, GFP_KERNEL); + + return status; +} + +static int vstusb_complete_urb(struct urb *urb, struct completion *done, + int timeout, int *actual_length) +{ + unsigned long expire; + int status; + + expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT; + if (!wait_for_completion_interruptible_timeout(done, expire)) { + usb_kill_urb(urb); + status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status; + + dev_dbg(&urb->dev->dev, + "%s timed out on ep%d%s len=%d/%d, urb status = %d\n", + current->comm, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->actual_length, + urb->transfer_buffer_length, + urb->status); + + } else { + if (signal_pending(current)) { + /* if really an error */ + if (urb->status && !((urb->status == -ENOENT) || + (urb->status == -ECONNRESET) || + (urb->status == -ESHUTDOWN))) { + status = -EINTR; + usb_kill_urb(urb); + } else { + status = 0; + } + + dev_dbg(&urb->dev->dev, + "%s: signal pending on ep%d%s len=%d/%d," + "urb status = %d\n", + current->comm, + usb_pipeendpoint(urb->pipe), + usb_pipein(urb->pipe) ? "in" : "out", + urb->actual_length, + urb->transfer_buffer_length, + urb->status); + + } else { + status = urb->status; + } + } + + if (actual_length) + *actual_length = urb->actual_length; + + return status; +} + +static ssize_t vstusb_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + struct vstusb_device *vstdev; + int cnt = -1; + void *buf; + int retval = 0; + + struct urb *urb; + struct usb_device *dev; + unsigned int pipe; + int timeout; + + DECLARE_COMPLETION_ONSTACK(done); + + vstdev = file->private_data; + + if (vstdev == NULL) + return -ENODEV; + + /* verify that we actually want to read some data */ + if ((count == 0) || (count > VST_MAXBUFFER)) + return -EINVAL; + + /* lock this object */ + if (mutex_lock_interruptible(&vstdev->lock)) + return -ERESTARTSYS; + + /* anyone home */ + if (!vstdev->present) { + mutex_unlock(&vstdev->lock); + printk(KERN_ERR KBUILD_MODNAME + ": %s: device not present\n", __func__); + return -ENODEV; + } + + /* pull out the necessary data */ + dev = vstdev->usb_dev; + pipe = usb_rcvbulkpipe(dev, vstdev->rd_pipe); + timeout = vstdev->rd_timeout_ms; + + buf = kmalloc(count, GFP_KERNEL); + if (buf == NULL) { + mutex_unlock(&vstdev->lock); + return -ENOMEM; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + kfree(buf); + mutex_unlock(&vstdev->lock); + return -ENOMEM; + } + + usb_anchor_urb(urb, &vstdev->submitted); + retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done); + mutex_unlock(&vstdev->lock); + if (retval) { + usb_unanchor_urb(urb); + dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n", + __func__, retval, pipe); + goto exit; + } + + retval = vstusb_complete_urb(urb, &done, timeout, &cnt); + if (retval) { + dev_err(&dev->dev, "%s: error %d completing urb %d\n", + __func__, retval, pipe); + goto exit; + } + + if (copy_to_user(buffer, buf, cnt)) { + dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__); + retval = -EFAULT; + } else { + retval = cnt; + dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n", + __func__, cnt, pipe); + } + +exit: + usb_free_urb(urb); + kfree(buf); + return retval; +} + +static ssize_t vstusb_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct vstusb_device *vstdev; + int cnt = -1; + void *buf; + int retval = 0; + + struct urb *urb; + struct usb_device *dev; + unsigned int pipe; + int timeout; + + DECLARE_COMPLETION_ONSTACK(done); + + vstdev = file->private_data; + + if (vstdev == NULL) + return -ENODEV; + + /* verify that we actually have some data to write */ + if ((count == 0) || (count > VST_MAXBUFFER)) + return retval; + + /* lock this object */ + if (mutex_lock_interruptible(&vstdev->lock)) + return -ERESTARTSYS; + + /* anyone home */ + if (!vstdev->present) { + mutex_unlock(&vstdev->lock); + printk(KERN_ERR KBUILD_MODNAME + ": %s: device not present\n", __func__); + return -ENODEV; + } + + /* pull out the necessary data */ + dev = vstdev->usb_dev; + pipe = usb_sndbulkpipe(dev, vstdev->wr_pipe); + timeout = vstdev->wr_timeout_ms; + + buf = kmalloc(count, GFP_KERNEL); + if (buf == NULL) { + mutex_unlock(&vstdev->lock); + return -ENOMEM; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + kfree(buf); + mutex_unlock(&vstdev->lock); + return -ENOMEM; + } + + if (copy_from_user(buf, buffer, count)) { + dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__); + retval = -EFAULT; + goto exit; + } + + usb_anchor_urb(urb, &vstdev->submitted); + retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done); + mutex_unlock(&vstdev->lock); + if (retval) { + usb_unanchor_urb(urb); + dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n", + __func__, retval, pipe); + goto exit; + } + + retval = vstusb_complete_urb(urb, &done, timeout, &cnt); + if (retval) { + dev_err(&dev->dev, "%s: error %d completing urb %d\n", + __func__, retval, pipe); + goto exit; + } else { + retval = cnt; + dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n", + __func__, cnt, pipe); + } + +exit: + usb_free_urb(urb); + kfree(buf); + return retval; +} + +static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + int cnt = -1; + void __user *data = (void __user *)arg; + struct vstusb_args usb_data; + + struct vstusb_device *vstdev; + void *buffer = NULL; /* must be initialized. buffer is + * referenced on exit but not all + * ioctls allocate it */ + + struct urb *urb = NULL; /* must be initialized. urb is + * referenced on exit but not all + * ioctls allocate it */ + struct usb_device *dev; + unsigned int pipe; + int timeout; + + DECLARE_COMPLETION_ONSTACK(done); + + vstdev = file->private_data; + + if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) { + dev_warn(&vstdev->usb_dev->dev, + "%s: ioctl command %x, bad ioctl magic %x, " + "expected %x\n", __func__, cmd, + _IOC_TYPE(cmd), VST_IOC_MAGIC); + return -EINVAL; + } + + if (vstdev == NULL) + return -ENODEV; + + if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) { + dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n", + __func__); + return -EFAULT; + } + + /* lock this object */ + if (mutex_lock_interruptible(&vstdev->lock)) { + retval = -ERESTARTSYS; + goto exit; + } + + /* anyone home */ + if (!vstdev->present) { + mutex_unlock(&vstdev->lock); + dev_err(&vstdev->usb_dev->dev, "%s: device not present\n", + __func__); + retval = -ENODEV; + goto exit; + } + + /* pull out the necessary data */ + dev = vstdev->usb_dev; + + switch (cmd) { + + case IOCTL_VSTUSB_CONFIG_RW: + + vstdev->rd_pipe = usb_data.rd_pipe; + vstdev->rd_timeout_ms = usb_data.rd_timeout_ms; + vstdev->wr_pipe = usb_data.wr_pipe; + vstdev->wr_timeout_ms = usb_data.wr_timeout_ms; + + mutex_unlock(&vstdev->lock); + + dev_dbg(&dev->dev, "%s: setting pipes/timeouts, " + "rdpipe = %d, rdtimeout = %d, " + "wrpipe = %d, wrtimeout = %d\n", __func__, + vstdev->rd_pipe, vstdev->rd_timeout_ms, + vstdev->wr_pipe, vstdev->wr_timeout_ms); + break; + + case IOCTL_VSTUSB_SEND_PIPE: + + if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { + mutex_unlock(&vstdev->lock); + retval = -EINVAL; + goto exit; + } + + buffer = kmalloc(usb_data.count, GFP_KERNEL); + if (buffer == NULL) { + mutex_unlock(&vstdev->lock); + retval = -ENOMEM; + goto exit; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + mutex_unlock(&vstdev->lock); + retval = -ENOMEM; + goto exit; + } + + timeout = usb_data.timeout_ms; + + pipe = usb_sndbulkpipe(dev, usb_data.pipe); + + if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) { + dev_err(&dev->dev, "%s: can't copy_from_user\n", + __func__); + mutex_unlock(&vstdev->lock); + retval = -EFAULT; + goto exit; + } + + usb_anchor_urb(urb, &vstdev->submitted); + retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer, + usb_data.count, &done); + mutex_unlock(&vstdev->lock); + if (retval) { + usb_unanchor_urb(urb); + dev_err(&dev->dev, + "%s: error %d filling and sending urb %d\n", + __func__, retval, pipe); + goto exit; + } + + retval = vstusb_complete_urb(urb, &done, timeout, &cnt); + if (retval) { + dev_err(&dev->dev, "%s: error %d completing urb %d\n", + __func__, retval, pipe); + } + + break; + case IOCTL_VSTUSB_RECV_PIPE: + + if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) { + mutex_unlock(&vstdev->lock); + retval = -EINVAL; + goto exit; + } + + buffer = kmalloc(usb_data.count, GFP_KERNEL); + if (buffer == NULL) { + mutex_unlock(&vstdev->lock); + retval = -ENOMEM; + goto exit; + } + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + mutex_unlock(&vstdev->lock); + retval = -ENOMEM; + goto exit; + } + + timeout = usb_data.timeout_ms; + + pipe = usb_rcvbulkpipe(dev, usb_data.pipe); + + usb_anchor_urb(urb, &vstdev->submitted); + retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer, + usb_data.count, &done); + mutex_unlock(&vstdev->lock); + if (retval) { + usb_unanchor_urb(urb); + dev_err(&dev->dev, + "%s: error %d filling and sending urb %d\n", + __func__, retval, pipe); + goto exit; + } + + retval = vstusb_complete_urb(urb, &done, timeout, &cnt); + if (retval) { + dev_err(&dev->dev, "%s: error %d completing urb %d\n", + __func__, retval, pipe); + goto exit; + } + + if (copy_to_user(usb_data.buffer, buffer, cnt)) { + dev_err(&dev->dev, "%s: can't copy_to_user\n", + __func__); + retval = -EFAULT; + goto exit; + } + + usb_data.count = cnt; + if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) { + dev_err(&dev->dev, "%s: can't copy_to_user\n", + __func__); + retval = -EFAULT; + } else { + dev_dbg(&dev->dev, "%s: recv %d bytes from pipe %d\n", + __func__, usb_data.count, usb_data.pipe); + } + + break; + + default: + mutex_unlock(&vstdev->lock); + dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n", + cmd); + return -EINVAL; + break; + } +exit: + usb_free_urb(urb); + kfree(buffer); + return retval; +} + +static const struct file_operations vstusb_fops = { + .owner = THIS_MODULE, + .read = vstusb_read, + .write = vstusb_write, + .unlocked_ioctl = vstusb_ioctl, + .compat_ioctl = vstusb_ioctl, + .open = vstusb_open, + .release = vstusb_release, +}; + +static struct usb_class_driver usb_vstusb_class = { + .name = "usb/vstusb%d", + .fops = &vstusb_fops, + .minor_base = VSTUSB_MINOR_BASE, +}; + +static int vstusb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev(intf); + struct vstusb_device *vstdev; + int i; + int retval = 0; + + /* allocate memory for our device state and intialize it */ + + vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL); + if (vstdev == NULL) + return -ENOMEM; + + /* must do usb_get_dev() prior to kref_init() since the kref_put() + * release function will do a usb_put_dev() */ + usb_get_dev(dev); + kref_init(&vstdev->kref); + mutex_init(&vstdev->lock); + + i = dev->descriptor.bcdDevice; + + dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n", + (i & 0xF000) >> 12, (i & 0xF00) >> 8, + (i & 0xF0) >> 4, (i & 0xF), dev->devnum); + + vstdev->present = 1; + vstdev->isopen = 0; + vstdev->usb_dev = dev; + init_usb_anchor(&vstdev->submitted); + + usb_set_intfdata(intf, vstdev); + retval = usb_register_dev(intf, &usb_vstusb_class); + if (retval) { + dev_err(&intf->dev, + "%s: Not able to get a minor for this device.\n", + __func__); + usb_set_intfdata(intf, NULL); + kref_put(&vstdev->kref, vstusb_delete); + return retval; + } + + /* let the user know what node this device is now attached to */ + dev_info(&intf->dev, + "VST USB Device #%d now attached to major %d minor %d\n", + (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor); + + dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION); + + return retval; +} + +static void vstusb_disconnect(struct usb_interface *intf) +{ + struct vstusb_device *vstdev = usb_get_intfdata(intf); + + usb_deregister_dev(intf, &usb_vstusb_class); + usb_set_intfdata(intf, NULL); + + if (vstdev) { + + mutex_lock(&vstdev->lock); + vstdev->present = 0; + + usb_kill_anchored_urbs(&vstdev->submitted); + + mutex_unlock(&vstdev->lock); + + kref_put(&vstdev->kref, vstusb_delete); + } + +} + +static int vstusb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct vstusb_device *vstdev = usb_get_intfdata(intf); + int time; + if (!vstdev) + return 0; + + mutex_lock(&vstdev->lock); + time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000); + if (!time) + usb_kill_anchored_urbs(&vstdev->submitted); + mutex_unlock(&vstdev->lock); + + return 0; +} + +static int vstusb_resume(struct usb_interface *intf) +{ + return 0; +} + +static struct usb_driver vstusb_driver = { + .name = "vstusb", + .probe = vstusb_probe, + .disconnect = vstusb_disconnect, + .suspend = vstusb_suspend, + .resume = vstusb_resume, + .id_table = id_table, +}; + +static int __init vstusb_init(void) +{ + int rc; + + rc = usb_register(&vstusb_driver); + if (rc) + printk(KERN_ERR "%s: failed to register (%d)", __func__, rc); + + return rc; +} + +static void __exit vstusb_exit(void) +{ + usb_deregister(&vstusb_driver); +} + +module_init(vstusb_init); +module_exit(vstusb_exit); + +MODULE_AUTHOR("Dennis O'Brien/Stephen Ware"); +MODULE_DESCRIPTION(DRIVER_VERSION); +MODULE_LICENSE("GPL"); |