diff options
Diffstat (limited to 'drivers/usb/misc/phidgetkit.c')
-rw-r--r-- | drivers/usb/misc/phidgetkit.c | 372 |
1 files changed, 198 insertions, 174 deletions
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index bfbbbfbb92b..78e419904ab 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -20,6 +20,8 @@ #include <linux/module.h> #include <linux/usb.h> +#include "phidget.h" + #define DRIVER_AUTHOR "Sean Young <sean@mess.org>" #define DRIVER_DESC "USB PhidgetInterfaceKit Driver" @@ -42,26 +44,35 @@ struct driver_interfacekit { int inputs; int outputs; int has_lcd; + int amnesiac; }; -#define ifkit(_sensors, _inputs, _outputs, _lcd) \ -static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \ + +#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \ +{ \ .sensors = _sensors, \ .inputs = _inputs, \ .outputs = _outputs, \ .has_lcd = _lcd, \ + .amnesiac = _amnesiac \ }; -ifkit(0, 0, 4, 0); -ifkit(8, 8, 8, 0); -ifkit(0, 4, 7, 1); -ifkit(8, 8, 4, 0); -ifkit(0, 8, 8, 1); -ifkit(0, 16, 16, 0); + +static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0); +static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1); +static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0); +static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0); +static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0); +static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0); +static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0); + +static unsigned long device_no; struct interfacekit { struct usb_device *udev; struct usb_interface *intf; struct driver_interfacekit *ifkit; + struct device *dev; unsigned long outputs; + int dev_no; u8 inputs[MAX_INTERFACES]; u16 sensors[MAX_INTERFACES]; u8 lcd_files_on; @@ -71,6 +82,7 @@ struct interfacekit { dma_addr_t data_dma; struct work_struct do_notify; + struct work_struct do_resubmit; unsigned long input_events; unsigned long sensor_events; }; @@ -78,8 +90,10 @@ struct interfacekit { static struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004), .driver_info = (kernel_ulong_t)&ph_004}, - {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888), - .driver_info = (kernel_ulong_t)&ph_888}, + {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814), + .driver_info = (kernel_ulong_t)&ph_888o}, + {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff), + .driver_info = (kernel_ulong_t)&ph_888n}, {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047), .driver_info = (kernel_ulong_t)&ph_047}, {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088), @@ -92,16 +106,11 @@ static struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int change_outputs(struct interfacekit *kit, int output_num, int enable) +static int set_outputs(struct interfacekit *kit) { u8 *buffer; int retval; - if (enable) - set_bit(output_num, &kit->outputs); - else - clear_bit(output_num, &kit->outputs); - buffer = kzalloc(4, GFP_KERNEL); if (!buffer) { dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); @@ -121,6 +130,9 @@ static int change_outputs(struct interfacekit *kit, int output_num, int enable) retval); kfree(buffer); + if (kit->ifkit->amnesiac) + schedule_delayed_work(&kit->do_resubmit, HZ / 2); + return retval < 0 ? retval : 0; } @@ -180,21 +192,24 @@ exit: } #define set_lcd_line(number) \ -static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ -{ \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct interfacekit *kit = usb_get_intfdata(intf); \ - change_string(kit, buf, number - 1); \ - return count; \ -} \ -static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number); +static ssize_t lcd_line_##number(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct interfacekit *kit = dev_get_drvdata(dev); \ + change_string(kit, buf, number - 1); \ + return count; \ +} + +#define lcd_line_attr(number) \ + __ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number) + set_lcd_line(1); set_lcd_line(2); static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_interface *intf = to_usb_interface(dev); - struct interfacekit *kit = usb_get_intfdata(intf); + struct interfacekit *kit = dev_get_drvdata(dev); int enabled; unsigned char *buffer; int retval = -ENOMEM; @@ -226,23 +241,30 @@ exit: kfree(buffer); return retval; } -static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight); + +static struct device_attribute dev_lcd_line_attrs[] = { + lcd_line_attr(1), + lcd_line_attr(2), + __ATTR(backlight, S_IWUGO, NULL, set_backlight) +}; static void remove_lcd_files(struct interfacekit *kit) { + int i; + if (kit->lcd_files_on) { dev_dbg(&kit->udev->dev, "Removing lcd files\n"); - device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1); - device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2); - device_remove_file(&kit->intf->dev, &dev_attr_backlight); + + for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) + device_remove_file(kit->dev, &dev_lcd_line_attrs[i]); } } static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct usb_interface *intf = to_usb_interface(dev); - struct interfacekit *kit = usb_get_intfdata(intf); + struct interfacekit *kit = dev_get_drvdata(dev); int enable; + int i, rc; if (kit->ifkit->has_lcd == 0) return -ENODEV; @@ -253,9 +275,12 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att if (enable) { if (!kit->lcd_files_on) { dev_dbg(&kit->udev->dev, "Adding lcd files\n"); - device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1); - device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2); - device_create_file(&kit->intf->dev, &dev_attr_backlight); + for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) { + rc = device_create_file(kit->dev, + &dev_lcd_line_attrs[i]); + if (rc) + goto out; + } kit->lcd_files_on = 1; } } else { @@ -266,7 +291,13 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att } return count; +out: + while (i-- > 0) + device_remove_file(kit->dev, &dev_lcd_line_attrs[i]); + + return rc; } + static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files); static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) @@ -362,44 +393,58 @@ static void do_notify(void *data) for (i=0; i<kit->ifkit->inputs; i++) { if (test_and_clear_bit(i, &kit->input_events)) { sprintf(sysfs_file, "input%d", i + 1); - sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file); + sysfs_notify(&kit->dev->kobj, NULL, sysfs_file); } } for (i=0; i<kit->ifkit->sensors; i++) { if (test_and_clear_bit(i, &kit->sensor_events)) { sprintf(sysfs_file, "sensor%d", i + 1); - sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file); + sysfs_notify(&kit->dev->kobj, NULL, sysfs_file); } } } +static void do_resubmit(void *data) +{ + set_outputs(data); +} + #define show_set_output(value) \ -static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \ - size_t count) \ +static ssize_t set_output##value(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ { \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct interfacekit *kit = usb_get_intfdata(intf); \ - int enabled; \ + struct interfacekit *kit = dev_get_drvdata(dev); \ + int enable; \ int retval; \ \ - if (sscanf(buf, "%d", &enabled) < 1) \ + if (sscanf(buf, "%d", &enable) < 1) \ return -EINVAL; \ \ - retval = change_outputs(kit, value - 1, enabled); \ + if (enable) \ + set_bit(value - 1, &kit->outputs); \ + else \ + clear_bit(value - 1, &kit->outputs); \ + \ + retval = set_outputs(kit); \ \ return retval ? retval : count; \ } \ \ -static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_output##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct interfacekit *kit = usb_get_intfdata(intf); \ + struct interfacekit *kit = dev_get_drvdata(dev); \ \ return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\ -} \ -static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \ - show_output##value, set_output##value); +} + +#define output_attr(value) \ + __ATTR(output##value, S_IWUGO | S_IRUGO, \ + show_output##value, set_output##value) + show_set_output(1); show_set_output(2); show_set_output(3); @@ -417,15 +462,24 @@ show_set_output(14); show_set_output(15); show_set_output(16); +static struct device_attribute dev_output_attrs[] = { + output_attr(1), output_attr(2), output_attr(3), output_attr(4), + output_attr(5), output_attr(6), output_attr(7), output_attr(8), + output_attr(9), output_attr(10), output_attr(11), output_attr(12), + output_attr(13), output_attr(14), output_attr(15), output_attr(16) +}; + #define show_input(value) \ -static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_input##value(struct device *dev, \ + struct device_attribute *attr, char *buf) \ { \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct interfacekit *kit = usb_get_intfdata(intf); \ + struct interfacekit *kit = dev_get_drvdata(dev); \ \ return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \ -} \ -static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL); +} + +#define input_attr(value) \ + __ATTR(input##value, S_IRUGO, show_input##value, NULL) show_input(1); show_input(2); @@ -444,15 +498,25 @@ show_input(14); show_input(15); show_input(16); +static struct device_attribute dev_input_attrs[] = { + input_attr(1), input_attr(2), input_attr(3), input_attr(4), + input_attr(5), input_attr(6), input_attr(7), input_attr(8), + input_attr(9), input_attr(10), input_attr(11), input_attr(12), + input_attr(13), input_attr(14), input_attr(15), input_attr(16) +}; + #define show_sensor(value) \ -static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t show_sensor##value(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ - struct usb_interface *intf = to_usb_interface(dev); \ - struct interfacekit *kit = usb_get_intfdata(intf); \ + struct interfacekit *kit = dev_get_drvdata(dev); \ \ return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \ -} \ -static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL); +} + +#define sensor_attr(value) \ + __ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL) show_sensor(1); show_sensor(2); @@ -463,6 +527,11 @@ show_sensor(6); show_sensor(7); show_sensor(8); +static struct device_attribute dev_sensor_attrs[] = { + sensor_attr(1), sensor_attr(2), sensor_attr(3), sensor_attr(4), + sensor_attr(5), sensor_attr(6), sensor_attr(7), sensor_attr(8) +}; + static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(intf); @@ -471,6 +540,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic struct interfacekit *kit; struct driver_interfacekit *ifkit; int pipe, maxp, rc = -ENOMEM; + int bit, value, i; ifkit = (struct driver_interfacekit *)id->driver_info; if (!ifkit) @@ -493,6 +563,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic if (!kit) goto out; + kit->dev_no = -1; kit->ifkit = ifkit; kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma); if (!kit->data) @@ -505,6 +576,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->udev = usb_get_dev(dev); kit->intf = intf; INIT_WORK(&kit->do_notify, do_notify, kit); + INIT_WORK(&kit->do_resubmit, do_resubmit, kit); usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, interfacekit_irq, kit, endpoint->bInterval); @@ -513,85 +585,80 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic usb_set_intfdata(intf, kit); + do { + bit = find_first_zero_bit(&device_no, sizeof(device_no)); + value = test_and_set_bit(bit, &device_no); + } while(value); + kit->dev_no = bit; + + kit->dev = device_create(phidget_class, &kit->udev->dev, 0, + "interfacekit%d", kit->dev_no); + if (IS_ERR(kit->dev)) { + rc = PTR_ERR(kit->dev); + kit->dev = NULL; + goto out; + } + dev_set_drvdata(kit->dev, kit); + if (usb_submit_urb(kit->irq, GFP_KERNEL)) { rc = -EIO; goto out; } - if (ifkit->outputs >= 4) { - device_create_file(&intf->dev, &dev_attr_output1); - device_create_file(&intf->dev, &dev_attr_output2); - device_create_file(&intf->dev, &dev_attr_output3); - device_create_file(&intf->dev, &dev_attr_output4); - } - if (ifkit->outputs >= 8) { - device_create_file(&intf->dev, &dev_attr_output5); - device_create_file(&intf->dev, &dev_attr_output6); - device_create_file(&intf->dev, &dev_attr_output7); - device_create_file(&intf->dev, &dev_attr_output8); - } - if (ifkit->outputs == 16) { - device_create_file(&intf->dev, &dev_attr_output9); - device_create_file(&intf->dev, &dev_attr_output10); - device_create_file(&intf->dev, &dev_attr_output11); - device_create_file(&intf->dev, &dev_attr_output12); - device_create_file(&intf->dev, &dev_attr_output13); - device_create_file(&intf->dev, &dev_attr_output14); - device_create_file(&intf->dev, &dev_attr_output15); - device_create_file(&intf->dev, &dev_attr_output16); + for (i=0; i<ifkit->outputs; i++ ) { + rc = device_create_file(kit->dev, &dev_output_attrs[i]); + if (rc) + goto out2; } - if (ifkit->inputs >= 4) { - device_create_file(&intf->dev, &dev_attr_input1); - device_create_file(&intf->dev, &dev_attr_input2); - device_create_file(&intf->dev, &dev_attr_input3); - device_create_file(&intf->dev, &dev_attr_input4); - } - if (ifkit->inputs >= 8) { - device_create_file(&intf->dev, &dev_attr_input5); - device_create_file(&intf->dev, &dev_attr_input6); - device_create_file(&intf->dev, &dev_attr_input7); - device_create_file(&intf->dev, &dev_attr_input8); - } - if (ifkit->inputs == 16) { - device_create_file(&intf->dev, &dev_attr_input9); - device_create_file(&intf->dev, &dev_attr_input10); - device_create_file(&intf->dev, &dev_attr_input11); - device_create_file(&intf->dev, &dev_attr_input12); - device_create_file(&intf->dev, &dev_attr_input13); - device_create_file(&intf->dev, &dev_attr_input14); - device_create_file(&intf->dev, &dev_attr_input15); - device_create_file(&intf->dev, &dev_attr_input16); + for (i=0; i<ifkit->inputs; i++ ) { + rc = device_create_file(kit->dev, &dev_input_attrs[i]); + if (rc) + goto out3; } - if (ifkit->sensors >= 4) { - device_create_file(&intf->dev, &dev_attr_sensor1); - device_create_file(&intf->dev, &dev_attr_sensor2); - device_create_file(&intf->dev, &dev_attr_sensor3); - device_create_file(&intf->dev, &dev_attr_sensor4); + for (i=0; i<ifkit->sensors; i++ ) { + rc = device_create_file(kit->dev, &dev_sensor_attrs[i]); + if (rc) + goto out4; } - if (ifkit->sensors >= 7) { - device_create_file(&intf->dev, &dev_attr_sensor5); - device_create_file(&intf->dev, &dev_attr_sensor6); - device_create_file(&intf->dev, &dev_attr_sensor7); - } - if (ifkit->sensors == 8) - device_create_file(&intf->dev, &dev_attr_sensor8); - if (ifkit->has_lcd) - device_create_file(&intf->dev, &dev_attr_lcd); + if (ifkit->has_lcd) { + rc = device_create_file(kit->dev, &dev_attr_lcd); + if (rc) + goto out4; + + } dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n", ifkit->sensors, ifkit->inputs, ifkit->outputs); return 0; +out4: + while (i-- > 0) + device_remove_file(kit->dev, &dev_sensor_attrs[i]); + + i = ifkit->inputs; +out3: + while (i-- > 0) + device_remove_file(kit->dev, &dev_input_attrs[i]); + + i = ifkit->outputs; +out2: + while (i-- > 0) + device_remove_file(kit->dev, &dev_output_attrs[i]); out: if (kit) { if (kit->irq) usb_free_urb(kit->irq); if (kit->data) usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma); + if (kit->dev) + device_unregister(kit->dev); + if (kit->dev_no >= 0) + clear_bit(kit->dev_no, &device_no); + kfree(kit); } @@ -601,6 +668,7 @@ out: static void interfacekit_disconnect(struct usb_interface *interface) { struct interfacekit *kit; + int i; kit = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); @@ -612,74 +680,30 @@ static void interfacekit_disconnect(struct usb_interface *interface) usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma); cancel_delayed_work(&kit->do_notify); + cancel_delayed_work(&kit->do_resubmit); - if (kit->ifkit->outputs >= 4) { - device_remove_file(&interface->dev, &dev_attr_output1); - device_remove_file(&interface->dev, &dev_attr_output2); - device_remove_file(&interface->dev, &dev_attr_output3); - device_remove_file(&interface->dev, &dev_attr_output4); - } - if (kit->ifkit->outputs >= 8) { - device_remove_file(&interface->dev, &dev_attr_output5); - device_remove_file(&interface->dev, &dev_attr_output6); - device_remove_file(&interface->dev, &dev_attr_output7); - device_remove_file(&interface->dev, &dev_attr_output8); - } - if (kit->ifkit->outputs == 16) { - device_remove_file(&interface->dev, &dev_attr_output9); - device_remove_file(&interface->dev, &dev_attr_output10); - device_remove_file(&interface->dev, &dev_attr_output11); - device_remove_file(&interface->dev, &dev_attr_output12); - device_remove_file(&interface->dev, &dev_attr_output13); - device_remove_file(&interface->dev, &dev_attr_output14); - device_remove_file(&interface->dev, &dev_attr_output15); - device_remove_file(&interface->dev, &dev_attr_output16); - } + for (i=0; i<kit->ifkit->outputs; i++) + device_remove_file(kit->dev, &dev_output_attrs[i]); - if (kit->ifkit->inputs >= 4) { - device_remove_file(&interface->dev, &dev_attr_input1); - device_remove_file(&interface->dev, &dev_attr_input2); - device_remove_file(&interface->dev, &dev_attr_input3); - device_remove_file(&interface->dev, &dev_attr_input4); - } - if (kit->ifkit->inputs >= 8) { - device_remove_file(&interface->dev, &dev_attr_input5); - device_remove_file(&interface->dev, &dev_attr_input6); - device_remove_file(&interface->dev, &dev_attr_input7); - device_remove_file(&interface->dev, &dev_attr_input8); - } - if (kit->ifkit->inputs == 16) { - device_remove_file(&interface->dev, &dev_attr_input9); - device_remove_file(&interface->dev, &dev_attr_input10); - device_remove_file(&interface->dev, &dev_attr_input11); - device_remove_file(&interface->dev, &dev_attr_input12); - device_remove_file(&interface->dev, &dev_attr_input13); - device_remove_file(&interface->dev, &dev_attr_input14); - device_remove_file(&interface->dev, &dev_attr_input15); - device_remove_file(&interface->dev, &dev_attr_input16); - } + for (i=0; i<kit->ifkit->inputs; i++) + device_remove_file(kit->dev, &dev_input_attrs[i]); - if (kit->ifkit->sensors >= 4) { - device_remove_file(&interface->dev, &dev_attr_sensor1); - device_remove_file(&interface->dev, &dev_attr_sensor2); - device_remove_file(&interface->dev, &dev_attr_sensor3); - device_remove_file(&interface->dev, &dev_attr_sensor4); - } - if (kit->ifkit->sensors >= 7) { - device_remove_file(&interface->dev, &dev_attr_sensor5); - device_remove_file(&interface->dev, &dev_attr_sensor6); - device_remove_file(&interface->dev, &dev_attr_sensor7); + for (i=0; i<kit->ifkit->sensors; i++) + device_remove_file(kit->dev, &dev_sensor_attrs[i]); + + if (kit->ifkit->has_lcd) { + device_remove_file(kit->dev, &dev_attr_lcd); + remove_lcd_files(kit); } - if (kit->ifkit->sensors == 8) - device_remove_file(&interface->dev, &dev_attr_sensor8); - if (kit->ifkit->has_lcd) - device_remove_file(&interface->dev, &dev_attr_lcd); + device_unregister(kit->dev); dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n", kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs); usb_put_dev(kit->udev); + clear_bit(kit->dev_no, &device_no); + kfree(kit); } |