Linux那些事儿之我是UHCI(18)Root Hub的控制传输(二)

医生,请把孩子取出来之后,顺便给我吸吸脂.

——广州一妇女在剖腹产手术前对医生说.

对于控制传输,rh_call_control会被调用.我也特别希望能有人给这个函数吸吸脂,我们的上下文是为了获取设备描述符,即当初那个usb_get_device_descriptor领着我们来到了这个函数,为了完成这件事情,实际上只需要很少的代码,但是rh_call_control这个函数涉及了所有的Root Hub相关的控制传输,以至于我们除了把孩子取出来之外,还不得不顺便看看其它的代码.当然了,既然是顺便,那么我们也就不会详细的去讲解每一行.这个函数定义于drivers/usb/core/hcd.c:

    343 /* Root hub control transfers execute synchronously */

    344 static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)

    345 {

    346         struct usb_ctrlrequest *cmd;

    347         u16             typeReq, wValue, wIndex, wLength;

    348         u8              *ubuf = urb->transfer_buffer;

    349         u8              tbuf [sizeof (struct usb_hub_descriptor)]

    350                 __attribute__((aligned(4)));

    351         const u8        *bufp = tbuf;

    352         int             len = 0;

    353         int             patch_wakeup = 0;

    354         unsigned long   flags;

    355         int             status = 0;

    356         int             n;

    357

    358         cmd = (struct usb_ctrlrequest *) urb->setup_packet;

    359         typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;

    360         wValue   = le16_to_cpu (cmd->wValue);

    361         wIndex   = le16_to_cpu (cmd->wIndex);

    362         wLength  = le16_to_cpu (cmd->wLength);

    363

    364         if (wLength > urb->transfer_buffer_length)

    365                 goto error;

    366

    367         urb->actual_length = 0;

    368         switch (typeReq) {

    369

    370         /* DEVICE REQUESTS */

    371

    372         /* The root hub's remote wakeup enable bit is implemented using

    373          * driver model wakeup flags.  If this system supports wakeup

    374          * through USB, userspace may change the default "allow wakeup"

    375          * policy through sysfs or these calls.

    376          *

    377          * Most root hubs support wakeup from downstream devices, for

    378          * runtime power management (disabling USB clocks and reducing

    379          * VBUS power usage).  However, not all of them do so; silicon,

    380          * board, and BIOS bugs here are not uncommon, so these can't

    381          * be treated quite like external hubs.

    382          *

    383          * Likewise, not all root hubs will pass wakeup events upstream,

384          * to wake up the whole system.  So don't assume root hub and

    385          * controller capabilities are identical.

    386          */

    387

    388         case DeviceRequest | USB_REQ_GET_STATUS:

    389                 tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev)

    390                                         << USB_DEVICE_REMOTE_WAKEUP)

    391                                 | (1 << USB_DEVICE_SELF_POWERED);

    392                 tbuf [1] = 0;

    393                 len = 2;

    394                 break;

    395         case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:

    396                 if (wValue == USB_DEVICE_REMOTE_WAKEUP)

    397                         device_set_wakeup_enable(&hcd->self.root_hub->dev, 0);

    398                 else

    399                         goto error;

    400                 break;

    401         case DeviceOutRequest | USB_REQ_SET_FEATURE:

    402                 if (device_can_wakeup(&hcd->self.root_hub->dev)

    403                                 && wValue == USB_DEVICE_REMOTE_WAKEUP)

    404                         device_set_wakeup_enable(&hcd->self.root_hub->dev, 1);

    405                 else

    406                         goto error;

    407                 break;

    408         case DeviceRequest | USB_REQ_GET_CONFIGURATION:

    409                 tbuf [0] = 1;

    410                 len = 1;

    411                         /* FALLTHROUGH */

    412         case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:

    413                 break;

    414         case DeviceRequest | USB_REQ_GET_DESCRIPTOR:

    415                 switch (wValue & 0xff00) {

    416                 case USB_DT_DEVICE << 8:

    417                         if (hcd->driver->flags & HCD_USB2)

    418                                 bufp = usb2_rh_dev_descriptor;

    419                         else if (hcd->driver->flags & HCD_USB11)

    420                                 bufp = usb11_rh_dev_descriptor;

    421                         else

    422                                 goto error;

    423                         len = 18;

    424                         break;

425                 case USB_DT_CONFIG << 8:

    426                         if (hcd->driver->flags & HCD_USB2) {

    427                                 bufp = hs_rh_config_descriptor;

    428                                 len = sizeof hs_rh_config_descriptor;

    429                         } else {

    430                                 bufp = fs_rh_config_descriptor;

    431                                 len = sizeof fs_rh_config_descriptor;

    432                         }

    433                         if (device_can_wakeup(&hcd->self.root_hub->dev))

    434                                 patch_wakeup = 1;

    435                         break;

    436                 case USB_DT_STRING << 8:

    437                         n = rh_string (wValue & 0xff, hcd, ubuf, wLength);

    438                         if (n < 0)

    439                                 goto error;

    440                         urb->actual_length = n;

    441                         break;

    442                 default:

    443                         goto error;

    444                 }

    445                 break;

    446         case DeviceRequest | USB_REQ_GET_INTERFACE:

    447                 tbuf [0] = 0;

    448                 len = 1;

    449                         /* FALLTHROUGH */

    450         case DeviceOutRequest | USB_REQ_SET_INTERFACE:

    451                 break;

    452         case DeviceOutRequest | USB_REQ_SET_ADDRESS:

    453                 // wValue == urb->dev->devaddr

    454                 dev_dbg (hcd->self.controller, "root hub device address %d/n",

    455                         wValue);

    456                 break;

    457

    458         /* INTERFACE REQUESTS (no defined feature/status flags) */

    459

    460         /* ENDPOINT REQUESTS */

    461

    462         case EndpointRequest | USB_REQ_GET_STATUS:

    463                 // ENDPOINT_HALT flag

    464                 tbuf [0] = 0;

    465                 tbuf [1] = 0;

