aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/cyapa.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse/cyapa.c')
-rw-r--r--drivers/input/mouse/cyapa.c289
1 files changed, 156 insertions, 133 deletions
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index b409c3d7d4fb..1bece8cad46f 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -6,7 +6,7 @@
6 * Daniel Kurtz <djkurtz@chromium.org> 6 * Daniel Kurtz <djkurtz@chromium.org>
7 * Benson Leung <bleung@chromium.org> 7 * Benson Leung <bleung@chromium.org>
8 * 8 *
9 * Copyright (C) 2011-2012 Cypress Semiconductor, Inc. 9 * Copyright (C) 2011-2014 Cypress Semiconductor, Inc.
10 * Copyright (C) 2011-2012 Google, Inc. 10 * Copyright (C) 2011-2012 Google, Inc.
11 * 11 *
12 * This file is subject to the terms and conditions of the GNU General Public 12 * This file is subject to the terms and conditions of the GNU General Public
@@ -206,7 +206,6 @@ struct cyapa {
206 struct i2c_client *client; 206 struct i2c_client *client;
207 struct input_dev *input; 207 struct input_dev *input;
208 char phys[32]; /* device physical location */ 208 char phys[32]; /* device physical location */
209 int irq;
210 bool irq_wake; /* irq wake is enabled */ 209 bool irq_wake; /* irq wake is enabled */
211 bool smbus; 210 bool smbus;
212 211
@@ -422,8 +421,8 @@ static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
422 */ 421 */
423static int cyapa_get_state(struct cyapa *cyapa) 422static int cyapa_get_state(struct cyapa *cyapa)
424{ 423{
425 int ret;
426 u8 status[BL_STATUS_SIZE]; 424 u8 status[BL_STATUS_SIZE];
425 int error;
427 426
428 cyapa->state = CYAPA_STATE_NO_DEVICE; 427 cyapa->state = CYAPA_STATE_NO_DEVICE;
429 428
@@ -433,18 +432,18 @@ static int cyapa_get_state(struct cyapa *cyapa)
433 * If the device is in operation mode, this will be the DATA regs. 432 * If the device is in operation mode, this will be the DATA regs.
434 * 433 *
435 */ 434 */
436 ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE, 435 error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
437 status); 436 status);
438 437
439 /* 438 /*
440 * On smbus systems in OP mode, the i2c_reg_read will fail with 439 * On smbus systems in OP mode, the i2c_reg_read will fail with
441 * -ETIMEDOUT. In this case, try again using the smbus equivalent 440 * -ETIMEDOUT. In this case, try again using the smbus equivalent
442 * command. This should return a BL_HEAD indicating CYAPA_STATE_OP. 441 * command. This should return a BL_HEAD indicating CYAPA_STATE_OP.
443 */ 442 */
444 if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO)) 443 if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO))
445 ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status); 444 error = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
446 445
447 if (ret != BL_STATUS_SIZE) 446 if (error != BL_STATUS_SIZE)
448 goto error; 447 goto error;
449 448
450 if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) { 449 if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
@@ -454,7 +453,7 @@ static int cyapa_get_state(struct cyapa *cyapa)
454 cyapa->state = CYAPA_STATE_OP; 453 cyapa->state = CYAPA_STATE_OP;
455 break; 454 break;
456 default: 455 default:
457 ret = -EAGAIN; 456 error = -EAGAIN;
458 goto error; 457 goto error;
459 } 458 }
460 } else { 459 } else {
@@ -468,7 +467,7 @@ static int cyapa_get_state(struct cyapa *cyapa)
468 467
469 return 0; 468 return 0;
470error: 469error:
471 return (ret < 0) ? ret : -EAGAIN; 470 return (error < 0) ? error : -EAGAIN;
472} 471}
473 472
474/* 473/*
@@ -487,31 +486,31 @@ error:
487 */ 486 */
488static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout) 487static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
489{ 488{
490 int ret; 489 int error;
491 int tries = timeout / 100; 490 int tries = timeout / 100;
492 491
493 ret = cyapa_get_state(cyapa); 492 error = cyapa_get_state(cyapa);
494 while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) { 493 while ((error || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
495 msleep(100); 494 msleep(100);
496 ret = cyapa_get_state(cyapa); 495 error = cyapa_get_state(cyapa);
497 } 496 }
498 return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret; 497 return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;
499} 498}
500 499
501static int cyapa_bl_deactivate(struct cyapa *cyapa) 500static int cyapa_bl_deactivate(struct cyapa *cyapa)
502{ 501{
503 int ret; 502 int error;
504 503
505 ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate), 504 error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
506 bl_deactivate); 505 bl_deactivate);
507 if (ret < 0) 506 if (error)
508 return ret; 507 return error;
509 508
510 /* wait for bootloader to switch to idle state; should take < 100ms */ 509 /* wait for bootloader to switch to idle state; should take < 100ms */
511 msleep(100); 510 msleep(100);
512 ret = cyapa_poll_state(cyapa, 500); 511 error = cyapa_poll_state(cyapa, 500);
513 if (ret < 0) 512 if (error)
514 return ret; 513 return error;
515 if (cyapa->state != CYAPA_STATE_BL_IDLE) 514 if (cyapa->state != CYAPA_STATE_BL_IDLE)
516 return -EAGAIN; 515 return -EAGAIN;
517 return 0; 516 return 0;
@@ -532,11 +531,11 @@ static int cyapa_bl_deactivate(struct cyapa *cyapa)
532 */ 531 */
533static int cyapa_bl_exit(struct cyapa *cyapa) 532static int cyapa_bl_exit(struct cyapa *cyapa)
534{ 533{
535 int ret; 534 int error;
536 535
537 ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit); 536 error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
538 if (ret < 0) 537 if (error)
539 return ret; 538 return error;
540 539
541 /* 540 /*
542 * Wait for bootloader to exit, and operation mode to start. 541 * Wait for bootloader to exit, and operation mode to start.
@@ -548,9 +547,9 @@ static int cyapa_bl_exit(struct cyapa *cyapa)
548 * updated to new firmware, it must first calibrate its sensors, which 547 * updated to new firmware, it must first calibrate its sensors, which
549 * can take up to an additional 2 seconds. 548 * can take up to an additional 2 seconds.
550 */ 549 */
551 ret = cyapa_poll_state(cyapa, 2000); 550 error = cyapa_poll_state(cyapa, 2000);
552 if (ret < 0) 551 if (error < 0)
553 return ret; 552 return error;
554 if (cyapa->state != CYAPA_STATE_OP) 553 if (cyapa->state != CYAPA_STATE_OP)
555 return -EAGAIN; 554 return -EAGAIN;
556 555
@@ -577,10 +576,13 @@ static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
577 power = ret & ~PWR_MODE_MASK; 576 power = ret & ~PWR_MODE_MASK;
578 power |= power_mode & PWR_MODE_MASK; 577 power |= power_mode & PWR_MODE_MASK;
579 ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power); 578 ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
580 if (ret < 0) 579 if (ret < 0) {
581 dev_err(dev, "failed to set power_mode 0x%02x err = %d\n", 580 dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
582 power_mode, ret); 581 power_mode, ret);
583 return ret; 582 return ret;
583 }
584
585 return 0;
584} 586}
585 587
586static int cyapa_get_query_data(struct cyapa *cyapa) 588static int cyapa_get_query_data(struct cyapa *cyapa)
@@ -637,28 +639,28 @@ static int cyapa_check_is_operational(struct cyapa *cyapa)
637{ 639{
638 struct device *dev = &cyapa->client->dev; 640 struct device *dev = &cyapa->client->dev;
639 static const char unique_str[] = "CYTRA"; 641 static const char unique_str[] = "CYTRA";
640 int ret; 642 int error;
641 643
642 ret = cyapa_poll_state(cyapa, 2000); 644 error = cyapa_poll_state(cyapa, 2000);
643 if (ret < 0) 645 if (error)
644 return ret; 646 return error;
645 switch (cyapa->state) { 647 switch (cyapa->state) {
646 case CYAPA_STATE_BL_ACTIVE: 648 case CYAPA_STATE_BL_ACTIVE:
647 ret = cyapa_bl_deactivate(cyapa); 649 error = cyapa_bl_deactivate(cyapa);
648 if (ret) 650 if (error)
649 return ret; 651 return error;
650 652
651 /* Fallthrough state */ 653 /* Fallthrough state */
652 case CYAPA_STATE_BL_IDLE: 654 case CYAPA_STATE_BL_IDLE:
653 ret = cyapa_bl_exit(cyapa); 655 error = cyapa_bl_exit(cyapa);
654 if (ret) 656 if (error)
655 return ret; 657 return error;
656 658
657 /* Fallthrough state */ 659 /* Fallthrough state */
658 case CYAPA_STATE_OP: 660 case CYAPA_STATE_OP:
659 ret = cyapa_get_query_data(cyapa); 661 error = cyapa_get_query_data(cyapa);
660 if (ret < 0) 662 if (error)
661 return ret; 663 return error;
662 664
663 /* only support firmware protocol gen3 */ 665 /* only support firmware protocol gen3 */
664 if (cyapa->gen != CYAPA_GEN3) { 666 if (cyapa->gen != CYAPA_GEN3) {
@@ -753,18 +755,42 @@ static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
753 return ret; 755 return ret;
754} 756}
755 757
758static int cyapa_open(struct input_dev *input)
759{
760 struct cyapa *cyapa = input_get_drvdata(input);
761 struct i2c_client *client = cyapa->client;
762 int error;
763
764 error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
765 if (error) {
766 dev_err(&client->dev, "set active power failed: %d\n", error);
767 return error;
768 }
769
770 enable_irq(client->irq);
771 return 0;
772}
773
774static void cyapa_close(struct input_dev *input)
775{
776 struct cyapa *cyapa = input_get_drvdata(input);
777
778 disable_irq(cyapa->client->irq);
779 cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
780}
781
756static int cyapa_create_input_dev(struct cyapa *cyapa) 782static int cyapa_create_input_dev(struct cyapa *cyapa)
757{ 783{
758 struct device *dev = &cyapa->client->dev; 784 struct device *dev = &cyapa->client->dev;
759 int ret;
760 struct input_dev *input; 785 struct input_dev *input;
786 int error;
761 787
762 if (!cyapa->physical_size_x || !cyapa->physical_size_y) 788 if (!cyapa->physical_size_x || !cyapa->physical_size_y)
763 return -EINVAL; 789 return -EINVAL;
764 790
765 input = cyapa->input = input_allocate_device(); 791 input = devm_input_allocate_device(dev);
766 if (!input) { 792 if (!input) {
767 dev_err(dev, "allocate memory for input device failed\n"); 793 dev_err(dev, "failed to allocate memory for input device.\n");
768 return -ENOMEM; 794 return -ENOMEM;
769 } 795 }
770 796
@@ -772,14 +798,17 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
772 input->phys = cyapa->phys; 798 input->phys = cyapa->phys;
773 input->id.bustype = BUS_I2C; 799 input->id.bustype = BUS_I2C;
774 input->id.version = 1; 800 input->id.version = 1;
775 input->id.product = 0; /* means any product in eventcomm. */ 801 input->id.product = 0; /* Means any product in eventcomm. */
776 input->dev.parent = &cyapa->client->dev; 802 input->dev.parent = &cyapa->client->dev;
777 803
804 input->open = cyapa_open;
805 input->close = cyapa_close;
806
778 input_set_drvdata(input, cyapa); 807 input_set_drvdata(input, cyapa);
779 808
780 __set_bit(EV_ABS, input->evbit); 809 __set_bit(EV_ABS, input->evbit);
781 810
782 /* finger position */ 811 /* Finger position */
783 input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0, 812 input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
784 0); 813 0);
785 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0, 814 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
@@ -801,35 +830,25 @@ static int cyapa_create_input_dev(struct cyapa *cyapa)
801 if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK) 830 if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
802 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); 831 __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
803 832
804 /* handle pointer emulation and unused slots in core */ 833 /* Handle pointer emulation and unused slots in core */
805 ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS, 834 error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
806 INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED); 835 INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
807 if (ret) { 836 if (error) {
808 dev_err(dev, "allocate memory for MT slots failed, %d\n", ret); 837 dev_err(dev, "failed to initialize MT slots: %d\n", error);
809 goto err_free_device; 838 return error;
810 } 839 }
811 840
812 /* Register the device in input subsystem */ 841 cyapa->input = input;
813 ret = input_register_device(input);
814 if (ret) {
815 dev_err(dev, "input device register failed, %d\n", ret);
816 goto err_free_device;
817 }
818 return 0; 842 return 0;
819
820err_free_device:
821 input_free_device(input);
822 cyapa->input = NULL;
823 return ret;
824} 843}
825 844
826static int cyapa_probe(struct i2c_client *client, 845static int cyapa_probe(struct i2c_client *client,
827 const struct i2c_device_id *dev_id) 846 const struct i2c_device_id *dev_id)
828{ 847{
829 int ret;
830 u8 adapter_func;
831 struct cyapa *cyapa;
832 struct device *dev = &client->dev; 848 struct device *dev = &client->dev;
849 struct cyapa *cyapa;
850 u8 adapter_func;
851 int error;
833 852
834 adapter_func = cyapa_check_adapter_functionality(client); 853 adapter_func = cyapa_check_adapter_functionality(client);
835 if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) { 854 if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
@@ -837,11 +856,9 @@ static int cyapa_probe(struct i2c_client *client,
837 return -EIO; 856 return -EIO;
838 } 857 }
839 858
840 cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL); 859 cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL);
841 if (!cyapa) { 860 if (!cyapa)
842 dev_err(dev, "allocate memory for cyapa failed\n");
843 return -ENOMEM; 861 return -ENOMEM;
844 }
845 862
846 cyapa->gen = CYAPA_GEN3; 863 cyapa->gen = CYAPA_GEN3;
847 cyapa->client = client; 864 cyapa->client = client;
@@ -852,67 +869,61 @@ static int cyapa_probe(struct i2c_client *client,
852 /* i2c isn't supported, use smbus */ 869 /* i2c isn't supported, use smbus */
853 if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS) 870 if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
854 cyapa->smbus = true; 871 cyapa->smbus = true;
872
855 cyapa->state = CYAPA_STATE_NO_DEVICE; 873 cyapa->state = CYAPA_STATE_NO_DEVICE;
856 ret = cyapa_check_is_operational(cyapa);
857 if (ret) {
858 dev_err(dev, "device not operational, %d\n", ret);
859 goto err_mem_free;
860 }
861 874
862 ret = cyapa_create_input_dev(cyapa); 875 error = cyapa_check_is_operational(cyapa);
863 if (ret) { 876 if (error) {
864 dev_err(dev, "create input_dev instance failed, %d\n", ret); 877 dev_err(dev, "device not operational, %d\n", error);
865 goto err_mem_free; 878 return error;
866 } 879 }
867 880
868 ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); 881 /* Power down the device until we need it */
869 if (ret) { 882 error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
870 dev_err(dev, "set active power failed, %d\n", ret); 883 if (error) {
871 goto err_unregister_device; 884 dev_err(dev, "failed to quiesce the device: %d\n", error);
885 return error;
872 } 886 }
873 887
874 cyapa->irq = client->irq; 888 error = cyapa_create_input_dev(cyapa);
875 ret = request_threaded_irq(cyapa->irq, 889 if (error)
876 NULL, 890 return error;
877 cyapa_irq, 891
878 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 892 error = devm_request_threaded_irq(dev, client->irq,
879 "cyapa", 893 NULL, cyapa_irq,
880 cyapa); 894 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
881 if (ret) { 895 "cyapa", cyapa);
882 dev_err(dev, "IRQ request failed: %d\n, ", ret); 896 if (error) {
883 goto err_unregister_device; 897 dev_err(dev, "failed to request threaded irq: %d\n", error);
898 return error;
884 } 899 }
885 900
886 return 0; 901 /* Disable IRQ until the device is opened */
902 disable_irq(client->irq);
887 903
888err_unregister_device: 904 /* Register the device in input subsystem */
889 input_unregister_device(cyapa->input); 905 error = input_register_device(cyapa->input);
890err_mem_free: 906 if (error) {
891 kfree(cyapa); 907 dev_err(dev, "failed to register input device: %d\n", error);
892 908 return error;
893 return ret; 909 }
894}
895
896static int cyapa_remove(struct i2c_client *client)
897{
898 struct cyapa *cyapa = i2c_get_clientdata(client);
899
900 free_irq(cyapa->irq, cyapa);
901 input_unregister_device(cyapa->input);
902 cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
903 kfree(cyapa);
904 910
905 return 0; 911 return 0;
906} 912}
907 913
908#ifdef CONFIG_PM_SLEEP 914static int __maybe_unused cyapa_suspend(struct device *dev)
909static int cyapa_suspend(struct device *dev)
910{ 915{
911 int ret; 916 struct i2c_client *client = to_i2c_client(dev);
917 struct cyapa *cyapa = i2c_get_clientdata(client);
918 struct input_dev *input = cyapa->input;
912 u8 power_mode; 919 u8 power_mode;
913 struct cyapa *cyapa = dev_get_drvdata(dev); 920 int error;
914 921
915 disable_irq(cyapa->irq); 922 error = mutex_lock_interruptible(&input->mutex);
923 if (error)
924 return error;
925
926 disable_irq(client->irq);
916 927
917 /* 928 /*
918 * Set trackpad device to idle mode if wakeup is allowed, 929 * Set trackpad device to idle mode if wakeup is allowed,
@@ -920,31 +931,44 @@ static int cyapa_suspend(struct device *dev)
920 */ 931 */
921 power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE 932 power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
922 : PWR_MODE_OFF; 933 : PWR_MODE_OFF;
923 ret = cyapa_set_power_mode(cyapa, power_mode); 934 error = cyapa_set_power_mode(cyapa, power_mode);
924 if (ret < 0) 935 if (error)
925 dev_err(dev, "set power mode failed, %d\n", ret); 936 dev_err(dev, "resume: set power mode to %d failed: %d\n",
937 power_mode, error);
926 938
927 if (device_may_wakeup(dev)) 939 if (device_may_wakeup(dev))
928 cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0); 940 cyapa->irq_wake = (enable_irq_wake(client->irq) == 0);
941
942 mutex_unlock(&input->mutex);
943
929 return 0; 944 return 0;
930} 945}
931 946
932static int cyapa_resume(struct device *dev) 947static int __maybe_unused cyapa_resume(struct device *dev)
933{ 948{
934 int ret; 949 struct i2c_client *client = to_i2c_client(dev);
935 struct cyapa *cyapa = dev_get_drvdata(dev); 950 struct cyapa *cyapa = i2c_get_clientdata(client);
951 struct input_dev *input = cyapa->input;
952 u8 power_mode;
953 int error;
954
955 mutex_lock(&input->mutex);
936 956
937 if (device_may_wakeup(dev) && cyapa->irq_wake) 957 if (device_may_wakeup(dev) && cyapa->irq_wake)
938 disable_irq_wake(cyapa->irq); 958 disable_irq_wake(client->irq);
959
960 power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF;
961 error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
962 if (error)
963 dev_warn(dev, "resume: set power mode to %d failed: %d\n",
964 power_mode, error);
965
966 enable_irq(client->irq);
939 967
940 ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE); 968 mutex_unlock(&input->mutex);
941 if (ret)
942 dev_warn(dev, "resume active power failed, %d\n", ret);
943 969
944 enable_irq(cyapa->irq);
945 return 0; 970 return 0;
946} 971}
947#endif /* CONFIG_PM_SLEEP */
948 972
949static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume); 973static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume);
950 974
@@ -962,7 +986,6 @@ static struct i2c_driver cyapa_driver = {
962 }, 986 },
963 987
964 .probe = cyapa_probe, 988 .probe = cyapa_probe,
965 .remove = cyapa_remove,
966 .id_table = cyapa_id_table, 989 .id_table = cyapa_id_table,
967}; 990};
968 991