longjin 2 years ago
parent
commit
1e94d1e7d0

+ 81 - 0
kernel/common/hid.h

@@ -0,0 +1,81 @@
+#pragma once
+#include <common/stddef.h>
+
+#define __HID_USAGE_TABLE_SIZE 64 // usage stack的大小
+#define HID_MAX_REPORT 300        // 最大允许的hid report数目(包括feature、input、output)
+#define HID_MAX_PATH_SIZE 16      // maximum depth for path
+
+/**
+ * @brief 描述hid path中的一个节点
+ *
+ */
+struct hid_node_t
+{
+    int u_page;
+    int usage;
+};
+
+/**
+ * @brief 描述一条hid path
+ *
+ */
+struct hid_path_t
+{
+    int size; // 路径中的节点数目
+    struct hid_node_t node[HID_MAX_PATH_SIZE];
+};
+
+/**
+ * @brief Describe a HID Data with its location in report
+ *
+ */
+struct hid_data_t
+{
+    int value;              // hid对象的值
+    struct hid_path_t path; // hid path
+
+    int report_count; // count of reports for this usage type
+    int offset;       // offset of data in report
+    int size;         // size of data in bits
+
+    uint8_t report_id; // report id(from incoming report)
+    uint8_t type;      // 数据类型:FEATURE / INPUT / OUTPUT
+    uint8_t attribue;  // 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 uuit_exp;   // unit exponent;
+
+    uint32_t uuit; // HID unit
+
+    int logical_min; // Logical min
+    int logical_max; // Logical max
+    int phys_min;    // Physical min
+    int phys_max;    // Physical max
+};
+
+/**
+ * @brief hid解析器
+ *
+ */
+struct hid_parser
+{
+    const uint8_t *report_desc; // 指向report descriptor的指针
+    int report_desc_size;       // report descriptor的大小(字节)
+    int pos;                    // report_desc中,当前正在处理的位置
+    uint8_t item;               // 暂存当前的item
+    uint32_t value;             // 暂存当前的值
+
+    struct hid_data_t data; // 存储当前的环境
+
+    int offset_table[HID_MAX_REPORT][3]; // 存储 hid report的ID、type、offset
+    int report_count;                    // hid report的数量
+    int count;                           // local items的计数
+
+    uint32_t u_page;
+    struct hid_node_t usage_table[__HID_USAGE_TABLE_SIZE]; // Usage stack
+    int usage_size;                                        // usage的数量
+    int usage_min;
+    int usage_max;
+
+    int cnt_objects; // report descriptor中的对象数目
+    int cnt_report   // report desc中的report数目
+};

+ 1 - 1
kernel/driver/Makefile

@@ -1,7 +1,7 @@
 
 CFLAGS += -I .
 
-kernel_driver_subdirs:=video interrupt usb pci uart acpi disk keyboard mouse multiboot2 timers tty
+kernel_driver_subdirs:=video interrupt usb pci uart acpi disk keyboard mouse multiboot2 timers tty hid
 
 ECHO:
 	@echo "$@"

+ 19 - 0
kernel/driver/hid/Makefile

