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;
const char *speed;
int devnum = udev->devnum;
const char *driver_name;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
*/
if (!hdev->parent) {
delay = HUB_ROOT_RESET_TIME;
if (port1 == hdev->bus->otg_port)
hdev->bus->b_hnp_enable = 0;
}
/* Some low speed devices have problems with the quick delay, so */
/* be a bit pessimistic with those devices. RHbug #23670 */
if (oldspeed == USB_SPEED_LOW) //根据速度设置重启延时时间
delay = HUB_LONG_RESET_TIME;
mutex_lock(hcd->address0_mutex);
/* Reset the device; full speed may morph to high speed */
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
retval = hub_port_reset(hub, port1, udev, delay, false); //重启设备
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
retval = -ENODEV;
/* Don't allow speed changes at reset, except usb 3.0 to faster */
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed && //重启前后速度不能改变,若改变,则出错了
!(oldspeed == USB_SPEED_SUPER && udev->speed > oldspeed)) {
dev_dbg(&udev->dev, "device reset changed speed!\n");
goto fail;
}
oldspeed = udev->speed;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) { //根据速度预置0号端点package的最大字节数,后期读取到设备描述符后会修正
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 */
/* to determine the ep0 maxpacket size, try to read
* the device descriptor to get bMaxPacketSize0 and
* then correct our initial guess.
*/
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;
default:
goto fail;
}
if (udev->speed == USB_SPEED_WIRELESS)
speed = "variable speed Wireless";
else
speed = usb_speed_string(udev->speed);
/*
* The controller driver may be NULL if the controller device
* is the middle device between platform device and roothub.
* This middle device may not need a device driver due to
* all hardware control can be at platform device driver, this
* platform device is usually a dual-role USB controller device.
*/
if (udev->bus->controller->driver)
driver_name = udev->bus->controller->driver->name;
else
driver_name = udev->bus->sysdev->driver->name;
if (udev->speed < USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s USB device number %d using %s\n",
(udev->config) ? "reset" : "new", speed,
devnum, driver_name);
/* Set up TT records, if needed */
if (hdev->tt) { //如果需要tt转换电路,则设置,一般只有高速hub才有
udev->tt = hdev->tt;
udev->ttport = hdev->ttport;
} else if (udev->speed != USB_SPEED_HIGH
&& hdev->speed == USB_SPEED_HIGH) {
if (!hub->tt.hub) {
dev_err(&udev->dev, "parent hub has no TT\n");
retval = -EINVAL;
goto fail;
}
udev->tt = &hub->tt;
udev->ttport = port1;
}
/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
* Because device hardware and firmware is sometimes buggy in
* this area, and this is how Linux has done it for ages.
* Change it cautiously.
*
* NOTE: If use_new_scheme() is true we will start by issuing
* a 64-byte GET_DESCRIPTOR request. This is what Windows does,
* so it may help with some non-standards-compliant devices.
* Otherwise we start with SET_ADDRESS and then try to read the
* first 8 bytes of the device descriptor to get the ep0 maxpacket
* value.
*/
//读取设备描述符,两种方式选一个,一种是windows的,new_scheme,一种是linux里面的
for (retries = 0; retries < GET_DESCRIPTOR_TRIES; (++retries, msleep(100))) {
bool did_new_scheme = false;
/**********************************************************************
windows中的new_scheme方式读取,总体思路:
for循环,尝试三次,每次读取64字节任意一次读取成功,r = 0,退出for循环,并修改ep0 的 max size。
读取成功的标志是:类型为设备描述符、bMaxPacketSize0在USB协议范围内。
*****************************************************************/
if (use_new_scheme(udev, retry_counter)) {
struct usb_device_descriptor *buf;
int r = 0;
did_new_scheme = true;
retval = hub_enable_device(udev); //使能设备
if (retval < 0) {
dev_err(&udev->dev,
"hub failed to enable device, error %d\n",
retval);
goto fail;
}
#define GET_DESCRIPTOR_BUFSIZE 64
buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
if (!buf) {
retval = -ENOMEM;
continue;
}
/* Retry on all errors; some devices are flakey.
* 255 is for WUSB devices, we actually need to use
* 512 (WUSB1.0[4.8.1]).
*/
for (operations = 0; operations < 3; ++operations) { //预或设备描述符,并检查其合法性,尝试三次获取,其中一次成功后
buf->bMaxPacketSize0 = 0;
printk(KERN_EMERG"pompey hub: %s get desc in new %d\n", _func__,__LINE__); //r = 0,则退出for,如果压根儿就没有获取到描述符,则 r = -EPROTO;
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); //获取设备描述符
switch (buf->bMaxPacketSize0) { // 查看描述符的合法性
case 8: case 16: case 32: case 64: case 255: //读取到设备描述符bMaxPacketSize0 在协议范围内
if (buf->bDescriptorType ==
USB_DT_DEVICE) { //描述符类型检查,必须为设备描述符
r = 0; //退出for循环的条件
break;
}
/* FALL THROUGH */
default: //压根儿就没有读到设备描述符的情况
if (r == 0)
r = -EPROTO;
break;
}
/*
* Some devices time out if they are powered on
* when already connected. They need a second
* reset. But only on the first attempt,
* lest we get into a time out/reset loop
*/
if (r == 0 || (r == -ETIMEDOUT &&
retries == 0 &&
udev->speed > USB_SPEED_FULL)) //结束该层for循环的两个条件 1. r = 0; 2.外层for也是第一次,且读取超时,且不是低速/全速设备。
break;
}
udev->descriptor.bMaxPacketSize0 = //修正端点0的最大包size,但是这里如果设备描述没有获取成功怎么办?
buf->bMaxPacketSize0;
kfree(buf);
retval = hub_port_reset(hub, port1, udev, delay, false);
if (retval < 0) /* error or disconnect */
goto fail;
if (oldspeed != udev->speed) {
dev_dbg(&udev->dev,
"device reset changed speed!\n");
retval = -ENODEV;
goto fail;
}
if (r) {
if (r != -ENODEV)
dev_err(&udev->dev, "device descriptor read/64, error %d\n",
r);
retval = -EMSGSIZE;
continue;
}
#undef GET_DESCRIPTOR_BUFSIZE
}
//结束windows new_sheme 获取设备描述符,即新方法获取设备描述符
/*
* If device is WUSB, we already assigned an
* unauthorized address in the Connect Ack sequence;
* authorization will assign the final address.
*/
if (udev->wusb == 0) { //如果不是非无线USB设备
for (operations = 0; operations < SET_ADDRESS_TRIES; ++operations) {
retval = hub_set_address(udev, devnum); //设置地址
if (retval >= 0)
break;
msleep(200);
}
if (retval < 0) {
if (retval != -ENODEV)
dev_err(&udev->dev, "device not accepting address %d, error %d\n",
devnum, retval);
goto fail;
}
if (udev->speed >= USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
"%s SuperSpeed%s USB device number %d using %s\n",
(udev->config) ? "reset" : "new",
(udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "",
devnum, driver_name);
}
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
/* use_new_scheme() checks the speed which may have
* changed since the initial look so we cache the result
* in did_new_scheme
*/
if (did_new_scheme) //即如果使用的是新方法获取,则彻底结束外层for循环,不然就用linux方法获取到描述符
break;
}
retval = usb_get_device_descriptor(udev, 8); //获取描述符前8个字节
if (retval < 8) {
if (retval != -ENODEV)
dev_err(&udev->dev,
"device descriptor read/8, error %d\n",
retval);
if (retval >= 0)
retval = -EMSGSIZE;
} else {
retval = 0; //获取到后退出最外层for循环,
break;
}
} //end for (retries = 0; retries < GET_DESCRIPTOR_TRIES;...
if (retval)
goto fail;
/*
* Some superspeed devices have finished the link training process
* and attached to a superspeed hub port, but the device descriptor
* got from those devices show they aren't superspeed devices. Warm
* reset the port attached by the devices can fix them.
*/
if ((udev->speed >= USB_SPEED_SUPER) && // 设备描述符合法性校验
(le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
dev_err(&udev->dev, "got a wrong device descriptor, "
"warm reset device\n");
hub_port_reset(hub, port1, udev,
HUB_BH_RESET_TIME, true);
retval = -EINVAL;
goto fail;
}
if (udev->descriptor.bMaxPacketSize0 == 0xff || //再次修正ep0 max size
udev->speed >= USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
if (udev->speed == USB_SPEED_LOW ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
retval = -EMSGSIZE;
goto fail;
}
if (udev->speed == USB_SPEED_FULL)
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
else
dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
usb_ep0_reinit(udev);
}
retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE); //获取全部的设备描述符
if (retval < (signed)sizeof(udev->descriptor)) {
if (retval != -ENODEV)
dev_err(&udev->dev, "device descriptor read/all, error %d\n",
retval);
if (retval >= 0)
retval = -ENOMSG;
goto fail;
}
usb_detect_quirks(udev);
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { //对于 USB3.0 获取设备的BOS描述符
retval = usb_get_bos_descriptor(udev);
if (!retval) {
udev->lpm_capable = usb_device_supports_lpm(udev);
usb_set_lpm_parameters(udev);
}
}
retval = 0;
/* notify HCD that we have a device connected and addressed */
if (hcd->driver->update_device)
hcd->driver->update_device(hcd, udev);
hub_set_initial_usb2_lpm_policy(udev);
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
update_devnum(udev, devnum); /* for disconnect processing */
}
mutex_unlock(hcd->address0_mutex);
return retval;
}
整体来说,就是对设备描述符进行读取并校验,先用windows或者linux方法读取一次,其目的是获取ep0 的 max size,然后再读取全部设备描述符,如果是USB3.0以上,还有BOS描述符;对于BOS描述符是什么,还不是特别了解,USB3.0协议还没看。后续看了3.0的协议,再来补充。