466                 len = 2;

    467                         /* FALLTHROUGH */

    468         case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:

    469         case EndpointOutRequest | USB_REQ_SET_FEATURE:

    470                 dev_dbg (hcd->self.controller, "no endpoint features yet/n");

    471                 break;

    472

    473         /* CLASS REQUESTS (and errors) */

    474

    475         default:

    476                 /* non-generic request */

    477                 switch (typeReq) {

    478                 case GetHubStatus:

    479                 case GetPortStatus:

    480                         len = 4;

    481                         break;

    482                 case GetHubDescriptor:

    483                         len = sizeof (struct usb_hub_descriptor);

    484                         break;

    485                 }

    486                 status = hcd->driver->hub_control (hcd,

    487                         typeReq, wValue, wIndex,

    488                         tbuf, wLength);

    489                 break;

    490 error:

    491                 /* "protocol stall" on error */

    492                 status = -EPIPE;

    493         }

    494

    495         if (status) {

    496                 len = 0;

    497                 if (status != -EPIPE) {

    498                         dev_dbg (hcd->self.controller,

    499                                 "CTRL: TypeReq=0x%x val=0x%x "

    500                                 "idx=0x%x len=%d ==> %d/n",

    501                                 typeReq, wValue, wIndex,

    502                                 wLength, status);

    503                 }

    504         }

    505         if (len) {

    506                 if (urb->transfer_buffer_length < len)

    507                         len = urb->transfer_buffer_length;

508                 urb->actual_length = len;

    509                 // always USB_DIR_IN, toward host

    510                 memcpy (ubuf, bufp, len);

    511

    512                 /* report whether RH hardware supports remote wakeup */

    513                 if (patch_wakeup &&

    514                                 len > offsetof (struct usb_config_descriptor,

    515                                                 bmAttributes))

    516                         ((struct usb_config_descriptor *)ubuf)->bmAttributes

    517                                 |= USB_CONFIG_ATT_WAKEUP;

    518         }

    519

    520         /* any errors get returned through the urb completion */

    521         local_irq_save (flags);

    522         spin_lock (&urb->lock);

    523         if (urb->status == -EINPROGRESS)

    524                 urb->status = status;

    525         spin_unlock (&urb->lock);

    526         usb_hcd_giveback_urb (hcd, urb);

    527         local_irq_restore (flags);

    528         return 0;

    529 }