@@ -0,0 +1,19 @@
+
+CFLAGS += -I .
+
+kernel_driver_hid_subdirs:= usbhid
+
+kernel_driver_hid_objs:= $(shell find ./*.c)
+
+ECHO:
+	@echo "$@"
+
+$(kernel_driver_hid_subdirs): ECHO
+	$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
+
+$(kernel_driver_hid_objs): ECHO
+	gcc $(CFLAGS) -c $@ -o [email protected]
+
+all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
+	@echo $(kernel_driver_hid_objs)
+

+ 366 - 0
kernel/driver/hid/hidparse.c

@@ -0,0 +1,366 @@
+#include <common/compiler.h>
+#include <common/glib.h>
+#include <common/hid.h>
+#include <common/printk.h>
+#include <common/string.h>
+#include <debug/bug.h>
+
+/*
+    参考文档:https://www.usb.org/document-library/device-class-definition-hid-111
+ */
+
+static bool HID_PARSE_OUTPUT = true; // 是否输出解析信息
+
+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);
+
+// hid item的低2位为size
+#define HID_SIZE_MASK 0x3
+// 高6bit为item内容
+#define HID_ITEM_MASK 0xFC
+#define HID_ITEM_UPAGE 0x04 // usage page
+#define HID_ITEM_USAGE 0x08 // local item
+#define HID_ITEM_LOG_MIN 0x14
+#define HID_ITEM_USAGE_MIN 0x18 // local item
+#define HID_ITEM_LOG_MAX 0x24
+#define HID_ITEM_USAGE_MAX 0x28 // local item
+#define HID_ITEM_PHY_MIN 0x34
+#define HID_ITEM_PHY_MAX 0x44
+#define HID_ITEM_UNIT_EXP 0x54
+#define HID_ITEM_UNIT 0x64
+#define HID_ITEM_REP_SIZE 0x74
+#define HID_ITEM_STRING 0x78 // local item?
+#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;
+    }
+
+    memset(__spaces_buf, ' ', 32);
+    __spaces_buf[cnt] = '\0';
+    return __spaces_buf;
+}
+
+/**
+ * @brief 重置parser
+ *
+ * @param parser 解析器
+ * @return int 状态码
+ */
+static void hid_reset_parser(struct hid_parser *parser)
+{
+    memset(parser, 0, sizeof(struct hid_parser));
+    parser->data.report_id = 1; // we must give it a non-zero value or the parser doesn't work
+}
+
+/**
+ * @brief 从usage_stack中弹出第一个元素
+ *
+ * @param parser 解析器
+ * @return __always_inline
+ */
+static __always_inline void __pop_usage_stack(struct hid_parser *parser)
+{
+    if (parser->usage_size > 0)
+    {
+        for (int js = 0; js < parser->usage_size - 1; ++js)
+            memmove(&parser->usage_table[js], &parser->usage_table[js + 1], sizeof(struct hid_node_t));
+
+        --parser->usage_size;
+    }
+}
+
+/**
+ * @brief 解析hid report,并获取下一个数据到data字段中
+ *
+ * @param parser 解析器
+ * @param data 返回的数据
+ * @return true 解析成功
+ * @return false 解析失败
+ */
+static bool hid_parse(struct hid_parser *parser, struct hid_data_t *data)
+{
+    bool found = false;
+    static uint8_t space_cnt = 0;
+    static bool did_collection = false;
+    static int item_size[4] = {0, 1, 2, 4};
+
+    // 循环解析
+    while (!found && (parser->pos < parser->report_desc_size))
+    {
+        // 当前parse过程还没有解析到report
+        if (parser->count == 0)
+        {
+            // 打印当前 report_data 的值
+            if (HID_PARSE_OUTPUT)
+                printk("\n %02X ", parser->report_desc[parser->pos]);
+            // 获取到report size
+            parser->item = parser->report_desc[parser->pos++];
+            parser->value = 0;
+            // 拷贝report的数据
+            memcpy(&parser->value, &parser->report_desc[parser->pos], item_size[parser->item & HID_SIZE_MASK]);
+
+            if (HID_PARSE_OUTPUT)
+            {
+                for (int i = 0; i < 4; ++i)
+                {
+                    if (i < item_size[parser->item & HID_SIZE_MASK])
+                        printk("%02X ", parser->report_desc[parser->pos + i]);
+                    else
+                        printk("   ");
+                }
+            }
+            // 将指针指向下一个item
+            parser->pos += item_size[parser->item & HID_SIZE_MASK];
+        }
+
+        switch (parser->item & HID_ITEM_MASK)
+        {
+        case HID_ITEM_UPAGE:
+            // 拷贝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));
+            // 拷贝到 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字节
+                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));
+            ++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));
+            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));
+            break;
+        case HID_ITEM_COLLECTION:
+            // 从usage table中取出第一个u_page和usage,并且将他们存储在parser->data.path
+            parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
+            parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
+            ++parser->data.path.size;
+
+            // 由于上面取出了元素,因此将队列往前移动1个位置
+            __pop_usage_stack(parser);
+
+            // 获取index(如果有的话)???
+            if (parser->value > 0x80)
+            {
+                kdebug("parser->value > 0x80");
+                parser->data.path.node[parser->data.path.size].u_page = 0xff;
+                parser->data.path.node[parser->data.path.size].usage = parser->value & 0x7f;
+                ++parser->data.path.size;
+            }
+            if (HID_PARSE_OUTPUT)
+            {
+                printk("%sCollection (%s)", __spaces(space_cnt), hid_print_collection(parser->value));
+                space_cnt += 2;
+            }
+            break;
+        case HID_ITEM_END_COLLECTION:
+            --parser->data.path.size; // 为什么要--?????
+            // 删除多余的(未识别的)node
+            if (parser->data.path.node[parser->data.path.size].u_page == 0xff)
+                --parser->data.path.size;
+            if (HID_PARSE_OUTPUT)
+            {
+                if (space_cnt >= 2)
+                    space_cnt -= 2;
+                printk("%sEnd Collection", __spaces(space_cnt));
+            }
+            break;
+        case HID_ITEM_FEATURE:
+        case HID_ITEM_INPUT:
+        case HID_ITEM_OUTPUT:
+            // 找到了一个对象
+            found = true;
+
+            // 增加对象计数器
+            ++parser->cnt_objects;
+
+            // 更新local items的计数
+            if (parser->count == 0)
+                parser->count = parser->report_count;
+
+            // 从usage_table获取u_page和usage,将他们存储到parser.data.path
+            parser->data.path.node[parser->data.path.size].u_page = parser->usage_table[0].u_page;
+            parser->data.path.node[parser->data.path.size].usage = parser->usage_table[0].usage;
+            ++parser->data.path.size;
+
+            // 从usage table中弹出刚刚那个node
+            __pop_usage_stack(parser);
+
+            // 拷贝数据到data
+            parser->data.type = (uint8_t)(parser->item & HID_ITEM_MASK);
+            parser->data.attribue = (uint8_t)parser->value;
+            int *offset_ptr =
+                __get_report_offset(parser, parser->data.report_id, (uint8_t)(parser->item & HID_ITEM_MASK));
+
+            if (unlikely(offset_ptr == NULL))
+            {
+                BUG_ON(1);
+                return false;
+            }
+            parser->data.offset = *offset_ptr;
+
+            // 获取pData中的对象
+            memcpy(data, &parser->data, sizeof(struct hid_data_t));
+
+            // 增加report offset
+            *offset_ptr = (*offset_ptr) + 1;
+
+            // 从path中删除最后一个节点(刚刚弹出的这个节点)
+            --parser->data.path.size;
+
+            // 减少local items计数
+            if (parser->count > 0)
+                --parser->count;
+
+            if (!did_collection)
+            {
+                if (HID_PARSE_OUTPUT)
+                {
+                    if ((parser->item & HID_ITEM_MASK) == HID_ITEM_FEATURE)
+                        printk("%sFeature ", __spaces(space_cnt));
+                    else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_INPUT)
+                        printk("%sInput ", __spaces(space_cnt));
+                    else if ((parser->item & HID_ITEM_MASK) == HID_ITEM_OUTPUT)
+                        printk("%sOutut ", __spaces(space_cnt));
+
+                    printk("(%s,%s,%s" /* ",%s,%s,%s,%s" */ ")", !(parser->value & (1 << 0)) ? "Data" : "Constant",
+                           !(parser->value & (1 << 1)) ? "Array" : "Variable",
+                           !(parser->value & (1 << 2)) ? "Absolute" : "Relative" /*,
+                              !(parser->value & (1<<3)) ? "No Wrap"  : "Wrap",
+                              !(parser->value & (1<<4)) ? "Linear"   : "Non Linear",
+                              !(parser->value & (1<<5)) ? "Preferred State" : "No Preferred",
+                              !(parser->value & (1<<6)) ? "No Null"  : "Null State",
+                              //!(parser->value & (1<<8)) ? "Bit Fueld" : "Buffered Bytes"
+                              */
+                    );
+                }
+
+                did_collection = true;
+            }
+            break;
+        case HID_ITEM_REP_ID:
+            // todo:
+            break;
+        case HID_ITEM_REP_SIZE:
+            // todo:
+            break;
+        case HID_ITEM_REP_COUNT:
+            // todo:
+            break;
+        case HID_ITEM_UNIT_EXP:
+            // todo:
+            break;
+        case HID_ITEM_UNIT:
+            // todo:
+            break;
+        }
+    }
+}
+
+/**
+ * @brief 解析hid report的数据
+ *
+ * @param report_data 从usb hid设备获取到hid report
+ * @param len report_data的大小(字节)
+ * @return int错误码
+ */
+int hid_parse_report(const void *report_data, const int len)
+{
+    struct hid_parser parser = {0};
+    struct hid_data_t data;
+
+    hid_reset_parser(&parser);
+    parser.report_desc = (const uint8_t *)report_data;
+    parser.report_desc_size = len;
+
+    while (hid_parse(&parser, &data))
+        ;
+    return 0;
+}
+
+/**
+ * @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)
+{
+    // todo:
+    return NULL;
+}
+
+/**
+ * @brief 打印usage page的类型
+ *
+ * @param page
+ * @param type
+ * @return const char*
+ */
+static const char *hid_print_usage_type(const int page, const int type)
+{
+    // todo:
+    return NULL;
+}
+
+/**
+ * @brief 输出colection字符串
+ *
+ * @param value
+ * @return const char*
+ */
+static const char *hid_print_collection(const int value)
+{
+    // todo:
+    return NULL;
+}
+
+/**
+ * @brief 从parser的offset table中,根据report_id和report_type,获取表中指向offset字段的指针
+ *
+ * @param hid_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)
+{
+    // todo:
+}

+ 15 - 0
kernel/driver/hid/usbhid/Makefile

@@ -0,0 +1,15 @@
+
+CFLAGS += -I .
+
+
+kernel_driver_usbhid_objs:= $(shell find ./*.c)
+
+ECHO:
+	@echo "$@"
+
+$(kernel_driver_usbhid_objs): ECHO
+	gcc $(CFLAGS) -c $@ -o [email protected]
+
+all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
+	@echo $(kernel_driver_hid_objs)
+