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 patrick.georgi@coresystems.de
Regards, Patrick
================================================================== --- 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;
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 patrick.georgi@coresystems.de
Acked-by: Jordan Crouse jordan.crouse@amd.com
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);
UHCI_INST (controller)->framelistptr[i].terminate = 0; UHCI_INST (controller)->framelistptr[i].queue_head = 1; }virt_to_phys (UHCI_INST (controller)->qh_prei);
- 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;
} uhci_reg_mask16 (controller, USBSTS, ~0, 0); // clear resettable registers udelay (30);timeout = 1000000;
@@ -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);
HUB_INST (dev)->ports[port] = -1; return; }usb_detach_device(dev->controller, devno);
@@ -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)
} printf ("no free address found\n");if (controller->devices[i] == 0) return i;
@@ -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)
free (dev->data); dev->data = 0;usbdisk_remove (dev);
} @@ -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: coreboot@coreboot.org http://www.coreboot.org/mailman/listinfo/coreboot