aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-wiimote-modules.c
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:55 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:02 -0400
commit0ea1675723021bc412bc9ea5d601e2b5660b5f8c (patch)
treeac28f5e21ce9ba1bfa5c0723695f12a015e02b27 /drivers/hid/hid-wiimote-modules.c
parent6c5ae01805e2cc1810328b538ccb2376b5f8bd9f (diff)
HID: wiimote: convert ACCEL to module
Accelerometer data is very similar to KEYS handling. Therefore, convert all ACCEL related handling into a sub-device module similar to KEYS. This doesn't change any semantics but only moves code over to wiimote-modules. Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-wiimote-modules.c')
-rw-r--r--drivers/hid/hid-wiimote-modules.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote-modules.c b/drivers/hid/hid-wiimote-modules.c
index f96de153971c..fbc09c8810b8 100644
--- a/drivers/hid/hid-wiimote-modules.c
+++ b/drivers/hid/hid-wiimote-modules.c
@@ -404,6 +404,128 @@ static const struct wiimod_ops wiimod_leds[4] = {
404 }, 404 },
405}; 405};
406 406
407/*
408 * Accelerometer
409 * 3 axis accelerometer data is part of nearly all DRMs. If not supported by a
410 * device, it's mostly cleared to 0. This module parses this data and provides
411 * it via a separate input device.
412 */
413
414static void wiimod_accel_in_accel(struct wiimote_data *wdata,
415 const __u8 *accel)
416{
417 __u16 x, y, z;
418
419 if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
420 return;
421
422 /*
423 * payload is: BB BB XX YY ZZ
424 * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
425 * contain the upper 8 bits of each value. The lower 2 bits are
426 * contained in the buttons data BB BB.
427 * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
428 * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
429 * accel value and bit 6 is the second bit of the Z value.
430 * The first bit of Y and Z values is not available and always set to 0.
431 * 0x200 is returned on no movement.
432 */
433
434 x = accel[2] << 2;
435 y = accel[3] << 2;
436 z = accel[4] << 2;
437
438 x |= (accel[0] >> 5) & 0x3;
439 y |= (accel[1] >> 4) & 0x2;
440 z |= (accel[1] >> 5) & 0x2;
441
442 input_report_abs(wdata->accel, ABS_RX, x - 0x200);
443 input_report_abs(wdata->accel, ABS_RY, y - 0x200);
444 input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
445 input_sync(wdata->accel);
446}
447
448static int wiimod_accel_open(struct input_dev *dev)
449{
450 struct wiimote_data *wdata = input_get_drvdata(dev);
451 unsigned long flags;
452
453 spin_lock_irqsave(&wdata->state.lock, flags);
454 wiiproto_req_accel(wdata, true);
455 spin_unlock_irqrestore(&wdata->state.lock, flags);
456
457 return 0;
458}
459
460static void wiimod_accel_close(struct input_dev *dev)
461{
462 struct wiimote_data *wdata = input_get_drvdata(dev);
463 unsigned long flags;
464
465 spin_lock_irqsave(&wdata->state.lock, flags);
466 wiiproto_req_accel(wdata, false);
467 spin_unlock_irqrestore(&wdata->state.lock, flags);
468}
469
470static int wiimod_accel_probe(const struct wiimod_ops *ops,
471 struct wiimote_data *wdata)
472{
473 int ret;
474
475 wdata->accel = input_allocate_device();
476 if (!wdata->accel)
477 return -ENOMEM;
478
479 input_set_drvdata(wdata->accel, wdata);
480 wdata->accel->open = wiimod_accel_open;
481 wdata->accel->close = wiimod_accel_close;
482 wdata->accel->dev.parent = &wdata->hdev->dev;
483 wdata->accel->id.bustype = wdata->hdev->bus;
484 wdata->accel->id.vendor = wdata->hdev->vendor;
485 wdata->accel->id.product = wdata->hdev->product;
486 wdata->accel->id.version = wdata->hdev->version;
487 wdata->accel->name = WIIMOTE_NAME " Accelerometer";
488
489 set_bit(EV_ABS, wdata->accel->evbit);
490 set_bit(ABS_RX, wdata->accel->absbit);
491 set_bit(ABS_RY, wdata->accel->absbit);
492 set_bit(ABS_RZ, wdata->accel->absbit);
493 input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
494 input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
495 input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
496
497 ret = input_register_device(wdata->accel);
498 if (ret) {
499 hid_err(wdata->hdev, "cannot register input device\n");
500 goto err_free;
501 }
502
503 return 0;
504
505err_free:
506 input_free_device(wdata->accel);
507 wdata->accel = NULL;
508 return ret;
509}
510
511static void wiimod_accel_remove(const struct wiimod_ops *ops,
512 struct wiimote_data *wdata)
513{
514 if (!wdata->accel)
515 return;
516
517 input_unregister_device(wdata->accel);
518 wdata->accel = NULL;
519}
520
521static const struct wiimod_ops wiimod_accel = {
522 .flags = 0,
523 .arg = 0,
524 .probe = wiimod_accel_probe,
525 .remove = wiimod_accel_remove,
526 .in_accel = wiimod_accel_in_accel,
527};
528
407/* module table */ 529/* module table */
408 530
409const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = { 531const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
@@ -414,4 +536,5 @@ const struct wiimod_ops *wiimod_table[WIIMOD_NUM] = {
414 [WIIMOD_LED2] = &wiimod_leds[1], 536 [WIIMOD_LED2] = &wiimod_leds[1],
415 [WIIMOD_LED3] = &wiimod_leds[2], 537 [WIIMOD_LED3] = &wiimod_leds[2],
416 [WIIMOD_LED4] = &wiimod_leds[3], 538 [WIIMOD_LED4] = &wiimod_leds[3],
539 [WIIMOD_ACCEL] = &wiimod_accel,
417}; 540};