new: usb hid parser

This commit is contained in:
longjin
2022-10-14 17:52:59 +08:00
parent 1e94d1e7d0
commit b815294832
7 changed files with 2123 additions and 140 deletions

View File

@ -1,3 +1,4 @@
#include "internal.h"
#include <common/compiler.h>
#include <common/glib.h>
#include <common/hid.h>
@ -7,16 +8,22 @@
/*
参考文档https://www.usb.org/document-library/device-class-definition-hid-111
本文件参考了FYSOS https://github.com/fysnet/FYSOS.git
*/
static bool HID_PARSE_OUTPUT = true; // 是否输出解析信息
static char __tmp_usage_page_str[128] = {0};
static void hid_reset_parser(struct hid_parser *parser);
static const char *hid_print_usage_page(const int u_page);
static const char *hid_print_usage_type(const int page, const int type);
static const char *hid_print_collection(const int value);
static int *__get_report_offset(struct hid_parser *hid_parser, const uint8_t report_id, const uint8_t report_type);
static const char *hid_get_usage_page_str(const int u_page);
static const char *hid_get_usage_type_str(const int page, const int type);
static const char *hid_get_collection_str(const int value);
static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type);
static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page);
static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
const struct hid_usage_pages_string *upage, const int type);
// hid item的低2位为size
#define HID_SIZE_MASK 0x3
@ -59,6 +66,20 @@ char *__spaces(uint8_t cnt)
return __spaces_buf;
}
static __always_inline uint32_t __format_value(uint32_t value, uint8_t size)
{
switch (size)
{
case 1:
value = (uint32_t)(uint8_t)value;
break;
case 2:
value = (uint32_t)(uint16_t)value;
break;
}
return value;
}
/**
* @brief 重置parser
*
@ -138,34 +159,34 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
// 拷贝upage
parser->u_page = (int)parser->value;
if (HID_PARSE_OUTPUT)
printk("%sUsage Page (%s)", __spaces(space_cnt), hid_print_usage_page(parser->u_page));
printk("%sUsage Page (%s)", __spaces(space_cnt), hid_get_usage_page_str(parser->u_page));
// 拷贝到 usage table。由于这是一个USAGE entry因此不增加usage_size(以便后面覆盖它)
parser->usage_table[parser->usage_size].u_page = parser->u_page;
parser->usage_table[parser->usage_size].usage = 0xff;
break;
case HID_ITEM_USAGE:
// 拷贝upage到usage table中
if (parser->item & HID_SIZE_MASK > 2) // item大小为32字节
if ((parser->item & HID_SIZE_MASK) > 2) // item大小为32字节
parser->usage_table[parser->usage_size].u_page = (int)(parser->value >> 16);
else
parser->usage_table[parser->usage_size].u_page = parser->u_page;
if (HID_PARSE_OUTPUT)
printk("%sUsage (%s)", __spaces(space_cnt),
hid_print_usage_type(parser->u_page, parser->value & 0xffff));
hid_get_usage_type_str(parser->u_page, parser->value & 0xffff));
++parser->usage_size;
break;
case HID_ITEM_USAGE_MIN:
// todo: 设置usage min
if (HID_PARSE_OUTPUT)
printk("%sUsage min (%i=%s)", __spaces(space_cnt), parser->value,
hid_print_usage_type(parser->u_page, parser->value));
hid_get_usage_type_str(parser->u_page, parser->value));
break;
case HID_ITEM_USAGE_MAX:
// todo: 设置usage max
if (HID_PARSE_OUTPUT)
printk("%sUsage max (%i=%s)", __spaces(space_cnt), parser->value,
hid_print_usage_type(parser->u_page, parser->value));
hid_get_usage_type_str(parser->u_page, parser->value));
break;
case HID_ITEM_COLLECTION:
// 从usage table中取出第一个u_page和usage并且将他们存储在parser->data.path
@ -177,7 +198,7 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
__pop_usage_stack(parser);
// 获取index(如果有的话)???
if (parser->value > 0x80)
if (parser->value >= 0x80)
{
kdebug("parser->value > 0x80");
parser->data.path.node[parser->data.path.size].u_page = 0xff;
@ -186,7 +207,7 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
}
if (HID_PARSE_OUTPUT)
{
printk("%sCollection (%s)", __spaces(space_cnt), hid_print_collection(parser->value));
printk("%sCollection (%s)", __spaces(space_cnt), hid_get_collection_str(parser->value));
space_cnt += 2;
}
break;
@ -225,7 +246,7 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
// 拷贝数据到data
parser->data.type = (uint8_t)(parser->item & HID_ITEM_MASK);
parser->data.attribue = (uint8_t)parser->value;
parser->data.attribute = (uint8_t)parser->value;
int *offset_ptr =
__get_report_offset(parser, parser->data.report_id, (uint8_t)(parser->item & HID_ITEM_MASK));
@ -240,7 +261,7 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
memcpy(data, &parser->data, sizeof(struct hid_data_t));
// 增加report offset
*offset_ptr = (*offset_ptr) + 1;
*offset_ptr = (*offset_ptr) + parser->data.size;
// 从path中删除最后一个节点刚刚弹出的这个节点
--parser->data.path.size;
@ -275,23 +296,59 @@ static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
did_collection = true;
}
break;
case HID_ITEM_REP_ID:
// todo:
case HID_ITEM_REP_ID: // 当前item表示report id
parser->data.report_id = (uint8_t)parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport ID: %i", __spaces(space_cnt), parser->data.report_id);
break;
case HID_ITEM_REP_SIZE:
// todo:
case HID_ITEM_REP_SIZE: // 当前item表示report size
parser->data.size = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport size (%i)", __spaces(space_cnt), parser->data.size);
break;
case HID_ITEM_REP_COUNT:
// todo:
parser->report_count = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sReport count (%i)", __spaces(space_cnt), parser->report_count);
break;
case HID_ITEM_UNIT_EXP:
// todo:
parser->data.unit_exp = (int8_t)parser->value;
if (parser->data.unit_exp > 7)
parser->data.unit_exp |= 0xf0;
if (HID_PARSE_OUTPUT)
printk("%sUnit Exp (%i)", __spaces(space_cnt), parser->data.unit_exp);
break;
case HID_ITEM_UNIT:
// todo:
parser->data.unit = parser->value;
if (HID_PARSE_OUTPUT)
printk("%sUnit (%i)", __spaces(space_cnt), parser->data.unit);
break;
case HID_ITEM_LOG_MIN: // logical min
parser->data.logical_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%sLogical Min (%i)", __spaces(space_cnt), parser->data.logical_min);
break;
case HID_ITEM_LOG_MAX:
parser->data.logical_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%sLogical Max (%i)", __spaces(space_cnt), parser->data.logical_max);
break;
case HID_ITEM_PHY_MIN:
parser->data.phys_min = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%Physical Min (%i)", __spaces(space_cnt), parser->data.phys_min);
break;
case HID_ITEM_PHY_MAX:
parser->data.phys_max = __format_value(parser->value, item_size[parser->item & HID_SIZE_MASK]);
if (HID_PARSE_OUTPUT)
printk("%Physical Max (%i)", __spaces(space_cnt), parser->data.phys_max);
break;
default:
printk("\n Found unknown item %#02X\n", parser->item & HID_ITEM_MASK);
return false;
}
}
return found;
}
/**
@ -316,51 +373,154 @@ int hid_parse_report(const void *report_data, const int len)
}
/**
* @brief 打印usage page的数据
* @brief 根据usage page的id获取usage page string结构体.当u_page不属于任何已知的id时返回NULL
*
* @param u_page usage page id
* @return const struct hid_usage_pages_string * usage page string结构体
*/
static __always_inline const struct hid_usage_pages_string *hid_get_usage_page(const int u_page)
{
int i = 0;
while ((hid_usage_page_strings[i].value < u_page) && (hid_usage_page_strings[i].value < 0xffff))
++i;
if ((hid_usage_page_strings[i].value != u_page) || (hid_usage_page_strings[i].value == 0xffff))
return NULL;
else
return &hid_usage_page_strings[i];
}
/**
* @brief 从指定的upage获取指定类型的usage type结构体。当不存在时返回NULL
*
* @param upage 指定的upage
* @param type usage的类型
* @return const struct hid_usage_types_string * 目标usage type结构体。
*/
static __always_inline const struct hid_usage_types_string *hid_get_usage_type(
const struct hid_usage_pages_string *upage, const int type)
{
if (unlikely(upage == NULL || upage->types == NULL))
{
BUG_ON(1);
return NULL;
}
struct hid_usage_types_string *types = upage->types;
int i = 0;
while ((types[i].value < type) && (types[i].value != 0xffff))
++i;
if ((types[i].value != type) || (types[i].value == 0xffff))
return NULL;
return &types[i];
}
/**
* @brief 获取usage page的名称
*
* @param u_page usage page的id
* @return const char* usage page的字符串
*/
static const char *hid_print_usage_page(const int u_page)
static const char *hid_get_usage_page_str(const int u_page)
{
// todo:
return NULL;
const struct hid_usage_pages_string *upage = hid_get_usage_page(u_page);
if (unlikely(upage == NULL))
{
sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", u_page);
return __tmp_usage_page_str;
}
return upage->string;
}
/**
* @brief 打印usage page的类型
* @brief 打印usage page的指定类型的usage
*
* @param page
* @param type
* @param page usage page id
* @param type usage的类型
* @return const char*
*/
static const char *hid_print_usage_type(const int page, const int type)
static const char *hid_get_usage_type_str(const int page, const int type)
{
// todo:
return NULL;
const struct hid_usage_pages_string *upage = hid_get_usage_page(page);
if (unlikely(upage == NULL))
{
sprintk(__tmp_usage_page_str, "Unknown Usage Page: %#04x", page);
return __tmp_usage_page_str;
}
// button press, ordinal, or UTC
if (page == 0x0009)
{
sprintk(__tmp_usage_page_str, "Button number %i", type);
return __tmp_usage_page_str;
}
else if (page == 0x000a)
{
sprintk(__tmp_usage_page_str, "Ordinal %i", type);
return __tmp_usage_page_str;
}
else if (page == 0x0010)
{
sprintk(__tmp_usage_page_str, "UTC %#04X", type);
return __tmp_usage_page_str;
}
const struct hid_usage_types_string *usage_type = hid_get_usage_type(upage, type);
if (unlikely(usage_type == NULL))
{
sprintk(__tmp_usage_page_str, "Usage Page %s, with Unknown Type: %#04X", upage->string, type);
return __tmp_usage_page_str;
}
return usage_type->string;
}
/**
* @brief 输出colection字符串
*
* @param value
* @param value collection的值
* @return const char*
*/
static const char *hid_print_collection(const int value)
static const char *hid_get_collection_str(const int value)
{
// todo:
return NULL;
if (value <= 0x06)
return hid_collection_str[value];
else if (value <= 0x7f)
return "Reserved";
else if (value <= 0xff)
return "Vendor-defined";
else
return "Error in get_collection_str(): value > 0xff";
}
/**
* @brief 从parser的offset table中根据report_id和report_type获取表中指向offset字段的指针
*
* @param hid_parser 解析器
* @param parser 解析器
* @param report_id report_id
* @param report_type report类型
* @return int* 指向offset字段的指针
*/
static int *__get_report_offset(struct hid_parser *hid_parser, const uint8_t report_id, const uint8_t report_type)
static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type)
{
// todo:
int pos = 0;
// 尝试从已有的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];
++pos;
}
// 在offset table中占用一个新的表项来存储这个report的offset
if (pos < HID_MAX_REPORT)
{
++parser->cnt_report;
parser->offset_table[pos][0] = report_id;
parser->offset_table[pos][1] = report_type;
parser->offset_table[pos][2] = 0;
return &parser->offset_table[pos][2];
}
// 当offset table满了且未找到结果的时候返回NULL
return NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#pragma once
#include <common/hid.h>
extern struct hid_usage_types_string hid_usage_type001[];
extern struct hid_usage_types_string hid_usage_type002[];
extern struct hid_usage_types_string hid_usage_type003[];
extern struct hid_usage_types_string hid_usage_type004[];
extern struct hid_usage_types_string hid_usage_type005[];
extern struct hid_usage_types_string hid_usage_type006[];
extern struct hid_usage_types_string hid_usage_type007[];
extern struct hid_usage_types_string hid_usage_type008[];
extern struct hid_usage_types_string hid_usage_type00B[];
extern struct hid_usage_types_string hid_usage_type00C[];
extern struct hid_usage_types_string hid_usage_type00D[];
extern struct hid_usage_types_string hid_usage_type00F[];
extern struct hid_usage_types_string hid_usage_type014[];
extern struct hid_usage_types_string hid_usage_type040[];
extern struct hid_usage_types_string hid_usage_type080[];
extern struct hid_usage_types_string hid_usage_type082[];
extern struct hid_usage_types_string hid_usage_type083[];
extern struct hid_usage_types_string hid_usage_type084[];
extern struct hid_usage_types_string hid_usage_type085[];
extern struct hid_usage_types_string hid_usage_type086[];
extern struct hid_usage_types_string hid_usage_type087[];
extern struct hid_usage_types_string hid_usage_type08C[];
extern struct hid_usage_types_string hid_usage_type08D[];
extern struct hid_usage_types_string hid_usage_type08E[];
extern struct hid_usage_types_string hid_usage_type08F[];
extern struct hid_usage_types_string hid_usage_type090[];
extern struct hid_usage_types_string hid_usage_type091[];
extern struct hid_usage_types_string hid_usage_typeFF00[];
extern struct hid_usage_types_string hid_usage_typeFF84[];
extern struct hid_usage_types_string hid_usage_typeFF85[];
extern struct hid_usage_pages_string hid_usage_page_strings[];
extern char hid_collection_str[][64];