- reduced memory requirements a lot (from >100kb/controller to
authorPatrick Georgi <patrick.georgi@coresystems.de>
Thu, 16 Oct 2008 19:20:51 +0000 (19:20 +0000)
committerPatrick Georgi <patrick.georgi@coresystems.de>
Thu, 16 Oct 2008 19:20:51 +0000 (19:20 +0000)
  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 <patrick.georgi@coresystems.de>
Acked-by: Jordan Crouse <jordan.crouse@amd.com>
git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3662 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1

13 files changed:
payloads/libpayload/curses/keyboard.c
payloads/libpayload/drivers/keyboard.c
payloads/libpayload/drivers/usb/uhci.c
payloads/libpayload/drivers/usb/uhci.h
payloads/libpayload/drivers/usb/uhci_rh.c
payloads/libpayload/drivers/usb/usb.c
payloads/libpayload/drivers/usb/usbhid.c
payloads/libpayload/drivers/usb/usbhub.c
payloads/libpayload/drivers/usb/usbmsc.c
payloads/libpayload/include/libpayload.h
payloads/libpayload/include/usb/usb.h
payloads/libpayload/include/usb/usbdisk.h
payloads/libpayload/libc/console.c

index 5fc54224a0f36ec53230e5ce1d9ae50e0f0d95a5..45bd4442fe3d540b73af1cda7b99bc473ab91231 100644 (file)
@@ -38,6 +38,7 @@
  */
 
 #include <config.h>
+#include <usb/usb.h>
 #include "local.h"
 
 static int _halfdelay = 0;
@@ -145,6 +146,14 @@ static int curses_getchar(int delay)
        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()) {
index 944b9a66a22c21dbd82a01743d65e58be0ecf2c2..0bf7c56161b9430b63a6e41f77f5491f78c12594 100644 (file)
@@ -299,7 +299,7 @@ static void keyboard_set_mode(unsigned char mode)
 /**
  * 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)
index 70bdc8f3df9215a0ac7ad02127e22a3beb54e2c4..34a6ec80d388a86e06b070981b635a248de3a3c8 100644 (file)
@@ -40,6 +40,9 @@ static int uhci_packet (usbdev_t *dev, int endp, int pid, int toggle,
 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 @@ uhci_init (pcidev_t addr)
        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 @@ uhci_init (pcidev_t addr)
        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_init (pcidev_t addr)
        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 @@ uhci_shutdown (hci_t *controller)
                                                  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 @@ uhci_stop (hci_t *controller)
 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 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
        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)
 {
index 0f56ff41801f2ec879eb4fc5a6231e2826cdbfba..dd015eea3a31891f3ed0b738cbcc4c77e4dd08ad 100644 (file)
@@ -111,7 +111,7 @@ typedef struct {
 
      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;
 
index e703e53f219fbb9f55de8505424c8d0d3200999d..cc3c60028949f63f24ccf943846f10f62779276c 100644 (file)
@@ -88,17 +88,13 @@ uhci_rh_scanport (usbdev_t *dev, int port)
        } 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 @@ uhci_rh_scanport (usbdev_t *dev, int port)
 
                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);
        }
 }
 
index 62619d6d89f24f48559be3d20fbf2ab93f9f4720..2290bc6d0900a8c93c945e6c8c620d8a6aa577d0 100644 (file)
@@ -75,8 +75,8 @@ usb_poll ()
        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 @@ usb_poll ()
 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 @@ get_free_address (hci_t *controller)
 {
        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 @@ set_address (hci_t *controller, int lowspeed)
        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 @@ set_address (hci_t *controller, int lowspeed)
        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 @@ set_address (hci_t *controller, int lowspeed)
        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 @@ set_address (hci_t *controller, int lowspeed)
        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;
+}
index 34e7cdb635c6e1297241363134559aa52480165c..8713cf48c8429e1dc3916d4ff83ac7e99815edf1 100644 (file)
  */
 
 #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,23 +43,42 @@ enum { GET_REPORT = 0x1, GET_IDLE = 0x2, GET_PROTOCOL = 0x3, SET_REPORT =
 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,
-       -1, -1, -1, -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,
@@ -74,64 +94,105 @@ char keymap[256] = {
 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;
+}
index ce1523302d2cb00e2ea8c9063e4cd596c1f20bb7..4625246e2247b75cafb4d31f546c09009a5d841c 100644 (file)
@@ -53,9 +53,7 @@ usb_hub_destroy (usbdev_t *dev)
 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 @@ usb_hub_scanport (usbdev_t *dev, int port)
                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 @@ usb_hub_scanport (usbdev_t *dev, int port)
        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
index c25c617a83ab24432077343cec6a96b9b2af4508..d9ffbd151e43c5ae4a5172b5a08a01e5859e0877 100644 (file)
@@ -69,7 +69,8 @@ static const char *msc_protocol_strings[0x51] = {
 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 @@ usb_msc_init (usbdev_t *dev)
        printf ("\n");
 
        read_capacity (dev);
-       usbdisk_create (dev);
+       if (usbdisk_create)
+               usbdisk_create (dev);
 }
index 9ad3c82dd1bfcd4b2296a02cb5c97c79c716023c..060e6b1919c10c49481c3269add2a817ae83bf5b 100644 (file)
@@ -114,6 +114,8 @@ void rtc_read_clock(struct tm *tm);
  * @{
  */
 int usb_initialize(void);                                                      
+int usbhid_havechar(void);
+int usbhid_getchar(void);
 /** @} */
 
 /**
index 1500b75a1eb2d53499b22ae7975422acd454745e..d06e8077dbf203d299d614b0adedfe58dedce26b 100644 (file)
@@ -114,7 +114,7 @@ struct usbdev_hc {
        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 @@ struct usbdev_hc {
        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 @@ gen_bmRequestType (dev_req_dir dir, dev_req_type type, dev_req_recp recp)
        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
index 3ac24631ac27601e15414ee32d6fc0705c15380b..3eb2f627a8382b74b773cdb5513e9e703daeff0c 100644 (file)
@@ -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 @@ void usbdisk_create (usbdev_t *dev);
  *
  * @param dev descriptor for the USB storage device
  */
-void usbdisk_remove (usbdev_t *dev);
+void __attribute__((weak)) usbdisk_remove (usbdev_t *dev);
 
 #endif
index d5ad0e46057fdfe907cd807e6bdb4334bf6aa995..ff6fc13e8e0da9b13b5394a00095becd0af830fb 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <config.h>
 #include <libpayload.h>
+#include <usb/usb.h>
 
 void console_init(void)
 {
@@ -77,6 +78,11 @@ int puts(const char *s)
 
 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 havekey(void)
 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();