看到这样近200行的函数,真是有一种叫天天不灵叫地地不应的感觉.不幸中的万幸,这个函数的结构还是很清晰的.自上而下的看过来就可以了.

对于控制传输,首先要获得它的setup_packet,来自urb结构体,正如我们当初在usb-storage中看到的那样.这里把这个setup_packet赋给cmd指针.然后把其中的各个成员都给取出来,分别放在临时变量typeReq,wValue,wIndex,wLength,然后来判断这个typeReq.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_STATUS,,设置len2.

如果是设备请求并且方向是OUT,而且是USB_REQ_CLEAR_FEATURE,则如何如何.

如果是设备请求并且方向是OUT,而且是USB_REQ_SET_FEATURE,则如何如何.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_CONFIGURATION,则设置len1.

如果是设备请求并且方向是OUT,而且是USB_REQ_SET_CONFIGURATION,则啥也不做.

如果是设备请求并且方向是IN,而且是USB_REQ_GET_DESCRIPTOR,则继续判断,wValue到底是什么来决定究竟是要获得什么描述符.如果是USB_DT_DEVICE,则说明要获得的是设备描述符,这正是咱们的上下文,而整个这段函数中其它的内容就只相当于顺便看看.(咱们传递给usb_get_descriptor的第二个参数就是USB_DT_DEVICE,传递给usb_control_msg的第三个参数正是USB_REQ_GET_DESCRIPTOR.)如果是USB_DT_CONFIG,则说明要获得的是配置描述符,如果是USB_DT_STRING,则说明要获得的是字符串描述符.实际上,对于Root Hub来说,这些东西都是一样的,咱们在drivers/usb/core/hcd.c中都预先定义好了,usb2_rh_dev_descriptor是针对usb 2.0,usb11_rh_dev_descriptor是针对usb 1.1,咱们的uhci driver里面设置了flagsHCD_USB11.

    108 /*-------------------------------------------------------------------------*/

    109

    110 /*

    111  * Sharable chunks of root hub code.

    112  */

    113

    114 /*-------------------------------------------------------------------------*/

    115

    116 #define KERNEL_REL      ((LINUX_VERSION_CODE >> 16) & 0x0ff)

    117 #define KERNEL_VER      ((LINUX_VERSION_CODE >> 8) & 0x0ff)

    118

    119 /* usb 2.0 root hub device descriptor */

    120 static const u8 usb2_rh_dev_descriptor [18] = {

    121         0x12,       /*  __u8  bLength; */

    122         0x01,       /*  __u8  bDescriptorType; Device */

    123         0x00, 0x02, /*  __le16 bcdUSB; v2.0 */

    124

    125         0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */

    126         0x00,       /*  __u8  bDeviceSubClass; */

    127         0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/

    128         0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

    129

    130         0x00, 0x00, /*  __le16 idVendor; */

    131         0x00, 0x00, /*  __le16 idProduct; */

    132         KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    133

    134         0x03,       /*  __u8  iManufacturer; */

    135         0x02,       /*  __u8  iProduct; */

    136         0x01,       /*  __u8  iSerialNumber; */

    137         0x01        /*  __u8  bNumConfigurations; */

    138 };

    139

    140 /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */

    141

    142 /* usb 1.1 root hub device descriptor */

    143 static const u8 usb11_rh_dev_descriptor [18] = {

    144         0x12,       /*  __u8  bLength; */

    145         0x01,       /*  __u8  bDescriptorType; Device */

    146         0x10, 0x01, /*  __le16 bcdUSB; v1.1 */

    147

    148         0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */

    149         0x00,       /*  __u8  bDeviceSubClass; */

    150         0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */

    151         0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */

    152

    153         0x00, 0x00, /*  __le16 idVendor; */

    154         0x00, 0x00, /*  __le16 idProduct; */

    155         KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */

    156

    157         0x03,       /*  __u8  iManufacturer; */

    158         0x02,       /*  __u8  iProduct; */

159         0x01,       /*  __u8  iSerialNumber; */

    160         0x01        /*  __u8  bNumConfigurations; */

    161 };

    162

    163

    164 /*-------------------------------------------------------------------------*/

    165

    166 /* Configuration descriptors for our root hubs */

    167

    168 static const u8 fs_rh_config_descriptor [] = {

    169

    170         /* one configuration */

    171         0x09,       /*  __u8  bLength; */

    172         0x02,       /*  __u8  bDescriptorType; Configuration */

    173         0x19, 0x00, /*  __le16 wTotalLength; */

    174         0x01,       /*  __u8  bNumInterfaces; (1) */

    175         0x01,       /*  __u8  bConfigurationValue; */

    176         0x00,       /*  __u8  iConfiguration; */

    177         0xc0,       /*  __u8  bmAttributes;

    178                                  Bit 7: must be set,

    179                                      6: Self-powered,

    180                                      5: Remote wakeup,

    181                                      4..0: resvd */

    182         0x00,       /*  __u8  MaxPower; */

    183

    184         /* USB 1.1:

    185          * USB 2.0, single TT organization (mandatory):

    186          *      one interface, protocol 0

    187          *

    188          * USB 2.0, multiple TT organization (optional):

    189          *      two interfaces, protocols 1 (like single TT)

    190          *      and 2 (multiple TT mode) ... config is

    191          *      sometimes settable

    192          *      NOT IMPLEMENTED

    193          */

    194

    195         /* one interface */

    196         0x09,       /*  __u8  if_bLength; */

    197         0x04,       /*  __u8  if_bDescriptorType; Interface */

    198         0x00,       /*  __u8  if_bInterfaceNumber; */

    199         0x00,       /*  __u8  if_bAlternateSetting; */

200         0x01,       /*  __u8  if_bNumEndpoints; */

    201         0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */

    202         0x00,       /*  __u8  if_bInterfaceSubClass; */

    203         0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */

    204         0x00,       /*  __u8  if_iInterface; */

    205

    206         /* one endpoint (status change endpoint) */

    207         0x07,       /*  __u8  ep_bLength; */

    208         0x05,       /*  __u8  ep_bDescriptorType; Endpoint */

    209         0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */

    210         0x03,       /*  __u8  ep_bmAttributes; Interrupt */

    211         0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */

    212         0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */

    213 };

    214

    215 static const u8 hs_rh_config_descriptor [] = {

    216

    217         /* one configuration */

    218         0x09,       /*  __u8  bLength; */

    219         0x02,       /*  __u8  bDescriptorType; Configuration */

    220         0x19, 0x00, /*  __le16 wTotalLength; */

    221         0x01,       /*  __u8  bNumInterfaces; (1) */

    222         0x01,       /*  __u8  bConfigurationValue; */

    223         0x00,       /*  __u8  iConfiguration; */

    224         0xc0,       /*  __u8  bmAttributes;

    225                                  Bit 7: must be set,

    226                                      6: Self-powered,

    227                                      5: Remote wakeup,

    228                                      4..0: resvd */

    229         0x00,       /*  __u8  MaxPower; */

    230

    231         /* USB 1.1:

    232          * USB 2.0, single TT organization (mandatory):

    233          *      one interface, protocol 0

    234          *

    235          * USB 2.0, multiple TT organization (optional):

    236          *      two interfaces, protocols 1 (like single TT)

    237          *      and 2 (multiple TT mode) ... config is

    238          *      sometimes settable

    239          *      NOT IMPLEMENTED

    240          */

    241

    242         /* one interface */

243         0x09,       /*  __u8  if_bLength; */

    244         0x04,       /*  __u8  if_bDescriptorType; Interface */

    245         0x00,       /*  __u8  if_bInterfaceNumber; */

    246         0x00,       /*  __u8  if_bAlternateSetting; */

    247         0x01,       /*  __u8  if_bNumEndpoints; */

    248         0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */

    249         0x00,       /*  __u8  if_bInterfaceSubClass; */

    250         0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */

    251         0x00,       /*  __u8  if_iInterface; */

    252

    253         /* one endpoint (status change endpoint) */

    254         0x07,       /*  __u8  ep_bLength; */

    255         0x05,       /*  __u8  ep_bDescriptorType; Endpoint */

    256         0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */

    257         0x03,       /*  __u8  ep_bmAttributes; Interrupt */

    258                     /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)

    259                      * see hub.c:hub_configure() for details. */

    260         (USB_MAXCHILDREN + 1 + 7) / 8, 0x00,

    261         0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */

    262 };

