diff options
Diffstat (limited to 'firmware/usbstack')
-rw-r--r-- | firmware/usbstack/usb_hid.c | 86 |
1 files changed, 63 insertions, 23 deletions
diff --git a/firmware/usbstack/usb_hid.c b/firmware/usbstack/usb_hid.c index 0b672e6452..5885b60e32 100644 --- a/firmware/usbstack/usb_hid.c +++ b/firmware/usbstack/usb_hid.c | |||
@@ -42,6 +42,7 @@ | |||
42 | /* HID main items (HID1_11.pdf, page 38) */ | 42 | /* HID main items (HID1_11.pdf, page 38) */ |
43 | #define INPUT 0x80 | 43 | #define INPUT 0x80 |
44 | #define OUTPUT 0x90 | 44 | #define OUTPUT 0x90 |
45 | #define FEATURE 0xB0 | ||
45 | #define COLLECTION 0xA0 | 46 | #define COLLECTION 0xA0 |
46 | #define COLLECTION_PHYSICAL 0x00 | 47 | #define COLLECTION_PHYSICAL 0x00 |
47 | #define COLLECTION_APPLICATION 0x01 | 48 | #define COLLECTION_APPLICATION 0x01 |
@@ -90,6 +91,7 @@ | |||
90 | #define HID_BUF_SIZE_REPORT 160 | 91 | #define HID_BUF_SIZE_REPORT 160 |
91 | #define HID_NUM_BUFFERS 5 | 92 | #define HID_NUM_BUFFERS 5 |
92 | #define SET_REPORT_BUF_LEN 2 | 93 | #define SET_REPORT_BUF_LEN 2 |
94 | #define GET_REPORT_BUF_LEN 2 | ||
93 | 95 | ||
94 | #ifdef LOGF_ENABLE | 96 | #ifdef LOGF_ENABLE |
95 | 97 | ||
@@ -103,6 +105,8 @@ | |||
103 | #define HID_BUF_INC(i) do { (i) = ((i) + 1) % HID_NUM_BUFFERS; } while (0) | 105 | #define HID_BUF_INC(i) do { (i) = ((i) + 1) % HID_NUM_BUFFERS; } while (0) |
104 | #define PACK_VAL(dest, val) *(dest)++ = (val) & 0xff | 106 | #define PACK_VAL(dest, val) *(dest)++ = (val) & 0xff |
105 | 107 | ||
108 | #define REPORT_ID_BACKGROUND REPORT_ID_COUNT | ||
109 | |||
106 | typedef enum | 110 | typedef enum |
107 | { | 111 | { |
108 | REPORT_ID_KEYBOARD = 1, | 112 | REPORT_ID_KEYBOARD = 1, |
@@ -110,7 +114,6 @@ typedef enum | |||
110 | #ifdef HAVE_USB_HID_MOUSE | 114 | #ifdef HAVE_USB_HID_MOUSE |
111 | REPORT_ID_MOUSE, | 115 | REPORT_ID_MOUSE, |
112 | #endif | 116 | #endif |
113 | REPORT_ID_BACKGROUND, | ||
114 | REPORT_ID_COUNT, | 117 | REPORT_ID_COUNT, |
115 | } report_id_t; | 118 | } report_id_t; |
116 | 119 | ||
@@ -452,15 +455,6 @@ static uint8_t buf_set_mouse(unsigned char *buf, int id) | |||
452 | } | 455 | } |
453 | #endif /* HAVE_USB_HID_MOUSE */ | 456 | #endif /* HAVE_USB_HID_MOUSE */ |
454 | 457 | ||
455 | #define BUF_LEN_BACKGROUND 1 | ||
456 | static uint8_t buf_set_background(unsigned char *buf, int id) | ||
457 | { | ||
458 | memset(buf, 0, BUF_LEN_BACKGROUND); | ||
459 | buf[0] = (uint8_t)id; | ||
460 | |||
461 | return BUF_LEN_BACKGROUND; | ||
462 | } | ||
463 | |||
464 | static size_t descriptor_report_get(unsigned char *dest) | 458 | static size_t descriptor_report_get(unsigned char *dest) |
465 | { | 459 | { |
466 | unsigned char *report = dest; | 460 | unsigned char *report = dest; |
@@ -562,22 +556,25 @@ static size_t descriptor_report_get(unsigned char *dest) | |||
562 | PACK_VAL(report, END_COLLECTION); | 556 | PACK_VAL(report, END_COLLECTION); |
563 | #endif /* HAVE_USB_HID_MOUSE */ | 557 | #endif /* HAVE_USB_HID_MOUSE */ |
564 | 558 | ||
565 | /* Background controls */ | 559 | /* Background reports */ |
566 | usb_hid_report = &usb_hid_reports[REPORT_ID_BACKGROUND]; | ||
567 | usb_hid_report->usage_page = HID_USAGE_PAGE_GENERIC_DEVICE_CONTROLS; | ||
568 | usb_hid_report->buf_set = buf_set_background; | ||
569 | usb_hid_report->is_key_released = 0; | ||
570 | |||
571 | pack_parameter(&report, 0, 1, USAGE_PAGE, HID_USAGE_PAGE_GENERIC_DEVICE_CONTROLS); | 560 | pack_parameter(&report, 0, 1, USAGE_PAGE, HID_USAGE_PAGE_GENERIC_DEVICE_CONTROLS); |
572 | pack_parameter(&report, 0, 0, CONSUMER_USAGE, HID_GENERIC_DEVICE_BACKGROUND_CONTROLS); | 561 | pack_parameter(&report, 0, 0, CONSUMER_USAGE, HID_GENERIC_DEVICE_BACKGROUND_CONTROLS); |
573 | pack_parameter(&report, 0, 1, COLLECTION, COLLECTION_APPLICATION); | 562 | pack_parameter(&report, 0, 1, COLLECTION, COLLECTION_APPLICATION); |
574 | pack_parameter(&report, 0, 1, REPORT_ID, REPORT_ID_BACKGROUND); | 563 | pack_parameter(&report, 0, 1, REPORT_ID, REPORT_ID_BACKGROUND); |
564 | /* Padding */ | ||
565 | pack_parameter(&report, 0, 0, CONSUMER_USAGE, HID_GENERIC_DEVICE_UNDEFINED); | ||
566 | pack_parameter(&report, 0, 1, LOGICAL_MINIMUM, 0); | ||
567 | pack_parameter(&report, 0, 1, LOGICAL_MAXIMUM, 255); | ||
568 | pack_parameter(&report, 0, 1, REPORT_SIZE, 8); | ||
569 | pack_parameter(&report, 0, 1, REPORT_COUNT, 1); | ||
570 | pack_parameter(&report, 0, 1, FEATURE, MAIN_ITEM_CONSTANT); | ||
571 | /* Battery percentage */ | ||
575 | pack_parameter(&report, 0, 0, CONSUMER_USAGE, HID_GENERIC_DEVICE_BATTERY_STRENGTH); | 572 | pack_parameter(&report, 0, 0, CONSUMER_USAGE, HID_GENERIC_DEVICE_BATTERY_STRENGTH); |
576 | pack_parameter(&report, 0, 1, LOGICAL_MINIMUM, 0); | 573 | pack_parameter(&report, 0, 1, LOGICAL_MINIMUM, 0); |
577 | pack_parameter(&report, 0, 1, LOGICAL_MAXIMUM, 100); | 574 | pack_parameter(&report, 0, 1, LOGICAL_MAXIMUM, 100); |
578 | pack_parameter(&report, 0, 1, REPORT_SIZE, 8); | 575 | pack_parameter(&report, 0, 1, REPORT_SIZE, 8); |
579 | pack_parameter(&report, 0, 1, REPORT_COUNT, 1); | 576 | pack_parameter(&report, 0, 1, REPORT_COUNT, 1); |
580 | pack_parameter(&report, 0, 1, INPUT, MAIN_ITEM_VARIABLE); | 577 | pack_parameter(&report, 0, 1, FEATURE, MAIN_ITEM_VARIABLE); |
581 | PACK_VAL(report, END_COLLECTION); | 578 | PACK_VAL(report, END_COLLECTION); |
582 | 579 | ||
583 | return (size_t)(report - dest); | 580 | return (size_t)(report - dest); |
@@ -622,7 +619,6 @@ void usb_hid_init_connection(void) | |||
622 | logf("hid: init connection"); | 619 | logf("hid: init connection"); |
623 | active = true; | 620 | active = true; |
624 | currently_sending = false; | 621 | currently_sending = false; |
625 | set_battery_reporting(true); | ||
626 | } | 622 | } |
627 | 623 | ||
628 | /* called by usb_core_init() */ | 624 | /* called by usb_core_init() */ |
@@ -643,7 +639,6 @@ void usb_hid_init(void) | |||
643 | void usb_hid_disconnect(void) | 639 | void usb_hid_disconnect(void) |
644 | { | 640 | { |
645 | logf("hid: disconnect"); | 641 | logf("hid: disconnect"); |
646 | set_battery_reporting(false); | ||
647 | active = false; | 642 | active = false; |
648 | currently_sending = false; | 643 | currently_sending = false; |
649 | } | 644 | } |
@@ -677,7 +672,7 @@ static int usb_hid_set_report(struct usb_ctrlrequest *req) | |||
677 | 672 | ||
678 | if ((req->wValue >> 8) != REPORT_TYPE_OUTPUT) | 673 | if ((req->wValue >> 8) != REPORT_TYPE_OUTPUT) |
679 | { | 674 | { |
680 | logf("Unsopported report type"); | 675 | logf("Unsupported report type"); |
681 | return 1; | 676 | return 1; |
682 | } | 677 | } |
683 | if ((req->wValue & 0xff) != REPORT_ID_KEYBOARD) | 678 | if ((req->wValue & 0xff) != REPORT_ID_KEYBOARD) |
@@ -718,14 +713,47 @@ static int usb_hid_set_report(struct usb_ctrlrequest *req) | |||
718 | return 0; | 713 | return 0; |
719 | } | 714 | } |
720 | 715 | ||
716 | static int usb_hid_get_report(struct usb_ctrlrequest *req, unsigned char** dest) | ||
717 | { | ||
718 | if ((req->wValue >> 8) != REPORT_TYPE_FEATURE) | ||
719 | { | ||
720 | logf("Unsupported report type"); | ||
721 | return 1; | ||
722 | } | ||
723 | |||
724 | if ((req->wValue & 0xff) != REPORT_ID_BACKGROUND) | ||
725 | { | ||
726 | logf("Wrong report id"); | ||
727 | return 2; | ||
728 | } | ||
729 | |||
730 | if (req->wIndex != (uint16_t)usb_interface) | ||
731 | { | ||
732 | logf("Wrong interface"); | ||
733 | return 3; | ||
734 | } | ||
735 | |||
736 | if (req->wLength < GET_REPORT_BUF_LEN) | ||
737 | { | ||
738 | logf("Wrong length"); | ||
739 | return 4; | ||
740 | } | ||
741 | |||
742 | (*dest)[0] = 0; | ||
743 | (*dest)[1] = battery_level(); | ||
744 | *dest += GET_REPORT_BUF_LEN; | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
721 | /* called by usb_core_control_request() */ | 749 | /* called by usb_core_control_request() */ |
722 | bool usb_hid_control_request(struct usb_ctrlrequest *req, unsigned char *dest) | 750 | bool usb_hid_control_request(struct usb_ctrlrequest *req, unsigned char *dest) |
723 | { | 751 | { |
752 | unsigned char *orig_dest = dest; | ||
724 | switch (req->bRequestType & USB_TYPE_MASK) | 753 | switch (req->bRequestType & USB_TYPE_MASK) |
725 | { | 754 | { |
726 | case USB_TYPE_STANDARD: | 755 | case USB_TYPE_STANDARD: |
727 | { | 756 | { |
728 | unsigned char *orig_dest = dest; | ||
729 | uint8_t type = req->wValue >> 8; | 757 | uint8_t type = req->wValue >> 8; |
730 | size_t len; | 758 | size_t len; |
731 | logf("hid: type %d %s", type, (type == USB_DT_HID) ? "hid" : | 759 | logf("hid: type %d %s", type, (type == USB_DT_HID) ? "hid" : |
@@ -755,14 +783,26 @@ bool usb_hid_control_request(struct usb_ctrlrequest *req, unsigned char *dest) | |||
755 | { | 783 | { |
756 | logf("req %d %s", req->bRequest, | 784 | logf("req %d %s", req->bRequest, |
757 | (req->bRequest == USB_HID_SET_IDLE) ? "set idle" : | 785 | (req->bRequest == USB_HID_SET_IDLE) ? "set idle" : |
758 | ((req->bRequest == USB_HID_SET_REPORT) ? "set report" : "")); | 786 | ((req->bRequest == USB_HID_SET_REPORT) ? "set report" : |
787 | ((req->bRequest == USB_HID_GET_REPORT) ? "get report" : ""))); | ||
759 | switch (req->bRequest) | 788 | switch (req->bRequest) |
760 | { | 789 | { |
761 | case USB_HID_SET_REPORT: | 790 | case USB_HID_SET_REPORT: |
762 | if (usb_hid_set_report(req)) | 791 | if (usb_hid_set_report(req)) |
763 | break; | 792 | break; |
793 | case USB_HID_GET_REPORT: | ||
794 | if (usb_hid_get_report(req, &dest)) | ||
795 | break; | ||
764 | case USB_HID_SET_IDLE: | 796 | case USB_HID_SET_IDLE: |
765 | usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ | 797 | if (dest != orig_dest) |
798 | { | ||
799 | usb_drv_recv(EP_CONTROL, NULL, 0); /* ack */ | ||
800 | usb_drv_send(EP_CONTROL, orig_dest, dest - orig_dest); | ||
801 | } | ||
802 | else | ||
803 | { | ||
804 | usb_drv_send(EP_CONTROL, NULL, 0); /* ack */ | ||
805 | } | ||
766 | return true; | 806 | return true; |
767 | } | 807 | } |
768 | break; | 808 | break; |