From 4727c0744615d7b49c843197433937721ce9acd1 Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Thu, 16 Oct 2008 19:20:51 +0000 Subject: - 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 Acked-by: Jordan Crouse git-svn-id: svn://svn.coreboot.org/coreboot/trunk@3662 2b7e53f0-3cfb-0310-b3e9-8179ed1497e1 --- payloads/libpayload/curses/keyboard.c | 9 ++ payloads/libpayload/drivers/keyboard.c | 2 +- payloads/libpayload/drivers/usb/uhci.c | 173 +++++++++++++++++++++++++++--- payloads/libpayload/drivers/usb/uhci.h | 2 +- payloads/libpayload/drivers/usb/uhci_rh.c | 22 +--- payloads/libpayload/drivers/usb/usb.c | 55 +++++++--- payloads/libpayload/drivers/usb/usbhid.c | 163 +++++++++++++++++++--------- payloads/libpayload/drivers/usb/usbhub.c | 18 +--- payloads/libpayload/drivers/usb/usbmsc.c | 6 +- payloads/libpayload/include/libpayload.h | 2 + payloads/libpayload/include/usb/usb.h | 7 +- payloads/libpayload/include/usb/usbdisk.h | 4 +- payloads/libpayload/libc/console.c | 11 ++ 13 files changed, 357 insertions(+), 117 deletions(-) diff --git a/payloads/libpayload/curses/keyboard.c b/payloads/libpayload/curses/keyboard.c index 5fc54224a0..45bd4442fe 100644 --- a/payloads/libpayload/curses/keyboard.c +++ b/payloads/libpayload/curses/keyboard.c @@ -38,6 +38,7 @@ */ #include +#include #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()) { diff --git a/payloads/libpayload/drivers/keyboard.c b/payloads/libpayload/drivers/keyboard.c index 944b9a66a2..0bf7c56161 100644 --- a/payloads/libpayload/drivers/keyboard.c +++ b/payloads/libpayload/drivers/keyboard.c @@ -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) diff --git a/payloads/libpayload/drivers/usb/uhci.c b/payloads/libpayload/drivers/usb/uhci.c index 70bdc8f3df..34a6ec80d3 100644 --- a/payloads/libpayload/drivers/usb/uhci.c +++ b/payloads/libpayload/drivers/usb/uhci.c @@ -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) { diff --git a/payloads/libpayload/drivers/usb/uhci.h b/payloads/libpayload/drivers/usb/uhci.h index 0f56ff4180..dd015eea3a 100644 --- a/payloads/libpayload/drivers/usb/uhci.h +++ b/payloads/libpayload/drivers/usb/uhci.h @@ -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; diff --git a/payloads/libpayload/drivers/usb/uhci_rh.c b/payloads/libpayload/drivers/usb/uhci_rh.c index e703e53f21..cc3c600289 100644 --- a/payloads/libpayload/drivers/usb/uhci_rh.c +++ b/payloads/libpayload/drivers/usb/uhci_rh.c @@ -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); } } diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c index 62619d6d89..2290bc6d09 100644 --- a/payloads/libpayload/drivers/usb/usb.c +++ b/payloads/libpayload/drivers/usb/usb.c @@ -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; +} diff --git a/payloads/libpayload/drivers/usb/usbhid.c b/payloads/libpayload/drivers/usb/usbhid.c index 34e7cdb635..8713cf48c8 100644 --- a/payloads/libpayload/drivers/usb/usbhid.c +++ b/payloads/libpayload/drivers/usb/usbhid.c @@ -28,9 +28,10 @@ */ #include +#include 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; +} diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c index ce1523302d..4625246e22 100644 --- a/payloads/libpayload/drivers/usb/usbhub.c +++ b/payloads/libpayload/drivers/usb/usbhub.c @@ -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 diff --git a/payloads/libpayload/drivers/usb/usbmsc.c b/payloads/libpayload/drivers/usb/usbmsc.c index c25c617a83..d9ffbd151e 100644 --- a/payloads/libpayload/drivers/usb/usbmsc.c +++ b/payloads/libpayload/drivers/usb/usbmsc.c @@ -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); } diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h index 9ad3c82dd1..060e6b1919 100644 --- a/payloads/libpayload/include/libpayload.h +++ b/payloads/libpayload/include/libpayload.h @@ -114,6 +114,8 @@ void rtc_read_clock(struct tm *tm); * @{ */ int usb_initialize(void); +int usbhid_havechar(void); +int usbhid_getchar(void); /** @} */ /** diff --git a/payloads/libpayload/include/usb/usb.h b/payloads/libpayload/include/usb/usb.h index 1500b75a1e..d06e8077db 100644 --- a/payloads/libpayload/include/usb/usb.h +++ b/payloads/libpayload/include/usb/usb.h @@ -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 diff --git a/payloads/libpayload/include/usb/usbdisk.h b/payloads/libpayload/include/usb/usbdisk.h index 3ac24631ac..3eb2f627a8 100644 --- a/payloads/libpayload/include/usb/usbdisk.h +++ b/payloads/libpayload/include/usb/usbdisk.h @@ -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 diff --git a/payloads/libpayload/libc/console.c b/payloads/libpayload/libc/console.c index d5ad0e4605..ff6fc13e8e 100644 --- a/payloads/libpayload/libc/console.c +++ b/payloads/libpayload/libc/console.c @@ -29,6 +29,7 @@ #include #include +#include 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(); -- cgit v1.2.3