如果是设备请求且方向为IN,而且是USB_REQ_GET_INTERFACE,则设置len1

如果是设备请求且方向为OUT,而且是USB_REQ_SET_INTERFACE,则如何如何.

如果是设备请求且方向为OUT,而且是USB_REQ_SET_ADDRESS,则如何如何.

如果是端点请求且方向为IN,而且是USB_REQ_GET_STATUS,则如何如何.

如果是端点请求且方向为OUT,而且是USB_REQ_CLEAR_FEATURE或者USB_REQ_SET_FEATURE,则如何如何.

以上这些设置,统统是和usb spec中规定的东西相匹配的.

如果是Hub特定的类请求,而且是GetHubStatus或者是GetPortStatus,则设置len4.

如果是Hub特定的类请求,而且是GetHubDescriptor,则设置lenusb_hub_descriptor结构体的大小.

最后对于Hub特定的类请求需要调用主机控制器驱动程序的hub_control函数,对于uhci_driver来说,这个指针被赋值为uhci_hub_control,来自drivers/usb/host/uhci-hub.c:

    238 /* size of returned buffer is part of USB spec */

    239 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,

    240                         u16 wIndex, char *buf, u16 wLength)

    241 {

    242         struct uhci_hcd *uhci = hcd_to_uhci(hcd);

    243         int status, lstatus, retval = 0, len = 0;

    244         unsigned int port = wIndex - 1;

    245         unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port;

    246         u16 wPortChange, wPortStatus;

    247         unsigned long flags;

    248

    249         if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)

    250                 return -ETIMEDOUT;

    251

    252         spin_lock_irqsave(&uhci->lock, flags);

    253         switch (typeReq) {

    254

    255         case GetHubStatus:

    256                 *(__le32 *)buf = cpu_to_le32(0);

    257                 OK(4);          /* hub power */

    258         case GetPortStatus:

    259                 if (port >= uhci->rh_numports)

    260                         goto err;

    261

    262                 uhci_check_ports(uhci);

    263                 status = inw(port_addr);

    264

    265                 /* Intel controllers report the OverCurrent bit active on.

    266                  * VIA controllers report it active off, so we'll adjust the

    267                  * bit value.  (It's not standardized in the UHCI spec.)

    268                  */

    269                 if (to_pci_dev(hcd->self.controller)->vendor ==

    270                                 PCI_VENDOR_ID_VIA)

    271                         status ^= USBPORTSC_OC;

    272

    273                 /* UHCI doesn't support C_RESET (always false) */

    274                 wPortChange = lstatus = 0;

    275                 if (status & USBPORTSC_CSC)

    276                         wPortChange |= USB_PORT_STAT_C_CONNECTION;

277                 if (status & USBPORTSC_PEC)

    278                         wPortChange |= USB_PORT_STAT_C_ENABLE;

    279                 if ((status & USBPORTSC_OCC) && !ignore_oc)

    280                         wPortChange |= USB_PORT_STAT_C_OVERCURRENT;

    281

    282                 if (test_bit(port, &uhci->port_c_suspend)) {

    283                         wPortChange |= USB_PORT_STAT_C_SUSPEND;

    284                         lstatus |= 1;

    285                 }

    286                 if (test_bit(port, &uhci->resuming_ports))

    287                         lstatus |= 4;

    288

    289                 /* UHCI has no power switching (always on) */

    290                 wPortStatus = USB_PORT_STAT_POWER;

    291                 if (status & USBPORTSC_CCS)

    292                         wPortStatus |= USB_PORT_STAT_CONNECTION;

    293                 if (status & USBPORTSC_PE) {

    294                         wPortStatus |= USB_PORT_STAT_ENABLE;

    295                         if (status & SUSPEND_BITS)

    296                                 wPortStatus |= USB_PORT_STAT_SUSPEND;

    297                 }

    298                 if (status & USBPORTSC_OC)

    299                         wPortStatus |= USB_PORT_STAT_OVERCURRENT;

    300                 if (status & USBPORTSC_PR)

    301                         wPortStatus |= USB_PORT_STAT_RESET;

    302                 if (status & USBPORTSC_LSDA)

    303                         wPortStatus |= USB_PORT_STAT_LOW_SPEED;

    304

    305                 if (wPortChange)

    306                         dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x/n",

    307                                         wIndex, status, lstatus);

    308

    309                 *(__le16 *)buf = cpu_to_le16(wPortStatus);

    310                 *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange);

    311                 OK(4);

    312         case SetHubFeature:             /* We don't implement these */

    313         case ClearHubFeature:

    314                 switch (wValue) {

    315                 case C_HUB_OVER_CURRENT:

    316                 case C_HUB_LOCAL_POWER:

    317                         OK(0);

    318                 default:

319                         goto err;

    320                 }

    321                 break;

    322         case SetPortFeature:

    323                 if (port >= uhci->rh_numports)

    324                         goto err;

    325

    326                 switch (wValue) {

    327                 case USB_PORT_FEAT_SUSPEND:

    328                         SET_RH_PORTSTAT(USBPORTSC_SUSP);

    329                         OK(0);

    330                 case USB_PORT_FEAT_RESET:

    331                         SET_RH_PORTSTAT(USBPORTSC_PR);

    332

    333                         /* Reset terminates Resume signalling */

    334                         uhci_finish_suspend(uhci, port, port_addr);

    335

    336                         /* USB v2.0 7.1.7.5 */

    337                         uhci->ports_timeout = jiffies + msecs_to_jiffies(50);

    338                         OK(0);

    339                 case USB_PORT_FEAT_POWER:

    340                         /* UHCI has no power switching */

    341                         OK(0);

    342                 default:

    343                         goto err;

    344                 }

    345                 break;

    346         case ClearPortFeature:

    347                 if (port >= uhci->rh_numports)

    348                         goto err;

    349

    350                 switch (wValue) {

    351                 case USB_PORT_FEAT_ENABLE:

    352                         CLR_RH_PORTSTAT(USBPORTSC_PE);

    353

    354                         /* Disable terminates Resume signalling */

    355                         uhci_finish_suspend(uhci, port, port_addr);

    356                         OK(0);

357                 case USB_PORT_FEAT_C_ENABLE:

    358                         CLR_RH_PORTSTAT(USBPORTSC_PEC);

    359                         OK(0);

    360                 case USB_PORT_FEAT_SUSPEND:

    361                         if (!(inw(port_addr) & USBPORTSC_SUSP)) {

    362

    363                                 /* Make certain the port isn't suspended */

    364                                 uhci_finish_suspend(uhci, port, port_addr);

    365                         } else if (!test_and_set_bit(port,

    366                                                 &uhci->resuming_ports)) {

    367                                 SET_RH_PORTSTAT(USBPORTSC_RD);

    368

    369                                 /* The controller won't allow RD to be set

    370                                  * if the port is disabled.  When this happens

    371                                  * just skip the Resume signalling.

    372                                  */

    373                                 if (!(inw(port_addr) & USBPORTSC_RD))

    374                                         uhci_finish_suspend(uhci, port,

    375                                                         port_addr);

    376                                 else

    377                                         /* USB v2.0 7.1.7.7 */

    378                                         uhci->ports_timeout = jiffies +

    379                                                 msecs_to_jiffies(20);

    380                         }

    381                         OK(0);

    382                 case USB_PORT_FEAT_C_SUSPEND:

    383                         clear_bit(port, &uhci->port_c_suspend);

    384                         OK(0);

    385                 case USB_PORT_FEAT_POWER:

    386                         /* UHCI has no power switching */

    387                         goto err;

    388                 case USB_PORT_FEAT_C_CONNECTION:

    389                         CLR_RH_PORTSTAT(USBPORTSC_CSC);

    390                         OK(0);

    391                 case USB_PORT_FEAT_C_OVER_CURRENT:

    392                         CLR_RH_PORTSTAT(USBPORTSC_OCC);

    393                         OK(0);

    394                 case USB_PORT_FEAT_C_RESET:

    395                         /* this driver won't report these */

    396                         OK(0);

    397                 default:

398                         goto err;

    399                 }

    400                 break;

    401         case GetHubDescriptor:

    402                 len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength);

    403                 memcpy(buf, root_hub_hub_des, len);

    404                 if (len > 2)

    405                         buf[2] = uhci->rh_numports;

    406                 OK(len);

    407         default:

    408 err:

    409                 retval = -EPIPE;

    410         }

    411         spin_unlock_irqrestore(&uhci->lock, flags);

    412

    413         return retval;

    414 }

