| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * USB PhidgetInterfaceKit driver 1.0 | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2004 Sean Young <sean@mess.org> | 
|  | 5 | * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> | 
|  | 6 | * | 
|  | 7 | * This program is free software; you can redistribute it and/or modify | 
|  | 8 | * it under the terms of the GNU General Public License as published by | 
|  | 9 | * the Free Software Foundation; either version 2 of the License, or | 
|  | 10 | * (at your option) any later version. | 
|  | 11 | * | 
|  | 12 | * This is a driver for the USB PhidgetInterfaceKit. | 
|  | 13 | */ | 
|  | 14 |  | 
|  | 15 | #include <linux/config.h> | 
|  | 16 | #include <linux/kernel.h> | 
|  | 17 | #include <linux/errno.h> | 
|  | 18 | #include <linux/init.h> | 
|  | 19 | #include <linux/slab.h> | 
|  | 20 | #include <linux/module.h> | 
|  | 21 | #include <linux/usb.h> | 
|  | 22 |  | 
|  | 23 | #define DRIVER_AUTHOR "Sean Young <sean@mess.org>" | 
|  | 24 | #define DRIVER_DESC "USB PhidgetInterfaceKit Driver" | 
|  | 25 |  | 
|  | 26 | #define USB_VENDOR_ID_GLAB		0x06c2 | 
|  | 27 | #define USB_DEVICE_ID_INTERFACEKIT004	0x0040 | 
|  | 28 | #define USB_DEVICE_ID_INTERFACEKIT888	0x0045 | 
|  | 29 | #define USB_DEVICE_ID_INTERFACEKIT047	0x0051 | 
|  | 30 | #define USB_DEVICE_ID_INTERFACEKIT088	0x0053 | 
|  | 31 |  | 
|  | 32 | #define USB_VENDOR_ID_WISEGROUP		0x0925 | 
|  | 33 | #define USB_DEVICE_ID_INTERFACEKIT884	0x8201 | 
|  | 34 |  | 
|  | 35 | #define MAX_INTERFACES			8 | 
|  | 36 |  | 
|  | 37 | struct driver_interfacekit { | 
|  | 38 | int sensors; | 
|  | 39 | int inputs; | 
|  | 40 | int outputs; | 
|  | 41 | int has_lcd; | 
|  | 42 | }; | 
|  | 43 | #define ifkit(_sensors, _inputs, _outputs, _lcd)			\ | 
|  | 44 | static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = {	\ | 
|  | 45 | .sensors	= _sensors,					\ | 
|  | 46 | .inputs		= _inputs,					\ | 
|  | 47 | .outputs	= _outputs,					\ | 
|  | 48 | .has_lcd	= _lcd,						\ | 
|  | 49 | }; | 
|  | 50 | ifkit(0, 0, 4, 0); | 
|  | 51 | ifkit(8, 8, 8, 0); | 
|  | 52 | ifkit(0, 4, 7, 1); | 
|  | 53 | ifkit(8, 8, 4, 0); | 
|  | 54 | ifkit(0, 8, 8, 1); | 
|  | 55 |  | 
|  | 56 | struct phidget_interfacekit { | 
|  | 57 | struct usb_device *udev; | 
|  | 58 | struct usb_interface *intf; | 
|  | 59 | struct driver_interfacekit *ifkit; | 
|  | 60 | int outputs[MAX_INTERFACES]; | 
|  | 61 | int inputs[MAX_INTERFACES]; | 
|  | 62 | int sensors[MAX_INTERFACES]; | 
|  | 63 | u8 lcd_files_on; | 
|  | 64 |  | 
|  | 65 | struct urb *irq; | 
|  | 66 | unsigned char *data; | 
|  | 67 | dma_addr_t data_dma; | 
|  | 68 | }; | 
|  | 69 |  | 
|  | 70 | static struct usb_device_id id_table[] = { | 
|  | 71 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004), | 
|  | 72 | .driver_info = (kernel_ulong_t)&ph_004}, | 
|  | 73 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888), | 
|  | 74 | .driver_info = (kernel_ulong_t)&ph_888}, | 
|  | 75 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047), | 
|  | 76 | .driver_info = (kernel_ulong_t)&ph_047}, | 
|  | 77 | {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088), | 
|  | 78 | .driver_info = (kernel_ulong_t)&ph_088}, | 
|  | 79 | {USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_INTERFACEKIT884), | 
|  | 80 | .driver_info = (kernel_ulong_t)&ph_884}, | 
|  | 81 | {} | 
|  | 82 | }; | 
|  | 83 | MODULE_DEVICE_TABLE(usb, id_table); | 
|  | 84 |  | 
|  | 85 | static int change_outputs(struct phidget_interfacekit *kit, int output_num, int enable) | 
|  | 86 | { | 
|  | 87 | unsigned char *buffer; | 
|  | 88 | int retval; | 
|  | 89 | int n; | 
|  | 90 |  | 
|  | 91 | buffer = kmalloc(4, GFP_KERNEL); | 
|  | 92 | if (!buffer) { | 
|  | 93 | dev_err(&kit->udev->dev, "%s - out of memory\n", | 
|  | 94 | __FUNCTION__); | 
|  | 95 | return -ENOMEM; | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | kit->outputs[output_num] = enable; | 
|  | 99 | memset(buffer, 0, 4); | 
|  | 100 | for (n=0; n<8; n++) { | 
|  | 101 | if (kit->outputs[n]) { | 
|  | 102 | buffer[0] |= 1 << n; | 
|  | 103 | } | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | dev_dbg(&kit->udev->dev, "sending data: %02x\n", buffer[0]); | 
|  | 107 |  | 
|  | 108 | retval = usb_control_msg(kit->udev, | 
|  | 109 | usb_sndctrlpipe(kit->udev, 0), | 
|  | 110 | 0x09, 0x21, 0x0200, 0x0000, buffer, 4, 2000); | 
|  | 111 |  | 
|  | 112 | if (retval != 4) | 
|  | 113 | dev_err(&kit->udev->dev, "usb_control_msg returned %d\n", | 
|  | 114 | retval); | 
|  | 115 | kfree(buffer); | 
|  | 116 |  | 
|  | 117 | return retval < 0 ? retval : 0; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | static int change_string(struct phidget_interfacekit *kit, const char *display, unsigned char row) | 
|  | 121 | { | 
|  | 122 | unsigned char *buffer; | 
|  | 123 | unsigned char *form_buffer; | 
|  | 124 | int retval = -ENOMEM; | 
|  | 125 | int i,j, len, buf_ptr; | 
|  | 126 |  | 
|  | 127 | buffer = kmalloc(8, GFP_KERNEL); | 
|  | 128 | form_buffer = kmalloc(30, GFP_KERNEL); | 
|  | 129 | if ((!buffer) || (!form_buffer)) { | 
|  | 130 | dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); | 
|  | 131 | goto exit; | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | len = strlen(display); | 
|  | 135 | if (len > 20) | 
|  | 136 | len = 20; | 
|  | 137 |  | 
|  | 138 | dev_dbg(&kit->udev->dev, "Setting LCD line %d to %s\n", row, display); | 
|  | 139 |  | 
|  | 140 | form_buffer[0] = row * 0x40 + 0x80; | 
|  | 141 | form_buffer[1] = 0x02; | 
|  | 142 | buf_ptr = 2; | 
|  | 143 | for (i = 0; i<len; i++) | 
|  | 144 | form_buffer[buf_ptr++] = display[i]; | 
|  | 145 |  | 
|  | 146 | for (i = 0; i < (20 - len); i++) | 
|  | 147 | form_buffer[buf_ptr++] = 0x20; | 
|  | 148 | form_buffer[buf_ptr++] = 0x01; | 
|  | 149 | form_buffer[buf_ptr++] = row * 0x40 + 0x80 + strlen(display); | 
|  | 150 |  | 
|  | 151 | for (i = 0; i < buf_ptr; i += 7) { | 
|  | 152 | if ((buf_ptr - i) > 7) | 
|  | 153 | len = 7; | 
|  | 154 | else | 
|  | 155 | len = (buf_ptr - i); | 
|  | 156 | for (j = 0; j < len; j++) | 
|  | 157 | buffer[j] = form_buffer[i + j]; | 
|  | 158 | buffer[7] = len; | 
|  | 159 |  | 
|  | 160 | retval = usb_control_msg(kit->udev, | 
|  | 161 | usb_sndctrlpipe(kit->udev, 0), | 
|  | 162 | 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000); | 
|  | 163 | if (retval < 0) | 
|  | 164 | goto exit; | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | retval = 0; | 
|  | 168 | exit: | 
|  | 169 | kfree(buffer); | 
|  | 170 | kfree(form_buffer); | 
|  | 171 |  | 
|  | 172 | return retval; | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | #define set_lcd_line(number)	\ | 
|  | 176 | static ssize_t lcd_line_##number(struct device *dev, const char *buf, size_t count)	\ | 
|  | 177 | {											\ | 
|  | 178 | struct usb_interface *intf = to_usb_interface(dev);				\ | 
|  | 179 | struct phidget_interfacekit *kit = usb_get_intfdata(intf);			\ | 
|  | 180 | change_string(kit, buf, number - 1);						\ | 
|  | 181 | return count;									\ | 
|  | 182 | }											\ | 
|  | 183 | static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number); | 
|  | 184 | set_lcd_line(1); | 
|  | 185 | set_lcd_line(2); | 
|  | 186 |  | 
|  | 187 | static ssize_t set_backlight(struct device *dev, const char *buf, size_t count) | 
|  | 188 | { | 
|  | 189 | struct usb_interface *intf = to_usb_interface(dev); | 
|  | 190 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); | 
|  | 191 | int enabled; | 
|  | 192 | unsigned char *buffer; | 
|  | 193 | int retval = -ENOMEM; | 
|  | 194 |  | 
|  | 195 | buffer = kmalloc(8, GFP_KERNEL); | 
|  | 196 | if (!buffer) { | 
|  | 197 | dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); | 
|  | 198 | goto exit; | 
|  | 199 | } | 
|  | 200 |  | 
|  | 201 | if (sscanf(buf, "%d", &enabled) < 1) { | 
|  | 202 | retval = -EINVAL; | 
|  | 203 | goto exit; | 
|  | 204 | } | 
|  | 205 | memset(buffer, 0x00, 8); | 
|  | 206 | if (enabled) | 
|  | 207 | buffer[0] = 0x01; | 
|  | 208 | buffer[7] = 0x11; | 
|  | 209 |  | 
|  | 210 | dev_dbg(&kit->udev->dev, "Setting backlight to %s\n", enabled ? "on" : "off"); | 
|  | 211 |  | 
|  | 212 | retval = usb_control_msg(kit->udev, | 
|  | 213 | usb_sndctrlpipe(kit->udev, 0), | 
|  | 214 | 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000); | 
|  | 215 | if (retval < 0) | 
|  | 216 | goto exit; | 
|  | 217 |  | 
|  | 218 | retval = count; | 
|  | 219 | exit: | 
|  | 220 | kfree(buffer); | 
|  | 221 | return retval; | 
|  | 222 | } | 
|  | 223 | static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight); | 
|  | 224 |  | 
|  | 225 | static void remove_lcd_files(struct phidget_interfacekit *kit) | 
|  | 226 | { | 
|  | 227 | if (kit->lcd_files_on) { | 
|  | 228 | dev_dbg(&kit->udev->dev, "Removing lcd files\n"); | 
|  | 229 | device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1); | 
|  | 230 | device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2); | 
|  | 231 | device_remove_file(&kit->intf->dev, &dev_attr_backlight); | 
|  | 232 | } | 
|  | 233 | } | 
|  | 234 |  | 
|  | 235 | static ssize_t enable_lcd_files(struct device *dev, const char *buf, size_t count) | 
|  | 236 | { | 
|  | 237 | struct usb_interface *intf = to_usb_interface(dev); | 
|  | 238 | struct phidget_interfacekit *kit = usb_get_intfdata(intf); | 
|  | 239 | int enable; | 
|  | 240 |  | 
|  | 241 | if (kit->ifkit->has_lcd == 0) | 
|  | 242 | return -ENODEV; | 
|  | 243 |  | 
|  | 244 | if (sscanf(buf, "%d", &enable) < 1) | 
|  | 245 | return -EINVAL; | 
|  | 246 |  | 
|  | 247 | if (enable) { | 
|  | 248 | if (!kit->lcd_files_on) { | 
|  | 249 | dev_dbg(&kit->udev->dev, "Adding lcd files\n"); | 
|  | 250 | device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1); | 
|  | 251 | device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2); | 
|  | 252 | device_create_file(&kit->intf->dev, &dev_attr_backlight); | 
|  | 253 | kit->lcd_files_on = 1; | 
|  | 254 | } | 
|  | 255 | } else { | 
|  | 256 | if (kit->lcd_files_on) { | 
|  | 257 | remove_lcd_files(kit); | 
|  | 258 | kit->lcd_files_on = 0; | 
|  | 259 | } | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | return count; | 
|  | 263 | } | 
|  | 264 | static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files); | 
|  | 265 |  | 
|  | 266 | static void interfacekit_irq(struct urb *urb, struct pt_regs *regs) | 
|  | 267 | { | 
|  | 268 | struct phidget_interfacekit *kit = urb->context; | 
|  | 269 | unsigned char *buffer = kit->data; | 
|  | 270 | int status; | 
|  | 271 | int n; | 
|  | 272 |  | 
|  | 273 | switch (urb->status) { | 
|  | 274 | case 0:			/* success */ | 
|  | 275 | break; | 
|  | 276 | case -ECONNRESET:	/* unlink */ | 
|  | 277 | case -ENOENT: | 
|  | 278 | case -ESHUTDOWN: | 
|  | 279 | return; | 
|  | 280 | /* -EPIPE:  should clear the halt */ | 
|  | 281 | default:		/* error */ | 
|  | 282 | goto resubmit; | 
|  | 283 | } | 
|  | 284 |  | 
|  | 285 | for (n=0; n<8; n++) { | 
|  | 286 | kit->inputs[n] = buffer[1] & (1 << n) ? 1 : 0; | 
|  | 287 | } | 
|  | 288 |  | 
|  | 289 | if (buffer[0] & 1) { | 
|  | 290 | kit->sensors[4] = buffer[2] + (buffer[3] & 0x0f) * 256; | 
|  | 291 | kit->sensors[5] = buffer[4] + (buffer[3] & 0xf0) * 16; | 
|  | 292 | kit->sensors[6] = buffer[5] + (buffer[6] & 0x0f) * 256; | 
|  | 293 | kit->sensors[7] = buffer[7] + (buffer[6] & 0xf0) * 16; | 
|  | 294 | } else { | 
|  | 295 | kit->sensors[0] = buffer[2] + (buffer[3] & 0x0f) * 256; | 
|  | 296 | kit->sensors[1] = buffer[4] + (buffer[3] & 0xf0) * 16; | 
|  | 297 | kit->sensors[2] = buffer[5] + (buffer[6] & 0x0f) * 256; | 
|  | 298 | kit->sensors[3] = buffer[7] + (buffer[6] & 0xf0) * 16; | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | resubmit: | 
|  | 302 | status = usb_submit_urb(urb, SLAB_ATOMIC); | 
|  | 303 | if (status) | 
|  | 304 | err("can't resubmit intr, %s-%s/interfacekit0, status %d", | 
|  | 305 | kit->udev->bus->bus_name, | 
|  | 306 | kit->udev->devpath, status); | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | #define show_set_output(value)		\ | 
|  | 310 | static ssize_t set_output##value(struct device *dev, const char *buf, 	\ | 
|  | 311 | size_t count)	\ | 
|  | 312 | {									\ | 
|  | 313 | struct usb_interface *intf = to_usb_interface(dev);		\ | 
|  | 314 | struct phidget_interfacekit *kit = usb_get_intfdata(intf);	\ | 
|  | 315 | int enabled;							\ | 
|  | 316 | int retval;							\ | 
|  | 317 | \ | 
|  | 318 | if (sscanf(buf, "%d", &enabled) < 1) {				\ | 
|  | 319 | return -EINVAL;						\ | 
|  | 320 | }								\ | 
|  | 321 | \ | 
|  | 322 | retval = change_outputs(kit, value - 1, enabled ? 1 : 0);	\ | 
|  | 323 | \ | 
|  | 324 | return retval ? retval : count;					\ | 
|  | 325 | }									\ | 
|  | 326 | \ | 
|  | 327 | static ssize_t show_output##value(struct device *dev, char *buf)	\ | 
|  | 328 | {									\ | 
|  | 329 | struct usb_interface *intf = to_usb_interface(dev);		\ | 
|  | 330 | struct phidget_interfacekit *kit = usb_get_intfdata(intf);	\ | 
|  | 331 | \ | 
|  | 332 | return sprintf(buf, "%d\n", kit->outputs[value - 1]);		\ | 
|  | 333 | }									\ | 
|  | 334 | static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO,			\ | 
|  | 335 | show_output##value, set_output##value); | 
|  | 336 | show_set_output(1); | 
|  | 337 | show_set_output(2); | 
|  | 338 | show_set_output(3); | 
|  | 339 | show_set_output(4); | 
|  | 340 | show_set_output(5); | 
|  | 341 | show_set_output(6); | 
|  | 342 | show_set_output(7); | 
|  | 343 | show_set_output(8);	/* should be MAX_INTERFACES - 1 */ | 
|  | 344 |  | 
|  | 345 | #define show_input(value)	\ | 
|  | 346 | static ssize_t show_input##value(struct device *dev, char *buf)	\ | 
|  | 347 | {									\ | 
|  | 348 | struct usb_interface *intf = to_usb_interface(dev);		\ | 
|  | 349 | struct phidget_interfacekit *kit = usb_get_intfdata(intf);	\ | 
|  | 350 | \ | 
|  | 351 | return sprintf(buf, "%d\n", kit->inputs[value - 1]);		\ | 
|  | 352 | }									\ | 
|  | 353 | static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL); | 
|  | 354 |  | 
|  | 355 | show_input(1); | 
|  | 356 | show_input(2); | 
|  | 357 | show_input(3); | 
|  | 358 | show_input(4); | 
|  | 359 | show_input(5); | 
|  | 360 | show_input(6); | 
|  | 361 | show_input(7); | 
|  | 362 | show_input(8);		/* should be MAX_INTERFACES - 1 */ | 
|  | 363 |  | 
|  | 364 | #define show_sensor(value)	\ | 
|  | 365 | static ssize_t show_sensor##value(struct device *dev, char *buf)	\ | 
|  | 366 | {									\ | 
|  | 367 | struct usb_interface *intf = to_usb_interface(dev);		\ | 
|  | 368 | struct phidget_interfacekit *kit = usb_get_intfdata(intf);	\ | 
|  | 369 | \ | 
|  | 370 | return sprintf(buf, "%d\n", kit->sensors[value - 1]);		\ | 
|  | 371 | }									\ | 
|  | 372 | static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL); | 
|  | 373 |  | 
|  | 374 | show_sensor(1); | 
|  | 375 | show_sensor(2); | 
|  | 376 | show_sensor(3); | 
|  | 377 | show_sensor(4); | 
|  | 378 | show_sensor(5); | 
|  | 379 | show_sensor(6); | 
|  | 380 | show_sensor(7); | 
|  | 381 | show_sensor(8);		/* should be MAX_INTERFACES - 1 */ | 
|  | 382 |  | 
|  | 383 | static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id) | 
|  | 384 | { | 
|  | 385 | struct usb_device *dev = interface_to_usbdev(intf); | 
|  | 386 | struct usb_host_interface *interface; | 
|  | 387 | struct usb_endpoint_descriptor *endpoint; | 
|  | 388 | struct phidget_interfacekit *kit; | 
|  | 389 | struct driver_interfacekit *ifkit; | 
|  | 390 | int pipe, maxp; | 
|  | 391 |  | 
|  | 392 | ifkit = (struct driver_interfacekit *)id->driver_info; | 
|  | 393 | if (!ifkit) | 
|  | 394 | return -ENODEV; | 
|  | 395 |  | 
|  | 396 | interface = intf->cur_altsetting; | 
|  | 397 | if (interface->desc.bNumEndpoints != 1) | 
|  | 398 | return -ENODEV; | 
|  | 399 |  | 
|  | 400 | endpoint = &interface->endpoint[0].desc; | 
|  | 401 | if (!(endpoint->bEndpointAddress & 0x80)) | 
|  | 402 | return -ENODEV; | 
|  | 403 | /* | 
|  | 404 | * bmAttributes | 
|  | 405 | */ | 
|  | 406 | pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | 
|  | 407 | maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | 
|  | 408 |  | 
|  | 409 | kit = kmalloc(sizeof(*kit), GFP_KERNEL); | 
|  | 410 | if (kit  == NULL) { | 
|  | 411 | dev_err(&intf->dev, "%s - out of memory\n", __FUNCTION__); | 
|  | 412 | return -ENOMEM; | 
|  | 413 | } | 
|  | 414 | memset(kit, 0, sizeof(*kit)); | 
|  | 415 | kit->ifkit = ifkit; | 
|  | 416 |  | 
|  | 417 | kit->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kit->data_dma); | 
|  | 418 | if (!kit->data) { | 
|  | 419 | kfree(kit); | 
|  | 420 | return -ENOMEM; | 
|  | 421 | } | 
|  | 422 |  | 
|  | 423 | kit->irq = usb_alloc_urb(0, GFP_KERNEL); | 
|  | 424 | if (!kit->irq) { | 
|  | 425 | usb_buffer_free(dev, 8, kit->data, kit->data_dma); | 
|  | 426 | kfree(kit); | 
|  | 427 | return -ENOMEM; | 
|  | 428 | } | 
|  | 429 |  | 
|  | 430 | kit->udev = usb_get_dev(dev); | 
|  | 431 | kit->intf = intf; | 
|  | 432 | usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, | 
|  | 433 | (maxp > 8 ? 8 : maxp), | 
|  | 434 | interfacekit_irq, kit, endpoint->bInterval); | 
|  | 435 | kit->irq->transfer_dma = kit->data_dma; | 
|  | 436 | kit->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 
|  | 437 |  | 
|  | 438 | usb_set_intfdata(intf, kit); | 
|  | 439 |  | 
|  | 440 | if (usb_submit_urb(kit->irq, GFP_KERNEL)) { | 
|  | 441 | return -EIO; | 
|  | 442 | } | 
|  | 443 |  | 
|  | 444 | if (ifkit->outputs >= 4) { | 
|  | 445 | device_create_file(&intf->dev, &dev_attr_output1); | 
|  | 446 | device_create_file(&intf->dev, &dev_attr_output2); | 
|  | 447 | device_create_file(&intf->dev, &dev_attr_output3); | 
|  | 448 | device_create_file(&intf->dev, &dev_attr_output4); | 
|  | 449 | } | 
|  | 450 | if (ifkit->outputs == 8) { | 
|  | 451 | device_create_file(&intf->dev, &dev_attr_output5); | 
|  | 452 | device_create_file(&intf->dev, &dev_attr_output6); | 
|  | 453 | device_create_file(&intf->dev, &dev_attr_output7); | 
|  | 454 | device_create_file(&intf->dev, &dev_attr_output8); | 
|  | 455 | } | 
|  | 456 |  | 
|  | 457 | if (ifkit->inputs >= 4) { | 
|  | 458 | device_create_file(&intf->dev, &dev_attr_input1); | 
|  | 459 | device_create_file(&intf->dev, &dev_attr_input2); | 
|  | 460 | device_create_file(&intf->dev, &dev_attr_input3); | 
|  | 461 | device_create_file(&intf->dev, &dev_attr_input4); | 
|  | 462 | } | 
|  | 463 | if (ifkit->inputs == 8) { | 
|  | 464 | device_create_file(&intf->dev, &dev_attr_input5); | 
|  | 465 | device_create_file(&intf->dev, &dev_attr_input6); | 
|  | 466 | device_create_file(&intf->dev, &dev_attr_input7); | 
|  | 467 | device_create_file(&intf->dev, &dev_attr_input8); | 
|  | 468 | } | 
|  | 469 |  | 
|  | 470 | if (ifkit->sensors >= 4) { | 
|  | 471 | device_create_file(&intf->dev, &dev_attr_sensor1); | 
|  | 472 | device_create_file(&intf->dev, &dev_attr_sensor2); | 
|  | 473 | device_create_file(&intf->dev, &dev_attr_sensor3); | 
|  | 474 | device_create_file(&intf->dev, &dev_attr_sensor4); | 
|  | 475 | } | 
|  | 476 | if (ifkit->sensors >= 7) { | 
|  | 477 | device_create_file(&intf->dev, &dev_attr_sensor5); | 
|  | 478 | device_create_file(&intf->dev, &dev_attr_sensor6); | 
|  | 479 | device_create_file(&intf->dev, &dev_attr_sensor7); | 
|  | 480 | } | 
|  | 481 | if (ifkit->sensors == 8) { | 
|  | 482 | device_create_file(&intf->dev, &dev_attr_sensor8); | 
|  | 483 | } | 
|  | 484 |  | 
|  | 485 | if (ifkit->has_lcd) | 
|  | 486 | device_create_file(&intf->dev, &dev_attr_lcd); | 
|  | 487 |  | 
|  | 488 | dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n", | 
|  | 489 | ifkit->sensors, ifkit->inputs, ifkit->outputs); | 
|  | 490 |  | 
|  | 491 | return 0; | 
|  | 492 | } | 
|  | 493 |  | 
|  | 494 | static void interfacekit_disconnect(struct usb_interface *interface) | 
|  | 495 | { | 
|  | 496 | struct phidget_interfacekit *kit; | 
|  | 497 |  | 
|  | 498 | kit = usb_get_intfdata(interface); | 
|  | 499 | usb_set_intfdata(interface, NULL); | 
|  | 500 | if (!kit) | 
|  | 501 | return; | 
|  | 502 |  | 
|  | 503 | if (kit->ifkit->outputs >= 4) { | 
|  | 504 | device_remove_file(&interface->dev, &dev_attr_output1); | 
|  | 505 | device_remove_file(&interface->dev, &dev_attr_output2); | 
|  | 506 | device_remove_file(&interface->dev, &dev_attr_output3); | 
|  | 507 | device_remove_file(&interface->dev, &dev_attr_output4); | 
|  | 508 | } | 
|  | 509 | if (kit->ifkit->outputs == 8) { | 
|  | 510 | device_remove_file(&interface->dev, &dev_attr_output5); | 
|  | 511 | device_remove_file(&interface->dev, &dev_attr_output6); | 
|  | 512 | device_remove_file(&interface->dev, &dev_attr_output7); | 
|  | 513 | device_remove_file(&interface->dev, &dev_attr_output8); | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | if (kit->ifkit->inputs >= 4) { | 
|  | 517 | device_remove_file(&interface->dev, &dev_attr_input1); | 
|  | 518 | device_remove_file(&interface->dev, &dev_attr_input2); | 
|  | 519 | device_remove_file(&interface->dev, &dev_attr_input3); | 
|  | 520 | device_remove_file(&interface->dev, &dev_attr_input4); | 
|  | 521 | } | 
|  | 522 | if (kit->ifkit->inputs == 8) { | 
|  | 523 | device_remove_file(&interface->dev, &dev_attr_input5); | 
|  | 524 | device_remove_file(&interface->dev, &dev_attr_input6); | 
|  | 525 | device_remove_file(&interface->dev, &dev_attr_input7); | 
|  | 526 | device_remove_file(&interface->dev, &dev_attr_input8); | 
|  | 527 | } | 
|  | 528 |  | 
|  | 529 | if (kit->ifkit->sensors >= 4) { | 
|  | 530 | device_remove_file(&interface->dev, &dev_attr_sensor1); | 
|  | 531 | device_remove_file(&interface->dev, &dev_attr_sensor2); | 
|  | 532 | device_remove_file(&interface->dev, &dev_attr_sensor3); | 
|  | 533 | device_remove_file(&interface->dev, &dev_attr_sensor4); | 
|  | 534 | } | 
|  | 535 | if (kit->ifkit->sensors >= 7) { | 
|  | 536 | device_remove_file(&interface->dev, &dev_attr_sensor5); | 
|  | 537 | device_remove_file(&interface->dev, &dev_attr_sensor6); | 
|  | 538 | device_remove_file(&interface->dev, &dev_attr_sensor7); | 
|  | 539 | } | 
|  | 540 | if (kit->ifkit->sensors == 8) { | 
|  | 541 | device_remove_file(&interface->dev, &dev_attr_sensor8); | 
|  | 542 | } | 
|  | 543 | if (kit->ifkit->has_lcd) | 
|  | 544 | device_remove_file(&interface->dev, &dev_attr_lcd); | 
|  | 545 |  | 
|  | 546 | dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n", | 
|  | 547 | kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs); | 
|  | 548 |  | 
|  | 549 | usb_kill_urb(kit->irq); | 
|  | 550 | usb_free_urb(kit->irq); | 
|  | 551 | usb_buffer_free(kit->udev, 8, kit->data, kit->data_dma); | 
|  | 552 |  | 
|  | 553 | usb_put_dev(kit->udev); | 
|  | 554 | kfree(kit); | 
|  | 555 | } | 
|  | 556 |  | 
|  | 557 | static struct usb_driver interfacekit_driver = { | 
|  | 558 | .owner = THIS_MODULE, | 
|  | 559 | .name = "phidgetkit", | 
|  | 560 | .probe = interfacekit_probe, | 
|  | 561 | .disconnect = interfacekit_disconnect, | 
|  | 562 | .id_table = id_table | 
|  | 563 | }; | 
|  | 564 |  | 
|  | 565 | static int __init interfacekit_init(void) | 
|  | 566 | { | 
|  | 567 | int retval = 0; | 
|  | 568 |  | 
|  | 569 | retval = usb_register(&interfacekit_driver); | 
|  | 570 | if (retval) | 
|  | 571 | err("usb_register failed. Error number %d", retval); | 
|  | 572 |  | 
|  | 573 | return retval; | 
|  | 574 | } | 
|  | 575 |  | 
|  | 576 | static void __exit interfacekit_exit(void) | 
|  | 577 | { | 
|  | 578 | usb_deregister(&interfacekit_driver); | 
|  | 579 | } | 
|  | 580 |  | 
|  | 581 | module_init(interfacekit_init); | 
|  | 582 | module_exit(interfacekit_exit); | 
|  | 583 |  | 
|  | 584 | MODULE_AUTHOR(DRIVER_AUTHOR); | 
|  | 585 | MODULE_DESCRIPTION(DRIVER_DESC); | 
|  | 586 | MODULE_LICENSE("GPL"); |