接下来我们来到了第四个函数,hub_port_init().这个函数和接下来要遇到的usb_new_device()是最重要的两个函数,也是相对复杂的函数.
2096 /* Reset device, (re)assign address, get device descriptor.
2097 * Device connection must be stable, no more debouncing needed.
2098 * Returns device in USB_STATE_ADDRESS, except on error.
2099 *
2100 * If this is called for an already-existing device (as part of
2101 * usb_reset_device), the caller must own the device lock. For a
2102 * newly detected device that is not accessible through any global
2103 * pointers, it's not necessary to lock the device.
2104 */
2105 static int
2106 hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
2107 int retry_counter)
2108 {
2109 static DEFINE_MUTEX(usb_address0_mutex);
2110
2111 struct usb_device *hdev = hub->hdev;
2112 int i, j, retval;
2113 unsigned delay = HUB_SHORT_RESET_TIME;
2114 enum usb_device_speed oldspeed = udev->speed;
2115 char *speed, *type;
2116
2117 /* root hub ports have a slightly longer reset period
2118 * (from USB 2.0 spec, section 7.1.7.5)
2119 */
2120 if (!hdev->parent) {
2121 delay = HUB_ROOT_RESET_TIME;
2122 if (port1 == hdev->bus->otg_port)
2123 hdev->bus->b_hnp_enable = 0;
2124 }
2125
2126 /* Some low speed devices have problems with the quick delay, so */
2127 /* be a bit pessimistic with those devices. RHbug #23670 */
2128 if (oldspeed == USB_SPEED_LOW)
2129 delay = HUB_LONG_RESET_TIME;
2130
2131 mutex_lock(&usb_address0_mutex);
2132
2133 /* Reset the device; full speed may morph to high speed */
2134 retval = hub_port_reset(hub, port1, udev, delay);
2135 if (retval < 0) /* error or disconnect */
2136 goto fail;
2138 retval = -ENODEV;
2139
2140 if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
2141 dev_dbg(&udev->dev, "device reset changed speed!/n");
2142 goto fail;
2143 }
2144 oldspeed = udev->speed;
2145
2146 /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
2147 * it's fixed size except for full speed devices.
2148 * For Wireless USB devices, ep0 max packet is always 512 (tho
2149 * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
2150 */
2151 switch (udev->speed) {
2152 case USB_SPEED_VARIABLE: /* fixed at 512 */
2153 udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
2154 break;
2155 case USB_SPEED_HIGH: /* fixed at 64 */
2156 udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
2157 break;
2158 case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
2159 /* to determine the ep0 maxpacket size, try to read
2160 * the device descriptor to get bMaxPacketSize0 and
2161 * then correct our initial guess.
2162 */
2163 udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
2164 break;
2165 case USB_SPEED_LOW: /* fixed at 8 */
2166 udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(8);
2167 break;
2168 default:
2169 goto fail;
2170 }
2171
2172 type = "";
2173 switch (udev->speed) {
2174 case USB_SPEED_LOW: speed = "low"; break;
2175 case USB_SPEED_FULL: speed = "full"; break;
2176 case USB_SPEED_HIGH: speed = "high"; break;
2177 case USB_SPEED_VARIABLE:
2178 speed = "variable";
2179 type = "Wireless ";
2180 break;
2181 default: speed = "?"; break;
2182 }
2183 dev_info (&udev->dev,
2184 "%s %s speed %sUSB device using %s and address %d/n",
2185 (udev->config) ? "reset" : "new", speed, type,
2186 udev->bus->controller->driver->name, udev->devnum);
2187
2188 /* Set up TT records, if needed */
2189 if (hdev->tt) {
2190 udev->tt = hdev->tt;
2191 udev->ttport = hdev->ttport;
2192 } else if (udev->speed != USB_SPEED_HIGH
2193 && hdev->speed == USB_SPEED_HIGH) {
2194 udev->tt = &hub->tt;
2195 udev->ttport = port1;
2196 }
2197
2198 /* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?
2199 * Because device hardware and firmware is sometimes buggy in
2200 * this area, and this is how Linux has done it for ages.
2201 * Change it cautiously.
2202 *
2203 * NOTE: If USE_NEW_SCHEME() is true we will start by issuing
2204 * a 64-byte GET_DESCRIPTOR request. This is what Windows does,
2205 * so it may help with some non-standards-compliant devices.
2206 * Otherwise we start with SET_ADDRESS and then try to read the
2207 * first 8 bytes of the device descriptor to get the ep0 maxpacket
2208 * value.
2209 */
2210 for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
2211 if (USE_NEW_SCHEME(retry_counter)) {
2212 struct usb_device_descriptor *buf;
2213 int r = 0;
2214
2215 #define GET_DESCRIPTOR_BUFSIZE 64
2216 buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);
2217 if (!buf) {
2218 retval = -ENOMEM;
2219 continue;
2220 }
2221
2222 /* Retry on all errors; some devices are flakey.
2223 * 255 is for WUSB devices, we actually need to use
2224 * 512 (WUSB1.0[4.8.1]).
2225 */
2226 for (j = 0; j < 3; ++j) {
2227 buf->bMaxPacketSize0 = 0;
2228 r = usb_control_msg(udev, usb_rcvaddr0pipe(),
2229 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
2230 USB_DT_DEVICE << 8, 0,
2231 buf, GET_DESCRIPTOR_BUFSIZE,
2232 USB_CTRL_GET_TIMEOUT);
2233 switch (buf->bMaxPacketSize0) {
2234 case 8: case 16: case 32: case 64: case 255:
2235 if (buf->bDescriptorType ==
2236 USB_DT_DEVICE) {
2237 r = 0;
2238 break;
2239 }
2240 /* FALL THROUGH */
2241 default:
2242 if (r == 0)
2243 r = -EPROTO;
2244 break;
2245 }
2246 if (r == 0)
2247 break;
2248 }
2249 udev->descriptor.bMaxPacketSize0 =
2250 buf->bMaxPacketSize0;
2251 kfree(buf);
2252
2253 retval = hub_port_reset(hub, port1, udev, delay);
2254 if (retval < 0) /* error or disconnect */
2255 goto fail;
2256 if (oldspeed != udev->speed) {
2257 dev_dbg(&udev->dev,
2258 "device reset changed speed!/n");
2259 retval = -ENODEV;
2260 goto fail;
2261 }
2262 if (r) {
2263 dev_err(&udev->dev, "device descriptor "
2264 "read/%s, error %d/n",
2265 "64", r);
2266 retval = -EMSGSIZE;
2267 continue;
2268 }
2269 #undef GET_DESCRIPTOR_BUFSIZE
2270 }
2271
2272 for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
2273 retval = hub_set_address(udev);
2274 if (retval >= 0)
2275 break;
2276 msleep(200);
2277 }
2278 if (retval < 0) {
2279 dev_err(&udev->dev,
2280 "device not accepting address %d, error %d/n",
2281 udev->devnum, retval);
2282 goto fail;
2283 }
2284
2285 /* cope with hardware quirkiness:
2286 * - let SET_ADDRESS settle, some device hardware wants it
2287 * - read ep0 maxpacket even for high and low speed,
2288 */
2289 msleep(10);
2290 if (USE_NEW_SCHEME(retry_counter))
2291 break;
2292
2293 retval = usb_get_device_descriptor(udev, 8);
2294 if (retval < 8) {
2295 dev_err(&udev->dev, "device descriptor "
2296 "read/%s, error %d/n",
2297 "8", retval);
2298 if (retval >= 0)
2299 retval = -EMSGSIZE;
2300 } else {
2301 retval = 0;
2302 break;
2303 }
2304 }
2305 if (retval)
2306 goto fail;
2307
2308 i = udev->descriptor.bMaxPacketSize0 == 0xff?
2309 512 : udev->descriptor.bMaxPacketSize0;
2310 if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
2311 if (udev->speed != USB_SPEED_FULL ||
2312 !(i == 8 || i == 16 || i == 32 || i == 64)) {
2313 dev_err(&udev->dev, "ep0 maxpacket = %d/n", i);
2314 retval = -EMSGSIZE;
2315 goto fail;
2316 }
2317 dev_dbg(&udev->dev, "ep0 maxpacket = %d/n", i);
2318 udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
2319 ep0_reinit(udev);
2320 }
2321
2322 retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);
2323 if (retval < (signed)sizeof(udev->descriptor)) {
2324 dev_err(&udev->dev, "device descriptor read/%s, error %d/n",
2325 "all", retval);
2326 if (retval >= 0)
2327 retval = -ENOMSG;
2328 goto fail;
2329 }
2330
2331 retval = 0;
2332
2333 fail:
2334 if (retval)
2335 hub_port_disable(hub, port1, 0);
2336 mutex_unlock(&usb_address0_mutex);
2337 return retval;
2338 }
像这种近300行的函数,这些年来,我竟也渐渐习惯了.我现在是以一种看文物的心态看这些变态的函数,竟也慢慢品出了一点周口店遗风.因为我明白,即便我像鲁迅先生那样呐喊,写代码的那些家伙也不会停下写这些函数的手.难怪江湖上称这些人的所作所为为行为艺术.
hub_port_init()这个函数的基本思想就是做初始化,首先是把一个设备reset,然后是分配地址.在然后是获得设备描述符.
首先DEFINE_MUTEX是来自于include/linux/mutex.h中的一个宏,用它可以定义一把互斥锁,在Linux内核中,其实是在2005年底才建立比较系统的完善的互斥锁机制,在那年冬天,北京的最后一场雪过后,来自RedHat公司的Ingo Molnar大侠大胆的提出了他所谓的Generic Mutex Subsystem,即通用的互斥锁机制.此前内核中很多地方使用的都是信号量,正如我们在2.6.10内核中usb-storage中所看到的那样,而当时间的箭头指向了2005年末的时候,区里(开源社区,下称区里)很多同志抱怨说信号量不灵,很多时候不好用,当然区里为这事展开了一场轰轰烈烈的讨论.老黑客Ingo Molnar受不了了,在一周之后,愤然提出要对内核进行一场大的革命,这次革命后来被称为一二一九运动.当时Ingo同志提出了诸多理由要求使用新的互斥锁机制,而不是过去普遍出现在内核中的信号量机制,比如新的机制占用更小的内存,代码更为紧凑,更快,更便于调试.在诸多优势的诱惑下,区里的群众将信将疑的便认可了这种做法.忽如一夜春风来,紧接着的几个月里,人民群众纷纷提交patch,把原来用信号量的地方都改成了互斥锁.而这种改变深入到Linux中usb子系统是始于2006年春天,农历二月二十二,Greg同志大旗一挥,将usb中的代码中绝大多数的信号量代码换成了互斥锁代码.所以到今天,您看2.6.22.1的代码中,整个usb子系统里几乎没有了down/up这一对函数的使用,取而代之的是mutex_lock()和mutex_unlock()函数对.而要初始化,只需像我们这里一样,DEFINE_MUTEX(name)即可.关于这个新的互斥锁的定义在include/linux/mutex.h中,而实现在kernel/mutex.c中.
Ok,让我们继续.hdev被定义用来记录hub所对应的那个struct usb_device,而delay记录延时,因为usb设备的reset工作不可能是瞬间的,通常会有一点点延时,这很容易理解,你的计算机永远不可能说你按一下reset键就立刻能够重起马上就能重新工作的,这里咱们首先给delay设置的初始值为10ms,即HUB_SHORT_RESET_TIME这个宏被定义为10ms.这个10ms的来源是usb spec 2.0中7.1.7.5节Reset Signaling里面说的,”The reset signaling must be driven for a minumum of 10ms”,这个10ms在usb spec中称之为TDRST.一个Hub端口在reset之后将进入Enabled状态.
然后定义一个oldspeed用来记录设备在没有reset之前的速度.
2120行,只有root hub没有父亲,而usb spec 2.0里说得很清楚,”It is required that resets from root ports have a duration of at least 50ms”,这个50ms被称为TDRSTR.即HUB_ROOT_RESET_TIME这个宏被定义为50ms.
2122和2123行是OTG相关的,HNP是OTG标准所支持的协议,HNP即Host Negotiation Protocol,坊间俗称主机通令协议.咱们既然不关注OTG,那么这里也就不做解释了.省得把问题复杂化了.当断不断,反受其乱. – 史记 春申君列传.
2128行,这两行代码来源于实践.实践表明,某些低速设备要求有比较高的延时才能完成好它们的reset,这很简单,286的机器重起肯定比P4的机器要慢.
好,调用mutex_lock获得互斥锁了,即表明下面这段代码一个时间只能被一个进程执行.
然后调用hub_port_reset().
1509 static int hub_port_reset(struct usb_hub *hub, int port1,
1510 struct usb_device *udev, unsigned int delay)
1511 {
1512 int i, status;
1513
1514 /* Reset the port */
1515 for (i = 0; i < PORT_RESET_TRIES; i++) {
1516 status = set_port_feature(hub->hdev,
1517 port1, USB_PORT_FEAT_RESET);
1518 if (status)
1519 dev_err(hub->intfdev,
1520 "cannot reset port %d (err = %d)/n",
1521 port1, status);
1522 else {
1523 status = hub_port_wait_reset(hub, port1, udev, delay);
1524 if (status && status != -ENOTCONN)
1525 dev_dbg(hub->intfdev,
1526 "port_wait_reset: err = %d/n",
1527 status);
1528 }
1529
1530 /* return on disconnect or reset */
1531 switch (status) {
1532 case 0:
1533 /* TRSTRCY = 10 ms; plus some extra */
1534 msleep(10 + 40);
1535 /* FALL THROUGH */
1536 case -ENOTCONN:
1537 case -ENODEV:
1538 clear_port_feature(hub->hdev,
1539 port1, USB_PORT_FEAT_C_RESET);
1540 /* FIXME need disconnect() for NOTATTACHED device */
1541 usb_set_device_state(udev, status
1542 ? USB_STATE_NOTATTACHED
1543 : USB_STATE_DEFAULT);
1544 return status;
1545 }
1546
1547 dev_dbg (hub->intfdev,
1548 "port %d not enabled, trying reset again.../n",
1549 port1);
1550 delay = HUB_LONG_RESET_TIME;
1551 }
1552
1553 dev_err (hub->intfdev,
1554 "Cannot enable port %i. Maybe the USB cable is bad?/n",
1555 port1);
1556
1557 return status;
1558 }
事到如今,有些函数不讲也不行了.这就是set_port_feature.其实之前我们遇见过,只是因为当时属于可讲可不讲,所以就先跳过去了.但现在不讲不行了,我们前面讲过它的搭档clear_port_feature,所以我不讲你也应该知道set_port_feature()干嘛用的,很显然,一个是清楚feature,一个是设置feature.Linux中很多这种成对的函数,刚才讲的那个mutex_lock()和mutex_unlock()不也是这样么?其实这种思想是借鉴了我国的黄梅戏<<天仙配>>中所描绘的那种”你耕田来我织布,我挑水来你浇园,你我好比鸳鸯鸟,比翼双飞在人间”的纯朴的爱情观.
172 /*
173 * USB 2.0 spec Section 11.24.2.13
174 */
175 static int set_port_feature(struct usb_device *hdev, int port1, int feature)
176 {
177 return usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0),
178 USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port1,
179 NULL, 0, 1000);
180 }
看明白了clear_port_feature()的一定不会觉得这个函数看不懂.发送一个控制请求,设置一个feature,咱们传递进来的feature是USB_PORT_FEAT_RESET,即对应于usb spec中的reset.发送好了之后就延时等待,调用hub_port_wait_reset():
1457 static int hub_port_wait_reset(struct usb_hub *hub, int port1,
1458 struct usb_device *udev, unsigned int delay)
1459 {
1460 int delay_time, ret;
1461 u16 portstatus;
1462 u16 portchange;
1463
1464 for (delay_time = 0;
1465 delay_time < HUB_RESET_TIMEOUT;
1466 delay_time += delay) {
1467 /* wait to give the device a chance to reset */
1468 msleep(delay);
1469
1470 /* read and decode port status */
1471 ret = hub_port_status(hub, port1, &portstatus, &portchange);
1472 if (ret < 0)
1473 return ret;
1474
1475 /* Device went away? */
1476 if (!(portstatus & USB_PORT_STAT_CONNECTION))
1477 return -ENOTCONN;
1478
1479 /* bomb out completely if something weird happened */
1480 if ((portchange & USB_PORT_STAT_C_CONNECTION))
1481 return -EINVAL;
1482
1483 /* if we`ve finished resetting, then break out of the loop */
1484 if (!(portstatus & USB_PORT_STAT_RESET) &&
1485 (portstatus & USB_PORT_STAT_ENABLE)) {
1486 if (hub_is_wusb(hub))
1487 udev->speed = USB_SPEED_VARIABLE;
1488 else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
1489 udev->speed = USB_SPEED_HIGH;
1490 else if (portstatus & USB_PORT_STAT_LOW_SPEED)
1491 udev->speed = USB_SPEED_LOW;
1492 else
1493 udev->speed = USB_SPEED_FULL;
1494 return 0;
1495 }
1496
1497 /* switch to the long delay after two short delay failures */
1498 if (delay_time >= 2 * HUB_SHORT_RESET_TIME)
1499 delay = HUB_LONG_RESET_TIME;
1500
1501 dev_dbg (hub->intfdev,
1502 "port %d not reset yet, waiting %dms/n",
1503 port1, delay);
1504 }
1505
1506 return -EBUSY;
1507 }
这里HUB_RESET_TIMEOUT是设置的一个超时,这个宏的值为500毫秒,即如果reset了500毫秒还没好那么就返回错误值,朽木不可雕也.而循环的步长正是我们前面设置的那个delay.
msleep(delay)就是休眠delay毫秒.
休眠完了就读取端口的状态.hub_port_status()不用说了,咱们前面讲过了.获得端口状态.错误就返回错误码,正确就把信息记录在portstatus和portchange里.
1476行判断,如果在reset期间设备都被撤掉了,那就返回吧,甭浪费感情了.
1480行判断,如果又一次汇报说有设备插入,那就是见鬼了.返回错误立刻向上级汇报说人鬼情未了.
正如刚才说过的,reset真正完成以后,status就应该是enabled,所以1484和1485行的if如果满足就说明reset好了.
1486行这个if是判断这是否是一个无线Root hub,即既是Root Hub,又是无线hub,因为在struct usb_hcd中有一个成员unsigned wireless,这个flag标志了该主机控制器是Wireless的.我们刚才说过了,Wireless的话,speed就是那个USB_SPEED_VARIABLE.
否则如果portstatus和USB_PORT_STAT_HIGH_SPEED相与为1,则是高速设备,如果与USB_PORT_STAT_LOW_SPEED相与为1则是低速设备,剩下来的可能就是全速设备.到这里,这个hub_port_wait_reset就可以返回了,正常的返回0.总之,注意,经过这里udev的speed就被设置好了.
1497和1498行,走到这里就说明还没有reset好.如果已经过了2个HUB_SHORT_RESET_TIME,就把步长设置为HUB_LONG_RESET_TIME,即200ms,然后打印一条警告信息,继续循环,如果循环完全结束还不行,那就说明超时了,返回-EBUSY.
回到hub_port_reset中来,下面走到了1531行,一个switch,根据刚才的返回值做一次选择,如果是0,说明正常, 安全起见,索性再等50ms.如果是错误码,并且错误码表明设备不在了,则首先清掉reset这个feature,然后把这个为刚才这个设备申请的struct usb_device结构体的状态设置为USB_STATE_NOTATTACHED.并且返回status.如果你问那个USB_STATE_DEFAULT是怎么回事?那么说明你没有好好学谭浩强的那本经典教材.在switch里面,如果status为0,那么由于case 0那一部分后面break语句,所以case –ENOTCONN和case –ENODEV下面的那几句代码都会执行,即clear_port_feature是总会执行的,usb_set_device_state()也会执行,而对于status为0的情况,属于正常情况,从这时候开始,struct usb_device结构体的状态就将记录为USB_STATE_DEFAULT,即所谓的默认状态,然后返回值就是0.而对于端口reset,我们设置的重复次数是PORT_RESET_TRIES,它等于5,你当然可以把它改为1,没人拦住你.只要你对自己的设备够自信,一次reset就肯定成功.信自己,金莱克!
如果1553行还会执行,那么说明肯定出了大问题了,reset都没法进行,于是返回错误状态吧.
回到hub_init_port()中来,如果刚才失败了,就goto fail,否则也暂时将retval这个临时变量设置为-ENODEV,而2140行,如果oldspeed不是USB_SPEED_UNKNOWN,并且也不等于刚刚设置的这个speed,那么说明reset之前设备已经在工作了,而这次reset把设备原来的速度状态也给改变了.这是不合理的,必须结束函数,并且disable这个端口.于是goto fail,而在fail那边可以看到,由于retval不为0,所以调用hub_port_disable()关掉这个端口.然后释放互斥锁,并且返回错误代码.
2144行,如果不是刚才这种情况,那么令oldspeed等于现在这个udev->speed.
2151行开始,又是一个switch,感觉这一段代码的选择出现得太多了点,代码的选择倒是简单,可是人,作为微小而孤独的个体,在人生的选择题前,则总会无可避免地徘徊起来.在一个又一个渡口上,在一次又一次险象中,我们究竟能选择什么,该选择什么?
其实这里是设置一个初始值,我们曾经介绍过ep0.ep0.desc.wMaxPacketSizep0.desc.wMaxPacketSize用来记录端点0的单个包的最大传输size.对于无线设备,无线usb spec规定了,端点0的最大包size就是512,而对于高速设备,这个size也是usb spec规定好了,64bytes,而低速设备同样是usb spec规定好了,8bytes.唯一存在变数的是全速设备,它可能是8,可能是16,可能是32,也可能是64,对于这种设备,没有办法,只能通过读取设备描述符来获得了.也正是这个全速设备引发了我们前面讨论的那个两种策略的问题.不过那时候我们没有点明说是这场PK是因为全速设备引起的,因为那时候说还太早了,说了您也忘了,而现在看到了代码就不会忘了.正如我们说过的,Linux向Windows妥协了,这里Full Speed的设备,默认先把wMaxPacketSize设置为64,而不是以前的那种8.
2172至2186这些行,仅仅是为了打印一行调试信息,对于写代码的人来说,可能很有用,而对读代码的人来说,也许就没有任何意义了,正如对聋子而言,正版唱片CD的作用只是拿来当照脸的镜子.
Sep 9 11:32:49 localhost kernel: usb 4-5: new high speed USB device using ehci_hcd and address 3
Sep 9 11:32:52 localhost kernel: usb 2-1: new low speed USB device using uhci_hcd and address 3
比如在我的计算机里,就可以在/var/log/messages日志文件里看到上面这样的信息.ehci_hcd和uhci_hcd就是主机控制器的驱动程序.这个3就是设备的devnum.
2189行,不是switch又是if,除了判断还是判断,只不过刚才是选择,现在是如果,如果明天是世界末日,我就会去抢银行,可是既然明天是世界末日了,那要很多钱又能做什么呢?这里如果hdev->tt为真,则如何如何,否则,如果设备本身不是高速的,而hub是高速的,那么如何如何.tt我们介绍过,transaction translator,而ttport是struct usb_device中的一个成员,int ttport,这个ttport以后会被用到,tt也将在以后会被用到,暂时先不细说,到时候再回来看.
GET_DESCRIPTOR_TRIES等于2,这段代码的思想我们以前就讲过,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.所以也就是说,先进行两次新的策略,如果不行就再进行两次旧的策略.所有这一切只有一个目的,就是为了获得设备的描述符.由于思想已经非常清楚,代码我们就不再一行一行讲了.尤其是那些错误判断的句子.
只是介绍一下其中调用的几个函数.对于新策略,首先定义一个struct usb_device_descriptor的指针buf,然后申请64个字节的空间,发送一个控制传输的请求,然后结束之后,察看buf->bMaxPackSize0,合理值只有8/16/32/64/512,这里255实际上是WUSB协议规定的,毕竟只有8位,最大就是255了,所以就用这个值来代表WUSB设备.实际上WUSB的大小是512.循环三次是保险起见.因为实践表明这类请求通常成功率很难达到100%.
然后2249行用udev->descriptor.bMaxPacketSize0来记录这个临时获得的值.然后buf的使命结束了,释放它的内存.
然后正如我们曾经分析的那样,把设备reset.
然后是设置地址.hub_set_address()
2076 static int hub_set_address(struct usb_device *udev)
2077 {
2078 int retval;
2079
2080 if (udev->devnum == 0)
2081 return -EINVAL;
2082 if (udev->state == USB_STATE_ADDRESS)
2083 return 0;
2084 if (udev->state != USB_STATE_DEFAULT)
2085 return -EINVAL;
2086 retval = usb_control_msg(udev, usb_sndaddr0pipe(),
2087 USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
2088 NULL, 0, USB_CTRL_SET_TIMEOUT);
2089 if (retval == 0) {
2090 usb_set_device_state(udev, USB_STATE_ADDRESS);
2091 ep0_reinit(udev);
2092 }
2093 return retval;
2094 }
和前面那个choose_address不同,choose_address是从软件意义上挑选一个地址.而这里要发送真正的请求,因为设置设备地址本身就是usb spec 2.0规定的标准的请求之一,这里我们用宏USB_REQ_SET_ADDRESS来代替,只有真正发送了请求之后硬件上才能真正通过这个地址进行通信.这里最关键的就是传递了udev->devnum,这正是我们前面选择的地址,这里赋给了wIndex,来自usb spec 2.0中图表说明了一切:
从此以后这个设备站起来了,并一举确立了它在usb江湖中的地位.
设好了地址之后,把设备的状态从开始的那个USB_STATE_DEFAULT变成了USB_STATE_ADDRESS,从此以后他就算是有户口的主了.在usb spec中,这一状态被称为Address state,我叫它有地址的状态.
然后调用了ep0_reinit().
2066 static void ep0_reinit(struct usb_device *udev)
2067 {
2068 usb_disable_endpoint(udev, 0 + USB_DIR_IN);
2069 usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
2070 udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
2071 }
usb_disable_endpoint是usbcore提供的一个函数,具体到咱们这个端点,它会让ep_out[0]和ep_in[0]置为NULL.然后会取消掉任何挂在endpoint上的urb.再然后这里2070行再次把ep_in[0]和ep_out[0]指向udev->ep0.须知ep0是真正占内存的数据结构,而ep_in[0]和ep_out[0]只是指针,而在host controller驱动程序里将被用到的正是这两个指针数组.
回到hub_port_init中来,设置好了地址,然后2289行,先睡10ms,然后如果还是新策略,那么就可以结束了,因为该做的都做完了.如果是旧策略,那么执行到这里还刚上路呢,我们说过了,思路就是先获得设备描述符的前8个字节,然后从中得知udev->descriptor的bMaxPacketSize0,然后再次调用usb_get_device_descriptor完整的获得一次设备描述符.然后就ok了,到2336行,释放互斥锁,所谓的解铃还须系铃人.
至此,hub_port_init()就可以返回了.
声明一下 ,usb_get_device_descriptor() 是来自 drivers/usb/core/message.c 中的函数 , 由 usbcore 提供 , 我们这里就不细讲了 . 其作用是很明显的 , 获取设备描述符 .