服了,彻底服了,变态的函数一个接着一个.莫非这群混蛋写一个200行的函数就跟我写一个20行的函数一样随便?

249,struct usb_hcd结构体的成员unsigned long flags,咱们当初在usb_add_hcd中调用set_bit函数设置了这么一个flag,HCD_FLAG_HW_ACCESSIBLE,基本上这个flag在咱们的故事中是被设置了的.另外,struct uhci_hcd结构体有一个成员unsigned int dead,它如果为1就表明控制器挂了.

然后用一个switch来处理hub特定的类请求.OK居然也是一个宏,定义于drivers/usb/host/uhci-hub.c:

     78 #define OK(x)                   len = (x); break

所以如果请求是GetHubStatus,则设置len4.

如果请求是GetPortStatus,则调用uhci_check_ports.然后读端口寄存器.USBPORTSC_CSC表示端口连接有变化,USBPORTSC_PEC表示Port Enable有变化.USBPORTSC_OCC表示Over Current有变化,struct uhci_hcd的两个成员,port_c_suspendresuming_ports都是电源管理相关的.

但无论如何,以上所做的这些都是为了获得两个东西,wPortStatuswPortChange.以此来响应GetPortStatus这个请求.

接下来,SetHubFeatureClearHubFeature咱们没啥好说的,不需要做什么.

