coreboot/payloads/libpayload/drivers/usb/usb.c
<<
>>
Prefs
   1/*
   2 * This file is part of the libpayload project.
   3 *
   4 * Copyright (C) 2008-2010 coresystems GmbH
   5 *
   6 * Redistribution and use in source and binary forms, with or without
   7 * modification, are permitted provided that the following conditions
   8 * are met:
   9 * 1. Redistributions of source code must retain the above copyright
  10 *    notice, this list of conditions and the following disclaimer.
  11 * 2. Redistributions in binary form must reproduce the above copyright
  12 *    notice, this list of conditions and the following disclaimer in the
  13 *    documentation and/or other materials provided with the distribution.
  14 * 3. The name of the author may not be used to endorse or promote products
  15 *    derived from this software without specific prior written permission.
  16 *
  17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27 * SUCH DAMAGE.
  28 */
  29
  30//#define USB_DEBUG
  31
  32#include <libpayload-config.h>
  33#include <usb/usb.h>
  34
  35hci_t *usb_hcs = 0;
  36
  37hci_t *
  38new_controller (void)
  39{
  40        hci_t *controller = malloc (sizeof (hci_t));
  41
  42        if (controller) {
  43                /* atomic */
  44                controller->next = usb_hcs;
  45                usb_hcs = controller;
  46                /* atomic end */
  47        }
  48
  49        return controller;
  50}
  51
  52void
  53detach_controller (hci_t *controller)
  54{
  55        if (controller == NULL)
  56                return;
  57        if (usb_hcs == controller) {
  58                usb_hcs = controller->next;
  59        } else {
  60                hci_t *it = usb_hcs;
  61                while (it != NULL) {
  62                        if (it->next == controller) {
  63                                it->next = controller->next;
  64                                return;
  65                        }
  66                }
  67        }
  68}
  69
  70/**
  71 * Polls all hubs on all USB controllers, to find out about device changes
  72 */
  73void
  74usb_poll (void)
  75{
  76        if (usb_hcs == 0)
  77                return;
  78        hci_t *controller = usb_hcs;
  79        while (controller != 0) {
  80                int i;
  81                for (i = 0; i < 128; i++) {
  82                        if (controller->devices[i] != 0) {
  83                                controller->devices[i]->poll (controller->devices[i]);
  84                        }
  85                }
  86                controller = controller->next;
  87        }
  88}
  89
  90void
  91init_device_entry (hci_t *controller, int i)
  92{
  93        if (controller->devices[i] != 0)
  94                printf("warning: device %d reassigned?\n", i);
  95        controller->devices[i] = malloc(sizeof(usbdev_t));
  96        controller->devices[i]->controller = controller;
  97        controller->devices[i]->address = -1;
  98        controller->devices[i]->hub = -1;
  99        controller->devices[i]->port = -1;
 100        controller->devices[i]->init = usb_nop_init;
 101        controller->devices[i]->init (controller->devices[i]);
 102}
 103
 104void
 105set_feature (usbdev_t *dev, int endp, int feature, int rtype)
 106{
 107        dev_req_t dr;
 108
 109        dr.bmRequestType = rtype;
 110        dr.data_dir = host_to_device;
 111        dr.bRequest = SET_FEATURE;
 112        dr.wValue = feature;
 113        dr.wIndex = endp;
 114        dr.wLength = 0;
 115        dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 116}
 117
 118void
 119get_status (usbdev_t *dev, int intf, int rtype, int len, void *data)
 120{
 121        dev_req_t dr;
 122
 123        dr.bmRequestType = rtype;
 124        dr.data_dir = device_to_host;
 125        dr.bRequest = GET_STATUS;
 126        dr.wValue = 0;
 127        dr.wIndex = intf;
 128        dr.wLength = len;
 129        dev->controller->control (dev, IN, sizeof (dr), &dr, len, data);
 130}
 131
 132u8 *
 133get_descriptor (usbdev_t *dev, unsigned char bmRequestType, int descType,
 134                int descIdx, int langID)
 135{
 136        u8 buf[8];
 137        u8 *result;
 138        dev_req_t dr;
 139        int size;
 140
 141        dr.bmRequestType = bmRequestType;
 142        dr.data_dir = device_to_host;   // always like this for descriptors
 143        dr.bRequest = GET_DESCRIPTOR;
 144        dr.wValue = (descType << 8) | descIdx;
 145        dr.wIndex = langID;
 146        dr.wLength = 8;
 147        if (dev->controller->control (dev, IN, sizeof (dr), &dr, 8, buf)) {
 148                printf ("getting descriptor size (type %x) failed\n",
 149                        descType);
 150        }
 151
 152        if (descType == 1) {
 153                device_descriptor_t *dd = (device_descriptor_t *) buf;
 154                debug ("maxPacketSize0: %x\n", dd->bMaxPacketSize0);
 155                if (dd->bMaxPacketSize0 != 0)
 156                        dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 157        }
 158
 159        /* special case for configuration descriptors: they carry all their
 160           subsequent descriptors with them, and keep the entire size at a
 161           different location */
 162        size = buf[0];
 163        if (buf[1] == 2) {
 164                int realsize = ((unsigned short *) (buf + 2))[0];
 165                size = realsize;
 166        }
 167        result = malloc (size);
 168        memset (result, 0, size);
 169        dr.wLength = size;
 170        if (dev->controller->
 171            control (dev, IN, sizeof (dr), &dr, size, result)) {
 172                printf ("getting descriptor (type %x, size %x) failed\n",
 173                        descType, size);
 174        }
 175
 176        return result;
 177}
 178
 179void
 180set_configuration (usbdev_t *dev)
 181{
 182        dev_req_t dr;
 183
 184        dr.bmRequestType = 0;
 185        dr.bRequest = SET_CONFIGURATION;
 186        dr.wValue = dev->configuration[5];
 187        dr.wIndex = 0;
 188        dr.wLength = 0;
 189        dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 190}
 191
 192int
 193clear_stall (endpoint_t *ep)
 194{
 195        usbdev_t *dev = ep->dev;
 196        int endp = ep->endpoint;
 197        dev_req_t dr;
 198
 199        dr.bmRequestType = 0;
 200        if (endp != 0) {
 201                dr.req_recp = endp_recp;
 202        }
 203        dr.bRequest = CLEAR_FEATURE;
 204        dr.wValue = ENDPOINT_HALT;
 205        dr.wIndex = endp;
 206        dr.wLength = 0;
 207        dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0);
 208        ep->toggle = 0;
 209        return 0;
 210}
 211
 212/* returns free address or -1 */
 213static int
 214get_free_address (hci_t *controller)
 215{
 216        int i;
 217        for (i = 1; i < 128; i++) {
 218                if (controller->devices[i] == 0)
 219                        return i;
 220        }
 221        printf ("no free address found\n");
 222        return -1;              // no free address
 223}
 224
 225int
 226set_address (hci_t *controller, int speed)
 227{
 228        int adr = get_free_address (controller);        // address to set
 229        dev_req_t dr;
 230        configuration_descriptor_t *cd;
 231        device_descriptor_t *dd;
 232
 233        memset (&dr, 0, sizeof (dr));
 234        dr.data_dir = host_to_device;
 235        dr.req_type = standard_type;
 236        dr.req_recp = dev_recp;
 237        dr.bRequest = SET_ADDRESS;
 238        dr.wValue = adr;
 239        dr.wIndex = 0;
 240        dr.wLength = 0;
 241
 242        init_device_entry(controller, adr);
 243        usbdev_t *dev = controller->devices[adr];
 244        // dummy values for registering the address
 245        dev->address = 0;
 246        dev->speed = speed;
 247        dev->endpoints[0].dev = dev;
 248        dev->endpoints[0].endpoint = 0;
 249        dev->endpoints[0].maxpacketsize = 8;
 250        dev->endpoints[0].toggle = 0;
 251        dev->endpoints[0].direction = SETUP;
 252        mdelay (50);
 253        if (dev->controller->control (dev, OUT, sizeof (dr), &dr, 0, 0)) {
 254                printf ("set_address failed\n");
 255                return -1;
 256        }
 257        mdelay (50);
 258        dev->address = adr;
 259        dev->descriptor = get_descriptor (dev, gen_bmRequestType
 260                (device_to_host, standard_type, dev_recp), 1, 0, 0);
 261        dd = (device_descriptor_t *) dev->descriptor;
 262
 263        printf ("device 0x%04x:0x%04x is USB %x.%x ",
 264                 dd->idVendor, dd->idProduct,
 265                 dd->bcdUSB >> 8, dd->bcdUSB & 0xff);
 266        dev->quirks = usb_quirk_check(dd->idVendor, dd->idProduct);
 267
 268        debug ("\ndevice has %x configurations\n", dd->bNumConfigurations);
 269        if (dd->bNumConfigurations == 0) {
 270                /* device isn't usable */
 271                printf ("... no usable configuration!\n");
 272                dev->address = 0;
 273                return -1;
 274        }
 275
 276        dev->configuration = get_descriptor (dev, gen_bmRequestType
 277                (device_to_host, standard_type, dev_recp), 2, 0, 0);
 278        cd = (configuration_descriptor_t *) dev->configuration;
 279        set_configuration (dev);
 280        interface_descriptor_t *interface =
 281                (interface_descriptor_t *) (((char *) cd) + cd->bLength);
 282        {
 283                int i;
 284                int num = cd->bNumInterfaces;
 285                interface_descriptor_t *current = interface;
 286                debug ("device has %x interfaces\n", num);
 287                if (num > 1) {
 288                        int interfaces = usb_interface_check(dd->idVendor, dd->idProduct);
 289                        if (interfaces) {
 290                                /* Well known device, don't warn */
 291                                num = interfaces;
 292                        } else {
 293
 294                                printf ("\nNOTICE: This driver defaults to using the first interface.\n"
 295                                        "This might be the wrong choice and lead to limited functionality\n"
 296                                        "of the device. Please report such a case to coreboot@coreboot.org\n"
 297                                        "as you might be the first.\n");
 298                                /* we limit to the first interface, as there was no need to
 299                                 * implement something else for the time being. If you need
 300                                 * it, see the SetInterface and GetInterface functions in
 301                                 * the USB specification, and adapt appropriately.
 302                                 */
 303                                num = (num > 1) ? 1 : num;
 304                        }
 305                }
 306                for (i = 0; i < num; i++) {
 307                        int j;
 308                        debug (" #%x has %x endpoints, interface %x:%x, protocol %x\n",
 309                                        current->bInterfaceNumber, current->bNumEndpoints, current->bInterfaceClass, current->bInterfaceSubClass, current->bInterfaceProtocol);
 310                        endpoint_descriptor_t *endp =
 311                                (endpoint_descriptor_t *) (((char *) current)
 312                                                           + current->bLength);
 313                        if (interface->bInterfaceClass == 0x3)
 314                                endp = (endpoint_descriptor_t *) (((char *) endp) + ((char *) endp)[0]);        // ignore HID descriptor
 315                        memset (dev->endpoints, 0, sizeof (dev->endpoints));
 316                        dev->num_endp = 1;      // 0 always exists
 317                        dev->endpoints[0].dev = dev;
 318                        dev->endpoints[0].maxpacketsize = dd->bMaxPacketSize0;
 319                        dev->endpoints[0].direction = SETUP;
 320                        dev->endpoints[0].type = CONTROL;
 321                        for (j = 1; j <= current->bNumEndpoints; j++) {
 322#ifdef USB_DEBUG
 323                                static const char *transfertypes[4] = {
 324                                        "control", "isochronous", "bulk", "interrupt"
 325                                };
 326                                debug ("   #%x: Endpoint %x (%s), max packet size %x, type %s\n", j, endp->bEndpointAddress & 0x7f, ((endp->bEndpointAddress & 0x80) != 0) ? "in" : "out", endp->wMaxPacketSize, transfertypes[endp->bmAttributes]);
 327#endif
 328                                endpoint_t *ep =
 329                                        &dev->endpoints[dev->num_endp++];
 330                                ep->dev = dev;
 331                                ep->endpoint = endp->bEndpointAddress;
 332                                ep->toggle = 0;
 333                                ep->maxpacketsize = endp->wMaxPacketSize;
 334                                ep->direction =
 335                                        ((endp->bEndpointAddress & 0x80) ==
 336                                         0) ? OUT : IN;
 337                                ep->type = endp->bmAttributes;
 338                                endp = (endpoint_descriptor_t
 339                                        *) (((char *) endp) + endp->bLength);
 340                        }
 341                        current = (interface_descriptor_t *) endp;
 342                }
 343        }
 344
 345        int class = dd->bDeviceClass;
 346        if (class == 0)
 347                class = interface->bInterfaceClass;
 348
 349        enum {
 350                audio_device      = 0x01,
 351                comm_device       = 0x02,
 352                hid_device        = 0x03,
 353                physical_device   = 0x05,
 354                imaging_device    = 0x06,
 355                printer_device    = 0x07,
 356                msc_device        = 0x08,
 357                hub_device        = 0x09,
 358                cdc_device        = 0x0a,
 359                ccid_device       = 0x0b,
 360                security_device   = 0x0d,
 361                video_device      = 0x0e,
 362                healthcare_device = 0x0f,
 363                diagnostic_device = 0xdc,
 364                wireless_device   = 0xe0,
 365                misc_device       = 0xef,
 366        };
 367
 368        switch (class) {
 369        case audio_device:
 370                printf("(Audio)\n");
 371                break;
 372        case comm_device:
 373                printf("(Communication)\n");
 374                break;
 375        case hid_device:
 376                printf ("(HID)\n");
 377#ifdef CONFIG_USB_HID
 378                controller->devices[adr]->init = usb_hid_init;
 379#else
 380                printf ("NOTICE: USB HID support not compiled in\n");
 381#endif
 382                break;
 383        case physical_device:
 384                printf("(Physical)\n");
 385                break;
 386        case imaging_device:
 387                printf("(Camera)\n");
 388                break;
 389        case printer_device:
 390                printf("(Printer)\n");
 391                break;
 392        case msc_device:
 393                printf ("(MSC)\n");
 394#ifdef CONFIG_USB_MSC
 395                controller->devices[adr]->init = usb_msc_init;
 396#else
 397                printf ("NOTICE: USB MSC support not compiled in\n");
 398#endif
 399                break;
 400        case hub_device:
 401                printf ("(Hub)\n");
 402#ifdef CONFIG_USB_HUB
 403                controller->devices[adr]->init = usb_hub_init;
 404#else
 405                printf ("NOTICE: USB hub support not compiled in.\n");
 406#endif
 407                break;
 408        case cdc_device:
 409                printf("(CDC)\n");
 410                break;
 411        case ccid_device:
 412                printf ("(Smart Card / CCID)\n");
 413                break;
 414        case security_device:
 415                printf("(Content Security)\n");
 416                break;
 417        case video_device:
 418                printf("(Video)\n");
 419                break;
 420        case healthcare_device:
 421                printf("(Healthcare)\n");
 422                break;
 423        case diagnostic_device:
 424                printf("(Diagnostic)\n");
 425                break;
 426        case wireless_device:
 427                printf("(Wireless)\n");
 428                break;
 429        default:
 430                printf ("(unsupported class %x)\n", class);
 431                break;
 432        }
 433        return adr;
 434}
 435
 436void
 437usb_detach_device(hci_t *controller, int devno)
 438{
 439        controller->devices[devno]->destroy (controller->devices[devno]);
 440        free(controller->devices[devno]);
 441        controller->devices[devno] = 0;
 442}
 443
 444int
 445usb_attach_device(hci_t *controller, int hubaddress, int port, int speed)
 446{
 447        static const char* speeds[] = { "full", "low", "high" };
 448        printf ("%sspeed device\n", (speed <= 2) ? speeds[speed] : "invalid value - no");
 449        int newdev = set_address (controller, speed);
 450        if (newdev == -1)
 451                return -1;
 452        usbdev_t *newdev_t = controller->devices[newdev];
 453
 454        newdev_t->address = newdev;
 455        newdev_t->hub = hubaddress;
 456        newdev_t->port = port;
 457        // determine responsible driver - current done in set_address
 458        newdev_t->init (newdev_t);
 459        return newdev;
 460}
 461
 462void
 463usb_fatal (const char *message)
 464{
 465        printf(message);
 466        for (;;) ;
 467}
 468
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.