1 #include "internal.h"
2 #include <common/compiler.h>
3 #include <common/glib.h>
4 #include <common/hid.h>
5 #include <common/printk.h>
6 #include <common/string.h>
7 #include <debug/bug.h>
8 
9 /*
10     参考文档:https://www.usb.org/document-library/device-class-definition-hid-111
11     本文件参考了FYSOS:  https://github.com/fysnet/FYSOS.git
12  */
13 
14 static bool HID_PARSE_OUTPUT = true; // 是否输出解析信息
15 static char __tmp_usage_page_str[128] = {0};
16 
17 static void hid_reset_parser(struct hid_parser *parser);
18 
19 static const char *hid_get_usage_page_str(const int u_page);
20 static const char *hid_get_usage_type_str(const int page, const int type);
21 static const char *hid_get_collection_str(const int value);
22 static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type);
23 static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page);
24 
25 static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
26     const struct hid_usage_pages_string *upage, const int type);
27 
28 // hid item的低2位为size
29 #define HID_SIZE_MASK 0x3
30 // 高6bit为item内容
31 #define HID_ITEM_MASK 0xFC
32 #define HID_ITEM_UPAGE 0x04 // usage page
33 #define HID_ITEM_USAGE 0x08 // local item
34 #define HID_ITEM_LOG_MIN 0x14
35 #define HID_ITEM_USAGE_MIN 0x18 // local item
36 #define HID_ITEM_LOG_MAX 0x24
37 #define HID_ITEM_USAGE_MAX 0x28 // local item
38 #define HID_ITEM_PHY_MIN 0x34
39 #define HID_ITEM_PHY_MAX 0x44
40 #define HID_ITEM_UNIT_EXP 0x54
41 #define HID_ITEM_UNIT 0x64
42 #define HID_ITEM_REP_SIZE 0x74
43 #define HID_ITEM_STRING 0x78 // local item?
44 #define HID_ITEM_REP_ID 0x84
45 #define HID_ITEM_REP_COUNT 0x94
46 
47 static char __spaces_buf[33];
__spaces(uint8_t cnt)48 char *__spaces(uint8_t cnt)
49 {
50     static char __space_overflow_str[] = "**";
51     if (cnt > 32)
52     {
53         return __space_overflow_str;
54     }
55 
56     memset(__spaces_buf, ' ', 32);
57     __spaces_buf[cnt] = '\0';
58     return __spaces_buf;
59 }
60 
__format_value(uint32_t value,uint8_t size)61 static __always_inline uint32_t __format_value(uint32_t value, uint8_t size)
62 {
63     switch (size)
64     {
65     case 1:
66         value = (uint32_t)(uint8_t)value;
67         break;
68     case 2:
69         value = (uint32_t)(uint16_t)value;
70         break;
71     }
72     return value;
73 }
74 
75 /**
76  * @brief 重置parser
77  *
78  * @param parser 解析器
79  * @return int 状态码
80  */
hid_reset_parser(struct hid_parser * parser)81 static void hid_reset_parser(struct hid_parser *parser)
82 {
83     memset(parser, 0, sizeof(struct hid_parser));
84     parser->data.report_id = 1; // we must give it a non-zero value or the parser doesn't work
85 }
86 
87 /**
88  * @brief 从usage_stack中弹出第一个元素
89  *
90  * @param parser 解析器
91  * @return __always_inline
92  */
__pop_usage_stack(struct hid_parser * parser)93 static __always_inline void __pop_usage_stack(struct hid_parser *parser)
94 {
95     if (parser->usage_size > 0)
96     {
97         for (int js = 0; js < parser->usage_size - 1; ++js)
98             memmove(&parser->usage_table[js], &parser->usage_table[js + 1], sizeof(struct hid_node_t));
99 
100         --parser->usage_size;
101     }
102 }
103 
104 /**
105  * @brief 解析hid report,并获取下一个数据到data字段中
106  * todo:(不知道为什么,在qemu上面,发现键盘的usage都是0xff)
107  *
108  * @param parser 解析器
109  * @param data 返回的数据
110  * @return true 解析成功
111  * @return false 解析失败
112  */
hid_parse(struct hid_parser * parser,struct hid_data_t * data)113 static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
114 {
115     bool found = false;
116     static uint8_t space_cnt = 0;
117     static bool did_collection = false;
118     static int item_size[4] = {0, 1, 2, 4};
119 
120     // 循环解析
121     while (!found && (parser->pos < parser->report_desc_size))
122     {
123         // 当前parse过程还没有解析到report
124         if (parser->count == 0)
125         {
126             // 打印当前 report_data 的值
127             if (HID_PARSE_OUTPUT)
128                 printk("\n %02X ", parser->report_desc[parser->pos]);
129             // 获取到report size
130             parser->item = parser->report_desc[parser->pos++];
131             parser->value = 0;
132             // 拷贝report的数据
133             memcpy(&parser->value, &parser->report_desc[parser->pos], item_size[parser->item & HID_SIZE_MASK]);
134 
135             if (HID_PARSE_OUTPUT)
136             {
137                 for (int i = 0; i < 4; ++i)
138                 {
139                     if (i < item_size[parser->item & HID_SIZE_MASK])
140                         printk("%02X ", parser->report_desc[parser->pos + i]);
141                     else
142                         printk("   ");
143                 }
144             }
145             // 将指针指向下一个item
146             parser->pos += item_size[parser->item & HID_SIZE_MASK];
147         }
148 
149         switch (parser->item & HID_ITEM_MASK)
150         {
151         case HID_ITEM_UPAGE:
152             // 拷贝upage
153             parser->u_page = (int)parser->value;
154             if (HID_PARSE_OUTPUT)
155                 printk("%sUsage Page (%s)", __spaces(space_cnt), hid_get_usage_page_str(parser->u_page));
156             // 拷贝到 usage table。由于这是一个USAGE entry,因此不增加usage_size(以便后面覆盖它)
157             parser->usage_table[parser->usage_size].u_page = parser->u_page;
158             parser->usage_table[parser->usage_size].usage = 0xff;
159             break;
160         case HID_ITEM_USAGE:
161             // 拷贝upage到usage table中
162             if ((parser->item & HID_SIZE_MASK) > 2) // item大小为32字节
163                 parser->usage_table[parser->usage_size].u_page = (int)(parser->value >> 16);
164             else
165                 parser->usage_table[parser->usage_size].u_page = parser->u_page;
166 
167             if (HID_PARSE_OUTPUT)
168                 printk("%sUsage (%s)", __spaces(space_cnt),
169                        hid_get_usage_type_str(parser->u_page, parser->value & 0xffff));
170             ++parser->usage_size;
171             break;
172         case HID_ITEM_USAGE_MIN:
173             // todo: 设置usage min
174             if (HID_PARSE_OUTPUT)
175                 printk("%sUsage min (%i=%s)", __spaces(space_cnt), parser->value,
176                        hid_get_usage_type_str(parser->u_page, parser->value));
177             break;
178         case HID_ITEM_USAGE_MAX:
179             // todo: 设置usage max
180             if (HID_PARSE_OUTPUT)
181                 printk("%sUsage max (%i=%s)", __spaces(space_cnt), parser->value,
182                        hid_get_usage_type_str(parser->u_page, parser->value));
183             break;
184         case HID_ITEM_COLLECTION:
185             // 从usage table中取出第一个u_page和usage,并且将他们存储在parser->data.path
186             parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
187             parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
188             ++parser->data.path.size;
189 
190             // 由于上面取出了元素,因此将队列往前移动1个位置
191             __pop_usage_stack(parser);
192 
193             // 获取index(如果有的话)???
194             if (parser->value >= 0x80)
195             {
196                 kdebug("parser->value > 0x80");
197                 parser->data.path.node[parser->data.path.size].u_page = 0xff;
198                 parser->data.path.node[parser->data.path.size].usage = parser->value & 0x7f;
199                 ++parser->data.path.size;
200             }
201             if (HID_PARSE_OUTPUT)
202             {
203                 printk("%sCollection (%s)", __spaces(space_cnt), hid_get_collection_str(parser->value));
204                 space_cnt += 2;
205             }
206             break;
207         case HID_ITEM_END_COLLECTION:
208             --parser->data.path.size; // 为什么要--?????
209             // 删除多余的(未识别的)node
210             if (parser->data.path.node[parser->data.path.size].u_page == 0xff)
211                 --parser->data.path.size;
212             if (HID_PARSE_OUTPUT)
213             {
214                 if (space_cnt >= 2)
215                     space_cnt -= 2;
216                 printk("%sEnd Collection", __spaces(space_cnt));
217             }
218             break;
219         case HID_ITEM_FEATURE:
220         case HID_ITEM_INPUT:
221         case HID_ITEM_OUTPUT:
222             // 找到了一个对象
223             found = true;
224 
225             // 增加对象计数器
226             ++parser->cnt_objects;
227 
228             // 更新local items的计数
229             if (parser->count == 0)
230                 parser->count = parser->report_count;
231 
232             // 从usage_table获取u_page和usage,将他们存储到parser.data.path
233             parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
234             parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
235             ++parser->data.path.size;
236 
237             // 从usage table中弹出刚刚那个node
238             __pop_usage_stack(parser);
239 
240             // 拷贝数据到data
241             parser->data.type = (uint8_t)(parser->item & HID_ITEM_MASK);
242             parser->data.attribute = (uint8_t)parser->value;
243             int *offset_ptr =
244                 __get_report_offset(parser, parser->data.report_id, (uint8_t)(parser->item & HID_ITEM_MASK));
245 
246             if (unlikely(offset_ptr == NULL))
247             {
248                 BUG_ON(1);
249                 return false;
250             }
251             parser->data.offset = *offset_ptr;
252 
253             // 获取pData中的对象
254             memcpy(data, &parser->data, sizeof(struct hid_data_t));
255 
256             // 增加report offset
257             *offset_ptr = (*offset_ptr) + parser->data.size;
258 
259             // 从path中删除最后一个节点(刚刚弹出的这个节点)
260             --parser->data.path.size;
261 
262             // 减少local items计数
263             if (parser->count > 0)
264                 --parser->count;
265 
266             if (!did_collection)
267             {
268                 if (HID_PARSE_OUTPUT)
269                 {
270                     if ((parser->item & HID_ITEM_MASK) == HID_ITEM_FEATURE)
271                         printk("%sFeature ", __spaces(space_cnt));
272                     else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_INPUT)
273                         printk("%sInput ", __spaces(space_cnt));
274                     else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_OUTPUT)
275                         printk("%sOutut ", __spaces(space_cnt));
276 
277                     printk("(%s,%s,%s" /* ",%s,%s,%s,%s" */ ")", !(parser->value & (1 << 0)) ? "Data" : "Constant",
278                            !(parser->value & (1 << 1)) ? "Array" : "Variable",
279                            !(parser->value & (1 << 2)) ? "Absolute" : "Relative" /*,
280                               !(parser->value & (1<<3)) ? "No Wrap"  : "Wrap",
281                               !(parser->value & (1<<4)) ? "Linear"   : "Non Linear",
282                               !(parser->value & (1<<5)) ? "Preferred State" : "No Preferred",
283                               !(parser->value & (1<<6)) ? "No Null"  : "Null State",
284                               //!(parser->value & (1<<8)) ? "Bit Fueld" : "Buffered Bytes"
285                               */
286                     );
287                 }
288 
289                 did_collection = true;
290             }
291             break;
292         case HID_ITEM_REP_ID: // 当前item表示report id
293             parser->data.report_id = (uint8_t)parser->value;
294             if (HID_PARSE_OUTPUT)
295                 printk("%sReport ID: %i", __spaces(space_cnt), parser->data.report_id);
296             break;
297         case HID_ITEM_REP_SIZE: // 当前item表示report size
298             parser->data.size = parser->value;
299             if (HID_PARSE_OUTPUT)
300                 printk("%sReport size (%i)", __spaces(space_cnt), parser->data.size);
301             break;
302         case HID_ITEM_REP_COUNT:
303             parser->report_count = parser->value;
304             if (HID_PARSE_OUTPUT)
305                 printk("%sReport count (%i)", __spaces(space_cnt), parser->report_count);
306             break;
307         case HID_ITEM_UNIT_EXP:
308             parser->data.unit_exp = (int8_t)parser->value;
309             if (parser->data.unit_exp > 7)
310                 parser->data.unit_exp |= 0xf0;
311             if (HID_PARSE_OUTPUT)
312                 printk("%sUnit Exp (%i)", __spaces(space_cnt), parser->data.unit_exp);
313             break;
314         case HID_ITEM_UNIT:
315             parser->data.unit = parser->value;
316             if (HID_PARSE_OUTPUT)
317                 printk("%sUnit (%i)", __spaces(space_cnt), parser->data.unit);
318             break;
319         case HID_ITEM_LOG_MIN: // logical min
320             parser->data.logical_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
321             if (HID_PARSE_OUTPUT)
322                 printk("%sLogical Min (%i)", __spaces(space_cnt), parser->data.logical_min);
323             break;
324         case HID_ITEM_LOG_MAX:
325             parser->data.logical_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
326             if (HID_PARSE_OUTPUT)
327                 printk("%sLogical Max (%i)", __spaces(space_cnt), parser->data.logical_max);
328             break;
329         case HID_ITEM_PHY_MIN:
330             parser->data.phys_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
331             if (HID_PARSE_OUTPUT)
332                 printk("%Physical Min (%i)", __spaces(space_cnt), parser->data.phys_min);
333             break;
334         case HID_ITEM_PHY_MAX:
335             parser->data.phys_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
336             if (HID_PARSE_OUTPUT)
337                 printk("%Physical Max (%i)", __spaces(space_cnt), parser->data.phys_max);
338             break;
339         default:
340             printk("\n Found unknown item %#02X\n", parser->item & HID_ITEM_MASK);
341             return found;
342         }
343     }
344     return found;
345 }
346 
347 /**
348  * @brief 解析hid report的数据
349  *
350  * @param report_data 从usb hid设备获取到hid report
351  * @param len report_data的大小(字节)
352  * @return int错误码
353  */
hid_parse_report(const void * report_data,const int len)354 int hid_parse_report(const void *report_data, const int len)
355 {
356     struct hid_parser parser = {0};
357     struct hid_data_t data;
358 
359     hid_reset_parser(&parser);
360     parser.report_desc = (const uint8_t *)report_data;
361     parser.report_desc_size = len;
362 
363     while (hid_parse(&parser, &data))
364         ;
365     return 0;
366 }
367 
368 /**
369  * @brief 根据usage page的id获取usage page string结构体.当u_page不属于任何已知的id时,返回NULL
370  *
371  * @param u_page usage page id
372  * @return const struct hid_usage_pages_string * usage page string结构体
373  */
hid_get_usage_page(const int u_page)374 static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page)
375 {
376     int i = 0;
377     while ((hid_usage_page_strings[i].value < u_page) && (hid_usage_page_strings[i].value < 0xffff))
378         ++i;
379     if ((hid_usage_page_strings[i].value != u_page) || (hid_usage_page_strings[i].value == 0xffff))
380         return NULL;
381     else
382         return &hid_usage_page_strings[i];
383 }
384 
385 /**
386  * @brief 从指定的upage获取指定类型的usage type结构体。当不存在时,返回NULL
387  *
388  * @param upage 指定的upage
389  * @param type usage的类型
390  * @return const struct hid_usage_types_string * 目标usage type结构体。
391  */
hid_get_usage_type(const struct hid_usage_pages_string * upage,const int type)392 static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
393     const struct hid_usage_pages_string *upage, const int type)
394 {
395     if (unlikely(upage == NULL || upage->types == NULL))
396     {
397         BUG_ON(1);
398         return NULL;
399     }
400     struct hid_usage_types_string *types = upage->types;
401     int i = 0;
402     while ((types[i].value < type) && (types[i].value != 0xffff))
403         ++i;
404 
405     if ((types[i].value != type) || (types[i].value == 0xffff))
406         return NULL;
407 
408     return &types[i];
409 }
410 
411 /**
412  * @brief 获取usage page的名称
413  *
414  * @param u_page usage page的id
415  * @return const char* usage page的字符串
416  */
hid_get_usage_page_str(const int u_page)417 static const char *hid_get_usage_page_str(const int u_page)
418 {
419 
420     const struct hid_usage_pages_string *upage = hid_get_usage_page(u_page);
421     if (unlikely(upage == NULL))
422     {
423         sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", u_page);
424         return __tmp_usage_page_str;
425     }
426     return upage->string;
427 }
428 
429 /**
430  * @brief 打印usage page的指定类型的usage
431  *
432  * @param page usage page id
433  * @param type usage的类型
434  * @return const char*
435  */
hid_get_usage_type_str(const int page,const int type)436 static const char *hid_get_usage_type_str(const int page, const int type)
437 {
438     const struct hid_usage_pages_string *upage = hid_get_usage_page(page);
439     if (unlikely(upage == NULL))
440     {
441         sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", page);
442         return __tmp_usage_page_str;
443     }
444 
445     // button press, ordinal, or UTC
446     if (page == 0x0009)
447     {
448         sprintk(__tmp_usage_page_str, "Button number %i", type);
449         return __tmp_usage_page_str;
450     }
451     else if (page == 0x000a)
452     {
453         sprintk(__tmp_usage_page_str, "Ordinal %i", type);
454         return __tmp_usage_page_str;
455     }
456     else if (page == 0x0010)
457     {
458         sprintk(__tmp_usage_page_str, "UTC %#04X", type);
459         return __tmp_usage_page_str;
460     }
461 
462     const struct hid_usage_types_string *usage_type = hid_get_usage_type(upage, type);
463     if (unlikely(usage_type == NULL))
464     {
465         sprintk(__tmp_usage_page_str, "Usage Page %s, with Unknown Type: %#04X", upage->string, type);
466         return __tmp_usage_page_str;
467     }
468 
469     return usage_type->string;
470 }
471 
472 /**
473  * @brief 输出colection字符串
474  *
475  * @param value collection的值
476  * @return const char*
477  */
hid_get_collection_str(const int value)478 static const char *hid_get_collection_str(const int value)
479 {
480     if (value <= 0x06)
481         return hid_collection_str[value];
482     else if (value <= 0x7f)
483         return "Reserved";
484     else if (value <= 0xff)
485         return "Vendor-defined";
486     else
487         return "Error in get_collection_str(): value > 0xff";
488 }
489 
490 /**
491  * @brief 从parser的offset table中,根据report_id和report_type,获取表中指向offset字段的指针
492  *
493  * @param parser 解析器
494  * @param report_id report_id
495  * @param report_type report类型
496  * @return int* 指向offset字段的指针
497  */
__get_report_offset(struct hid_parser * parser,const uint8_t report_id,const uint8_t report_type)498 static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type)
499 {
500     int pos = 0;
501     // 尝试从已有的report中获取
502     while ((pos < HID_MAX_REPORT) && (parser->offset_table[pos][0] != 0)) // 当offset的id不为0时
503     {
504         if ((parser->offset_table[pos][0] == report_id) && (parser->offset_table[pos][1] == report_type))
505             return &parser->offset_table[pos][2];
506         ++pos;
507     }
508     // 在offset table中占用一个新的表项来存储这个report的offset
509     if (pos < HID_MAX_REPORT)
510     {
511         ++parser->cnt_report;
512         parser->offset_table[pos][0] = report_id;
513         parser->offset_table[pos][1] = report_type;
514         parser->offset_table[pos][2] = 0;
515         return &parser->offset_table[pos][2];
516     }
517     // 当offset table满了,且未找到结果的时候,返回NULL
518     return NULL;
519 }
520 
__find_object(struct hid_parser * parser,struct hid_data_t * data)521 static __always_inline bool __find_object(struct hid_parser *parser, struct hid_data_t *data)
522 {
523     kdebug("target_type=%d report_id=%d, offset=%d, size=%d", data->type, data->report_id, data->offset, data->size);
524     struct hid_data_t found_data = {0};
525 
526     while (hid_parse(parser, &found_data))
527     {
528         kdebug("size=%d, type=%d, report_id=%d, u_page=%d, usage=%d", found_data.size, found_data.type,
529                found_data.report_id, found_data.path.node[0].u_page, found_data.path.node[0].usage);
530         // 按照路径完整匹配data
531         if ((data->path.size > 0) && (found_data.type == data->type) &&
532             (memcmp(found_data.path.node, data->path.node, data->path.size * sizeof(struct hid_node_t)) == 0))
533         {
534             goto found;
535         }
536         // 通过report id以及offset匹配成功
537         else if ((found_data.report_id == data->report_id) && (found_data.type == data->type) &&
538                  (found_data.offset == data->offset))
539         {
540             goto found;
541         }
542     }
543     return false;
544 
545 found:;
546     memcpy(data, &found_data, sizeof(struct hid_data_t));
547     data->report_count = parser->report_count;
548     return true;
549 }
550 /**
551  * @brief 在hid report中寻找参数data给定的节点数据,并将结果写入到data中
552  *
553  * @param hid_report hid report 数据
554  * @param report_size report_data的大小(字节)
555  * @param data 要寻找的节点数据。
556  * @return true 找到指定的节点
557  * @return false 未找到指定的节点
558  */
hid_parse_find_object(const void * hid_report,const int report_size,struct hid_data_t * data)559 bool hid_parse_find_object(const void *hid_report, const int report_size, struct hid_data_t *data)
560 {
561     struct hid_parser parser = {0};
562     hid_reset_parser(&parser);
563     parser.report_desc = hid_report;
564     parser.report_desc_size = report_size;
565     // HID_PARSE_OUTPUT = false;
566 
567     printk("\nFinding Coordinate value:");
568     if (__find_object(&parser, data))
569     {
570         printk("    size: %i (in bits)\n"
571                "  offset: %i (in bits)\n"
572                "     min: %i\n"
573                "     max: %i\n"
574                "  attrib: 0x%02X (input, output, or feature, etc.)\n",
575                data->size, data->offset, data->logical_min, data->logical_max, data->attribute);
576         return true;
577     }
578     else
579     {
580         printk("  Did not find Coordinate value.\n");
581         return false;
582     }
583 }