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; |
