mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
parent
80edc58cf0
commit
39f11c5b4b
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -145,7 +145,8 @@
|
||||
"kthread.h": "c",
|
||||
"lockref.h": "c",
|
||||
"compiler_attributes.h": "c",
|
||||
"timer.h": "c"
|
||||
"timer.h": "c",
|
||||
"hid.h": "c"
|
||||
},
|
||||
"C_Cpp.errorSquiggles": "Enabled",
|
||||
"esbonio.sphinx.confDir": ""
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <common/stddef.h>
|
||||
|
||||
// 当函数的返回值未被使用时,编译器抛出警告信息
|
||||
#define __must_check __attribute__((__warn_unused_result__))
|
||||
|
97
kernel/common/hid.h
Normal file
97
kernel/common/hid.h
Normal file
@ -0,0 +1,97 @@
|
||||
#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 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;
|
||||
|
||||
uint32_t unit; // 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数目
|
||||
};
|
||||
|
||||
|
||||
struct hid_usage_types_string
|
||||
{
|
||||
int value;
|
||||
const char *string;
|
||||
};
|
||||
|
||||
struct hid_usage_pages_string
|
||||
{
|
||||
int value;
|
||||
struct hid_usage_types_string * types;
|
||||
const char * string;
|
||||
};
|
||||
|
||||
int hid_parse_report(const void *report_data, const int len);
|
@ -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
kernel/driver/hid/Makefile
Normal file
19
kernel/driver/hid/Makefile
Normal file
@ -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 $@.o
|
||||
|
||||
all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
|
||||
@echo $(kernel_driver_hid_objs)
|
||||
|
526
kernel/driver/hid/hidparse.c
Normal file
526
kernel/driver/hid/hidparse.c
Normal file
@ -0,0 +1,526 @@
|
||||
#include "internal.h"
|
||||
#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
|
||||
本文件参考了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_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
|
||||
// 高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;
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @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_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字节
|
||||
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_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_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_get_usage_type_str(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_get_collection_str(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.attribute = (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) + parser->data.size;
|
||||
|
||||
// 从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: // 当前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: // 当前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:
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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的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_get_usage_page_str(const int u_page)
|
||||
{
|
||||
|
||||
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的指定类型的usage
|
||||
*
|
||||
* @param page usage page id
|
||||
* @param type usage的类型
|
||||
* @return const char*
|
||||
*/
|
||||
static const char *hid_get_usage_type_str(const int page, const int type)
|
||||
{
|
||||
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 collection的值
|
||||
* @return const char*
|
||||
*/
|
||||
static const char *hid_get_collection_str(const int value)
|
||||
{
|
||||
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 parser 解析器
|
||||
* @param report_id report_id
|
||||
* @param report_type report类型
|
||||
* @return int* 指向offset字段的指针
|
||||
*/
|
||||
static int *__get_report_offset(struct hid_parser *parser, const uint8_t report_id, const uint8_t report_type)
|
||||
{
|
||||
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;
|
||||
}
|
1580
kernel/driver/hid/hidstrings.c
Normal file
1580
kernel/driver/hid/hidstrings.c
Normal file
File diff suppressed because it is too large
Load Diff
37
kernel/driver/hid/internal.h
Normal file
37
kernel/driver/hid/internal.h
Normal 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];
|
15
kernel/driver/hid/usbhid/Makefile
Normal file
15
kernel/driver/hid/usbhid/Makefile
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
|
||||
kernel_driver_usbhid_objs:= $(shell find ./*.c)
|
||||
|
||||
ECHO:
|
||||
@echo "$@"
|
||||
|
||||
$(kernel_driver_usbhid_objs): ECHO
|
||||
gcc $(CFLAGS) -c $@ -o $@.o
|
||||
|
||||
all: $(kernel_driver_hid_objs) $(kernel_driver_hid_subdirs)
|
||||
@echo $(kernel_driver_hid_objs)
|
||||
|
@ -105,7 +105,8 @@ struct usb_interface_desc
|
||||
uint8_t num_endpoints; // 当前interface的端点数量
|
||||
uint8_t interface_class; // Class code
|
||||
uint8_t interface_sub_class; // Sub class code
|
||||
uint8_t interface_protocol; // 协议 These codes are qualified by the value of thebInterfaceClass and the bInterfaceSubClass fields.
|
||||
uint8_t interface_protocol; // 协议 These codes are qualified by the value of thebInterfaceClass and the
|
||||
// bInterfaceSubClass fields.
|
||||
uint8_t index; // index of String Descriptor describing this interface
|
||||
} __attribute__((packed));
|
||||
|
||||
@ -162,6 +163,7 @@ struct usb_request_packet_t
|
||||
|
||||
#define USB_REQ_TYPE_GET_REQUEST (__USB_REQ_TYPE_D2H | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_DEVICE)
|
||||
#define USB_REQ_TYPE_SET_REQUEST (__USB_REQ_TYPE_H2D | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_DEVICE)
|
||||
#define USB_REQ_TYPE_GET_INTERFACE_REQUEST (__USB_REQ_TYPE_D2H | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_INTERFACE)
|
||||
#define USB_REQ_TYPE_SET_INTERFACE (__USB_REQ_TYPE_H2D | __USB_REQ_TYPE_STANDARD | __USB_REQ_TYPE_INTERFACE)
|
||||
#define USB_REQ_TYPE_SET_CLASS_INTERFACE (__USB_REQ_TYPE_H2D | __USB_REQ_TYPE_CLASS | __USB_REQ_TYPE_INTERFACE)
|
||||
|
||||
@ -283,6 +285,22 @@ enum
|
||||
USB_CLASS_VENDOR_SPEC = 0XFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief usb hid descriptor的结构体
|
||||
*
|
||||
*/
|
||||
struct usb_hid_desc
|
||||
{
|
||||
uint8_t len;
|
||||
uint8_t type; // USB_DT_HID
|
||||
uint16_t bcdHID; // 标识HIDClass规范版本的数字表达式。
|
||||
|
||||
uint8_t country_code;
|
||||
uint8_t descriptors_num; // the number of class descriptors
|
||||
uint8_t desc_type; // Constant name identifying type of class descriptor
|
||||
uint16_t report_desc_len; // Report descriptor的大小
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化usb驱动程序
|
||||
*
|
||||
|
@ -1,14 +1,15 @@
|
||||
#include "xhci.h"
|
||||
#include "internal.h"
|
||||
#include <common/hid.h>
|
||||
#include <common/kprint.h>
|
||||
#include <debug/bug.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/time.h>
|
||||
#include <debug/bug.h>
|
||||
#include <debug/traceback/traceback.h>
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
#include <exception/irq.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/slab.h>
|
||||
#include <debug/traceback/traceback.h>
|
||||
#include <common/time.h>
|
||||
#include <exception/irq.h>
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
|
||||
// 由于xhci寄存器读取需要对齐,因此禁用GCC优化选项
|
||||
#pragma GCC optimize("O0")
|
||||
@ -30,7 +31,8 @@ static int xhci_hc_reset(int id);
|
||||
static int xhci_hc_stop_legacy(int id);
|
||||
static int xhci_hc_start_sched(int id);
|
||||
static int xhci_hc_stop_sched(int id);
|
||||
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag);
|
||||
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset,
|
||||
uint32_t *count, uint16_t *protocol_flag);
|
||||
static int xhci_hc_pair_ports(int id);
|
||||
static uint64_t xhci_create_ring(int trbs);
|
||||
static uint64_t xhci_create_event_ring(int trbs, uint64_t *ret_ring_addr);
|
||||
@ -40,25 +42,38 @@ static int xhci_hc_start_ports(int id);
|
||||
|
||||
static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring);
|
||||
static uint64_t xhci_initialize_slot(const int id, const int port, const int speed, const int max_packet);
|
||||
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int port_id, const int ep_num, const int max_packet, const int max_burst, const int type, const int direction, const int speed, const int ep_interval);
|
||||
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int port_id, const int ep_num,
|
||||
const int max_packet, const int max_burst, const int type, const int direction,
|
||||
const int speed, const int ep_interval);
|
||||
static int xhci_set_address(const int id, const uint64_t slot_vaddr, const int slot_id, const bool block);
|
||||
static int xhci_control_in(const int id, struct usb_request_packet_t *packet, void *target, const int port_id, const int max_packet);
|
||||
static int xhci_control_out(const int id, struct usb_request_packet_t *packet, void *target, const int slot_id, const int max_packet);
|
||||
static int xhci_setup_stage(struct xhci_ep_info_t *ep, const struct usb_request_packet_t *packet, const uint8_t direction);
|
||||
static int xhci_data_stage(struct xhci_ep_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size, uint8_t direction, const int max_packet, const uint64_t status_vaddr);
|
||||
static int xhci_control_in(const int id, struct usb_request_packet_t *packet, void *target, const int port_id,
|
||||
const int max_packet);
|
||||
static int xhci_control_out(const int id, struct usb_request_packet_t *packet, void *target, const int slot_id,
|
||||
const int max_packet);
|
||||
static int xhci_setup_stage(struct xhci_ep_info_t *ep, const struct usb_request_packet_t *packet,
|
||||
const uint8_t direction);
|
||||
static int xhci_data_stage(struct xhci_ep_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size,
|
||||
uint8_t direction, const int max_packet, const uint64_t status_vaddr);
|
||||
static int xhci_status_stage(struct xhci_ep_info_t *ep, uint8_t direction, uint64_t status_buf_vaddr);
|
||||
static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr);
|
||||
static inline int xhci_get_desc(const int id, const int port_id, void *target, const uint16_t desc_type, const uint8_t desc_index, const uint16_t lang_id, const uint16_t length);
|
||||
static inline int xhci_get_desc(const int id, const int port_id, void *target, const uint16_t desc_type,
|
||||
const uint8_t desc_index, const uint16_t lang_id, const uint16_t length);
|
||||
static int xhci_get_config_desc(const int id, const int port_id, struct usb_config_desc *conf_desc);
|
||||
static inline int xhci_get_config_desc_full(const int id, const int port_id, const struct usb_config_desc *conf_desc, void *target);
|
||||
static inline int xhci_get_config_desc_full(const int id, const int port_id, const struct usb_config_desc *conf_desc,
|
||||
void *target);
|
||||
static int xhci_get_interface_desc(const void *in_buf, const uint8_t if_num, struct usb_interface_desc **if_desc);
|
||||
static inline int xhci_get_endpoint_desc(const struct usb_interface_desc *if_desc, const uint8_t ep_num, struct usb_endpoint_desc **ep_desc);
|
||||
static inline int xhci_get_endpoint_desc(const struct usb_interface_desc *if_desc, const uint8_t ep_num,
|
||||
struct usb_endpoint_desc **ep_desc);
|
||||
static int xhci_get_descriptor(const int id, const int port_id, struct usb_device_desc *dev_desc);
|
||||
static int xhci_configure_port(const int id, const int port_id);
|
||||
static int xhci_configure_endpoint(const int id, const int port_id, const uint8_t ep_num, const uint8_t ep_type, struct usb_endpoint_desc *ep_desc);
|
||||
static int xhci_configure_endpoint(const int id, const int port_id, const uint8_t ep_num, const uint8_t ep_type,
|
||||
struct usb_endpoint_desc *ep_desc);
|
||||
static int xhci_get_hid_report(int id, int port_id, int interface_number, void *ret_hid_report,
|
||||
uint32_t hid_report_len);
|
||||
static int xhci_get_hid_descriptor(int id, int port_id, const void *full_conf, int interface_number,
|
||||
struct usb_hid_desc **ret_hid_desc);
|
||||
|
||||
hardware_intr_controller xhci_hc_intr_controller =
|
||||
{
|
||||
hardware_intr_controller xhci_hc_intr_controller = {
|
||||
.enable = xhci_hc_irq_enable,
|
||||
.disable = xhci_hc_irq_disable,
|
||||
.install = xhci_hc_irq_install,
|
||||
@ -207,7 +222,8 @@ static __always_inline void __xhci_write_trb(struct xhci_ep_info_t *ep_info, str
|
||||
*/
|
||||
static __always_inline uint64_t xhci_get_device_context_vaddr(const int id, const int port_id)
|
||||
{
|
||||
return (uint64_t)phys_2_virt(__read8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port_id].slot_id * sizeof(uint64_t))));
|
||||
return (uint64_t)phys_2_virt(
|
||||
__read8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port_id].slot_id * sizeof(uint64_t))));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,11 +310,13 @@ static int xhci_hc_stop_legacy(int id)
|
||||
{
|
||||
io_mfence();
|
||||
// 接管控制权
|
||||
xhci_write_cap_reg32(id, current_offset, xhci_read_cap_reg32(id, current_offset) | XHCI_XECP_LEGACY_OS_OWNED);
|
||||
xhci_write_cap_reg32(id, current_offset,
|
||||
xhci_read_cap_reg32(id, current_offset) | XHCI_XECP_LEGACY_OS_OWNED);
|
||||
io_mfence();
|
||||
// 等待响应完成
|
||||
int timeout = XHCI_XECP_LEGACY_TIMEOUT;
|
||||
while ((xhci_read_cap_reg32(id, current_offset) & XHCI_XECP_LEGACY_OWNING_MASK) != XHCI_XECP_LEGACY_OS_OWNED)
|
||||
while ((xhci_read_cap_reg32(id, current_offset) & XHCI_XECP_LEGACY_OWNING_MASK) !=
|
||||
XHCI_XECP_LEGACY_OS_OWNED)
|
||||
{
|
||||
io_mfence();
|
||||
usleep(1000);
|
||||
@ -361,7 +379,8 @@ static int xhci_hc_stop_sched(int id)
|
||||
* @param protocol_flag 返回的与协议相关的flag
|
||||
* @return uint32_t 下一个列表项的偏移量
|
||||
*/
|
||||
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset, uint32_t *count, uint16_t *protocol_flag)
|
||||
static uint32_t xhci_hc_get_protocol_offset(int id, uint32_t list_off, const int version, uint32_t *offset,
|
||||
uint32_t *count, uint16_t *protocol_flag)
|
||||
{
|
||||
if (count)
|
||||
*count = 0;
|
||||
@ -467,7 +486,8 @@ static int xhci_hc_pair_ports(int id)
|
||||
continue;
|
||||
io_mfence();
|
||||
if ((xhci_hc[id].ports[i].offset == xhci_hc[id].ports[j].offset) &&
|
||||
((xhci_hc[id].ports[i].flags & XHCI_PROTOCOL_INFO) != (xhci_hc[id].ports[j].flags & XHCI_PROTOCOL_INFO)))
|
||||
((xhci_hc[id].ports[i].flags & XHCI_PROTOCOL_INFO) !=
|
||||
(xhci_hc[id].ports[j].flags & XHCI_PROTOCOL_INFO)))
|
||||
{
|
||||
xhci_hc[id].ports[i].paired_port_num = j;
|
||||
xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_HAS_PAIR;
|
||||
@ -482,11 +502,11 @@ static int xhci_hc_pair_ports(int id)
|
||||
for (int i = 0; i < xhci_hc[id].port_num; ++i)
|
||||
{
|
||||
io_mfence();
|
||||
if (XHCI_PORT_IS_USB3(id, i) ||
|
||||
(XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))))
|
||||
if (XHCI_PORT_IS_USB3(id, i) || (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))))
|
||||
xhci_hc[id].ports[i].flags |= XHCI_PROTOCOL_ACTIVE;
|
||||
}
|
||||
kinfo("Found %d ports on root hub, usb2 ports:%d, usb3 ports:%d", xhci_hc[id].port_num, xhci_hc[id].port_num_u2, xhci_hc[id].port_num_u3);
|
||||
kinfo("Found %d ports on root hub, usb2 ports:%d, usb3 ports:%d", xhci_hc[id].port_num, xhci_hc[id].port_num_u2,
|
||||
xhci_hc[id].port_num_u3);
|
||||
|
||||
/*
|
||||
// 打印配对结果
|
||||
@ -494,8 +514,9 @@ static int xhci_hc_pair_ports(int id)
|
||||
{
|
||||
if (XHCI_PORT_IS_USB3(id, i))
|
||||
{
|
||||
kdebug("USB3 port %d, offset=%d, pair with usb2 port %d, current port is %s", i, xhci_hc[id].ports[i].offset,
|
||||
xhci_hc[id].ports[i].paired_port_num, XHCI_PORT_IS_ACTIVE(id, i) ? "active" : "inactive");
|
||||
kdebug("USB3 port %d, offset=%d, pair with usb2 port %d, current port is %s", i,
|
||||
xhci_hc[id].ports[i].offset, xhci_hc[id].ports[i].paired_port_num, XHCI_PORT_IS_ACTIVE(id, i) ? "active" :
|
||||
"inactive");
|
||||
}
|
||||
else if (XHCI_PORT_IS_USB2(id, i) && (!XHCI_PORT_HAS_PAIR(id, i))) // 单独的2.0接口
|
||||
{
|
||||
@ -721,8 +742,10 @@ void xhci_hc_irq_handler(uint64_t irq_num, uint64_t cid, struct pt_regs *regs)
|
||||
switch (event_trb_ptr->TRB_type)
|
||||
{
|
||||
case TRB_TYPE_TRANS_EVENT: // 当前 event trb是 transfer event TRB
|
||||
// If SPD was encountered in this TD, comp_code will be SPD, else it should be SUCCESS (specs 4.10.1.1)
|
||||
__write4b((uint64_t)phys_2_virt(event_trb.param), (event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred
|
||||
// If SPD was encountered in this TD, comp_code will be SPD, else it should be SUCCESS
|
||||
// (specs 4.10.1.1)
|
||||
__write4b((uint64_t)phys_2_virt(event_trb.param),
|
||||
(event_trb.status | XHCI_IRQ_DONE)); // return code + bytes *not* transferred
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -871,7 +894,8 @@ static uint64_t xhci_initialize_slot(const int id, const int port, const int spe
|
||||
uint64_t device_context_vaddr = (uint64_t)kzalloc(xhci_hc[id].context_size * 32, 0);
|
||||
// kdebug("slot id=%d, device_context_vaddr=%#018lx, port=%d", slot_id, device_context_vaddr, port);
|
||||
// 写到数组中
|
||||
__write8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port].slot_id * sizeof(uint64_t)), virt_2_phys(device_context_vaddr));
|
||||
__write8b(xhci_hc[id].dcbaap_vaddr + (xhci_hc[id].ports[port].slot_id * sizeof(uint64_t)),
|
||||
virt_2_phys(device_context_vaddr));
|
||||
struct xhci_slot_context_t slot_ctx = {0};
|
||||
slot_ctx.entries = 1;
|
||||
slot_ctx.speed = speed;
|
||||
@ -904,7 +928,9 @@ static uint64_t xhci_initialize_slot(const int id, const int port, const int spe
|
||||
* @param speed 传输速度
|
||||
* @param ep_interval 端点的连续请求间隔
|
||||
*/
|
||||
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int port_id, const int ep_num, const int max_packet, const int max_burst, const int type, const int direction, const int speed, const int ep_interval)
|
||||
static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const int port_id, const int ep_num,
|
||||
const int max_packet, const int max_burst, const int type, const int direction,
|
||||
const int speed, const int ep_interval)
|
||||
{
|
||||
// 由于目前只实现获取设备的描述符,因此暂时只支持control ep
|
||||
if (type != USB_EP_CONTROL && type != USB_EP_INTERRUPT)
|
||||
@ -917,10 +943,12 @@ static void xhci_initialize_ep(const int id, const uint64_t slot_vaddr, const in
|
||||
ep_ctx.tr_dequeue_ptr = virt_2_phys(xhci_hc[id].ports[port_id].ep_info[ep_num].ep_ring_vbase);
|
||||
xhci_ep_set_dequeue_cycle_state(&ep_ctx, XHCI_TRB_CYCLE_ON);
|
||||
|
||||
xhci_hc[id].ports[port_id].ep_info[ep_num].current_ep_ring_vaddr = xhci_hc[id].ports[port_id].ep_info[ep_num].ep_ring_vbase;
|
||||
xhci_hc[id].ports[port_id].ep_info[ep_num].current_ep_ring_vaddr =
|
||||
xhci_hc[id].ports[port_id].ep_info[ep_num].ep_ring_vbase;
|
||||
xhci_hc[id].ports[port_id].ep_info[ep_num].current_ep_ring_cycle = xhci_ep_get_dequeue_cycle_state(&ep_ctx);
|
||||
// kdebug("ep_ctx.tr_dequeue_ptr = %#018lx", ep_ctx.tr_dequeue_ptr);
|
||||
// kdebug("xhci_hc[id].control_ep_info.current_ep_ring_cycle = %d", xhci_hc[id].control_ep_info.current_ep_ring_cycle);
|
||||
// kdebug("xhci_hc[id].control_ep_info.current_ep_ring_cycle = %d",
|
||||
// xhci_hc[id].control_ep_info.current_ep_ring_cycle);
|
||||
kdebug("max_packet=%d, max_burst=%d", max_packet, max_burst);
|
||||
switch (type)
|
||||
{
|
||||
@ -1032,7 +1060,8 @@ failed:;
|
||||
* @param direction 传输的方向
|
||||
* @return int 产生的TRB数量
|
||||
*/
|
||||
static int xhci_setup_stage(struct xhci_ep_info_t *ep, const struct usb_request_packet_t *packet, const uint8_t direction)
|
||||
static int xhci_setup_stage(struct xhci_ep_info_t *ep, const struct usb_request_packet_t *packet,
|
||||
const uint8_t direction)
|
||||
{
|
||||
// kdebug("ep->current_ep_ring_cycle=%d", ep->current_ep_ring_cycle);
|
||||
struct xhci_TRB_setup_stage_t trb = {0};
|
||||
@ -1066,7 +1095,8 @@ static int xhci_setup_stage(struct xhci_ep_info_t *ep, const struct usb_request_
|
||||
* @param status_vaddr event data TRB的缓冲区(4字节,且地址按照16字节对齐)
|
||||
* @return int 产生的TRB数量
|
||||
*/
|
||||
static int xhci_data_stage(struct xhci_ep_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size, uint8_t direction, const int max_packet, const uint64_t status_vaddr)
|
||||
static int xhci_data_stage(struct xhci_ep_info_t *ep, uint64_t buf_vaddr, uint8_t trb_type, const uint32_t size,
|
||||
uint8_t direction, const int max_packet, const uint64_t status_vaddr)
|
||||
{
|
||||
if (size == 0)
|
||||
return 0;
|
||||
@ -1204,10 +1234,12 @@ static int xhci_wait_for_interrupt(const int id, uint64_t status_vaddr)
|
||||
* @param max_packet 最大数据包大小
|
||||
* @return int 读取到的数据的大小
|
||||
*/
|
||||
static int xhci_control_in(const int id, struct usb_request_packet_t *packet, void *target, const int port_id, const int max_packet)
|
||||
static int xhci_control_in(const int id, struct usb_request_packet_t *packet, void *target, const int port_id,
|
||||
const int max_packet)
|
||||
{
|
||||
|
||||
uint64_t status_buf_vaddr = (uint64_t)kzalloc(16, 0); // 本来是要申请4bytes的buffer的,但是因为xhci控制器需要16bytes对齐,因此申请16bytes
|
||||
uint64_t status_buf_vaddr =
|
||||
(uint64_t)kzalloc(16, 0); // 本来是要申请4bytes的buffer的,但是因为xhci控制器需要16bytes对齐,因此申请16bytes
|
||||
uint64_t data_buf_vaddr = 0;
|
||||
int retval = 0;
|
||||
|
||||
@ -1216,7 +1248,8 @@ static int xhci_control_in(const int id, struct usb_request_packet_t *packet, vo
|
||||
if (packet->length)
|
||||
{
|
||||
data_buf_vaddr = (uint64_t)kzalloc(packet->length, 0);
|
||||
xhci_data_stage(&xhci_hc[id].ports[port_id].ep_info[XHCI_EP_CONTROL], data_buf_vaddr, TRB_TYPE_DATA_STAGE, packet->length, XHCI_DIR_IN_BIT, max_packet, status_buf_vaddr);
|
||||
xhci_data_stage(&xhci_hc[id].ports[port_id].ep_info[XHCI_EP_CONTROL], data_buf_vaddr, TRB_TYPE_DATA_STAGE,
|
||||
packet->length, XHCI_DIR_IN_BIT, max_packet, status_buf_vaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1275,7 +1308,8 @@ done:;
|
||||
* @param max_packet 最大数据包大小
|
||||
* @return int 读取到的数据的大小
|
||||
*/
|
||||
static int xhci_control_out(const int id, struct usb_request_packet_t *packet, void *target, const int port_id, const int max_packet)
|
||||
static int xhci_control_out(const int id, struct usb_request_packet_t *packet, void *target, const int port_id,
|
||||
const int max_packet)
|
||||
{
|
||||
uint64_t status_buf_vaddr = (uint64_t)kzalloc(16, 0);
|
||||
uint64_t data_buf_vaddr = 0;
|
||||
@ -1287,7 +1321,8 @@ static int xhci_control_out(const int id, struct usb_request_packet_t *packet, v
|
||||
if (packet->length)
|
||||
{
|
||||
data_buf_vaddr = (uint64_t)kzalloc(packet->length, 0);
|
||||
xhci_data_stage(&xhci_hc[id].ports[port_id].ep_info[XHCI_EP_CONTROL], data_buf_vaddr, TRB_TYPE_DATA_STAGE, packet->length, XHCI_DIR_OUT_BIT, max_packet, status_buf_vaddr);
|
||||
xhci_data_stage(&xhci_hc[id].ports[port_id].ep_info[XHCI_EP_CONTROL], data_buf_vaddr, TRB_TYPE_DATA_STAGE,
|
||||
packet->length, XHCI_DIR_OUT_BIT, max_packet, status_buf_vaddr);
|
||||
}
|
||||
|
||||
#ifndef __QEMU_EMULATION__
|
||||
@ -1338,7 +1373,8 @@ done:;
|
||||
* @param length 要传输的数据长度
|
||||
* @return int 错误码
|
||||
*/
|
||||
static inline int xhci_get_desc(const int id, const int port_id, void *target, const uint16_t desc_type, const uint8_t desc_index, const uint16_t lang_id, const uint16_t length)
|
||||
static inline int xhci_get_desc(const int id, const int port_id, void *target, const uint16_t desc_type,
|
||||
const uint8_t desc_index, const uint16_t lang_id, const uint16_t length)
|
||||
{
|
||||
struct usb_device_desc *dev_desc = xhci_hc[id].ports[port_id].dev_desc;
|
||||
int count;
|
||||
@ -1347,7 +1383,13 @@ static inline int xhci_get_desc(const int id, const int port_id, void *target, c
|
||||
// 设备端口没有对应的描述符
|
||||
if (unlikely(dev_desc == NULL))
|
||||
return -EINVAL;
|
||||
DECLARE_USB_PACKET(ctrl_in_packet, USB_REQ_TYPE_GET_REQUEST, USB_REQ_GET_DESCRIPTOR, (desc_type << 8) | desc_index, lang_id, length);
|
||||
|
||||
uint8_t req_type = USB_REQ_TYPE_GET_REQUEST;
|
||||
if (desc_type == USB_DT_HID_REPORT)
|
||||
req_type = USB_REQ_TYPE_GET_INTERFACE_REQUEST;
|
||||
|
||||
DECLARE_USB_PACKET(ctrl_in_packet, req_type, USB_REQ_GET_DESCRIPTOR, (desc_type << 8) | desc_index, lang_id,
|
||||
length);
|
||||
count = xhci_control_in(id, &ctrl_in_packet, target, port_id, dev_desc->max_packet_size);
|
||||
if (unlikely(count == 0))
|
||||
return -EAGAIN;
|
||||
@ -1364,9 +1406,9 @@ static inline int xhci_set_configuration(const int id, const int port_id, const
|
||||
if (unlikely(dev_desc == NULL))
|
||||
return -EINVAL;
|
||||
DECLARE_USB_PACKET(ctrl_out_packet, USB_REQ_TYPE_SET_REQUEST, USB_REQ_SET_CONFIGURATION, conf_value & 0xff, 0, 0);
|
||||
kdebug("set conf: to control out");
|
||||
// kdebug("set conf: to control out");
|
||||
count = xhci_control_out(id, &ctrl_out_packet, NULL, port_id, dev_desc->max_packet_size);
|
||||
kdebug("set conf: count=%d", count);
|
||||
// kdebug("set conf: count=%d", count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1387,7 +1429,10 @@ static int xhci_get_config_desc(const int id, const int port_id, struct usb_conf
|
||||
int retval = xhci_get_desc(id, port_id, conf_desc, USB_DT_CONFIG, 0, 0, 9);
|
||||
if (unlikely(retval != 0))
|
||||
return retval;
|
||||
kdebug("port %d got conf ok. type=%d, len=%d, total_len=%d, num_interfaces=%d, max_power=%dmA", port_id, conf_desc->type, conf_desc->len, conf_desc->total_len, conf_desc->num_interfaces, (xhci_get_port_speed(id, port_id) == XHCI_PORT_SPEED_SUPER) ? (conf_desc->max_power * 8) : (conf_desc->max_power * 2));
|
||||
kdebug("port %d got conf ok. type=%d, len=%d, total_len=%d, num_interfaces=%d, max_power=%dmA", port_id,
|
||||
conf_desc->type, conf_desc->len, conf_desc->total_len, conf_desc->num_interfaces,
|
||||
(xhci_get_port_speed(id, port_id) == XHCI_PORT_SPEED_SUPER) ? (conf_desc->max_power * 8)
|
||||
: (conf_desc->max_power * 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1400,7 +1445,8 @@ static int xhci_get_config_desc(const int id, const int port_id, struct usb_conf
|
||||
* @param target 最终结果要拷贝到的地址
|
||||
* @return int 错误码
|
||||
*/
|
||||
static inline int xhci_get_config_desc_full(const int id, const int port_id, const struct usb_config_desc *conf_desc, void *target)
|
||||
static inline int xhci_get_config_desc_full(const int id, const int port_id, const struct usb_config_desc *conf_desc,
|
||||
void *target)
|
||||
{
|
||||
if (unlikely(conf_desc == NULL || target == NULL))
|
||||
return -EINVAL;
|
||||
@ -1420,20 +1466,31 @@ static int xhci_get_interface_desc(const void *in_buf, const uint8_t if_num, str
|
||||
{
|
||||
if (unlikely(if_desc == NULL || in_buf == NULL))
|
||||
return -EINVAL;
|
||||
kdebug("to get interface.");
|
||||
// 判断接口index是否合理
|
||||
if (if_num >= ((struct usb_config_desc *)in_buf)->num_interfaces)
|
||||
return -EINVAL;
|
||||
struct usb_interface_desc *ptr = (struct usb_interface_desc *)(in_buf + sizeof(struct usb_config_desc));
|
||||
for (int i = 0; i < if_num; ++i)
|
||||
uint32_t total_len = ((struct usb_config_desc *)in_buf)->total_len;
|
||||
uint32_t pos = 0;
|
||||
while (pos < total_len)
|
||||
{
|
||||
ptr = (struct usb_interface_desc *)(((uint64_t)ptr) + sizeof(struct usb_interface_desc) + sizeof(struct usb_endpoint_desc) * ptr->num_endpoints);
|
||||
struct usb_interface_desc *ptr = (struct usb_interface_desc *)(in_buf + pos);
|
||||
if (ptr->type != USB_DT_INTERFACE)
|
||||
{
|
||||
pos += ptr->len;
|
||||
continue;
|
||||
}
|
||||
// 返回结果
|
||||
*if_desc = ptr;
|
||||
|
||||
kdebug("get interface desc ok. interface_number=%d, num_endpoints=%d, class=%d, subclass=%d", ptr->interface_number, ptr->num_endpoints, ptr->interface_class, ptr->interface_sub_class);
|
||||
if (ptr->interface_number == if_num) // 找到目标interface desc
|
||||
{
|
||||
kdebug("get interface desc ok. interface_number=%d, num_endpoints=%d, class=%d, subclass=%d",
|
||||
ptr->interface_number, ptr->num_endpoints, ptr->interface_class, ptr->interface_sub_class);
|
||||
*if_desc = ptr;
|
||||
return 0;
|
||||
}
|
||||
pos += ptr->len;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1444,14 +1501,16 @@ static int xhci_get_interface_desc(const void *in_buf, const uint8_t if_num, str
|
||||
* @param ep_desc 返回的指向端点描述符的指针
|
||||
* @return int 错误码
|
||||
*/
|
||||
static inline int xhci_get_endpoint_desc(const struct usb_interface_desc *if_desc, const uint8_t ep_num, struct usb_endpoint_desc **ep_desc)
|
||||
static inline int xhci_get_endpoint_desc(const struct usb_interface_desc *if_desc, const uint8_t ep_num,
|
||||
struct usb_endpoint_desc **ep_desc)
|
||||
{
|
||||
if (unlikely(if_desc == NULL || ep_desc == NULL))
|
||||
return -EINVAL;
|
||||
BUG_ON(ep_num >= if_desc->num_endpoints);
|
||||
|
||||
*ep_desc = (struct usb_endpoint_desc *)((uint64_t)(if_desc + 1) + ep_num * sizeof(struct usb_endpoint_desc));
|
||||
kdebug("get endpoint desc: ep_addr=%d, max_packet=%d, attr=%#06x, interval=%d", (*ep_desc)->endpoint_addr, (*ep_desc)->max_packet, (*ep_desc)->attributes, (*ep_desc)->interval);
|
||||
kdebug("get endpoint desc: ep_addr=%d, max_packet=%d, attr=%#06x, interval=%d", (*ep_desc)->endpoint_addr,
|
||||
(*ep_desc)->max_packet, (*ep_desc)->attributes, (*ep_desc)->interval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1552,11 +1611,11 @@ static int xhci_get_descriptor(const int id, const int port_id, struct usb_devic
|
||||
" product index: %i\n"
|
||||
" serial index: %i\n"
|
||||
" number of configs: %i\n",
|
||||
port_id, dev_desc->len, dev_desc->type, dev_desc->usb_version >> 8, dev_desc->usb_version & 0xFF, dev_desc->_class, dev_desc->subclass,
|
||||
dev_desc->protocol, dev_desc->max_packet_size, dev_desc->vendor_id, dev_desc->product_id,
|
||||
(dev_desc->device_rel & 0xF000) >> 12, (dev_desc->device_rel & 0x0F00) >> 8,
|
||||
(dev_desc->device_rel & 0x00F0) >> 4, (dev_desc->device_rel & 0x000F) >> 0,
|
||||
dev_desc->manufacturer_index, dev_desc->procuct_index, dev_desc->serial_index, dev_desc->config);
|
||||
port_id, dev_desc->len, dev_desc->type, dev_desc->usb_version >> 8, dev_desc->usb_version & 0xFF,
|
||||
dev_desc->_class, dev_desc->subclass, dev_desc->protocol, dev_desc->max_packet_size, dev_desc->vendor_id,
|
||||
dev_desc->product_id, (dev_desc->device_rel & 0xF000) >> 12, (dev_desc->device_rel & 0x0F00) >> 8,
|
||||
(dev_desc->device_rel & 0x00F0) >> 4, (dev_desc->device_rel & 0x000F) >> 0, dev_desc->manufacturer_index,
|
||||
dev_desc->procuct_index, dev_desc->serial_index, dev_desc->config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1605,7 +1664,8 @@ static int xhci_hc_start_ports(int id)
|
||||
// kdebug("initializing usb2: %d", i);
|
||||
// reset该端口
|
||||
// kdebug("to reset port %d, rflags=%#018lx", i, get_rflags());
|
||||
if (likely(xhci_reset_port(id, i) == 0)) // 如果端口reset成功,就获取它的描述符
|
||||
if (likely(xhci_reset_port(id, i) ==
|
||||
0)) // 如果端口reset成功,就获取它的描述符
|
||||
// 否则,reset函数会把它给设置为未激活,并且标志配对的usb2端口是激活的
|
||||
{
|
||||
// kdebug("reset port %d ok", id);
|
||||
@ -1657,7 +1717,8 @@ static int xhci_hid_set_idle(const int id, const int port_id, struct usb_interfa
|
||||
* @param ep_desc 端点描述符
|
||||
* @return int 错误码
|
||||
*/
|
||||
static int xhci_configure_endpoint(const int id, const int port_id, const uint8_t ep_num, const uint8_t ep_type, struct usb_endpoint_desc *ep_desc)
|
||||
static int xhci_configure_endpoint(const int id, const int port_id, const uint8_t ep_num, const uint8_t ep_type,
|
||||
struct usb_endpoint_desc *ep_desc)
|
||||
{
|
||||
|
||||
int retval = 0;
|
||||
@ -1672,7 +1733,7 @@ static int xhci_configure_endpoint(const int id, const int port_id, const uint8_
|
||||
// 创建输入上下文缓冲区
|
||||
uint64_t input_ctx_buffer = (uint64_t)kzalloc(xhci_hc[id].context_size * 33, 0);
|
||||
// 置位对应的add bit
|
||||
__write4b(input_ctx_buffer + 4, (1 << ep_num)|1);
|
||||
__write4b(input_ctx_buffer + 4, (1 << ep_num) | 1);
|
||||
__write4b(input_ctx_buffer + 0x1c, 1);
|
||||
|
||||
// 拷贝slot上下文
|
||||
@ -1736,38 +1797,83 @@ static int xhci_configure_port(const int id, const int port_id)
|
||||
void *full_conf = NULL;
|
||||
struct usb_interface_desc *if_desc = NULL;
|
||||
struct usb_endpoint_desc *ep_desc = NULL;
|
||||
int retval = 0;
|
||||
|
||||
// hint: 暂时只考虑对键盘的初始化
|
||||
// 获取完整的config
|
||||
{
|
||||
struct usb_config_desc conf_desc = {0};
|
||||
xhci_get_config_desc(id, port_id, &conf_desc);
|
||||
retval = xhci_get_config_desc(id, port_id, &conf_desc);
|
||||
if (unlikely(retval != 0))
|
||||
return retval;
|
||||
|
||||
full_conf = kzalloc(conf_desc.total_len, 0);
|
||||
xhci_get_config_desc_full(id, port_id, &conf_desc, full_conf);
|
||||
if (unlikely(full_conf == NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
retval = xhci_get_config_desc_full(id, port_id, &conf_desc, full_conf);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
}
|
||||
|
||||
xhci_get_interface_desc(full_conf, 0, &if_desc);
|
||||
retval = xhci_get_interface_desc(full_conf, 0, &if_desc);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
|
||||
if (if_desc->interface_class == USB_CLASS_HID)
|
||||
{
|
||||
// 由于暂时只支持键盘,因此把键盘的驱动也写在这里
|
||||
// todo: 分离usb键盘驱动
|
||||
|
||||
xhci_get_endpoint_desc(if_desc, 0, &ep_desc);
|
||||
|
||||
retval = xhci_get_endpoint_desc(if_desc, 0, &ep_desc);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
// kdebug("to set conf, val=%#010lx", ((struct usb_config_desc *)full_conf)->value);
|
||||
xhci_set_configuration(id, port_id, ((struct usb_config_desc *)full_conf)->value);
|
||||
retval = xhci_set_configuration(id, port_id, ((struct usb_config_desc *)full_conf)->value);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
// kdebug("set conf ok");
|
||||
|
||||
// todo: configure endpoint
|
||||
xhci_configure_endpoint(id, port_id, ep_desc->endpoint_addr, USB_EP_INTERRUPT, ep_desc);
|
||||
// configure endpoint
|
||||
retval = xhci_configure_endpoint(id, port_id, ep_desc->endpoint_addr, USB_EP_INTERRUPT, ep_desc);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
|
||||
xhci_hid_set_idle(id, port_id, if_desc);
|
||||
retval = xhci_hid_set_idle(id, port_id, if_desc);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
|
||||
// 获取report desc
|
||||
// todo: parse hid report
|
||||
struct usb_hid_desc *hid_desc = NULL;
|
||||
uint32_t hid_desc_len = 0;
|
||||
// 获取hid desc
|
||||
retval = xhci_get_hid_descriptor(id, port_id, full_conf, if_desc->interface_number, &hid_desc);
|
||||
if (unlikely(retval != 0))
|
||||
goto failed;
|
||||
|
||||
// 获取hid report
|
||||
void *hid_report_data = kzalloc(hid_desc->report_desc_len, 0);
|
||||
if (unlikely(hid_report_data == NULL))
|
||||
goto failed;
|
||||
retval =
|
||||
xhci_get_hid_report(id, port_id, if_desc->interface_number, hid_report_data, hid_desc->report_desc_len);
|
||||
if (unlikely(retval != 0))
|
||||
{
|
||||
kfree(hid_report_data);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
kdebug("to parse hid report");
|
||||
// todo: parse hid report
|
||||
hid_parse_report(hid_report_data, hid_desc->report_desc_len);
|
||||
kdebug("parse hid report done");
|
||||
kfree(hid_report_data);
|
||||
}
|
||||
goto out;
|
||||
failed:;
|
||||
kerror("failed at xhci_configure_port, retval=%d", retval);
|
||||
out:;
|
||||
kfree(full_conf);
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
/**
|
||||
* @brief 初始化xhci主机控制器的中断控制
|
||||
@ -1796,7 +1902,8 @@ static int xhci_hc_init_intr(int id)
|
||||
if (unlikely((int64_t)(retval) == -ENOMEM))
|
||||
return -ENOMEM;
|
||||
xhci_hc[id].event_ring_table_vaddr = retval;
|
||||
xhci_hc[id].current_event_ring_vaddr = xhci_hc[id].event_ring_vaddr; // 设置驱动程序要读取的下一个event ring trb的地址
|
||||
xhci_hc[id].current_event_ring_vaddr =
|
||||
xhci_hc[id].event_ring_vaddr; // 设置驱动程序要读取的下一个event ring trb的地址
|
||||
retval = 0;
|
||||
|
||||
xhci_hc[id].current_event_ring_cycle = 1;
|
||||
@ -1809,7 +1916,9 @@ static int xhci_hc_init_intr(int id)
|
||||
io_mfence();
|
||||
xhci_write_intr_reg32(id, 0, XHCI_IR_TABLE_SIZE, 1); // 当前只有1个segment
|
||||
io_mfence();
|
||||
xhci_write_intr_reg64(id, 0, XHCI_IR_DEQUEUE, virt_2_phys(xhci_hc[id].current_event_ring_vaddr) | (1 << 3)); // 写入dequeue寄存器,并清除busy位(写1就会清除)
|
||||
xhci_write_intr_reg64(id, 0, XHCI_IR_DEQUEUE,
|
||||
virt_2_phys(xhci_hc[id].current_event_ring_vaddr) |
|
||||
(1 << 3)); // 写入dequeue寄存器,并清除busy位(写1就会清除)
|
||||
io_mfence();
|
||||
xhci_write_intr_reg64(id, 0, XHCI_IR_TABLE_ADDR, virt_2_phys(xhci_hc[id].event_ring_table_vaddr)); // 写入table地址
|
||||
io_mfence();
|
||||
@ -1894,6 +2003,62 @@ static int xhci_send_command(int id, struct xhci_TRB_t *trb, const bool do_ring)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取接口的hid descriptor
|
||||
*
|
||||
* @param id 主机控制器号
|
||||
* @param port_id 端口号
|
||||
* @param full_conf 完整的cofig缓冲区
|
||||
* @param interface_number 接口号
|
||||
* @param ret_hid_desc 返回的指向hid描述符的指针
|
||||
* @return int 错误码
|
||||
*/
|
||||
static int xhci_get_hid_descriptor(int id, int port_id, const void *full_conf, int interface_number,
|
||||
struct usb_hid_desc **ret_hid_desc)
|
||||
{
|
||||
if (unlikely(ret_hid_desc == NULL || full_conf == NULL))
|
||||
return -EINVAL;
|
||||
kdebug("to get hid_descriptor.");
|
||||
// 判断接口index是否合理
|
||||
if (interface_number >= ((struct usb_config_desc *)full_conf)->num_interfaces)
|
||||
return -EINVAL;
|
||||
uint32_t total_len = ((struct usb_config_desc *)full_conf)->total_len;
|
||||
uint32_t pos = 0;
|
||||
while (pos < total_len)
|
||||
{
|
||||
struct usb_hid_desc *ptr = (struct usb_hid_desc *)(full_conf + pos);
|
||||
if (ptr->type != USB_DT_HID)
|
||||
{
|
||||
pos += ptr->len;
|
||||
continue;
|
||||
}
|
||||
// 找到目标hid描述符
|
||||
*ret_hid_desc = ptr;
|
||||
kdebug("Found hid descriptor for port:%d, if:%d, report_desc_len=%d", port_id, interface_number,
|
||||
ptr->report_desc_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送get_hid_descriptor请求,将hid
|
||||
*
|
||||
* @param id 主机控制器号
|
||||
* @param port_id 端口号
|
||||
* @param interface_number 接口号
|
||||
* @param ret_hid_report hid report要拷贝到的地址
|
||||
* @param hid_report_len hid report的长度
|
||||
* @return int 错误码
|
||||
*/
|
||||
static int xhci_get_hid_report(int id, int port_id, int interface_number, void *ret_hid_report, uint32_t hid_report_len)
|
||||
{
|
||||
int retval = xhci_get_desc(id, port_id, ret_hid_report, USB_DT_HID_REPORT, 0, interface_number, hid_report_len);
|
||||
if (unlikely(retval != 0))
|
||||
kerror("xhci_get_hid_report failed: host_controller:%d, port:%d, interface %d", id, port_id, interface_number);
|
||||
return retval;
|
||||
}
|
||||
/**
|
||||
* @brief 初始化xhci控制器
|
||||
*
|
||||
@ -1909,7 +2074,10 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
|
||||
}
|
||||
|
||||
spin_lock(&xhci_controller_init_lock);
|
||||
kinfo("Initializing xhci host controller: bus=%#02x, device=%#02x, func=%#02x, VendorID=%#04x, irq_line=%d, irq_pin=%d", dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, dev_hdr->header.Vendor_ID, dev_hdr->Interrupt_Line, dev_hdr->Interrupt_PIN);
|
||||
kinfo("Initializing xhci host controller: bus=%#02x, device=%#02x, func=%#02x, VendorID=%#04x, irq_line=%d, "
|
||||
"irq_pin=%d",
|
||||
dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, dev_hdr->header.Vendor_ID,
|
||||
dev_hdr->Interrupt_Line, dev_hdr->Interrupt_PIN);
|
||||
io_mfence();
|
||||
int cid = xhci_hc_find_available_id();
|
||||
if (cid < 0)
|
||||
@ -1930,7 +2098,8 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
|
||||
}
|
||||
io_mfence();
|
||||
// 为当前控制器映射寄存器地址空间
|
||||
xhci_hc[cid].vbase = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + 65536 * xhci_hc[cid].controller_id;
|
||||
xhci_hc[cid].vbase =
|
||||
SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + XHCI_MAPPING_OFFSET + 65536 * xhci_hc[cid].controller_id;
|
||||
// kdebug("dev_hdr->BAR0 & (~0xf)=%#018lx", dev_hdr->BAR0 & (~0xf));
|
||||
mm_map_phys_addr(xhci_hc[cid].vbase, dev_hdr->BAR0 & (~0xf), 65536, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD, true);
|
||||
io_mfence();
|
||||
@ -1975,7 +2144,8 @@ void xhci_init(struct pci_device_structure_general_device_t *dev_hdr)
|
||||
}
|
||||
// if it is a Panther Point device, make sure sockets are xHCI controlled.
|
||||
if (((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0) & 0xffff) == 0x8086) &&
|
||||
(((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0) >> 16) & 0xffff) == 0x1E31) &&
|
||||
(((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 0) >> 16) & 0xffff) ==
|
||||
0x1E31) &&
|
||||
((pci_read_config(dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func, 8) & 0xff) == 4))
|
||||
{
|
||||
kdebug("Is a Panther Point device");
|
||||
@ -2082,6 +2252,7 @@ failed:;
|
||||
memset((void *)&xhci_hc[cid], 0, sizeof(struct xhci_host_controller_t));
|
||||
|
||||
failed_exceed_max:;
|
||||
kerror("Failed to initialize controller: bus=%d, dev=%d, func=%d", dev_hdr->header.bus, dev_hdr->header.device, dev_hdr->header.func);
|
||||
kerror("Failed to initialize controller: bus=%d, dev=%d, func=%d", dev_hdr->header.bus, dev_hdr->header.device,
|
||||
dev_hdr->header.func);
|
||||
spin_unlock(&xhci_controller_init_lock);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user