首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux那些事儿之我是Hub(20)八大重量级函数闪亮登场(四)

Linux那些事儿之我是Hub(20)八大重量级函数闪亮登场(四)

接下来我们来到了第四个函数,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,把原来用信号量的地方都改成了互斥锁.而这种改变深入到Linuxusb子系统是始于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.07.1.7.5Reset Signaling里面说的,”The reset signaling must be driven for a minumum of 10ms”,这个10msusb 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.
21222123行是OTG相关的,HNPOTG标准所支持的协议,HNPHost 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,咱们传递进来的featureUSB_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毫秒,即如果reset500毫秒还没好那么就返回错误值,朽木不可雕也.而循环的步长正是我们前面设置的那个delay.
msleep(delay)就是休眠delay毫秒.
休眠完了就读取端口的状态.hub_port_status()不用说了,咱们前面讲过了.获得端口状态.错误就返回错误码,正确就把信息记录在portstatusportchange.
1476行判断,如果在reset期间设备都被撤掉了,那就返回吧,甭浪费感情了.
1480行判断,如果又一次汇报说有设备插入,那就是见鬼了.返回错误立刻向上级汇报说人鬼情未了.
正如刚才说过的,reset真正完成以后,status就应该是enabled,所以14841485行的if如果满足就说明reset好了.
1486行这个if是判断这是否是一个无线Root hub,即既是Root Hub,又是无线hub,因为在struct usb_hcd中有一个成员unsigned wireless,这个flag标志了该主机控制器是Wireless.我们刚才说过了,Wireless的话,speed就是那个USB_SPEED_VARIABLE.
否则如果portstatusUSB_PORT_STAT_HIGH_SPEED相与为1,则是高速设备,如果与USB_PORT_STAT_LOW_SPEED相与为1则是低速设备,剩下来的可能就是全速设备.到这里,这个hub_port_wait_reset就可以返回了,正常的返回0.总之,注意,经过这里udevspeed就被设置好了.
14971498,走到这里就说明还没有reset.如果已经过了2HUB_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里面,如果status0,那么由于case 0那一部分后面break语句,所以case –ENOTCONNcase –ENODEV下面的那几句代码都会执行,clear_port_feature是总会执行的,usb_set_device_state()也会执行,而对于status0的情况,属于正常情况,从这时候开始,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是因为全速设备引起的,因为那时候说还太早了,说了您也忘了,而现在看到了代码就不会忘了.正如我们说过的,LinuxWindows妥协了,这里Full Speed的设备,默认先把wMaxPacketSize设置为64,而不是以前的那种8.
21722186这些行,仅仅是为了打印一行调试信息,对于写代码的人来说,可能很有用,而对读代码的人来说,也许就没有任何意义了,正如对聋子而言,正版唱片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_hcduhci_hcd就是主机控制器的驱动程序.这个3就是设备的devnum.
2189,不是switch又是if,除了判断还是判断,只不过刚才是选择,现在是如果,如果明天是世界末日,我就会去抢银行,可是既然明天是世界末日了,那要很多钱又能做什么呢?这里如果hdev->tt为真,则如何如何,否则,如果设备本身不是高速的,hub是高速的,那么如何如何.tt我们介绍过,transaction translator,ttportstruct usb_device中的一个成员,int ttport,这个ttport以后会被用到,tt也将在以后会被用到,暂时先不细说,到时候再回来看.
GET_DESCRIPTOR_TRIES等于2,这段代码的思想我们以前就讲过,USB_NEW_SCHEME(retry_counter),retry_counter就是hub_port_init()传递进来的最后一个参数,而我们给它的实参正是那个从0SET_CONFIG_TRIES-1的那个i.假设我们什么也没有设置,都是使用默认值,那么use_both_schemes默认值为1,old_scheme_first默认值为0,于是SET_CONFIG_TRIES4,i将从0变到3,USB_NEW_SCHEME(i)将在i01的时候为1,i23的时候为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_endpointusbcore提供的一个函数,具体到咱们这个端点,它会让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->descriptorbMaxPacketSize0,然后再次调用usb_get_device_descriptor完整的获得一次设备描述符.然后就ok,2336,释放互斥锁,所谓的解铃还须系铃人.
至此,hub_port_init()就可以返回了.
声明一下,usb_get_device_descriptor()是来自drivers/usb/core/message.c中的函数,usbcore提供,我们这里就不细讲了.其作用是很明显的,获取设备描述符.
返回列表