From 0385e0324e068fe37e9f8977aef185e1b7099047 Mon Sep 17 00:00:00 2001 From: login Date: Sun, 23 Oct 2022 20:38:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8usb=E8=AE=BE=E5=A4=87=E7=9A=84hid=20pa?= =?UTF-8?q?th=E4=B8=AD=E5=AF=BB=E6=89=BE=E7=BB=99=E5=AE=9A=E7=9A=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=EF=BC=88=E5=AD=98=E5=9C=A8=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=90=8E=E5=86=8D=E8=A7=A3=E5=86=B3=EF=BC=89?= =?UTF-8?q?=20(#67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/common/hid.h | 79 +++++++++++++++++++++++++++++++--- kernel/driver/hid/hidparse.c | 81 +++++++++++++++++++++++++++++------ kernel/driver/usb/xhci/xhci.c | 17 ++++++-- 3 files changed, 156 insertions(+), 21 deletions(-) diff --git a/kernel/common/hid.h b/kernel/common/hid.h index a864bc76..fd797233 100644 --- a/kernel/common/hid.h +++ b/kernel/common/hid.h @@ -5,6 +5,73 @@ #define HID_MAX_REPORT 300 // 最大允许的hid report数目(包括feature、input、output) #define HID_MAX_PATH_SIZE 16 // maximum depth for path +// 这部分请参考hid_1_11.pdf Section 6.2.2.4 + +#define HID_ITEM_COLLECTION 0xA0 +#define HID_ITEM_END_COLLECTION 0xC0 +#define HID_ITEM_FEATURE 0xB0 +#define HID_ITEM_INPUT 0x80 +#define HID_ITEM_OUTPUT 0x90 + +/** + * @brief 枚举hid的usage page列表。 + * 原始数据请见。 + * 该文件可从usb.org下载 + */ +enum HID_USAGE_PAGE_TYPES +{ + HID_USAGE_PAGE_GEN_DESKTOP = 0x1, + HID_USAGE_PAGE_SIMU_CTRL, // simulation controls + HID_USAGE_PAGE_VR_CTRL, // vr controls page + HID_USAGE_PAGE_SPORT_CTRL, // sport controls + HID_USAGE_PAGE_GAME_CTRL, // game controls + HID_USAGE_PAGE_GEN_DEVICE_CTRL, // general device controls + HID_USAGE_PAGE_KBD_KPD, // keyboard/ keypad page + HID_USAGE_PAGE_LED, // LED + HID_USAGE_PAGE_BUTTON, // button page + HID_USAGE_PAGE_ORDINAL, // ordinal page + HID_USAGE_PAGE_TEL_DEVICE, // telephony device + HID_USAGE_PAGE_CONSUMER, // consumer page + HID_USAGE_PAGE_DIGITIZER, // digitizers page + HID_USAGE_PAGE_HAPTICS, // haptics page + HID_USAGE_PAGE_PHY_INPUT_DEVICE, // physical input device page + HID_USAGE_PAGE_UNICODE = 0x10, // unicode page + HID_USAGE_PAGE_EYE_HEAD_TRACKER = 0x12, // eye and head trackers page + HID_USAGE_PAGE_AUX_DISPLAY = 0x14, // auxiliary display page + HID_USAGE_PAGE_SENSORS = 0x20, // sensors page + HID_USAGE_PAGE_MEDICAL = 0x40, // medical instruments + HID_USAGE_PAGE_BRAILLE_DISPLAY, // barille display + HID_USAGE_PAGE_LIGHTNING_ILLU = 0x59, // lighting and illumination page + HID_USAGE_PAGE_MONITOR = 0x80, // monitor page + HID_USAGE_PAGE_MONITOR_ENUMERATED, // monitor enumerated page + HID_USAGE_PAGE_VESA_VIRT_CTRL, // VESA virtual controls page + HID_USAGE_PAGE_POWER = 0x84, // power page + HID_USAGE_PAGE_BATTERY_SYSTEM, // battery system page + HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c, // barcode scanner page + HID_USAGE_PAGE_SCALES, // scales page + HID_USAGE_PAGE_MAGNET_STRIPE_READER, // magnetic stript reader page + HID_USAGE_PAGE_CAMERA_CONTROL = 0x90, // camera control page + HID_USAGE_PAGE_ARCADE, // arcade page + HID_USAGE_PAGE_GAMING_DEVICE, // gaming device page + HID_USAGE_PAGE_FIDO_ALLIANCE = 0xf1d0, // FIDO alliance page +}; + +/** + * @brief usage type for HID_USAGE_PAGE_GEN_DESKTOP page + * + */ +enum USAGE_TYPE_GENDESK +{ + HID_USAGE_GENDESK_UNDEF = 0, // undefined + HID_USAGE_GENDESK_POINTER, + HID_USAGE_GENDESK_MOUSE, + HID_USAGE_GENDESK_KEYBOARD = 0x6, + HID_USAGE_GENDESK_POINTER_X = 0x30, + HID_USAGE_GENDESK_POINTER_Y, + HID_USAGE_GENDESK_WHEEL = 0x38, + HID_USAGE_GENDESK_NOTHING = 0xff, +}; + /** * @brief 描述hid path中的一个节点 * @@ -40,7 +107,7 @@ struct hid_data_t uint8_t report_id; // report id(from incoming report) uint8_t type; // 数据类型:FEATURE / INPUT / OUTPUT - uint8_t attribute; // report field attribute. (2 = (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)) + uint8_t attribute; // report field attribute. (2 = (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)) // (6 = (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)) int8_t unit_exp; // unit exponent; @@ -78,11 +145,9 @@ struct hid_parser int cnt_objects; // report descriptor中的对象数目 - int cnt_report; // report desc中的report数目 - + int cnt_report; // report desc中的report数目 }; - struct hid_usage_types_string { int value; @@ -92,8 +157,10 @@ struct hid_usage_types_string struct hid_usage_pages_string { int value; - struct hid_usage_types_string * types; - const char * string; + struct hid_usage_types_string *types; + const char *string; }; int hid_parse_report(const void *report_data, const int len); + +bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data); \ No newline at end of file diff --git a/kernel/driver/hid/hidparse.c b/kernel/driver/hid/hidparse.c index c882f47a..bb49d269 100644 --- a/kernel/driver/hid/hidparse.c +++ b/kernel/driver/hid/hidparse.c @@ -44,21 +44,13 @@ static __always_inline const struct hid_usage_types_string *hid_get_usage_type( #define HID_ITEM_REP_ID 0x84 #define HID_ITEM_REP_COUNT 0x94 -// 这部分请参考hid_1_11.pdf Section 6.2.2.4 - -#define HID_ITEM_COLLECTION 0xA0 -#define HID_ITEM_END_COLLECTION 0xC0 -#define HID_ITEM_FEATURE 0xB0 -#define HID_ITEM_INPUT 0x80 -#define HID_ITEM_OUTPUT 0x90 - static char __spaces_buf[33]; char *__spaces(uint8_t cnt) { static char __space_overflow_str[] = "**"; if (cnt > 32) { - return &__space_overflow_str; + return __space_overflow_str; } memset(__spaces_buf, ' ', 32); @@ -111,7 +103,8 @@ static __always_inline void __pop_usage_stack(struct hid_parser *parser) /** * @brief 解析hid report,并获取下一个数据到data字段中 - * + * todo:(不知道为什么,在qemu上面,发现键盘的usage都是0xff) + * * @param parser 解析器 * @param data 返回的数据 * @return true 解析成功 @@ -345,7 +338,7 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data) break; default: printk("\n Found unknown item %#02X\n", parser->item & HID_ITEM_MASK); - return false; + return found; } } return found; @@ -509,7 +502,7 @@ static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_ while ((pos < HID_MAX_REPORT) && (parser->offset_table[pos][0] != 0)) // 当offset的id不为0时 { if ((parser->offset_table[pos][0] == report_id) && (parser->offset_table[pos][1] == report_type)) - return &parser->offset_table[2]; + return &parser->offset_table[pos][2]; ++pos; } // 在offset table中占用一个新的表项来存储这个report的offset @@ -523,4 +516,68 @@ static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_ } // 当offset table满了,且未找到结果的时候,返回NULL return NULL; +} + +static __always_inline bool __find_object(struct hid_parser *parser, struct hid_data_t *data) +{ + kdebug("target_type=%d report_id=%d, offset=%d, size=%d", data->type, data->report_id, data->offset, data->size); + struct hid_data_t found_data = {0}; + + while (hid_parse(parser, &found_data)) + { + kdebug("size=%d, type=%d, report_id=%d, u_page=%d, usage=%d", found_data.size, found_data.type, + found_data.report_id, found_data.path.node[0].u_page, found_data.path.node[0].usage); + // 按照路径完整匹配data + if ((data->path.size > 0) && (found_data.type == data->type) && + (memcmp(found_data.path.node, data->path.node, data->path.size * sizeof(struct hid_node_t)) == 0)) + { + goto found; + } + // 通过report id以及offset匹配成功 + else if ((found_data.report_id == data->report_id) && (found_data.type == data->type) && + (found_data.offset == data->offset)) + { + goto found; + } + } + return false; + +found:; + memcpy(data, &found_data, sizeof(struct hid_data_t)); + data->report_count = parser->report_count; + return true; +} +/** + * @brief 在hid report中寻找参数data给定的节点数据,并将结果写入到data中 + * + * @param hid_report hid report 数据 + * @param report_size report_data的大小(字节) + * @param data 要寻找的节点数据。 + * @return true 找到指定的节点 + * @return false 未找到指定的节点 + */ +bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data) +{ + struct hid_parser parser = {0}; + hid_reset_parser(&parser); + parser.report_desc = hid_report; + parser.report_desc_size = report_size; + // HID_PARSE_OUTPUT = false; + + printk("\nFinding Coordinate value:"); + if (__find_object(&parser, data)) + { + printk(" size: %i (in bits)\n" + " offset: %i (in bits)\n" + " min: %i\n" + " max: %i\n" + " attrib: 0x%02X (input, output, or feature, etc.)\n", + data->size, data->offset, data->logical_min, data->logical_max, data->attribute); + return true; + } + else + { + printk(" Did not find Coordinate value.\n"); + return false; + } } \ No newline at end of file diff --git a/kernel/driver/usb/xhci/xhci.c b/kernel/driver/usb/xhci/xhci.c index 07de8ca2..7d45fdd5 100644 --- a/kernel/driver/usb/xhci/xhci.c +++ b/kernel/driver/usb/xhci/xhci.c @@ -1383,7 +1383,7 @@ static inline int xhci_get_desc(const int id, const int port_id, void *target, c // 设备端口没有对应的描述符 if (unlikely(dev_desc == NULL)) return -EINVAL; - + uint8_t req_type = USB_REQ_TYPE_GET_REQUEST; if (desc_type == USB_DT_HID_REPORT) req_type = USB_REQ_TYPE_GET_INTERFACE_REQUEST; @@ -1863,9 +1863,20 @@ static int xhci_configure_port(const int id, const int port_id) } kdebug("to parse hid report"); - // todo: parse hid report - hid_parse_report(hid_report_data, hid_desc->report_desc_len); + // todo:这里的parse有问题,详见hid_parse函数的注释 + // hid_parse_report(hid_report_data, hid_desc->report_desc_len); kdebug("parse hid report done"); + + // kdebug("to find object from hid path"); + // struct hid_data_t data = {0}; + // data.type = HID_ITEM_INPUT; + // data.path.node[0].u_page = HID_USAGE_PAGE_GEN_DESKTOP; + // data.path.node[0].usage = 0xff; + // data.path.node[2].usage = USAGE_POINTER_Y; // to get the Y Coordinate, comment X above and uncomment this + // line data.path.node[2].usage = USAGE_POINTER_WHEEL; // to get the Wheel Coordinate, comment X above and + // uncomment this line + // data.path.size = 1; + // hid_parse_find_object(hid_report_data, hid_desc->report_desc_len, &data); kfree(hid_report_data); } goto out;