On 16/10/08 20:39 +0200, Patrick Georgi wrote:
> Hi,
> 
> the following patch contains lots of changes to the USB code. While some
> of it isn't finished yet, it should only improve matters.
> what's in:
>  - reduced memory requirements a lot (from >100kb/controller to
> 560bytes/controller)
>  - no need for the client of libpayload to implement
> usbdisk_{create,remove}, just because USB was compiled in.
>  - usb hub support compiles, and works for some trivial cases (no device
> detach, trivial power management)
>  - usb keyboard support works in qemu, though there are reports that it
> doesn't work on real hardware yet.
>  - usb keyboard is integrated in both libc-getchar() and curses, if
> CONFIG_USB_HID is enabled
> 
> Signed-off-by: Patrick Georgi <[EMAIL PROTECTED]>
 
Acked-by: Jordan Crouse <[EMAIL PROTECTED]>

Numerous cleanups and issues here, but we can fix those as we go along.

> ==================================================================
> --- include/libpayload.h      (/coreboot/libpayload)  (revision 2215)
> +++ include/libpayload.h      (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -114,6 +114,8 @@
>   * @{
>   */
>  int usb_initialize(void);                                                    
>   
> +int usbhid_havechar(void);
> +int usbhid_getchar(void);
>  /** @} */
>  
>  /**
> ==================================================================
> --- include/usb/usb.h (/coreboot/libpayload)  (revision 2215)
> +++ include/usb/usb.h (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -114,7 +114,7 @@
>       struct usbdev_hc *next;
>       pcidev_t bus_address;
>       u32 reg_base;
> -     usbdev_t devices[128];  // dev 0 is root hub, 127 is last addressable
> +     usbdev_t *devices[128]; // dev 0 is root hub, 127 is last addressable
>       void (*start) (hci_t *controller);
>       void (*stop) (hci_t *controller);
>       void (*reset) (hci_t *controller);
> @@ -124,6 +124,9 @@
>       int (*bulk) (endpoint_t *ep, int size, u8 *data, int finalize);
>       int (*control) (usbdev_t *dev, pid_t pid, int dr_length,
>                       void *devreq, int data_length, u8 *data);
> +     void* (*create_intr_queue) (endpoint_t *ep, int reqsize, int reqcount, 
> int reqtiming);
> +     void (*destroy_intr_queue) (endpoint_t *ep, void *queue);
> +     u8* (*poll_intr_queue) (void *queue);
>       void *instance;
>  };
>  
> @@ -221,4 +224,6 @@
>       return (dir << 7) | (type << 5) | recp;
>  }
>  
> +void usb_detach_device(hci_t *controller, int devno);
> +int usb_attach_device(hci_t *controller, int hubaddress, int port, int 
> lowspeed);
>  #endif
> === include/usb/usbdisk.h
> ==================================================================
> --- include/usb/usbdisk.h     (/coreboot/libpayload)  (revision 2215)
> +++ include/usb/usbdisk.h     (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -38,7 +38,7 @@
>   *
>   * @param dev descriptor for the USB storage device
>   */
> -void usbdisk_create (usbdev_t *dev);
> +void __attribute__((weak)) usbdisk_create (usbdev_t *dev);
>  
>  /**
>   * To be implemented by libpayload-client. It's called by the USB stack
> @@ -46,6 +46,6 @@
>   *
>   * @param dev descriptor for the USB storage device
>   */
> -void usbdisk_remove (usbdev_t *dev);
> +void __attribute__((weak)) usbdisk_remove (usbdev_t *dev);
>  
>  #endif
> === curses/keyboard.c
> ==================================================================
> --- curses/keyboard.c (/coreboot/libpayload)  (revision 2215)
> +++ curses/keyboard.c (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -38,6 +38,7 @@
>   */
>  
>  #include <config.h>
> +#include <usb/usb.h>
>  #include "local.h"
>  
>  static int _halfdelay = 0;
> @@ -145,6 +146,14 @@
>       unsigned short c;
>  
>       do {
> +#ifdef CONFIG_USB_HID
> +             usb_poll();
> +             if ((curses_flags & F_ENABLE_CONSOLE) &&
> +                 usbhid_havechar()) {
> +                     c = usbhid_getchar();
> +                     if (c != 0) return c;
> +             }
> +#endif
>  #ifdef CONFIG_PC_KEYBOARD
>               if ((curses_flags & F_ENABLE_CONSOLE) &&
>                   keyboard_havechar()) {
> === libc/console.c
> ==================================================================
> --- libc/console.c    (/coreboot/libpayload)  (revision 2215)
> +++ libc/console.c    (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -29,6 +29,7 @@
>  
>  #include <config.h>
>  #include <libpayload.h>
> +#include <usb/usb.h>
>  
>  void console_init(void)
>  {
> @@ -77,6 +78,11 @@
>  
>  int havekey(void)
>  {
> +#ifdef CONFIG_USB_HID
> +     usb_poll();
> +     if (usbhid_havechar())
> +             return 1;
> +#endif
>  #ifdef CONFIG_SERIAL_CONSOLE
>       if (serial_havechar())
>               return 1;
> @@ -95,6 +101,11 @@
>  int getchar(void)
>  {
>       while (1) {
> +#ifdef CONFIG_USB_HID
> +             usb_poll();
> +             if (usbhid_havechar())
> +                     return usbhid_getchar();
> +#endif
>  #ifdef CONFIG_SERIAL_CONSOLE
>               if (serial_havechar())
>                       return serial_getchar();
> === drivers/keyboard.c
> ==================================================================
> --- drivers/keyboard.c        (/coreboot/libpayload)  (revision 2215)
> +++ drivers/keyboard.c        (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -299,7 +299,7 @@
>  /**
>   * Set keyboard layout
>   * @param country string describing the keyboard layout language. 
> - * Valid values are "en", "de".
> + * Valid values are "us", "de".
>   */
>  
>  int keyboard_set_layout(char *country)
> 
> === drivers/usb/usbhid.c
> ==================================================================
> --- drivers/usb/usbhid.c      (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/usbhid.c      (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -28,9 +28,10 @@
>   */
>  
>  #include <usb/usb.h>
> +#include <curses.h>
>  
>  enum { hid_subclass_none = 0, hid_subclass_boot = 1 };
> -enum { hid_proto_boot = 0, hid_proto_report = 1 };
> +typedef enum { hid_proto_boot = 0, hid_proto_report = 1 } hid_proto;
>  enum { hid_boot_proto_none = 0, hid_boot_proto_keyboard =
>               1, hid_boot_proto_mouse = 2
>  };
> @@ -42,22 +43,42 @@
>  static void
>  usb_hid_destroy (usbdev_t *dev)
>  {
> +     free (dev->data);
>  }
>  
> +typedef struct {
> +     void* queue;
> +} usbhid_inst_t;
> +
> +#define HID_INST(dev) ((usbhid_inst_t*)(dev)->data)
> +
> +/* buffer is global to all keyboard drivers */
> +int count;
> +short keybuffer[16];
> +
>  int keypress;
> -char keymap[256] = {
> -     -1, -1, -1, -1, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
> -     'l',
> -     'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
> -     '1', '2',
> -     '3', '4', '5', '6', '7', '8', '9', '0', '\n', TERM_ESC,
> -     TERM_BACKSPACE, TERM_TAB, ' ', '-', '=', '[',
> -     ']', '\\', -1, ';', '\'', '`', ',', '.', '/', -1, -1, -1, -1, -1, -1,
> -     -1,
> -     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, TERM_HOME, TERM_PPAGE, -1,
> -     TERM_END, TERM_NPAGE, TERM_RIGHT,
> -     TERM_LEFT, TERM_DOWN, TERM_UP, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> -     -1, -1, -1,
> +short keymap[256] = {
> +     -1, -1, -1, -1, 'a', 'b', 'c', 'd',
> +     'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
> +
> +     'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
> +     'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
> +
> +     '3', '4', '5', '6', '7', '8', '9', '0',
> +     '\n', '\e', '\b', '\t', ' ', '-', '=', '[',
> +
> +     ']', '\\', -1, ';', '\'', '`', ',', '.',
> +     '/', -1, KEY_F(1), KEY_F(2), KEY_F(3), KEY_F(4), KEY_F(5), KEY_F(6),
> +
> +     KEY_F(7), KEY_F(8), KEY_F(9), KEY_F(10), KEY_F(11), KEY_F(12), -1, -1,
> +     -1, -1, -1, -1, -1, -1, -1, -1,
> +/* 50 */
> +     -1, -1, -1, -1, -1, '*', '-', '+',
> +     -1, KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT, -1, KEY_RIGHT, KEY_HOME,
> +
> +     KEY_UP, KEY_PPAGE, -1, -1, -1, -1, -1, -1,
> +     -1, -1, -1, -1, -1, -1, -1, -1,
> +
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> @@ -67,71 +88,111 @@
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
>       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
> -     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
>  };
>  
>  
>  static void
>  usb_hid_poll (usbdev_t *dev)
>  {
> -     char buf[8];
> -     static int toggle = 0;
> -     // hardcode to endpoint 1, 8 bytes
> -     dev->controller->packet (dev, 1, IN, toggle, 8, buf);
> -     toggle ^= 1;
> -     // FIXME: manage buf[0]=special keys, too
> -     keypress = keymap[buf[2]];
> -     if ((keypress == -1) && (buf[2] != 0)) {
> -             printf ("%x %x %x %x %x %x %x %x\n", buf[0], buf[1], buf[2],
> -                     buf[3], buf[4], buf[5], buf[6], buf[7]);
> +     u8* buf;
> +     while ((buf=dev->controller->poll_intr_queue (HID_INST(dev)->queue))) {
> +             // FIXME: manage buf[0]=special keys, too
> +             int i;
> +             keypress = 0;
> +             for (i=2; i<9; i++) {
> +                     if (buf[i] != 0)
> +                             keypress = keymap[buf[i]];
> +                     else
> +                             break;
> +             }
> +             if ((keypress == -1) && (buf[2] != 0)) {
> +                     printf ("%x %x %x %x %x %x %x %x\n", buf[0], buf[1], 
> buf[2],
> +                             buf[3], buf[4], buf[5], buf[6], buf[7]);
> +             }
> +             if (keypress != -1) {
> +                     /* ignore key presses if buffer full */
> +                     if (count < 16)
> +                             keybuffer[count++] = keypress;
> +             }
>       }
>  }
>  
> -int (*oldhook) (void);
> +static void
> +usb_hid_set_idle (usbdev_t *dev, interface_descriptor_t *interface, u16 
> duration)
> +{
> +     dev_req_t dr;
> +     dr.data_dir = host_to_device;
> +     dr.req_type = class_type;
> +     dr.req_recp = iface_recp;
> +     dr.bRequest = SET_IDLE;
> +     dr.wValue = (duration >> 2) << 8;
> +     dr.wIndex = interface->bInterfaceNumber;
> +     dr.wLength = 0;
> +     dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
> +}
>  
> -int
> -hookfunc (void)
> +static void
> +usb_hid_set_protocol (usbdev_t *dev, interface_descriptor_t *interface, 
> hid_proto proto)
>  {
> -     int key;
> -     if (oldhook != 0)
> -             key = oldhook ();
> -     if (key == -1)
> -             key = keypress;
> -     return key;
> +     dev_req_t dr;
> +     dr.data_dir = host_to_device;
> +     dr.req_type = class_type;
> +     dr.req_recp = iface_recp;
> +     dr.bRequest = SET_PROTOCOL;
> +     dr.wValue = proto;
> +     dr.wIndex = interface->bInterfaceNumber;
> +     dr.wLength = 0;
> +     dev->controller->control (dev, OUT, sizeof (dev_req_t), &dr, 0, 0);
>  }
>  
>  void
>  usb_hid_init (usbdev_t *dev)
>  {
>  
> -     configuration_descriptor_t *cd = dev->configuration;
> -     interface_descriptor_t *interface = ((char *) cd) + cd->bLength;
> +     configuration_descriptor_t *cd = 
> (configuration_descriptor_t*)dev->configuration;
> +     interface_descriptor_t *interface = (interface_descriptor_t*)(((char *) 
> cd) + cd->bLength);
>  
>       if (interface->bInterfaceSubClass == hid_subclass_boot) {
>               printf ("  supports boot interface..\n");
>               printf ("  it's a %s\n",
>                       boot_protos[interface->bInterfaceProtocol]);
>               if (interface->bInterfaceProtocol == hid_boot_proto_keyboard) {
> +                     dev->data = malloc (sizeof (usbhid_inst_t));
> +                     printf ("  configuring...\n");
> +                     usb_hid_set_protocol(dev, interface, hid_proto_boot);
> +                     usb_hid_set_idle(dev, interface, 0);
>                       printf ("  activating...\n");
> -                     dev_req_t dr;
> -                     // set_protocol(hid_proto_boot)
> -                     dr.data_dir = host_to_device;
> -                     dr.req_type = class_type;
> -                     dr.req_recp = iface_recp;
> -                     dr.bRequest = SET_PROTOCOL;
> -                     dr.wValue = hid_proto_boot;
> -                     dr.wIndex = interface->bInterfaceNumber;
> -                     dr.wLength = 0;
> -                     dev->controller->control (dev, OUT,
> -                                               sizeof (dev_req_t), &dr, 0,
> -                                               0);
>  
>                       // only add here, because we only support boot-keyboard 
> HID devices
> -                     // FIXME: make this a real console input driver 
> instead, once the API is there
>                       dev->destroy = usb_hid_destroy;
>                       dev->poll = usb_hid_poll;
> -                     oldhook = getkey_hook;
> -                     getkey_hook = hookfunc;
> +                     int i;
> +                     for (i = 1; i <= dev->num_endp; i++) {
> +                             if (dev->endpoints[i].endpoint == 0)
> +                                     continue;
> +                             if (dev->endpoints[i].type != INTERRUPT)
> +                                     continue;
> +                             if (dev->endpoints[i].direction != IN)
> +                                     continue;
> +                             break;
> +                     }
> +                     /* 20 buffers of 8 bytes, for every 10 msecs */
> +                     HID_INST(dev)->queue = 
> dev->controller->create_intr_queue (&dev->endpoints[i], 8, 20, 10);
> +                     count = 0;
> +                     printf ("  configuration done.\n");
>               }
>       }
>  }
> +
> +int usbhid_havechar (void)
> +{
> +     return (count != 0);
> +}
> +
> +int usbhid_getchar (void)
> +{
> +     if (count == 0) return 0;
> +     short ret = keybuffer[0];
> +     memmove (keybuffer, keybuffer+1, --count);
> +     return ret;
> +}
> === drivers/usb/uhci_rh.c
> ==================================================================
> --- drivers/usb/uhci_rh.c     (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/uhci_rh.c     (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -88,17 +88,13 @@
>       } else
>               return;
>       int devno = RH_INST (dev)->port[offset];
> -     if (devno != -1) {
> -             dev->controller->devices[devno].destroy (&dev->controller->
> -                                                      devices[devno]);
> -             init_device_entry (dev->controller, devno);
> +     if ((dev->controller->devices[devno] != 0) && (devno != -1)) {
> +             usb_detach_device(dev->controller, devno);
>               RH_INST (dev)->port[offset] = -1;
>       }
>       uhci_reg_mask16 (dev->controller, portsc, ~0, (1 << 3) | (1 << 2));     
> // clear port state change, enable port
>  
>       if ((uhci_reg_read16 (dev->controller, portsc) & 1) != 0) {
> -             int newdev;
> -             usbdev_t *newdev_t;
>               // device attached
>  
>               uhci_rh_disable_port (dev, port);
> @@ -106,18 +102,8 @@
>  
>               int lowspeed =
>                       (uhci_reg_read16 (dev->controller, portsc) >> 8) & 1;
> -             printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
>  
> -             newdev = set_address (dev->controller, lowspeed);
> -             if (newdev == -1)
> -                     return;
> -             newdev_t = &dev->controller->devices[newdev];
> -             RH_INST (dev)->port[offset] = newdev;
> -             newdev_t->address = newdev;
> -             newdev_t->hub = dev->address;
> -             newdev_t->port = portsc;
> -             // determine responsible driver
> -             newdev_t->init (newdev_t);
> +             RH_INST (dev)->port[offset] = 
> usb_attach_device(dev->controller, dev->address, portsc, lowspeed);
>       }
>  }
>  
> === drivers/usb/uhci.c
> ==================================================================
> --- drivers/usb/uhci.c        (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/uhci.c        (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -40,6 +40,9 @@
>  static int uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize);
>  static int uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq,
>                        int dalen, u8 *data);
> +static void* uhci_create_intr_queue (endpoint_t *ep, int reqsize, int 
> reqcount, int reqtiming);
> +static void uhci_destroy_intr_queue (endpoint_t *ep, void *queue);
> +static u8* uhci_poll_intr_queue (void *queue);
>  
>  #if 0
>  /* dump uhci */
> @@ -119,7 +122,14 @@
>       controller->packet = uhci_packet;
>       controller->bulk = uhci_bulk;
>       controller->control = uhci_control;
> -     UHCI_INST (controller)->roothub = &(controller->devices[0]);
> +     controller->create_intr_queue = uhci_create_intr_queue;
> +     controller->destroy_intr_queue = uhci_destroy_intr_queue;
> +     controller->poll_intr_queue = uhci_poll_intr_queue;
> +     for (i = 1; i < 128; i++) {
> +             controller->devices[i] = 0;
> +     }
> +     init_device_entry (controller, 0);
> +     UHCI_INST (controller)->roothub = controller->devices[0];
>  
>       controller->bus_address = addr;
>       controller->reg_base = pci_read_config32 (controller->bus_address, 
> 0x20) & ~1;  /* ~1 clears the register type indicator that is set to 1 for IO 
> space */
> @@ -134,10 +144,27 @@
>       memset (UHCI_INST (controller)->framelistptr, 0,
>               1024 * sizeof (flistp_t));
>  
> +     /* According to the *BSD UHCI code, this one is needed on some
> +        PIIX chips, because otherwise they misbehave. It must be
> +        added to the last chain.
> +
> +        FIXME: this leaks, if the driver should ever be reinited
> +               for some reason. Not a problem now.
> +        */
> +     td_t *antiberserk = memalign(16, sizeof(td_t));
> +     memset(antiberserk, 0, sizeof(td_t));
> +
> +     UHCI_INST (controller)->qh_prei = memalign (16, sizeof (qh_t));
>       UHCI_INST (controller)->qh_intr = memalign (16, sizeof (qh_t));
>       UHCI_INST (controller)->qh_data = memalign (16, sizeof (qh_t));
>       UHCI_INST (controller)->qh_last = memalign (16, sizeof (qh_t));
>  
> +     UHCI_INST (controller)->qh_prei->headlinkptr.ptr =
> +             virt_to_phys (UHCI_INST (controller)->qh_intr);
> +     UHCI_INST (controller)->qh_prei->headlinkptr.queue_head = 1;
> +     UHCI_INST (controller)->qh_prei->elementlinkptr.ptr = 0;
> +     UHCI_INST (controller)->qh_prei->elementlinkptr.terminate = 1;
> +
>       UHCI_INST (controller)->qh_intr->headlinkptr.ptr =
>               virt_to_phys (UHCI_INST (controller)->qh_data);
>       UHCI_INST (controller)->qh_intr->headlinkptr.queue_head = 1;
> @@ -150,23 +177,20 @@
>       UHCI_INST (controller)->qh_data->elementlinkptr.ptr = 0;
>       UHCI_INST (controller)->qh_data->elementlinkptr.terminate = 1;
>  
> -     UHCI_INST (controller)->qh_last->headlinkptr.ptr = 0;
> +     UHCI_INST (controller)->qh_last->headlinkptr.ptr = virt_to_phys 
> (UHCI_INST (controller)->qh_data);
>       UHCI_INST (controller)->qh_last->headlinkptr.terminate = 1;
> -     UHCI_INST (controller)->qh_last->elementlinkptr.ptr = 0;
> +     UHCI_INST (controller)->qh_last->elementlinkptr.ptr = virt_to_phys 
> (antiberserk);
>       UHCI_INST (controller)->qh_last->elementlinkptr.terminate = 1;
>  
>       for (i = 0; i < 1024; i++) {
>               UHCI_INST (controller)->framelistptr[i].ptr =
> -                     virt_to_phys (UHCI_INST (controller)->qh_intr);
> +                     virt_to_phys (UHCI_INST (controller)->qh_prei);
>               UHCI_INST (controller)->framelistptr[i].terminate = 0;
>               UHCI_INST (controller)->framelistptr[i].queue_head = 1;
>       }
> -     for (i = 1; i < 128; i++) {
> -             init_device_entry (controller, i);
> -     }
> -     controller->devices[0].controller = controller;
> -     controller->devices[0].init = uhci_rh_init;
> -     controller->devices[0].init (&controller->devices[0]);
> +     controller->devices[0]->controller = controller;
> +     controller->devices[0]->init = uhci_rh_init;
> +     controller->devices[0]->init (controller->devices[0]);
>       uhci_reset (controller);
>       return controller;
>  }
> @@ -181,6 +205,7 @@
>                                                 roothub);
>       uhci_reg_mask16 (controller, USBCMD, 0, 0);     // stop work
>       free (UHCI_INST (controller)->framelistptr);
> +     free (UHCI_INST (controller)->qh_prei);
>       free (UHCI_INST (controller)->qh_intr);
>       free (UHCI_INST (controller)->qh_data);
>       free (UHCI_INST (controller)->qh_last);
> @@ -205,12 +230,12 @@
>  static td_t *
>  wait_for_completed_qh (hci_t *controller, qh_t *qh)
>  {
> -     int timeout = 1000;     /* max 30 ms. */
> +     int timeout = 1000000;  /* max 30 ms. */
>       void *current = GET_TD (qh->elementlinkptr.ptr);
>       while ((qh->elementlinkptr.terminate == 0) && (timeout-- > 0)) {
>               if (current != GET_TD (qh->elementlinkptr.ptr)) {
>                       current = GET_TD (qh->elementlinkptr.ptr);
> -                     timeout = 1000;
> +                     timeout = 1000000;
>               }
>               uhci_reg_mask16 (controller, USBSTS, ~0, 0);    // clear 
> resettable registers
>               udelay (30);
> @@ -449,6 +474,130 @@
>       return 0;
>  }
>  
> +typedef struct {
> +     qh_t *qh;
> +     td_t *tds;
> +     td_t *last_td;
> +     u8 *data;
> +     int lastread;
> +     int total;
> +     int reqsize;
> +} intr_q;
> +
> +/* create and hook-up an intr queue into device schedule */
> +static void*
> +uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int 
> reqtiming)
> +{
> +     u8 *data = malloc(reqsize*reqcount);
> +     td_t *tds = memalign(16, sizeof(td_t) * reqcount);
> +     qh_t *qh = memalign(16, sizeof(qh_t));
> +
> +     qh->elementlinkptr.ptr = virt_to_phys(tds);
> +     qh->elementlinkptr.terminate = 0;
> +
> +     intr_q *q = malloc(sizeof(intr_q));
> +     q->qh = qh;
> +     q->tds = tds;
> +     q->data = data;
> +     q->lastread = 0;
> +     q->total = reqcount;
> +     q->reqsize = reqsize;
> +     q->last_td = &tds[reqcount - 1];
> +
> +     memset (tds, 0, sizeof (td_t) * reqcount);
> +     int i;
> +     for (i = 0; i < reqcount; i++) {
> +             tds[i].ptr = virt_to_phys (&tds[i + 1]);
> +             tds[i].terminate = 0;
> +             tds[i].queue_head = 0;
> +             tds[i].depth_first = 0;
> +
> +             tds[i].pid = ep->direction;
> +             tds[i].dev_addr = ep->dev->address;
> +             tds[i].endp = ep->endpoint & 0xf;
> +             tds[i].maxlen = maxlen (reqsize);
> +             tds[i].counter = 0;
> +             tds[i].data_toggle = ep->toggle & 1;
> +             tds[i].lowspeed = ep->dev->lowspeed;
> +             tds[i].bufptr = virt_to_phys (data);
> +             tds[i].status_active = 1;
> +             ep->toggle ^= 1;
> +             data += reqsize;
> +     }
> +     tds[reqcount - 1].ptr = 0;
> +     tds[reqcount - 1].terminate = 1;
> +     tds[reqcount - 1].queue_head = 0;
> +     tds[reqcount - 1].depth_first = 0;
> +     for (i = reqtiming; i < 1024; i += reqtiming) {
> +             /* FIXME: wrap in another qh, one for each occurance of the qh 
> in the framelist */
> +             qh->headlinkptr.ptr = UHCI_INST 
> (ep->dev->controller)->framelistptr[i].ptr;
> +             qh->headlinkptr.terminate = 0;
> +             UHCI_INST (ep->dev->controller)->framelistptr[i].ptr = 
> virt_to_phys(qh);
> +             UHCI_INST (ep->dev->controller)->framelistptr[i].terminate = 0;
> +             UHCI_INST (ep->dev->controller)->framelistptr[i].queue_head = 1;
> +     }
> +     return q;
> +}
> +
> +/* remove queue from device schedule, dropping all data that came in */
> +static void
> +uhci_destroy_intr_queue (endpoint_t *ep, void *q_)
> +{
> +     intr_q *q = (intr_q*)q_;
> +     u32 val = virt_to_phys (q->qh);
> +     u32 end = virt_to_phys (UHCI_INST (ep->dev->controller)->qh_intr);
> +     int i;
> +     for (i=0; i<1024; i++) {
> +             u32 oldptr = 0;
> +             u32 ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
> +             while (ptr != end) {
> +                     if (((qh_t*)phys_to_virt(ptr))->elementlinkptr.ptr == 
> val) {
> +                             ((qh_t*)phys_to_virt(oldptr))->headlinkptr.ptr 
> = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
> +                             free(phys_to_virt(ptr));
> +                             break;
> +                     }
> +                     oldptr = ptr;
> +                     ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
> +             }
> +     }
> +     free(q->data);
> +     free(q->tds);
> +     free(q->qh);
> +     free(q);
> +}
> +
> +/* read one intr-packet from queue, if available. extend the queue for new 
> input.
> +   return NULL if nothing new available.
> +   Recommended use: while (data=poll_intr_queue(q)) process(data);
> + */
> +static u8*
> +uhci_poll_intr_queue (void *q_)
> +{
> +     intr_q *q = (intr_q*)q_;
> +     if (q->tds[q->lastread].status_active == 0) {
> +             /* FIXME: handle errors */
> +             int current = q->lastread;
> +             int previous;
> +             if (q->lastread == 0) {
> +                     previous = q->total - 1;
> +             } else {
> +                     previous = q->lastread - 1;
> +             }
> +             q->tds[previous].status = 0;
> +             q->tds[previous].ptr = 0;
> +             q->tds[previous].terminate = 1;
> +             if (q->last_td != &q->tds[previous]) {
> +                     q->last_td->ptr = virt_to_phys(&q->tds[previous]);
> +                     q->last_td->terminate = 0;
> +                     q->last_td = &q->tds[previous];
> +             }
> +             q->tds[previous].status_active = 1;
> +             q->lastread = (q->lastread + 1) % q->total;
> +             return &q->data[current*q->reqsize];
> +     }
> +     return NULL;
> +}
> +
>  void
>  uhci_reg_write32 (hci_t *ctrl, usbreg reg, u32 value)
>  {
> === drivers/usb/usbhub.c
> ==================================================================
> --- drivers/usb/usbhub.c      (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/usbhub.c      (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -53,9 +53,7 @@
>  static void
>  usb_hub_scanport (usbdev_t *dev, int port)
>  {
> -     int newdev;
>       unsigned short buf[2];
> -     usbdev_t *newdev_t;
>  
>       get_status (dev, port, DR_PORT, 4, buf);
>       int portstatus = ((buf[0] & 1) == 0);
> @@ -67,9 +65,7 @@
>               int devno = HUB_INST (dev)->ports[port];
>               if (devno == -1)
>                       fatal ("FATAL: illegal devno!\n");
> -             dev->controller->devices[devno].destroy (&dev->controller->
> -                                                      devices[devno]);
> -             init_device_entry (dev->controller, devno);
> +             usb_detach_device(dev->controller, devno);
>               HUB_INST (dev)->ports[port] = -1;
>               return;
>       }
> @@ -80,17 +76,7 @@
>       get_status (dev, port, DR_PORT, 4, buf);
>       int lowspeed = (buf[0] >> 9) & 1;
>  
> -     newdev = set_address (dev->controller, lowspeed);
> -     if (newdev == -1)
> -             return;
> -     newdev_t = &dev->controller->devices[newdev];
> -
> -     HUB_INST (dev)->ports[port] = newdev;
> -     newdev_t->address = newdev;
> -     newdev_t->hub = dev->address;
> -     newdev_t->port = port;
> -     // determine responsible driver
> -     newdev_t->init (newdev_t);
> +     HUB_INST (dev)->ports[port] = usb_attach_device(dev->controller, 
> dev->address, port, lowspeed);
>  }
>  
>  static int
> === drivers/usb/usb.c
> ==================================================================
> --- drivers/usb/usb.c (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/usb.c (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -75,8 +75,8 @@
>       while (controller != 0) {
>               int i;
>               for (i = 0; i < 128; i++) {
> -                     if (controller->devices[i].address != -1) {
> -                             controller->devices[i].poll (&controller->
> +                     if (controller->devices[i] != 0) {
> +                             controller->devices[i]->poll (controller->
>                                                            devices[i]);
>                       }
>               }
> @@ -87,12 +87,15 @@
>  void
>  init_device_entry (hci_t *controller, int i)
>  {
> -     controller->devices[i].controller = controller;
> -     controller->devices[i].address = -1;
> -     controller->devices[i].hub = -1;
> -     controller->devices[i].port = -1;
> -     controller->devices[i].init = usb_nop_init;
> -     controller->devices[i].init (&controller->devices[i]);
> +     if (controller->devices[i] != 0)
> +             printf("warning: device %d reassigned?\n", i);
> +     controller->devices[i] = malloc(sizeof(usbdev_t));
> +     controller->devices[i]->controller = controller;
> +     controller->devices[i]->address = -1;
> +     controller->devices[i]->hub = -1;
> +     controller->devices[i]->port = -1;
> +     controller->devices[i]->init = usb_nop_init;
> +     controller->devices[i]->init (controller->devices[i]);
>  }
>  
>  void
> @@ -208,7 +211,7 @@
>  {
>       int i;
>       for (i = 1; i < 128; i++) {
> -             if (controller->devices[i].address != i)
> +             if (controller->devices[i] == 0)
>                       return i;
>       }
>       printf ("no free address found\n");
> @@ -232,7 +235,8 @@
>       dr.wIndex = 0;
>       dr.wLength = 0;
>  
> -     usbdev_t *dev = &controller->devices[adr];
> +     init_device_entry(controller, adr);
> +     usbdev_t *dev = controller->devices[adr];
>       // dummy values for registering the address
>       dev->address = 0;
>       dev->lowspeed = lowspeed;
> @@ -325,7 +329,7 @@
>       if (class == hub_device) {
>               printf ("hub found\n");
>  #ifdef CONFIG_USB_HUB
> -             controller->devices[adr].init = usb_hub_init;
> +             controller->devices[adr]->init = usb_hub_init;
>  #else
>               printf ("support not compiled in\n");
>  #endif
> @@ -333,7 +337,7 @@
>       if (class == hid_device) {
>               printf ("HID found\n");
>  #ifdef CONFIG_USB_HID
> -             controller->devices[adr].init = usb_hid_init;
> +             controller->devices[adr]->init = usb_hid_init;
>  #else
>               printf ("support not compiled in\n");
>  #endif
> @@ -341,10 +345,35 @@
>       if (class == msc_device) {
>               printf ("MSC found\n");
>  #ifdef CONFIG_USB_MSC
> -             controller->devices[adr].init = usb_msc_init;
> +             controller->devices[adr]->init = usb_msc_init;
>  #else
>               printf ("support not compiled in\n");
>  #endif
>       }
>       return adr;
>  }
> +
> +void
> +usb_detach_device(hci_t *controller, int devno)
> +{
> +     controller->devices[devno]->destroy (controller->devices[devno]);
> +     free(controller->devices[devno]);
> +     controller->devices[devno] = 0;
> +}
> +
> +int
> +usb_attach_device(hci_t *controller, int hubaddress, int port, int lowspeed)
> +{
> +     printf ("%sspeed device\n", (lowspeed == 1) ? "low" : "full");
> +     int newdev = set_address (controller, lowspeed);
> +     if (newdev == -1)
> +             return -1;
> +     usbdev_t *newdev_t = controller->devices[newdev];
> +
> +     newdev_t->address = newdev;
> +     newdev_t->hub = hubaddress;
> +     newdev_t->port = port;
> +     // determine responsible driver - current done in set_address
> +     newdev_t->init (newdev_t);
> +     return newdev;
> +}
> === drivers/usb/usbmsc.c
> ==================================================================
> --- drivers/usb/usbmsc.c      (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/usbmsc.c      (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -69,7 +69,8 @@
>  static void
>  usb_msc_destroy (usbdev_t *dev)
>  {
> -     usbdisk_remove (dev);
> +     if (usbdisk_remove)
> +             usbdisk_remove (dev);
>       free (dev->data);
>       dev->data = 0;
>  }
> @@ -393,5 +394,6 @@
>       printf ("\n");
>  
>       read_capacity (dev);
> -     usbdisk_create (dev);
> +     if (usbdisk_create)
> +             usbdisk_create (dev);
>  }
> === drivers/usb/uhci.h
> ==================================================================
> --- drivers/usb/uhci.h        (/coreboot/libpayload)  (revision 2215)
> +++ drivers/usb/uhci.h        (/coresystems/untitled-pain/filo/libpayload)    
> (revision 2215)
> @@ -111,7 +111,7 @@
>  
>       typedef struct uhci {
>            flistp_t *framelistptr;
> -          qh_t *qh_intr, *qh_data, *qh_last;
> +          qh_t *qh_prei, *qh_intr, *qh_data, *qh_last;
>            usbdev_t *roothub;
>       } uhci_t;
>  
> 
> 

> --
> coreboot mailing list: [email protected]
> http://www.coreboot.org/mailman/listinfo/coreboot


-- 
Jordan Crouse
Systems Software Development Engineer 
Advanced Micro Devices, Inc.


--
coreboot mailing list: [email protected]
http://www.coreboot.org/mailman/listinfo/coreboot

Reply via email to