diff options
Diffstat (limited to 'drivers/hid/hid-steam.c')
-rw-r--r-- | drivers/hid/hid-steam.c | 154 |
1 files changed, 90 insertions, 64 deletions
diff --git a/drivers/hid/hid-steam.c b/drivers/hid/hid-steam.c index 0422ec2b13d2..dc4128bfe2ca 100644 --- a/drivers/hid/hid-steam.c +++ b/drivers/hid/hid-steam.c | |||
@@ -23,8 +23,9 @@ | |||
23 | * In order to avoid breaking them this driver creates a layered hidraw device, | 23 | * In order to avoid breaking them this driver creates a layered hidraw device, |
24 | * so it can detect when the client is running and then: | 24 | * so it can detect when the client is running and then: |
25 | * - it will not send any command to the controller. | 25 | * - it will not send any command to the controller. |
26 | * - this input device will be disabled, to avoid double input of the same | 26 | * - this input device will be removed, to avoid double input of the same |
27 | * user action. | 27 | * user action. |
28 | * When the client is closed, this input device will be created again. | ||
28 | * | 29 | * |
29 | * For additional functions, such as changing the right-pad margin or switching | 30 | * For additional functions, such as changing the right-pad margin or switching |
30 | * the led, you can use the user-space tool at: | 31 | * the led, you can use the user-space tool at: |
@@ -113,7 +114,7 @@ struct steam_device { | |||
113 | spinlock_t lock; | 114 | spinlock_t lock; |
114 | struct hid_device *hdev, *client_hdev; | 115 | struct hid_device *hdev, *client_hdev; |
115 | struct mutex mutex; | 116 | struct mutex mutex; |
116 | bool client_opened, input_opened; | 117 | bool client_opened; |
117 | struct input_dev __rcu *input; | 118 | struct input_dev __rcu *input; |
118 | unsigned long quirks; | 119 | unsigned long quirks; |
119 | struct work_struct work_connect; | 120 | struct work_struct work_connect; |
@@ -279,18 +280,6 @@ static void steam_set_lizard_mode(struct steam_device *steam, bool enable) | |||
279 | } | 280 | } |
280 | } | 281 | } |
281 | 282 | ||
282 | static void steam_update_lizard_mode(struct steam_device *steam) | ||
283 | { | ||
284 | mutex_lock(&steam->mutex); | ||
285 | if (!steam->client_opened) { | ||
286 | if (steam->input_opened) | ||
287 | steam_set_lizard_mode(steam, false); | ||
288 | else | ||
289 | steam_set_lizard_mode(steam, lizard_mode); | ||
290 | } | ||
291 | mutex_unlock(&steam->mutex); | ||
292 | } | ||
293 | |||
294 | static int steam_input_open(struct input_dev *dev) | 283 | static int steam_input_open(struct input_dev *dev) |
295 | { | 284 | { |
296 | struct steam_device *steam = input_get_drvdata(dev); | 285 | struct steam_device *steam = input_get_drvdata(dev); |
@@ -301,7 +290,6 @@ static int steam_input_open(struct input_dev *dev) | |||
301 | return ret; | 290 | return ret; |
302 | 291 | ||
303 | mutex_lock(&steam->mutex); | 292 | mutex_lock(&steam->mutex); |
304 | steam->input_opened = true; | ||
305 | if (!steam->client_opened && lizard_mode) | 293 | if (!steam->client_opened && lizard_mode) |
306 | steam_set_lizard_mode(steam, false); | 294 | steam_set_lizard_mode(steam, false); |
307 | mutex_unlock(&steam->mutex); | 295 | mutex_unlock(&steam->mutex); |
@@ -313,7 +301,6 @@ static void steam_input_close(struct input_dev *dev) | |||
313 | struct steam_device *steam = input_get_drvdata(dev); | 301 | struct steam_device *steam = input_get_drvdata(dev); |
314 | 302 | ||
315 | mutex_lock(&steam->mutex); | 303 | mutex_lock(&steam->mutex); |
316 | steam->input_opened = false; | ||
317 | if (!steam->client_opened && lizard_mode) | 304 | if (!steam->client_opened && lizard_mode) |
318 | steam_set_lizard_mode(steam, true); | 305 | steam_set_lizard_mode(steam, true); |
319 | mutex_unlock(&steam->mutex); | 306 | mutex_unlock(&steam->mutex); |
@@ -400,7 +387,7 @@ static int steam_battery_register(struct steam_device *steam) | |||
400 | return 0; | 387 | return 0; |
401 | } | 388 | } |
402 | 389 | ||
403 | static int steam_register(struct steam_device *steam) | 390 | static int steam_input_register(struct steam_device *steam) |
404 | { | 391 | { |
405 | struct hid_device *hdev = steam->hdev; | 392 | struct hid_device *hdev = steam->hdev; |
406 | struct input_dev *input; | 393 | struct input_dev *input; |
@@ -414,17 +401,6 @@ static int steam_register(struct steam_device *steam) | |||
414 | return 0; | 401 | return 0; |
415 | } | 402 | } |
416 | 403 | ||
417 | /* | ||
418 | * Unlikely, but getting the serial could fail, and it is not so | ||
419 | * important, so make up a serial number and go on. | ||
420 | */ | ||
421 | if (steam_get_serial(steam) < 0) | ||
422 | strlcpy(steam->serial_no, "XXXXXXXXXX", | ||
423 | sizeof(steam->serial_no)); | ||
424 | |||
425 | hid_info(hdev, "Steam Controller '%s' connected", | ||
426 | steam->serial_no); | ||
427 | |||
428 | input = input_allocate_device(); | 404 | input = input_allocate_device(); |
429 | if (!input) | 405 | if (!input) |
430 | return -ENOMEM; | 406 | return -ENOMEM; |
@@ -492,11 +468,6 @@ static int steam_register(struct steam_device *steam) | |||
492 | goto input_register_fail; | 468 | goto input_register_fail; |
493 | 469 | ||
494 | rcu_assign_pointer(steam->input, input); | 470 | rcu_assign_pointer(steam->input, input); |
495 | |||
496 | /* ignore battery errors, we can live without it */ | ||
497 | if (steam->quirks & STEAM_QUIRK_WIRELESS) | ||
498 | steam_battery_register(steam); | ||
499 | |||
500 | return 0; | 471 | return 0; |
501 | 472 | ||
502 | input_register_fail: | 473 | input_register_fail: |
@@ -504,27 +475,88 @@ input_register_fail: | |||
504 | return ret; | 475 | return ret; |
505 | } | 476 | } |
506 | 477 | ||
507 | static void steam_unregister(struct steam_device *steam) | 478 | static void steam_input_unregister(struct steam_device *steam) |
508 | { | 479 | { |
509 | struct input_dev *input; | 480 | struct input_dev *input; |
481 | rcu_read_lock(); | ||
482 | input = rcu_dereference(steam->input); | ||
483 | rcu_read_unlock(); | ||
484 | if (!input) | ||
485 | return; | ||
486 | RCU_INIT_POINTER(steam->input, NULL); | ||
487 | synchronize_rcu(); | ||
488 | input_unregister_device(input); | ||
489 | } | ||
490 | |||
491 | static void steam_battery_unregister(struct steam_device *steam) | ||
492 | { | ||
510 | struct power_supply *battery; | 493 | struct power_supply *battery; |
511 | 494 | ||
512 | rcu_read_lock(); | 495 | rcu_read_lock(); |
513 | input = rcu_dereference(steam->input); | ||
514 | battery = rcu_dereference(steam->battery); | 496 | battery = rcu_dereference(steam->battery); |
515 | rcu_read_unlock(); | 497 | rcu_read_unlock(); |
516 | 498 | ||
517 | if (battery) { | 499 | if (!battery) |
518 | RCU_INIT_POINTER(steam->battery, NULL); | 500 | return; |
519 | synchronize_rcu(); | 501 | RCU_INIT_POINTER(steam->battery, NULL); |
520 | power_supply_unregister(battery); | 502 | synchronize_rcu(); |
503 | power_supply_unregister(battery); | ||
504 | } | ||
505 | |||
506 | static int steam_register(struct steam_device *steam) | ||
507 | { | ||
508 | int ret; | ||
509 | |||
510 | /* | ||
511 | * This function can be called several times in a row with the | ||
512 | * wireless adaptor, without steam_unregister() between them, because | ||
513 | * another client send a get_connection_status command, for example. | ||
514 | * The battery and serial number are set just once per device. | ||
515 | */ | ||
516 | if (!steam->serial_no[0]) { | ||
517 | /* | ||
518 | * Unlikely, but getting the serial could fail, and it is not so | ||
519 | * important, so make up a serial number and go on. | ||
520 | */ | ||
521 | if (steam_get_serial(steam) < 0) | ||
522 | strlcpy(steam->serial_no, "XXXXXXXXXX", | ||
523 | sizeof(steam->serial_no)); | ||
524 | |||
525 | hid_info(steam->hdev, "Steam Controller '%s' connected", | ||
526 | steam->serial_no); | ||
527 | |||
528 | /* ignore battery errors, we can live without it */ | ||
529 | if (steam->quirks & STEAM_QUIRK_WIRELESS) | ||
530 | steam_battery_register(steam); | ||
531 | |||
532 | mutex_lock(&steam_devices_lock); | ||
533 | list_add(&steam->list, &steam_devices); | ||
534 | mutex_unlock(&steam_devices_lock); | ||
521 | } | 535 | } |
522 | if (input) { | 536 | |
523 | RCU_INIT_POINTER(steam->input, NULL); | 537 | mutex_lock(&steam->mutex); |
524 | synchronize_rcu(); | 538 | if (!steam->client_opened) { |
539 | steam_set_lizard_mode(steam, lizard_mode); | ||
540 | ret = steam_input_register(steam); | ||
541 | } else { | ||
542 | ret = 0; | ||
543 | } | ||
544 | mutex_unlock(&steam->mutex); | ||
545 | |||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | static void steam_unregister(struct steam_device *steam) | ||
550 | { | ||
551 | steam_battery_unregister(steam); | ||
552 | steam_input_unregister(steam); | ||
553 | if (steam->serial_no[0]) { | ||
525 | hid_info(steam->hdev, "Steam Controller '%s' disconnected", | 554 | hid_info(steam->hdev, "Steam Controller '%s' disconnected", |
526 | steam->serial_no); | 555 | steam->serial_no); |
527 | input_unregister_device(input); | 556 | mutex_lock(&steam_devices_lock); |
557 | list_del(&steam->list); | ||
558 | mutex_unlock(&steam_devices_lock); | ||
559 | steam->serial_no[0] = 0; | ||
528 | } | 560 | } |
529 | } | 561 | } |
530 | 562 | ||
@@ -600,6 +632,9 @@ static int steam_client_ll_open(struct hid_device *hdev) | |||
600 | mutex_lock(&steam->mutex); | 632 | mutex_lock(&steam->mutex); |
601 | steam->client_opened = true; | 633 | steam->client_opened = true; |
602 | mutex_unlock(&steam->mutex); | 634 | mutex_unlock(&steam->mutex); |
635 | |||
636 | steam_input_unregister(steam); | ||
637 | |||
603 | return ret; | 638 | return ret; |
604 | } | 639 | } |
605 | 640 | ||
@@ -609,13 +644,13 @@ static void steam_client_ll_close(struct hid_device *hdev) | |||
609 | 644 | ||
610 | mutex_lock(&steam->mutex); | 645 | mutex_lock(&steam->mutex); |
611 | steam->client_opened = false; | 646 | steam->client_opened = false; |
612 | if (steam->input_opened) | ||
613 | steam_set_lizard_mode(steam, false); | ||
614 | else | ||
615 | steam_set_lizard_mode(steam, lizard_mode); | ||
616 | mutex_unlock(&steam->mutex); | 647 | mutex_unlock(&steam->mutex); |
617 | 648 | ||
618 | hid_hw_close(steam->hdev); | 649 | hid_hw_close(steam->hdev); |
650 | if (steam->connected) { | ||
651 | steam_set_lizard_mode(steam, lizard_mode); | ||
652 | steam_input_register(steam); | ||
653 | } | ||
619 | } | 654 | } |
620 | 655 | ||
621 | static int steam_client_ll_raw_request(struct hid_device *hdev, | 656 | static int steam_client_ll_raw_request(struct hid_device *hdev, |
@@ -744,11 +779,6 @@ static int steam_probe(struct hid_device *hdev, | |||
744 | } | 779 | } |
745 | } | 780 | } |
746 | 781 | ||
747 | mutex_lock(&steam_devices_lock); | ||
748 | steam_update_lizard_mode(steam); | ||
749 | list_add(&steam->list, &steam_devices); | ||
750 | mutex_unlock(&steam_devices_lock); | ||
751 | |||
752 | return 0; | 782 | return 0; |
753 | 783 | ||
754 | hid_hw_open_fail: | 784 | hid_hw_open_fail: |
@@ -774,10 +804,6 @@ static void steam_remove(struct hid_device *hdev) | |||
774 | return; | 804 | return; |
775 | } | 805 | } |
776 | 806 | ||
777 | mutex_lock(&steam_devices_lock); | ||
778 | list_del(&steam->list); | ||
779 | mutex_unlock(&steam_devices_lock); | ||
780 | |||
781 | hid_destroy_device(steam->client_hdev); | 807 | hid_destroy_device(steam->client_hdev); |
782 | steam->client_opened = false; | 808 | steam->client_opened = false; |
783 | cancel_work_sync(&steam->work_connect); | 809 | cancel_work_sync(&steam->work_connect); |
@@ -792,12 +818,14 @@ static void steam_remove(struct hid_device *hdev) | |||
792 | static void steam_do_connect_event(struct steam_device *steam, bool connected) | 818 | static void steam_do_connect_event(struct steam_device *steam, bool connected) |
793 | { | 819 | { |
794 | unsigned long flags; | 820 | unsigned long flags; |
821 | bool changed; | ||
795 | 822 | ||
796 | spin_lock_irqsave(&steam->lock, flags); | 823 | spin_lock_irqsave(&steam->lock, flags); |
824 | changed = steam->connected != connected; | ||
797 | steam->connected = connected; | 825 | steam->connected = connected; |
798 | spin_unlock_irqrestore(&steam->lock, flags); | 826 | spin_unlock_irqrestore(&steam->lock, flags); |
799 | 827 | ||
800 | if (schedule_work(&steam->work_connect) == 0) | 828 | if (changed && schedule_work(&steam->work_connect) == 0) |
801 | dbg_hid("%s: connected=%d event already queued\n", | 829 | dbg_hid("%s: connected=%d event already queued\n", |
802 | __func__, connected); | 830 | __func__, connected); |
803 | } | 831 | } |
@@ -1019,13 +1047,8 @@ static int steam_raw_event(struct hid_device *hdev, | |||
1019 | return 0; | 1047 | return 0; |
1020 | rcu_read_lock(); | 1048 | rcu_read_lock(); |
1021 | input = rcu_dereference(steam->input); | 1049 | input = rcu_dereference(steam->input); |
1022 | if (likely(input)) { | 1050 | if (likely(input)) |
1023 | steam_do_input_event(steam, input, data); | 1051 | steam_do_input_event(steam, input, data); |
1024 | } else { | ||
1025 | dbg_hid("%s: input data without connect event\n", | ||
1026 | __func__); | ||
1027 | steam_do_connect_event(steam, true); | ||
1028 | } | ||
1029 | rcu_read_unlock(); | 1052 | rcu_read_unlock(); |
1030 | break; | 1053 | break; |
1031 | case STEAM_EV_CONNECT: | 1054 | case STEAM_EV_CONNECT: |
@@ -1074,7 +1097,10 @@ static int steam_param_set_lizard_mode(const char *val, | |||
1074 | 1097 | ||
1075 | mutex_lock(&steam_devices_lock); | 1098 | mutex_lock(&steam_devices_lock); |
1076 | list_for_each_entry(steam, &steam_devices, list) { | 1099 | list_for_each_entry(steam, &steam_devices, list) { |
1077 | steam_update_lizard_mode(steam); | 1100 | mutex_lock(&steam->mutex); |
1101 | if (!steam->client_opened) | ||
1102 | steam_set_lizard_mode(steam, lizard_mode); | ||
1103 | mutex_unlock(&steam->mutex); | ||
1078 | } | 1104 | } |
1079 | mutex_unlock(&steam_devices_lock); | 1105 | mutex_unlock(&steam_devices_lock); |
1080 | return 0; | 1106 | return 0; |