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 }