但是SetPortFeature就有事情要做了.wValue表明具体是什么特征.

SET_RH_PORTSTAT这个宏就是专门用于设置Root Hub的端口特征的.

     80 #define CLR_RH_PORTSTAT(x) /

     81         status = inw(port_addr); /

     82         status &= ~(RWC_BITS|WZ_BITS); /

     83         status &= ~(x); /

     84         status |= RWC_BITS & (x); /

     85         outw(status, port_addr)

     86

     87 #define SET_RH_PORTSTAT(x) /

     88         status = inw(port_addr); /

     89         status |= (x); /

     90         status &= ~(RWC_BITS|WZ_BITS); /

     91         outw(status, port_addr)

对于USB_PORT_FEAT_RESET,还需要调用uhci_finish_suspend.

如果是USB_PORT_FEAT_POWER,则什么也不做,因为UHCI不吃这一套.

如果请求是ClearPortFeature,基本上也是一样的做法.除了调用的宏变成了CLR_RH_PORTSTAT.

如果请求是GetHubDescriptor,那就满足它呗.root_hub_hub_des是早就在drivers/usb/host/uhci-hub.c中定义好的:

     15 static __u8 root_hub_hub_des[] =

     16 {

     17         0x09,                   /*  __u8  bLength; */

     18         0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */

     19         0x02,                   /*  __u8  bNbrPorts; */

     20         0x0a,                   /* __u16  wHubCharacteristics; */

     21         0x00,                   /*   (per-port OC, no power switching) */

     22         0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */

     23         0x00,                   /*  __u8  bHubContrCurrent; 0 mA */

     24         0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */

     25         0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */

     26 };

