#include "includes.h" #include "asm/includes.h" #include "app_config.h" #include "system/timer.h" #include "device/ioctl_cmds.h" #include "device_drive.h" #if TCFG_HID_HOST_ENABLE #include "usb/host/usb_host.h" #include "usb_ctrl_transfer.h" #include "usb_bulk_transfer.h" #include "hid.h" #include "usb_config.h" #include "usb_hid_keys.h" #define MAIN_ITEM 0 #define GLOBAL_ITEM 1 #define LOCAL_ITEM 2 #define LOG_TAG_CONST USB #define LOG_TAG "[HID]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" struct hid_device_t hid_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE]; static int set_power(struct usb_host_device *host_dev, u32 value) { const usb_dev usb_id = host_device2id(host_dev); memset(hid_device[usb_id], 0, sizeof(hid_device[usb_id])); return DEV_ERR_NONE; } static int get_power(struct usb_host_device *host_dev, u32 value) { return DEV_ERR_NONE; } static const struct interface_ctrl hid_ctrl = { .interface_class = USB_CLASS_HID, .set_power = set_power, .get_power = get_power, .ioctl = NULL, }; static const struct usb_interface_info _usb_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = { { { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[0][0], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[0][1], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[0][2], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[0][3], }, }, #if USB_MAX_HW_NUM > 1 { { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[1][0], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[1][1], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[1][2], }, { .ctrl = (struct interface_ctrl *) &hid_ctrl, .dev.hid = &hid_device[1][3], }, }, #endif }; static u8 interval[USB_MAX_HW_NUM][16]; int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf) { struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf; pBuf += sizeof(struct usb_interface_descriptor); int len = 0; const usb_dev usb_id = host_device2id(host_dev); struct usb_endpoint_descriptor *endpoint; pBuf += 9;//hid desc; const struct usb_interface_info *usb_if = &_usb_if[usb_id][interface_num]; memset(usb_if->dev.p, 0, sizeof(struct hid_device_t)); host_dev->interface_info[interface_num] = usb_if; usb_if->dev.hid->parent = host_dev; log_info("hid eps %d %d %x %x", interface->bNumEndpoints, interface_num, usb_if, usb_if->dev.p); log_info("parent %x hid @ interface %d usb_if %x hid %x", host_dev, interface_num, usb_if, usb_if->dev.hid); if ((interface->bInterfaceProtocol == 0x02) || (interface->bInterfaceProtocol == 0x01)) { //mouse & keyboard usb_if->dev.hid->bNumEndpoints = interface->bNumEndpoints; usb_if->dev.hid->report_list[0].usage = interface->bInterfaceProtocol; for (int i = 0 ; i < interface->bNumEndpoints; i++) { endpoint = (struct usb_endpoint_descriptor *)pBuf; if (USB_DIR_IN & endpoint->bEndpointAddress) { const u8 ep = endpoint->bEndpointAddress & 0x0f; usb_if->dev.hid->ep_pair[i] = ep; interval[usb_id][ep] = endpoint->bInterval; log_info("interfacenum = %d,endpoint = %x interval = %x", interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval); } pBuf += endpoint->bLength; } } else { log_info("vendor"); host_dev->interface_info[interface_num] = NULL; //??? for (int i = 0 ; i < interface->bNumEndpoints; i++) { endpoint = (struct usb_endpoint_descriptor *)pBuf; if (USB_DIR_IN & endpoint->bEndpointAddress) { /* interface_endpoint[interface->bInterfaceNumber] = endpoint->bEndpointAddress & 0x0f; */ log_info("interfacenum = %d,endpoint = %x interval = %x", interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval); } pBuf += endpoint->bLength; } return sizeof(struct usb_interface_descriptor); } return pBuf - (u8 *)interface; } static u32 _hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len) { hid->report_count = 0; struct report_info_t null_rpt; struct report_info_t *const rpt = &null_rpt; memset(rpt, 0, sizeof(*rpt)); unsigned char ops; int index = 0; u8 report_size = 0; u8 report_count = 0; u8 cur_ops_is_report_size_count = 0; u8 old_ops_is_report_size_count = 0; s8 cur_section_bit = 0; u8 input_bit_index = 0; u8 total_bits = 0; u8 output_bit_index = 0; u8 cur_usage = 0; u32 undef_type = 0; u8 undef_usage = 0; u8 collection_deep = 0; while (index < len) { ops = (char)report[index++]; char bSize = ops & 0x03; bSize = bSize == 3 ? 4 : bSize; // size is 4 when bSize is 3 char bType = (ops >> 2) & 0x03; char bTag = (ops >> 4) & 0x0F; cur_ops_is_report_size_count = 0; char bSizeActual = 0; int itemVal = 0; for (int j = 0; j < bSize; j++) { if (index + j < len) { itemVal += report[index + j] << (8 * j); bSizeActual++; } } if (undef_type) { undef_type ++; if (bTag == 0x0A) { undef_usage ++; } else if (bTag == 0x0C) { undef_usage --; } if (undef_usage == 0 && undef_type > 2) { undef_type = 0; } index += bSize; continue; } if (undef_type) { index += bSize; continue; } if (itemVal == 0xffb5) { undef_type = 1; index += bSize; continue; } else { undef_type = 0; } if (bType == MAIN_ITEM) { if (old_ops_is_report_size_count) { cur_section_bit += report_size * report_count; } if (bTag == 0x08) { /* log_info("input %X", itemVal); */ /* log_info("\tusage %x", cur_usage); */ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */ if (rpt->usage == 0x02) { //mouse if (cur_usage == 1) { if (rpt->btn_start_bit == 0) { rpt->btn_start_bit = total_bits ; } rpt->btn_width += cur_section_bit ; /* log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); */ } else if ((cur_usage == 0x30) || (cur_usage == 0x31)) { if (rpt->xy_start_bit == 0) { rpt->xy_start_bit = total_bits; } rpt->xy_width = cur_section_bit; /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */ } else if (cur_usage == 0x38) { if (rpt->wheel_start_bit == 0) { rpt->wheel_start_bit = total_bits; } if (rpt->xy_width || cur_section_bit < 24) { rpt->wheel_width = cur_section_bit; /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */ } else { rpt->wheel_width = rpt->xy_width = cur_section_bit / 3; rpt->xy_start_bit = total_bits; rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2; /* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */ /* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */ } } else if (cur_usage == 0xb8) { rpt->wheel_width = rpt->xy_width = cur_section_bit / 4; rpt->xy_start_bit = total_bits; rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2; } } total_bits += cur_section_bit; /* input_bit[input_bit_index++] = cur_section_bit; */ cur_section_bit = -1; } else if (bTag == 0x09) { /* log_info("OUTPUT %X", itemVal); */ /* log_info("\tusage %x", cur_usage); */ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */ /* output_bit[output_bit_index++] = cur_section_bit; */ cur_section_bit = -1; } else if (bTag == 0x0B) { /* log_info("Feature %X", itemVal); */ /* log_info("\tusage %x", cur_usage); */ /* log_info("\t\tcur_section_bit %d", cur_section_bit); */ /* output_bit[output_bit_index++] = cur_section_bit; */ cur_section_bit = -1; } else if (bTag == 0x0A) { collection_deep ++ ; log_info("Collection %d %x", collection_deep, rpt->usage); } else if (bTag == 0x0C) { collection_deep --; log_info("End Collection %d %x", collection_deep, rpt->usage); if (collection_deep == 0) { if (rpt->usage == 0x02 || rpt->usage == 0x06 || rpt->usage == 0x07) { memcpy(&hid->report_list[hid->report_count], rpt, sizeof(*rpt)); memset(rpt, 0, sizeof(*rpt)); hid->report_count ++; } } if (index < len) { continue; } } else { log_info("MAIN_ITEM Unknown btag :%x", bTag); return 1; } } else if (bType == GLOBAL_ITEM) { /* log_info("GLOBAL_ITEM"); */ if (bTag == 0x00) { /* log_info("Usage Page %x", itemVal); */ if (rpt->usage == 0x06) { if (itemVal == 0x07) { rpt->usage = 0x07; log_info("re set type %x", 0x07); } } if (itemVal == 0x02) { rpt->usage = 0x02; log_info("re set type %x", 0x02); } } else if (bTag == 0x01) { //log_info("Logical Minimum %x", itemVal); } else if (bTag == 0x02) { //log_info("Logical Maximum %x", itemVal); } else if (bTag == 0x03) { /* log_info("Physical Minimum %x", itemVal); */ } else if (bTag == 0x04) { /* log_info("Physical Maximum %x", itemVal); */ } else if (bTag == 0x05) { /* log_info("Unit Exponent %x", itemVal); */ } else if (bTag == 0x06) { /* log_info("Unit %x", itemVal); */ } else if (bTag == 0x07) { /* log_info("Report Size %x", itemVal); */ report_size = itemVal; cur_ops_is_report_size_count = 1; } else if (bTag == 0x08) { log_info("Report ID %x", itemVal, rpt->usage); rpt->report_id = itemVal; } else if (bTag == 0x09) { /* log_info("Report Count %x", itemVal); */ report_count = itemVal; cur_ops_is_report_size_count = 1; } else if (bTag == 0x0A) { /* log_info("Push %x", bSizeActual); */ } else if (bTag == 0x0B) { /* log_info("Pop %x", bSizeActual); */ } else { log_info("GLOBAL_ITEM Unknown btag :%x", bTag); return 2; } } else if (bType == LOCAL_ITEM) { /* log_info("LOCAL_ITEM"); */ if (bTag == 0x00) { if (rpt->usage == 0) { rpt->usage = itemVal; log_info("set type %x", rpt->usage); } if (itemVal == 0x30) { //X } else if (itemVal == 0x31) { //y } else if (itemVal == 0x38) { //wheel } else { } /* log_info("\t change usage %x -> %x", cur_usage, itemVal); */ cur_usage = itemVal; if (!collection_deep) { if (itemVal == 0x06 || itemVal == 0x07 || itemVal == 0x02) { //仅限键盘和鼠标 rpt->usage = itemVal; log_info("set typee %x", rpt->usage); } } /* type = itemVal; */ } else if (bTag == 0x01) { // log_info("Usage Minimum %x", itemVal); } else if (bTag == 0x02) { // log_info("Usage Maximum %x", itemVal); } else if (bTag == 0x03) { /* log_info("Designator Index %x", itemVal); */ } else if (bTag == 0x04) { /* log_info("Designator Minimum %x", itemVal); */ } else if (bTag == 0x05) { /* log_info("Designator Maximum %x", itemVal); */ } else if (bTag == 0x07) { /* log_info("String Index %x", itemVal); */ } else if (bTag == 0x08) { /* log_info("String Minimum %x", itemVal); */ } else if (bTag == 0x09) { /* log_info("String Maximum %x", itemVal); */ } else if (bTag == 0x0A) { /* log_info("Delimiter %x", itemVal); */ } else { log_info("LOCAL_ITEM Unknown btag :%x", bTag); return 3; } } else { log_info("OTHER Unknown btag :%x", bTag); return 4; } if (!cur_ops_is_report_size_count && old_ops_is_report_size_count) { if (cur_section_bit != -1) { cur_section_bit += report_size * report_count; } else { cur_section_bit = 0; } } if (cur_section_bit == -1) { cur_section_bit = 0; } old_ops_is_report_size_count = cur_ops_is_report_size_count; index += bSize; } return 0; } static u32 hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len) { u8 type = _hid_report_parse(hid, report, len); for (int i = 0; i < hid->report_count; i++) { struct report_info_t *rpt = &hid->report_list[i]; if (rpt->usage == 0x02) { if (rpt->report_id == 0) { rpt->report_id = 0xff; } rpt->btn_start_bit /= 8; rpt->btn_width /= 8; rpt->xy_start_bit /= 8; rpt->xy_width /= 8; rpt->wheel_start_bit /= 8; rpt->wheel_width /= 8; log_info("mouse report_id %d", rpt->report_id); log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); if (rpt->btn_width != 2) { rpt->btn_width = 1; } log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); } else if (rpt->usage == 6 || rpt->usage == 7) { if (rpt->report_id == 0) { rpt->report_id = 0xff; } log_info("keyboard report_id %d", rpt->report_id); } else { log_info("unknown usage %d", rpt->usage); } } return 0; } void mouse_route(const struct mouse_data_t *p); /* __attribute__((weak)) void mouse_route(const struct mouse_data_t *p) */ /* { */ /* log_info("btn: %x x-y %d %d wheel %d ac_pan %d", */ /* p->btn, p->x, p->y, p->wheel, p->ac_pan); */ /* } */ static void hid_convert_mouse(const struct report_info_t *mouse, const u8 *buffer) { struct mouse_data_t mouse_data; memset(&mouse_data, 0, sizeof(mouse_data)); if (mouse->report_id != 0xff) { if (mouse->report_id != buffer[0]) { log_error("report_id = %x buffer[0] = %x", mouse->report_id, buffer[0]); return; } buffer++; } const u8 *ptr; ptr = &buffer[mouse->btn_start_bit]; if (mouse->btn_width == 2) { mouse_data.btn = ptr[0] | (ptr[1] << 8); } else { mouse_data.btn = ptr[0] ; } s16 tmp; ptr = &buffer[mouse->xy_start_bit]; if (mouse->xy_width == 1 || mouse->xy_width == 2) { mouse_data.x = (char)ptr[0]; mouse_data.y = (char)ptr[1]; } else if (mouse->xy_width == 4) { mouse_data.x = ptr[0] | (ptr[1] << 8); ptr += 2; mouse_data.y = ptr[0] | (ptr[1] << 8); } else if (mouse->xy_width == 3) { tmp = (ptr[1] & 0xf) << 12 | ptr[0] << 4; tmp = tmp >> 4; mouse_data.x = tmp; tmp = (ptr[2] << 8) | ((ptr[1] >> 4) << 4); tmp = tmp >> 4; mouse_data.y = tmp; } else { log_error("error mouse xy_width %d", mouse->xy_width); } ptr = &buffer[mouse->wheel_start_bit]; if (mouse->wheel_width == 1) { mouse_data.wheel = (char)ptr[0]; } else { mouse_data.wheel = ptr[0] | (ptr[1] << 8); } mouse_route(&mouse_data); } __attribute__((weak)) void keyboard_route(const u8 *p) { log_info("keyboard_buffer:"); printf_buf(p, 12); } void hid_convert_krbd(const struct report_info_t *kbd, u8 *buffer) { #if 0 u8 keyboard_buffer[12]; memset(keyboard_buffer, 0, sizeof(keyboard_buffer)); if (kbd->report_id != 0xff) { if (kbd->report_id != buffer[0]) { log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]); return; } buffer++; } u8 idx = 0; u8 index = 0; int i = 0; for (i = 0; i < 8; i++) { if (buffer[0] & BIT(i)) { keyboard_buffer[idx++] = 0xe0 + i; } } if (buffer[1] == 0) { buffer += 2; } index = idx; for (; idx < 12; idx++) { if (*buffer) { keyboard_buffer[index] = *buffer; index++; } buffer ++; } keyboard_route(keyboard_buffer); #else if (kbd->report_id != 0xff) { if (kbd->report_id != buffer[0]) { log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]); return; } buffer++; } u8 keyboard_buffer[8]; memset(keyboard_buffer, 0, sizeof(keyboard_buffer)); keyboard_buffer[0] = *buffer; buffer ++; if (*buffer == 0) { buffer ++; } keyboard_buffer[1] = 0; /* memcpy(&keyboard_buffer[2], buffer, 6); */ u8 pos = 2; for (int i = pos; i < 8; i++) { if (*buffer) { keyboard_buffer[pos] = *buffer; pos++; } buffer++; } keyboard_route(keyboard_buffer); #endif } static void hid_route(const struct hid_device_t *hid, const u8 *buffer) { for (int i = 0; i < hid->report_count; i++) { if (hid->report_list[i].usage == 0x02) { hid_convert_mouse(&hid->report_list[i], buffer); } else if ((hid->report_list[i].usage == 0x06) || (hid->report_list[i].usage == 0x07)) { hid_convert_krbd(&hid->report_list[i], buffer); } else { r_printf("usage %x", hid->report_list[i].usage); } } } static void hid_isr(struct usb_interface_info *usb_if, u32 ep) { u8 buffer[64] = {0}; struct usb_host_device *host_dev = usb_if->dev.hid->parent; usb_dev usb_id = host_device2id(host_dev); u32 target_ep = usb_if->dev.hid->ep_pair[ep]; u32 rx_len = usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 64, USB_ENDPOINT_XFER_INT, 0); if (rx_len) { hid_route(usb_if->dev.hid, buffer); } /* printf_buf(buffer, rx_len); */ usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 8, USB_ENDPOINT_XFER_INT, 1); } void hid_process(u32 id) { struct usb_host_device *host_dev = host_id2device(id); u8 report[256 + 2]; u8 ep_pair[4]; for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) { struct usb_interface_info *usb_if = host_dev->interface_info[i]; log_info("parent %x hid @ interface %d usb_if %x hid %x", host_dev, i, usb_if, usb_if ? usb_if->dev.hid : 0); if (usb_if && (usb_if->ctrl->interface_class == USB_CLASS_HID)) { hid_set_idle(host_dev, i); memset(report, 0, sizeof(report)); hid_get_report(host_dev, report, i, 0xff); printf_buf(report, 256); hid_report_parse(usb_if->dev.hid, report, 256); memcpy(ep_pair, usb_if->dev.hid->ep_pair, 4); if (usb_if->dev.hid->report_count == 0) { continue; } for (int i = 0; i < usb_if->dev.hid->bNumEndpoints; i++) { u32 host_ep = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_INT); ASSERT(host_ep != -1, "ep not enough"); u32 target_ep = ep_pair[i]; usb_if->dev.hid->ep_pair[host_ep] = target_ep; log_info("D2H ep: %x --> %x interval %d", target_ep, host_ep, interval[id][target_ep]); usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, hid_isr, usb_if); u8 *ep_buffer = usb_h_get_ep_buffer(id, host_ep | USB_DIR_OUT); usb_h_ep_config(id, host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 1, interval[id][target_ep], ep_buffer, 64); int r = usb_h_ep_read_async(id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_INT, 1); } } else { if (usb_if) { log_error("error hid class %x", usb_if->ctrl->interface_class); } } } } #endif