static
int
hub_port_init (struct usb_hub
*hub,
struct usb_device *udev,
int port1,
int retry_counter)
{
static DEFINE_MUTEX(usb_address0_mutex);
//取得集线器的usb设备结构
struct usb_device *hdev
= hub->hdev;
int i, j, retval;
unsigned delay
= HUB_SHORT_RESET_TIME;
//获取设备的速度模式
enum usb_device_speed oldspeed
= udev->speed;
char *speed,
*type;
//获取设备的设备号
int devnum
= udev->devnum;
/* 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(&usb_address0_mutex);
/* Reset the device; full speed may morph to high speed */
//重置设备
retval = hub_port_reset(hub, port1, udev, delay);
if (retval
< 0) /* error or disconnect */
goto fail;
/* success, speed is known */
retval = -ENODEV;
//检测设备的速度模式是否改变
if (oldspeed
!= USB_SPEED_UNKNOWN
&& oldspeed
!= udev->speed)
{
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].
*/
//检测设备的速度模式,为端点0分配不同的包大小
switch (udev->speed)
{
case USB_SPEED_VARIABLE: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize
= __constant_cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize
= __constant_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
= __constant_cpu_to_le16(64);
break;
case USB_SPEED_LOW: /* fixed at 8 */
udev->ep0.desc.wMaxPacketSize
= __constant_cpu_to_le16(8);
break;
default:
goto fail;
}
type = "";
switch (udev->speed)
{
case USB_SPEED_LOW: speed
= "low"; break;
case USB_SPEED_FULL: speed
= "full"; break;
case USB_SPEED_HIGH: speed
= "high"; break;
case USB_SPEED_VARIABLE:
speed =
"variable";
type =
"Wireless ";
break;
default: speed
= "?"; break;
}
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config)
? "reset"
: "new", speed, type,
udev->bus->controller->driver->name,
devnum);
/* Set up TT records, if needed */
//检测集线器是否有高低速转换电路
if (hdev->tt)
{
udev->tt
= hdev->tt;
udev->ttport
= hdev->ttport;
}
else if
(udev->speed
!= USB_SPEED_HIGH
&& hdev->speed
== USB_SPEED_HIGH)
{
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.
*/
//尝试读取设备描述符到2次
for (i
= 0; i < GET_DESCRIPTOR_TRIES;
(++i, msleep(100)))
{
//是否使用新方案
//微软的方案,一次读取64字节
if (USE_NEW_SCHEME(retry_counter))
{
struct usb_device_descriptor
*buf;
int r
= 0;
#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 (j
= 0; j
< 3; ++j)
{
buf->bMaxPacketSize0
= 0;
r = usb_control_msg(udev, usb_rcvaddr0pipe(),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, GET_DESCRIPTOR_BUFSIZE,
USB_CTRL_GET_TIMEOUT);
switch
(buf->bMaxPacketSize0)
{
case 8:
case 16:
case 32: case 64:
case 255:
if
(buf->bDescriptorType
==USB_DT_DEVICE)
{
r = 0;
break;
}
/* FALL THROUGH */
default:
if
(r == 0)
r =
-EPROTO;
break;
}
if
(r == 0)
break;
}
udev->descriptor.bMaxPacketSize0
= buf->bMaxPacketSize0;
kfree(buf);
retval = hub_port_reset(hub, port1, udev, delay);
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)
{
dev_err(&udev->dev,
"device descriptor "
"read/%s, error %d\n","64", r);
retval =
-EMSGSIZE;
continue;
}
#undef GET_DESCRIPTOR_BUFSIZE
}
/*
* If device is WUSB, we already assigned an
* unauthorized address in the Connect Ack sequence;
* authorization will assign the final address.
*/
//检测设备是否不为wusb设备
if (udev->wusb
== 0)
{
//重试设置地址到2次
for (j
= 0; j
< SET_ADDRESS_TRIES;
++j)
{
retval = hub_set_address(udev, devnum);
if
(retval >= 0)
break;
msleep(200);
}
if (retval
< 0)
{
dev_err(&udev->dev,"device not accepting
address %d, error %d\n",devnum, retval);
goto fail;
}
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
if (USE_NEW_SCHEME(retry_counter))
break;
}
//获取设备描述符
retval = usb_get_device_descriptor(udev, 8);
if (retval
< 8)
{
dev_err(&udev->dev,
"device descriptor "
"read/%s, error %d\n","8", retval);
if (retval
>= 0)
retval =
-EMSGSIZE;
}
else
{
retval = 0;
break;
}
}
if (retval)
goto fail;
i = udev->descriptor.bMaxPacketSize0
== 0xff? /* wusb device? */
512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize)
!= i)
{
if (udev->speed
!= USB_SPEED_FULL
||
!(i == 8
|| i
== 16 || i
== 32
|| i == 64))
{
dev_err(&udev->dev,
"ep0 maxpacket = %d\n", i);
retval =
-EMSGSIZE;
goto fail;
}
dev_dbg(&udev->dev,
"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))
{
dev_err(&udev->dev,
"device descriptor read/%s, error %d\n","all", retval);
if (retval
>= 0)
retval =
-ENOMSG;
goto fail;
}
retval = 0;
fail:
if (retval)
{
hub_port_disable(hub, port1, 0);
update_address(udev, devnum); /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
}
|