diff options
Diffstat (limited to 'drivers/usb/input/powermate.c')
| -rw-r--r-- | drivers/usb/input/powermate.c | 136 |
1 files changed, 70 insertions, 66 deletions
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index ad4afe7e5897..b7476233ef5d 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c | |||
| @@ -68,7 +68,7 @@ struct powermate_device { | |||
| 68 | struct usb_ctrlrequest *configcr; | 68 | struct usb_ctrlrequest *configcr; |
| 69 | dma_addr_t configcr_dma; | 69 | dma_addr_t configcr_dma; |
| 70 | struct usb_device *udev; | 70 | struct usb_device *udev; |
| 71 | struct input_dev input; | 71 | struct input_dev *input; |
| 72 | spinlock_t lock; | 72 | spinlock_t lock; |
| 73 | int static_brightness; | 73 | int static_brightness; |
| 74 | int pulse_speed; | 74 | int pulse_speed; |
| @@ -106,10 +106,10 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs) | |||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | /* handle updates to device state */ | 108 | /* handle updates to device state */ |
| 109 | input_regs(&pm->input, regs); | 109 | input_regs(pm->input, regs); |
| 110 | input_report_key(&pm->input, BTN_0, pm->data[0] & 0x01); | 110 | input_report_key(pm->input, BTN_0, pm->data[0] & 0x01); |
| 111 | input_report_rel(&pm->input, REL_DIAL, pm->data[1]); | 111 | input_report_rel(pm->input, REL_DIAL, pm->data[1]); |
| 112 | input_sync(&pm->input); | 112 | input_sync(pm->input); |
| 113 | 113 | ||
| 114 | exit: | 114 | exit: |
| 115 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 115 | retval = usb_submit_urb (urb, GFP_ATOMIC); |
| @@ -153,10 +153,10 @@ static void powermate_sync_state(struct powermate_device *pm) | |||
| 153 | 153 | ||
| 154 | Only values of 'arg' quite close to 255 are particularly useful/spectacular. | 154 | Only values of 'arg' quite close to 255 are particularly useful/spectacular. |
| 155 | */ | 155 | */ |
| 156 | if (pm->pulse_speed < 255){ | 156 | if (pm->pulse_speed < 255) { |
| 157 | op = 0; // divide | 157 | op = 0; // divide |
| 158 | arg = 255 - pm->pulse_speed; | 158 | arg = 255 - pm->pulse_speed; |
| 159 | } else if (pm->pulse_speed > 255){ | 159 | } else if (pm->pulse_speed > 255) { |
| 160 | op = 2; // multiply | 160 | op = 2; // multiply |
| 161 | arg = pm->pulse_speed - 255; | 161 | arg = pm->pulse_speed - 255; |
| 162 | } else { | 162 | } else { |
| @@ -166,11 +166,11 @@ static void powermate_sync_state(struct powermate_device *pm) | |||
| 166 | pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); | 166 | pm->configcr->wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); |
| 167 | pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); | 167 | pm->configcr->wIndex = cpu_to_le16( (arg << 8) | op ); |
| 168 | pm->requires_update &= ~UPDATE_PULSE_MODE; | 168 | pm->requires_update &= ~UPDATE_PULSE_MODE; |
| 169 | }else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ | 169 | } else if (pm->requires_update & UPDATE_STATIC_BRIGHTNESS) { |
| 170 | pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); | 170 | pm->configcr->wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); |
| 171 | pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); | 171 | pm->configcr->wIndex = cpu_to_le16( pm->static_brightness ); |
| 172 | pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; | 172 | pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; |
| 173 | }else{ | 173 | } else { |
| 174 | printk(KERN_ERR "powermate: unknown update required"); | 174 | printk(KERN_ERR "powermate: unknown update required"); |
| 175 | pm->requires_update = 0; /* fudge the bug */ | 175 | pm->requires_update = 0; /* fudge the bug */ |
| 176 | return; | 176 | return; |
| @@ -228,19 +228,19 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne | |||
| 228 | spin_lock_irqsave(&pm->lock, flags); | 228 | spin_lock_irqsave(&pm->lock, flags); |
| 229 | 229 | ||
| 230 | /* mark state updates which are required */ | 230 | /* mark state updates which are required */ |
| 231 | if (static_brightness != pm->static_brightness){ | 231 | if (static_brightness != pm->static_brightness) { |
| 232 | pm->static_brightness = static_brightness; | 232 | pm->static_brightness = static_brightness; |
| 233 | pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; | 233 | pm->requires_update |= UPDATE_STATIC_BRIGHTNESS; |
| 234 | } | 234 | } |
| 235 | if (pulse_asleep != pm->pulse_asleep){ | 235 | if (pulse_asleep != pm->pulse_asleep) { |
| 236 | pm->pulse_asleep = pulse_asleep; | 236 | pm->pulse_asleep = pulse_asleep; |
| 237 | pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); | 237 | pm->requires_update |= (UPDATE_PULSE_ASLEEP | UPDATE_STATIC_BRIGHTNESS); |
| 238 | } | 238 | } |
| 239 | if (pulse_awake != pm->pulse_awake){ | 239 | if (pulse_awake != pm->pulse_awake) { |
| 240 | pm->pulse_awake = pulse_awake; | 240 | pm->pulse_awake = pulse_awake; |
| 241 | pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); | 241 | pm->requires_update |= (UPDATE_PULSE_AWAKE | UPDATE_STATIC_BRIGHTNESS); |
| 242 | } | 242 | } |
| 243 | if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table){ | 243 | if (pulse_speed != pm->pulse_speed || pulse_table != pm->pulse_table) { |
| 244 | pm->pulse_speed = pulse_speed; | 244 | pm->pulse_speed = pulse_speed; |
| 245 | pm->pulse_table = pulse_table; | 245 | pm->pulse_table = pulse_table; |
| 246 | pm->requires_update |= UPDATE_PULSE_MODE; | 246 | pm->requires_update |= UPDATE_PULSE_MODE; |
| @@ -283,6 +283,7 @@ static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_dev | |||
| 283 | SLAB_ATOMIC, &pm->data_dma); | 283 | SLAB_ATOMIC, &pm->data_dma); |
| 284 | if (!pm->data) | 284 | if (!pm->data) |
| 285 | return -1; | 285 | return -1; |
| 286 | |||
| 286 | pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), | 287 | pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), |
| 287 | SLAB_ATOMIC, &pm->configcr_dma); | 288 | SLAB_ATOMIC, &pm->configcr_dma); |
| 288 | if (!pm->configcr) | 289 | if (!pm->configcr) |
| @@ -308,8 +309,9 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i | |||
| 308 | struct usb_host_interface *interface; | 309 | struct usb_host_interface *interface; |
| 309 | struct usb_endpoint_descriptor *endpoint; | 310 | struct usb_endpoint_descriptor *endpoint; |
| 310 | struct powermate_device *pm; | 311 | struct powermate_device *pm; |
| 312 | struct input_dev *input_dev; | ||
| 311 | int pipe, maxp; | 313 | int pipe, maxp; |
| 312 | char path[64]; | 314 | int err = -ENOMEM; |
| 313 | 315 | ||
| 314 | interface = intf->cur_altsetting; | 316 | interface = intf->cur_altsetting; |
| 315 | endpoint = &interface->endpoint[0].desc; | 317 | endpoint = &interface->endpoint[0].desc; |
| @@ -323,42 +325,61 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i | |||
| 323 | 0, interface->desc.bInterfaceNumber, NULL, 0, | 325 | 0, interface->desc.bInterfaceNumber, NULL, 0, |
| 324 | USB_CTRL_SET_TIMEOUT); | 326 | USB_CTRL_SET_TIMEOUT); |
| 325 | 327 | ||
| 326 | if (!(pm = kmalloc(sizeof(struct powermate_device), GFP_KERNEL))) | 328 | pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL); |
| 327 | return -ENOMEM; | 329 | input_dev = input_allocate_device(); |
| 328 | 330 | if (!pm || !input_dev) | |
| 329 | memset(pm, 0, sizeof(struct powermate_device)); | 331 | goto fail1; |
| 330 | pm->udev = udev; | ||
| 331 | 332 | ||
| 332 | if (powermate_alloc_buffers(udev, pm)) { | 333 | if (powermate_alloc_buffers(udev, pm)) |
| 333 | powermate_free_buffers(udev, pm); | 334 | goto fail2; |
| 334 | kfree(pm); | ||
| 335 | return -ENOMEM; | ||
| 336 | } | ||
| 337 | 335 | ||
| 338 | pm->irq = usb_alloc_urb(0, GFP_KERNEL); | 336 | pm->irq = usb_alloc_urb(0, GFP_KERNEL); |
| 339 | if (!pm->irq) { | 337 | if (!pm->irq) |
| 340 | powermate_free_buffers(udev, pm); | 338 | goto fail2; |
| 341 | kfree(pm); | ||
| 342 | return -ENOMEM; | ||
| 343 | } | ||
| 344 | 339 | ||
| 345 | pm->config = usb_alloc_urb(0, GFP_KERNEL); | 340 | pm->config = usb_alloc_urb(0, GFP_KERNEL); |
| 346 | if (!pm->config) { | 341 | if (!pm->config) |
| 347 | usb_free_urb(pm->irq); | 342 | goto fail3; |
| 348 | powermate_free_buffers(udev, pm); | 343 | |
| 349 | kfree(pm); | 344 | pm->udev = udev; |
| 350 | return -ENOMEM; | 345 | pm->input = input_dev; |
| 351 | } | 346 | |
| 347 | usb_make_path(udev, pm->phys, sizeof(pm->phys)); | ||
| 348 | strlcpy(pm->phys, "/input0", sizeof(pm->phys)); | ||
| 352 | 349 | ||
| 353 | spin_lock_init(&pm->lock); | 350 | spin_lock_init(&pm->lock); |
| 354 | init_input_dev(&pm->input); | 351 | |
| 352 | switch (le16_to_cpu(udev->descriptor.idProduct)) { | ||
| 353 | case POWERMATE_PRODUCT_NEW: | ||
| 354 | input_dev->name = pm_name_powermate; | ||
| 355 | break; | ||
| 356 | case POWERMATE_PRODUCT_OLD: | ||
| 357 | input_dev->name = pm_name_soundknob; | ||
| 358 | break; | ||
| 359 | default: | ||
| 360 | input_dev->name = pm_name_soundknob; | ||
| 361 | printk(KERN_WARNING "powermate: unknown product id %04x\n", | ||
| 362 | le16_to_cpu(udev->descriptor.idProduct)); | ||
| 363 | } | ||
| 364 | |||
| 365 | input_dev->phys = pm->phys; | ||
| 366 | usb_to_input_id(udev, &input_dev->id); | ||
| 367 | input_dev->cdev.dev = &intf->dev; | ||
| 368 | input_dev->private = pm; | ||
| 369 | |||
| 370 | input_dev->event = powermate_input_event; | ||
| 371 | |||
| 372 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); | ||
| 373 | input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
| 374 | input_dev->relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); | ||
| 375 | input_dev->mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); | ||
| 355 | 376 | ||
| 356 | /* get a handle to the interrupt data pipe */ | 377 | /* get a handle to the interrupt data pipe */ |
| 357 | pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); | 378 | pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); |
| 358 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | 379 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); |
| 359 | 380 | ||
| 360 | if(maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX){ | 381 | if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) { |
| 361 | printk("powermate: Expected payload of %d--%d bytes, found %d bytes!\n", | 382 | printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n", |
| 362 | POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); | 383 | POWERMATE_PAYLOAD_SIZE_MIN, POWERMATE_PAYLOAD_SIZE_MAX, maxp); |
| 363 | maxp = POWERMATE_PAYLOAD_SIZE_MAX; | 384 | maxp = POWERMATE_PAYLOAD_SIZE_MAX; |
| 364 | } | 385 | } |
| @@ -371,35 +392,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i | |||
| 371 | 392 | ||
| 372 | /* register our interrupt URB with the USB system */ | 393 | /* register our interrupt URB with the USB system */ |
| 373 | if (usb_submit_urb(pm->irq, GFP_KERNEL)) { | 394 | if (usb_submit_urb(pm->irq, GFP_KERNEL)) { |
| 374 | powermate_free_buffers(udev, pm); | 395 | err = -EIO; |
| 375 | kfree(pm); | 396 | goto fail4; |
| 376 | return -EIO; /* failure */ | ||
| 377 | } | 397 | } |
| 378 | 398 | ||
| 379 | switch (le16_to_cpu(udev->descriptor.idProduct)) { | 399 | input_register_device(pm->input); |
| 380 | case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break; | ||
| 381 | case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break; | ||
| 382 | default: | ||
| 383 | pm->input.name = pm_name_soundknob; | ||
| 384 | printk(KERN_WARNING "powermate: unknown product id %04x\n", | ||
| 385 | le16_to_cpu(udev->descriptor.idProduct)); | ||
| 386 | } | ||
| 387 | |||
| 388 | pm->input.private = pm; | ||
| 389 | pm->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_MSC); | ||
| 390 | pm->input.keybit[LONG(BTN_0)] = BIT(BTN_0); | ||
| 391 | pm->input.relbit[LONG(REL_DIAL)] = BIT(REL_DIAL); | ||
| 392 | pm->input.mscbit[LONG(MSC_PULSELED)] = BIT(MSC_PULSELED); | ||
| 393 | usb_to_input_id(udev, &pm->input.id); | ||
| 394 | pm->input.event = powermate_input_event; | ||
| 395 | pm->input.dev = &intf->dev; | ||
| 396 | pm->input.phys = pm->phys; | ||
| 397 | |||
| 398 | input_register_device(&pm->input); | ||
| 399 | |||
| 400 | usb_make_path(udev, path, 64); | ||
| 401 | snprintf(pm->phys, 64, "%s/input0", path); | ||
| 402 | printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys); | ||
| 403 | 400 | ||
| 404 | /* force an update of everything */ | 401 | /* force an update of everything */ |
| 405 | pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; | 402 | pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS; |
| @@ -407,6 +404,13 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i | |||
| 407 | 404 | ||
| 408 | usb_set_intfdata(intf, pm); | 405 | usb_set_intfdata(intf, pm); |
| 409 | return 0; | 406 | return 0; |
| 407 | |||
| 408 | fail4: usb_free_urb(pm->config); | ||
| 409 | fail3: usb_free_urb(pm->irq); | ||
| 410 | fail2: powermate_free_buffers(udev, pm); | ||
| 411 | fail1: input_free_device(input_dev); | ||
| 412 | kfree(pm); | ||
| 413 | return err; | ||
| 410 | } | 414 | } |
| 411 | 415 | ||
| 412 | /* Called when a USB device we've accepted ownership of is removed */ | 416 | /* Called when a USB device we've accepted ownership of is removed */ |
| @@ -418,7 +422,7 @@ static void powermate_disconnect(struct usb_interface *intf) | |||
| 418 | if (pm) { | 422 | if (pm) { |
| 419 | pm->requires_update = 0; | 423 | pm->requires_update = 0; |
| 420 | usb_kill_urb(pm->irq); | 424 | usb_kill_urb(pm->irq); |
| 421 | input_unregister_device(&pm->input); | 425 | input_unregister_device(pm->input); |
| 422 | usb_free_urb(pm->irq); | 426 | usb_free_urb(pm->irq); |
| 423 | usb_free_urb(pm->config); | 427 | usb_free_urb(pm->config); |
| 424 | powermate_free_buffers(interface_to_usbdev(intf), pm); | 428 | powermate_free_buffers(interface_to_usbdev(intf), pm); |