回到rh_call_control,switch结束了,下面是判断statuslen.

然后调用usb_hcd_giveback_urb().来自drivers/usb/core/hcd.c:

   1373 /**

   1374  * usb_hcd_giveback_urb - return URB from HCD to device driver

   1375  * @hcd: host controller returning the URB

   1376  * @urb: urb being returned to the USB device driver.

   1377  * Context: in_interrupt()

   1378  *

   1379  * This hands the URB from HCD to its USB device driver, using its

   1380  * completion function.  The HCD has freed all per-urb resources

   1381  * (and is done using urb->hcpriv).  It also released all HCD locks;

   1382  * the device driver won't cause problems if it frees, modifies,

   1383  * or resubmits this URB.

   1384  */

   1385 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)

   1386 {

   1387         int at_root_hub;

   1388

   1389         at_root_hub = (urb->dev == hcd->self.root_hub);

   1390         urb_unlink (urb);

   1391

   1392         /* lower level hcd code should use *_dma exclusively if the

   1393          * host controller does DMA */

   1394         if (hcd->self.uses_dma && !at_root_hub) {

   1395                 if (usb_pipecontrol (urb->pipe)

   1396                         && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))

   1397                         dma_unmap_single (hcd->self.controller, urb->setup_dma,

   1398                                         sizeof (struct usb_ctrlrequest),

   1399                                         DMA_TO_DEVICE);

   1400                 if (urb->transfer_buffer_length != 0

   1401                         && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))

   1402                         dma_unmap_single (hcd->self.controller,

   1403                                         urb->transfer_dma,

   1404                                         urb->transfer_buffer_length,

   1405                                         usb_pipein (urb->pipe)

   1406                                             ? DMA_FROM_DEVICE

   1407                                             : DMA_TO_DEVICE);

   1408         }

   1409

   1410         usbmon_urb_complete (&hcd->self, urb);

   1411         /* pass ownership to the completion handler */

   1412         urb->complete (urb);

   1413         atomic_dec (&urb->use_count);

   1414         if (unlikely (urb->reject))

   1415                 wake_up (&usb_kill_urb_queue);

   1416         usb_put_urb (urb);

   1417 }

   1418 EXPORT_SYMBOL (usb_hcd_giveback_urb);

这里最重要最有意义的一行当然就是1412,调用urbcomplete函数,这正是我们在usb-storage里期待的那个函数.从此rh_call_control函数也该返回了,以后设备驱动又获得了控制权.事实上令人欣喜的是对于Root Hub,1394行开始的这一段if是不会被执行的,因为at_root_hub显然是为真.不过就算这段要执行也没什么可怕的,无非就是把之前为这个urb建立的dma映射给取消掉.而另一方面,对于Root Hub来说,complete函数基本上是什么也不做,只不过是让咱们再次回到usb_start_wait_urb,而控制传输需要的数据也已经copy到了urb->transfer_buffer中去了. 至此,Root Hub的控制传输就算结束了,即我们的usb_get_device_descriptor函数取得了空前绝后的圆满成功.

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值