diff options
Diffstat (limited to 'drivers/usb/misc/phidgetkit.c')
| -rw-r--r-- | drivers/usb/misc/phidgetkit.c | 396 | 
1 files changed, 211 insertions, 185 deletions
| diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index bfbbbfbb92b..371bf2b1197 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; @@ -70,7 +81,8 @@ struct interfacekit {  	unsigned char *data;  	dma_addr_t data_dma; -	struct work_struct do_notify; +	struct delayed_work do_notify; +	struct delayed_work 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,10 +291,16 @@ 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) +static void interfacekit_irq(struct urb *urb)  {  	struct interfacekit *kit = urb->context;  	unsigned char *buffer = kit->data; @@ -343,63 +374,80 @@ static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)  	}  	if (kit->input_events || kit->sensor_events) -		schedule_work(&kit->do_notify); +		schedule_delayed_work(&kit->do_notify, 0);  resubmit: -	status = usb_submit_urb(urb, SLAB_ATOMIC); +	status = usb_submit_urb(urb, GFP_ATOMIC);  	if (status)  		err("can't resubmit intr, %s-%s/interfacekit0, status %d",  			kit->udev->bus->bus_name,  			kit->udev->devpath, status);  } -static void do_notify(void *data) +static void do_notify(struct work_struct *work)  { -	struct interfacekit *kit = data; +	struct interfacekit *kit = +		container_of(work, struct interfacekit, do_notify.work);  	int i;  	char sysfs_file[8];  	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(struct work_struct *work) +{ +	struct interfacekit *kit = +		container_of(work, struct interfacekit, do_resubmit.work); +	set_outputs(kit); +} +  #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 +465,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 +501,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 +530,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 +543,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) @@ -481,7 +554,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic  		return -ENODEV;  	endpoint = &interface->endpoint[0].desc; -	if (!(endpoint->bEndpointAddress & 0x80))  +	if (!usb_endpoint_dir_in(endpoint))  		return -ENODEV;  	/*  	 * bmAttributes @@ -493,8 +566,9 @@ 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); +	kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &kit->data_dma);  	if (!kit->data)  		goto out; @@ -504,7 +578,8 @@ 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_DELAYED_WORK(&kit->do_notify, do_notify); +	INIT_DELAYED_WORK(&kit->do_resubmit, do_resubmit);  	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 +588,79 @@ 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); +		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 +670,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 +682,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);  } | 
