参考文章:Linux那些事儿之我是Hub(20)八大重量级函数闪亮登场(四)-CSDN博客
资料:https://pan.baidu.com/s/1AZlZsqF_-VGREzLaQPdY9Q 提取码:15ky
static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
.bInterfaceClass = USB_CLASS_HUB},
{ } /* Terminating entry */
};
static struct usb_driver hub_driver = {
.name = "hub",
.probe = hub_probe,
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};
前篇分析usb主控制器驱动的时候谈过,注册完root_hub的时候,由于满足这里的struct usb_device_id要求 ,所以会调用这里的hub_probe函数:
int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_host_interface *desc;
struct usb_device *hdev;
struct usb_hub *hub;
hdev = interface_to_usbdev(intf); //hdev设备对应的就是上面注册的root_hub设备
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
hub->hdev = hdev;
INIT_WORK(&hub->events, hub_event);
if (hdev->speed == USB_SPEED_HIGH) //表示当是高速hub时,highspeed_hubs加1
highspeed_hubs++;
hub_configure(hub, &desc->endpoint[0].desc)
}
hub_configure函数:
int hub_configure(struct usb_hub *hub,struct usb_endpoint_descriptor *endpoint)
{
struct usb_hcd *hcd;
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
get_hub_descriptor(hdev, hub->descriptor);
hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL);
for (i = 0; i < maxchild; i++) {
usb_hub_create_port_device(hub, i + 1);
}
}
hub_configure函数会根据hub的端口数创建端口设备。
usb_hub_create_port_device函数:
int usb_hub_create_port_device(struct usb_hub *hub, int port1)
{
struct usb_port *port_dev;
struct usb_device *hdev = hub->hdev;
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
hub->ports[port1 - 1] = port_dev;
port_dev->portnum = port1;
dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),port1);
device_register(&port_dev->dev);
}
usb_hub_create_port_device函数具体负责创建注册第几个端口设备,并赋值给hub端口数组。
hub_event服务程序:
void hub_event(struct work_struct *work)
{
port_event(hub, i);
}
port_event函数:
void port_event(struct usb_hub *hub, int port1)
{
hub_port_connect_change(hub, port1, portstatus, portchange);
}
hub_port_connect_change函数:
void hub_port_connect_change(struct usb_hub *hub, int port1,u16 portstatus, u16 portchange)
{
hub_port_connect(hub, port1, portstatus, portchange);
}
hub_port_connect函数:
void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,u16 portchange)
{
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
struct usb_port *port_dev = hub->ports[port1 - 1];
struct usb_device *udev = port_dev->child; //NULL
//SET_CONFIG_TRIES值是4
//尝试4次,成功一次就退出
for (i = 0; i < SET_CONFIG_TRIES; i++) {
udev = usb_alloc_dev(hdev, hdev->bus, port1);
choose_devnum(udev);
status = hub_port_init(hub, udev, port1, i);
port_dev->child = udev; //NOT NULL
usb_new_device(udev);
return;
}
}
当发觉hub端口有插入变化时,hub_port_connect函数会先分配一个usb设备,并进行初始化,然后把刚才分配的usb设备给注册了。usb_new_device函数注册usb设备之前会从设备描述符里面获取pid、vid等信息,所以需要在usb_new_device函数前先获取设备描述符,该操作在hub_port_init函数里完成的。
hub_port_init函数:
static int hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,int retry_counter)
{
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
int retries, operations, retval, i;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed; //记录设备在没有reset之前的速度
const char *speed;
int devnum = udev->devnum;
const char *driver_name;
//root hub
if (!hdev->parent) {
delay = HUB_ROOT_RESET_TIME;
}
if (oldspeed == USB_SPEED_LOW)
delay = HUB_LONG_RESET_TIME;
retval = hub_port_reset(hub, port1, udev, delay, false);
oldspeed = udev->speed;
//hub_port_reset函数设置udev->speed值,usb2.0 spec规定了不同速度的usb设备对应的不同大小
switch (udev->speed) {
case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER:
case USB_SPEED_WIRELESS: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(64);
break;
case USB_SPEED_LOW: /* fixed at 8 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(8);
break;
}
if (udev->speed == USB_SPEED_WIRELESS)
speed = "variable speed Wireless";
else
speed = usb_speed_string(udev->speed);
//如果出错,多给几次机会
for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
bool did_new_scheme = false;
//判断用的是新策略还是老策略 scheme:计划,策划
if (use_new_scheme(udev, retry_counter)) {
struct usb_device_descriptor *buf;
int r = 0;
did_new_scheme = true;
retval = hub_enable_device(udev);
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
//获取设备描述符成功概率比较低,所以循环获取三次
for (operations = 0; operations < 3; ++operations) {
buf->bMaxPacketSize0 = 0;
//发送获取设备描述符命令,只获取前64字节数据
r = usb_control_msg(udev, usb_rcvaddr0pipe(),USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,USB_DT_DEVICE << 8, 0, buf,
GET_DESCRIPTOR_BUFSIZE,initial_descriptor_timeout);
// 判断获取到的前64字节里的buf->bMaxPackSize0值,该值的合理值只有
// 8/16/32/64/512,这里255实际上是WUSB协议规定的,毕竟只有8位,最大就是255了
switch (buf->bMaxPacketSize0) {
case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==USB_DT_DEVICE) {
r = 0;
break;
}
//包括未响应设备,向设备获取设备描述符,设备不回应,buf->bMaxPackSize0=0
default:
if (r == 0)
r = -EPROTO;
break;
}
if (r == 0 || (r == -ETIMEDOUT && retries == 0 && udev->speed
> USB_SPEED_FULL))
break;
}
//用udev->descriptor.bMaxPacketSize0来记录这个临时获得的值
udev->descriptor.bMaxPacketSize0 =buf->bMaxPacketSize0;
kfree(buf);
retval = hub_port_reset(hub, port1, udev, delay, false);
if (oldspeed != udev->speed) {
dev_dbg(&udev->dev,"[DEBUG][USB] device reset changed speed!\n");
retval = -ENODEV;
goto fail;
}
#undef GET_DESCRIPTOR_BUFSIZE
}
if (udev->wusb == 0) { //wusb:wireless usb
for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
//设置usb地址
retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
msleep(200);
}
// 如果是用新策略,did_new_scheme等于true,跳出循环,不执行后面的
if (did_new_scheme)
break;
}
//旧策略先设置地址,后在这里获取描述符
retval = usb_get_device_descriptor(udev, 8);
if (retval < 8) {} else {
retval = 0;
break;
}
}
usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
if (hcd->driver->update_device)
hcd->driver->update_device(hcd, udev);
}
a、hub_port_init函数先是对usb设备进行复位,然后根据udev->speed值设置usb设备的包的最大字节大小,再然后是分配地址,获取设备描述符。
b、hub_port_init函数里面delay不同取值也是有相应意义的,默认HUB_SHORT_RESET_TIME,表示复位信号的最短时间,如果该hub是root hub,那么root hub要求时间的最短时间是HUB_ROOT_RESET_TIME。如果是低速设备的话,需要一个较长的延迟时间,否则可能会出错,所有要取HUB_LONG_RESET_TIME。参考usb2.0 spec手册 7.1.7.5章节复位信号。
c、USB_NEW_SCHEME(retry_counter),retry_counter就是hub_port_init()传递进来的最后一个参数,而我们给它的实参正是那个从0到SET_CONFIG_TRIES-1的那个i.假设我们什么也没有设置,都是使用默认值,那么use_both_schemes默认值为1,而old_scheme_first默认值为0,于是SET_CONFIG_TRIES为4,即i将从0变到3,而USB_NEW_SCHEME(i)将在i为0和1的时候为1,在i为2和3的时候为0.再加上i每取一次值,在hub_port_init函数里面都会循环两次,所以也就是说,先进行四次新的策略,如果不行就再进行四次旧的策略.所有这一切只有一个目的,就是为了获得设备的描述符。
d、由于 hub_port_reset函数比较长,又是重点,放到后面,可以先看下其它的一些函数。
use_new_scheme函数:
bool use_new_scheme(struct usb_device *udev, int retry)
{
if (udev->speed >= USB_SPEED_SUPER)
return false;
return USE_NEW_SCHEME(retry);
}
// old_scheme_first: bool类型的变量
#define USE_NEW_SCHEME(i) ((i) / 2 == (int)old_scheme_first)
hub_enable_device函数:
static int hub_enable_device(struct usb_device *udev)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (!hcd->driver->enable_device)
return 0;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
return hcd->driver->enable_device(hcd, udev);
}
分析函数:usb_control_msg(udev, usb_rcvaddr0pipe(),USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,USB_DT_DEVICE << 8, 0, buf,
GET_DESCRIPTOR_BUFSIZE,initial_descriptor_timeout);
这个函数的参数说明请往下看,传的参数如下:
//USB_DIR_IN对应的请求类型是获取描述符
#define USB_DIR_IN 0x80
#define GET_DESCRIPTOR_BUFSIZE 64
#define USB_DT_DEVICE 0x01
Get Descriptor请求(获取描述符,具体哪种,还得看wvalue,wvalue是16bit的数据,高字节表示描述符类型,低字节表示描述符索引,具体参考usb spec2.0手册):
GET_DESCTIPTOR的值:
描述符类型如下:
wvalue= USB_DT_DEVICE << 8,USB_DT_DEVICE << 8等于0x0100,高字节等于1,所以获取的是设备描述符。
usb所有的标准请求命令:
hub_set_address函数:
static int hub_set_address(struct usb_device *udev, int devnum)
{
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
}
该函数设置usb地址 。
现在回来重点讲hub_port_reset函数:
static int hub_port_reset(struct usb_hub *hub, int port1,struct usb_device *udev,
unsigned int delay, bool warm)
{
int i, status;
u16 portchange, portstatus;
struct usb_port *port_dev = hub->ports[port1 - 1];
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
//#define USB_PORT_FEAT_RESET 4
//USB_PORT_FEAT_RESET 对应的功能是复位,参考下面的表11-17
status = set_port_feature(hub->hdev, port1, (warm ? USB_PORT_FEAT_BH_PORT_RESET
:USB_PORT_FEAT_RESET));
status = hub_port_wait_reset(hub, port1, udev, delay,warm);
if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
usb_clear_port_feature(hub->hdev, port1,USB_PORT_FEAT_C_RESET);
if (!hub_is_superspeed(hub->hdev))
goto done;
}
}
done:
if (status == 0) {
msleep(10 + 40);
if (udev) {
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (hcd->driver->reset_device)
hcd->driver->reset_device(hcd, udev);
usb_set_device_state(udev, USB_STATE_DEFAULT);
}
}
return status;
}
hub_port_reset函数先是通过set_port_feature函数发出复位命令,进行复位,再通过 hub_port_wait_reset函数实时查询复位是否已完成。如果完成,通过usb_clear_port_feature函数发出清除复位命令。
//发出复位命令
int set_port_feature(struct usb_device *hdev, int port1, int feature)
{
//USB_RT_PORT对应的请求类型是Set Feature
return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),USB_REQ_SET_FEATURE,
USB_RT_PORT, feature, port1, NULL, 0, 1000);
}
//USB_RT_PORT的值是:0010,0011
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
#define USB_TYPE_CLASS (0x01 << 5)
#define USB_RECIP_OTHER 0x03
Set Feature请求(参考usb2.0 spec手册):
Feature Selector(功能选择) 参考表11-17:
usb_control_msg函数说明:
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)
@dev: pointer to the usb device to send the message to
@pipe: endpoint "pipe" to send the message to
@request: USB message request value
@requesttype: USB message request type value
@value: USB message value
@index: USB message index value
@data: pointer to the data to send
@size: length in bytes of the data to send
@timeout: time in msecs to wait for the message to complete before timing out (if 0 the
wait is forever)
Return: If successful, the number of bytes transferred. Otherwise, a negative error number.
static int hub_port_wait_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm)
{
int delay_time, ret;
u16 portstatus;
u16 portchange;
u32 ext_portstatus = 0;
for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT; delay_time += delay) {
msleep(delay);
ret = hub_port_status(hub, port1, &portstatus,&portchange);
//复位完成,跳出循环
if (!(portstatus & USB_PORT_STAT_RESET) &&(portstatus & USB_PORT_STAT_CONNECTION))
break;
if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
delay = HUB_LONG_RESET_TIME;
}
if ((portstatus & USB_PORT_STAT_RESET))
return -EBUSY;
if (!(portstatus & USB_PORT_STAT_ENABLE))
return -EBUSY;
if (!udev)
return 0;
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_WIRELESS;
else if (hub_is_superspeedplus(hub->hdev) &&
port_speed_is_ssp(hub->hdev, ext_portstatus &
USB_EXT_PORT_STAT_RX_SPEED_ID))
udev->speed = USB_SPEED_SUPER_PLUS;
else if (hub_is_superspeed(hub->hdev))
udev->speed = USB_SPEED_SUPER;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
udev->speed = USB_SPEED_LOW;
else
udev->speed = USB_SPEED_FULL;
return 0;
}
hub_port_wait_reset函数通过for循环每隔delay毫秒查询一次reset状态。reset状态是通过hub_port_status函数获取的,该函数还能区分是高速、全速还是低速设备。
hub_port_status函数:
static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change)
{
return hub_ext_port_status(hub, port1, HUB_PORT_STATUS,status, change, NULL);
}
hub_ext_port_status函数:
static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
u16 *status, u16 *change, u32 *ext_status)
{
int ret;
int len = 4;
if (type != HUB_PORT_STATUS)
len = 8;
ret = get_port_status(hub->hdev, port1, &hub->status->port, type, len);
*status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange);
if (type != HUB_PORT_STATUS && ext_status)
*ext_status = le32_to_cpu(hub->status->port.dwExtPortStatus);
}
struct usb_hub结构:
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
struct urb *urb; /* for interrupt polling pipe */
u8 (*buffer)[8];
union {
struct usb_hub_status hub;
struct usb_port_status port;
}*status; /* buffer for status reports */
}
struct usb_port_status结构:
struct usb_port_status {
__le16 wPortStatus;
__le16 wPortChange;
__le32 dwExtPortStatus;
} __attribute__ ((packed));
get_port_status函数:
static int get_port_status(struct usb_device *hdev, int port1,
void *data, u16 value, u16 length)
{
int i, status = -ETIMEDOUT;
for (i = 0; i < USB_STS_RETRIES &&
(status == -ETIMEDOUT || status == -EPIPE); i++) {
status = usb_control_msg(hdev, usb_rcvctrlpipe(hdev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, value,
port1, data, length, USB_STS_TIMEOUT);
}
return status;
}
#define USB_DIR_IN 0x80 /* to host */
/*由上面知USB_RT_PORT: 0010,0011 */
#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER)
Get Port Status请求(参考usb2.0 spec手册):
该命令请求不但能获取reset状态,还能获取是高速、全速还是低速设备。