Browse Source

在usb设备的hid path中寻找给定的节点(存在问题,以后再解决) (#67)

login 2 years ago
parent
commit
0385e0324e
3 changed files with 156 additions and 21 deletions
  1. 73 6
      kernel/common/hid.h
  2. 69 12
      kernel/driver/hid/hidparse.c
  3. 14 3
      kernel/driver/usb/xhci/xhci.c

+ 73 - 6
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列表。
+ * 原始数据请见<HID Usage Tables FOR Universal Serial Bus (USB)>。
+ * 该文件可从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);

+ 69 - 12
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;
+    }
 }

+ 14 - 3
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;