libpayload: Remove bitfield use from UHCI data structures
[coreboot.git] / payloads / libpayload / drivers / usb / uhci.c
index def6b45084a9b088378ee5921705fd06d67f0a1f..07a074291d752f839edac738157cc152be183bae 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the libpayload project.
  *
- * Copyright (C) 2008 coresystems GmbH
+ * Copyright (C) 2008-2010 coresystems GmbH
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * SUCH DAMAGE.
  */
 
+//#define USB_DEBUG
+
+#include <arch/virtual.h>
 #include <usb/usb.h>
 #include "uhci.h"
-#include <arch/virtual.h>
+#include "uhci_private.h"
 
 static void uhci_start (hci_t *controller);
 static void uhci_stop (hci_t *controller);
 static void uhci_reset (hci_t *controller);
 static void uhci_shutdown (hci_t *controller);
-static int uhci_packet (usbdev_t *dev, int endp, int pid, int toggle,
-                       int length, u8 *data);
 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,
+static int uhci_control (usbdev_t *dev, direction_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);
@@ -49,14 +50,14 @@ static u8* uhci_poll_intr_queue (void *queue);
 static void
 uhci_dump (hci_t *controller)
 {
-       printf ("dump:\nUSBCMD: %x\n", uhci_reg_read16 (controller, USBCMD));
-       printf ("USBSTS: %x\n", uhci_reg_read16 (controller, USBSTS));
-       printf ("USBINTR: %x\n", uhci_reg_read16 (controller, USBINTR));
-       printf ("FRNUM: %x\n", uhci_reg_read16 (controller, FRNUM));
-       printf ("FLBASEADD: %x\n", uhci_reg_read32 (controller, FLBASEADD));
-       printf ("SOFMOD: %x\n", uhci_reg_read8 (controller, SOFMOD));
-       printf ("PORTSC1: %x\n", uhci_reg_read16 (controller, PORTSC1));
-       printf ("PORTSC2: %x\n", uhci_reg_read16 (controller, PORTSC2));
+       debug ("dump:\nUSBCMD: %x\n", uhci_reg_read16 (controller, USBCMD));
+       debug ("USBSTS: %x\n", uhci_reg_read16 (controller, USBSTS));
+       debug ("USBINTR: %x\n", uhci_reg_read16 (controller, USBINTR));
+       debug ("FRNUM: %x\n", uhci_reg_read16 (controller, FRNUM));
+       debug ("FLBASEADD: %x\n", uhci_reg_read32 (controller, FLBASEADD));
+       debug ("SOFMOD: %x\n", uhci_reg_read8 (controller, SOFMOD));
+       debug ("PORTSC1: %x\n", uhci_reg_read16 (controller, PORTSC1));
+       debug ("PORTSC2: %x\n", uhci_reg_read16 (controller, PORTSC2));
 }
 #endif
 
@@ -64,36 +65,37 @@ static void
 td_dump (td_t *td)
 {
        char td_value[3];
-       char *td_type;
-       switch (td->pid) {
-               case SETUP:
+       const char *td_type;
+       switch (td->token & TD_PID_MASK) {
+               case UHCI_SETUP:
                        td_type="SETUP";
                        break;
-               case IN:
+               case UHCI_IN:
                        td_type="IN";
                        break;
-               case OUT:
+               case UHCI_OUT:
                        td_type="OUT";
                        break;
                default:
-                       sprintf(td_value, "%x", td->pid);
+                       sprintf(td_value, "%x", td->token & TD_PID_MASK);
                        td_type=td_value;
        }
-       printf ("%s packet (at %lx) to %x.%x failed\n", td_type,
-               virt_to_phys (td), td->dev_addr, td->endp);
-       printf ("td (counter at %x) returns: ", td->counter);
-       printf (" bitstuff err: %x, ", td->status_bitstuff_err);
-       printf (" CRC err: %x, ", td->status_crc_err);
-       printf (" NAK rcvd: %x, ", td->status_nakrcvd);
-       printf (" Babble: %x, ", td->status_babble);
-       printf (" Data Buffer err: %x, ", td->status_databuf_err);
-       printf (" Stalled: %x, ", td->status_stalled);
-       printf (" Active: %x\n", td->status_active);
-       if (td->status_babble)
-               printf (" Babble because of %s\n",
-                       td->status_bitstuff_err ? "host" : "device");
-       if (td->status_active)
-               printf (" still active - timeout?\n");
+       debug ("%s packet (at %lx) to %x.%x failed\n", td_type,
+               virt_to_phys (td), (td->token & TD_DEVADDR_MASK) >> TD_DEVADDR_SHIFT,
+               (td->token & TD_EP_MASK) >> TD_EP_SHIFT);
+       debug ("td (counter at %x) returns: ", td->ctrlsts >> TD_COUNTER_SHIFT);
+       debug (" bitstuff err: %x, ", !!(td->ctrlsts & TD_STATUS_BITSTUFF_ERR));
+       debug (" CRC err: %x, ", !!(td->ctrlsts & TD_STATUS_CRC_ERR));
+       debug (" NAK rcvd: %x, ", !!(td->ctrlsts & TD_STATUS_NAK_RCVD));
+       debug (" Babble: %x, ", !!(td->ctrlsts & TD_STATUS_BABBLE));
+       debug (" Data Buffer err: %x, ", !!(td->ctrlsts & TD_STATUS_DATABUF_ERR));
+       debug (" Stalled: %x, ", !!(td->ctrlsts & TD_STATUS_STALLED));
+       debug (" Active: %x\n", !!(td->ctrlsts & TD_STATUS_ACTIVE));
+       if (td->ctrlsts & TD_STATUS_BABBLE)
+               debug (" Babble because of %s\n",
+                       (td->ctrlsts & TD_STATUS_BITSTUFF_ERR) ? "host" : "device");
+       if (td->ctrlsts & TD_STATUS_ACTIVE)
+               debug (" still active - timeout?\n");
 }
 
 static void
@@ -111,7 +113,7 @@ uhci_reset (hci_t *controller)
        uhci_reg_write32 (controller, FLBASEADD,
                          (u32) virt_to_phys (UHCI_INST (controller)->
                                              framelistptr));
-       //printf ("framelist at %p\n",UHCI_INST(controller)->framelistptr);
+       //debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr);
 
        /* disable irqs */
        uhci_reg_write16 (controller, USBINTR, 0);
@@ -119,7 +121,8 @@ uhci_reset (hci_t *controller)
        /* reset framelist index */
        uhci_reg_write16 (controller, FRNUM, 0);
 
-       uhci_reg_mask16 (controller, USBCMD, ~0, 0xc0); // max packets, configure flag
+       uhci_reg_write16(controller, USBCMD,
+                        uhci_reg_read16(controller, USBCMD) | 0xc0);   // max packets, configure flag
 
        uhci_start (controller);
 }
@@ -128,20 +131,21 @@ hci_t *
 uhci_init (pcidev_t addr)
 {
        int i;
+       u16 reg16;
+
        hci_t *controller = new_controller ();
 
        if (!controller)
-               usb_fatal("Could not create USB controller instance.\n");
+               fatal("Could not create USB controller instance.\n");
 
        controller->instance = malloc (sizeof (uhci_t));
        if(!controller->instance)
-               usb_fatal("Not enough memory creating USB controller instance.\n");
+               fatal("Not enough memory creating USB controller instance.\n");
 
        controller->start = uhci_start;
        controller->stop = uhci_stop;
        controller->reset = uhci_reset;
        controller->shutdown = uhci_shutdown;
-       controller->packet = uhci_packet;
        controller->bulk = uhci_bulk;
        controller->control = uhci_control;
        controller->create_intr_queue = uhci_create_intr_queue;
@@ -160,11 +164,13 @@ uhci_init (pcidev_t addr)
        uhci_stop (controller);
        mdelay (1);
        uhci_reg_write16 (controller, USBSTS, 0x3f);
-       pci_write_config32 (controller->bus_address, 0xc0, 0x8f00);
+       reg16 = pci_read_config16(controller->bus_address, 0xc0);
+       reg16 &= 0xdf80;
+       pci_write_config16 (controller->bus_address, 0xc0, reg16);
 
        UHCI_INST (controller)->framelistptr = memalign (0x1000, 1024 * sizeof (flistp_t *));   /* 4kb aligned to 4kb */
        if (! UHCI_INST (controller)->framelistptr)
-               usb_fatal("Not enough memory for USB frame list pointer.\n");
+               fatal("Not enough memory for USB frame list pointer.\n");
 
        memset (UHCI_INST (controller)->framelistptr, 0,
                1024 * sizeof (flistp_t));
@@ -178,7 +184,7 @@ uhci_init (pcidev_t addr)
           */
        td_t *antiberserk = memalign(16, sizeof(td_t));
        if (!antiberserk)
-               usb_fatal("Not enough memory for chipset workaround.\n");
+               fatal("Not enough memory for chipset workaround.\n");
        memset(antiberserk, 0, sizeof(td_t));
 
        UHCI_INST (controller)->qh_prei = memalign (16, sizeof (qh_t));
@@ -190,36 +196,26 @@ uhci_init (pcidev_t addr)
            ! UHCI_INST (controller)->qh_intr ||
            ! UHCI_INST (controller)->qh_data ||
            ! UHCI_INST (controller)->qh_last)
-               usb_fatal ("Not enough memory for USB controller queues.\n");
-
-       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;
-       UHCI_INST (controller)->qh_intr->elementlinkptr.ptr = 0;
-       UHCI_INST (controller)->qh_intr->elementlinkptr.terminate = 1;
-
-       UHCI_INST (controller)->qh_data->headlinkptr.ptr =
-               virt_to_phys (UHCI_INST (controller)->qh_last);
-       UHCI_INST (controller)->qh_data->headlinkptr.queue_head = 1;
-       UHCI_INST (controller)->qh_data->elementlinkptr.ptr = 0;
-       UHCI_INST (controller)->qh_data->elementlinkptr.terminate = 1;
-
-       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 = virt_to_phys (antiberserk);
-       UHCI_INST (controller)->qh_last->elementlinkptr.terminate = 1;
+               fatal("Not enough memory for USB controller queues.\n");
+
+       UHCI_INST (controller)->qh_prei->headlinkptr =
+               virt_to_phys (UHCI_INST (controller)->qh_intr) | FLISTP_QH;
+       UHCI_INST (controller)->qh_prei->elementlinkptr = 0 | FLISTP_TERMINATE;
+
+       UHCI_INST (controller)->qh_intr->headlinkptr =
+               virt_to_phys (UHCI_INST (controller)->qh_data) | FLISTP_QH;
+       UHCI_INST (controller)->qh_intr->elementlinkptr = 0 | FLISTP_TERMINATE;
+
+       UHCI_INST (controller)->qh_data->headlinkptr =
+               virt_to_phys (UHCI_INST (controller)->qh_last) | FLISTP_QH;
+       UHCI_INST (controller)->qh_data->elementlinkptr = 0 | FLISTP_TERMINATE;
+
+       UHCI_INST (controller)->qh_last->headlinkptr = virt_to_phys (UHCI_INST (controller)->qh_data) | FLISTP_TERMINATE;
+       UHCI_INST (controller)->qh_last->elementlinkptr = virt_to_phys (antiberserk) | FLISTP_TERMINATE;
 
        for (i = 0; i < 1024; i++) {
-               UHCI_INST (controller)->framelistptr[i].ptr =
-                       virt_to_phys (UHCI_INST (controller)->qh_prei);
-               UHCI_INST (controller)->framelistptr[i].terminate = 0;
-               UHCI_INST (controller)->framelistptr[i].queue_head = 1;
+               UHCI_INST (controller)->framelistptr[i] =
+                       virt_to_phys (UHCI_INST (controller)->qh_prei) | FLISTP_QH;
        }
        controller->devices[0]->controller = controller;
        controller->devices[0]->init = uhci_rh_init;
@@ -236,7 +232,8 @@ uhci_shutdown (hci_t *controller)
        detach_controller (controller);
        UHCI_INST (controller)->roothub->destroy (UHCI_INST (controller)->
                                                  roothub);
-       uhci_reg_mask16 (controller, USBCMD, 0, 0);     // stop work
+       uhci_reg_write16(controller, USBCMD,
+                        uhci_reg_read16(controller, USBCMD) & 0);      // stop work
        free (UHCI_INST (controller)->framelistptr);
        free (UHCI_INST (controller)->qh_prei);
        free (UHCI_INST (controller)->qh_intr);
@@ -249,13 +246,15 @@ uhci_shutdown (hci_t *controller)
 static void
 uhci_start (hci_t *controller)
 {
-       uhci_reg_mask16 (controller, USBCMD, ~0, 1);    // start work on schedule
+       uhci_reg_write16(controller, USBCMD,
+                        uhci_reg_read16(controller, USBCMD) | 1);      // start work on schedule
 }
 
 static void
 uhci_stop (hci_t *controller)
 {
-       uhci_reg_mask16 (controller, USBCMD, ~1, 0);    // stop work on schedule
+       uhci_reg_write16(controller, USBCMD,
+                        uhci_reg_read16(controller, USBCMD) & ~1);     // stop work on schedule
 }
 
 #define GET_TD(x) ((void*)(((unsigned int)(x))&~0xf))
@@ -264,29 +263,18 @@ static td_t *
 wait_for_completed_qh (hci_t *controller, qh_t *qh)
 {
        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);
+       void *current = GET_TD (qh->elementlinkptr);
+       while (((qh->elementlinkptr & FLISTP_TERMINATE) == 0) && (timeout-- > 0)) {
+               if (current != GET_TD (qh->elementlinkptr)) {
+                       current = GET_TD (qh->elementlinkptr);
                        timeout = 1000000;
                }
-               uhci_reg_mask16 (controller, USBSTS, ~0, 0);    // clear resettable registers
+               uhci_reg_write16(controller, USBSTS,
+                                uhci_reg_read16(controller, USBSTS) | 0);      // clear resettable registers
                udelay (30);
        }
-       return (GET_TD (qh->elementlinkptr.ptr) ==
-               0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr.ptr));
-}
-
-static void
-wait_for_completed_td (hci_t *controller, td_t *td)
-{
-       int timeout = 10000;
-       while ((td->status_active == 1)
-              && ((uhci_reg_read16 (controller, USBSTS) & 2) == 0)
-              && (timeout-- > 0)) {
-               uhci_reg_mask16 (controller, USBSTS, ~0, 0);    // clear resettable registers
-               udelay (10);
-       }
+       return (GET_TD (qh->elementlinkptr) ==
+               0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr));
 }
 
 static int
@@ -305,7 +293,7 @@ min (int a, int b)
 }
 
 static int
-uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
+uhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
              unsigned char *data)
 {
        int endp = 0;           /* this is control: always 0 */
@@ -317,52 +305,51 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
        memset (tds, 0, sizeof (td_t) * count);
        count--;                /* to compensate for 0-indexed array */
        for (i = 0; i < count; i++) {
-               tds[i].ptr = virt_to_phys (&tds[i + 1]);
-               tds[i].depth_first = 1;
-               tds[i].terminate = 0;
+               tds[i].ptr = virt_to_phys (&tds[i + 1]) | TD_DEPTH_FIRST;
        }
-       tds[count].ptr = 0;
-       tds[count].depth_first = 1;
-       tds[count].terminate = 1;
-
-       tds[0].pid = SETUP;
-       tds[0].dev_addr = dev->address;
-       tds[0].endp = endp;
-       tds[0].maxlen = maxlen (drlen);
-       tds[0].counter = 3;
-       tds[0].data_toggle = 0;
-       tds[0].lowspeed = dev->lowspeed;
+       tds[count].ptr = 0 | TD_DEPTH_FIRST | TD_TERMINATE;
+
+       tds[0].token = UHCI_SETUP |
+               dev->address << TD_DEVADDR_SHIFT |
+               endp << TD_EP_SHIFT |
+               TD_TOGGLE_DATA0 |
+               maxlen(drlen) << TD_MAXLEN_SHIFT;
        tds[0].bufptr = virt_to_phys (devreq);
-       tds[0].status_active = 1;
+       tds[0].ctrlsts = (3 << TD_COUNTER_SHIFT) |
+               (dev->speed?TD_LOWSPEED:0) |
+               TD_STATUS_ACTIVE;
 
        int toggle = 1;
        for (i = 1; i < count; i++) {
-               tds[i].pid = dir;
-               tds[i].dev_addr = dev->address;
-               tds[i].endp = endp;
-               tds[i].maxlen = maxlen (min (mlen, dalen));
-               tds[i].counter = 3;
-               tds[i].data_toggle = toggle;
-               tds[i].lowspeed = dev->lowspeed;
+               switch (dir) {
+                       case SETUP: tds[i].token = UHCI_SETUP; break;
+                       case IN:    tds[i].token = UHCI_IN;    break;
+                       case OUT:   tds[i].token = UHCI_OUT;   break;
+               }
+               tds[i].token |= dev->address << TD_DEVADDR_SHIFT |
+                       endp << TD_EP_SHIFT |
+                       maxlen (min (mlen, dalen)) << TD_MAXLEN_SHIFT |
+                       toggle << TD_TOGGLE_SHIFT;
                tds[i].bufptr = virt_to_phys (data);
-               tds[i].status_active = 1;
+               tds[i].ctrlsts = (3 << TD_COUNTER_SHIFT) |
+                       (dev->speed?TD_LOWSPEED:0) |
+                       TD_STATUS_ACTIVE;
                toggle ^= 1;
                dalen -= mlen;
                data += mlen;
        }
 
-       tds[count].pid = (dir == OUT) ? IN : OUT;
-       tds[count].dev_addr = dev->address;
-       tds[count].endp = endp;
-       tds[count].maxlen = maxlen (0);
-       tds[count].counter = 0; /* as per linux 2.4.10 */
-       tds[count].data_toggle = 1;
-       tds[count].lowspeed = dev->lowspeed, tds[count].bufptr = 0;
-       tds[count].status_active = 1;
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
-               virt_to_phys (tds);
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
+       tds[count].token = (dir == OUT) ? UHCI_IN : UHCI_OUT |
+               dev->address << TD_DEVADDR_SHIFT |
+               endp << TD_EP_SHIFT |
+               maxlen(0) << TD_MAXLEN_SHIFT |
+               TD_TOGGLE_DATA1;
+       tds[count].bufptr = 0;
+       tds[0].ctrlsts = (0 << TD_COUNTER_SHIFT) | /* as Linux 2.4.10 does */
+               (dev->speed?TD_LOWSPEED:0) |
+               TD_STATUS_ACTIVE;
+       UHCI_INST (dev->controller)->qh_data->elementlinkptr =
+               virt_to_phys (tds) & ~(FLISTP_QH | FLISTP_TERMINATE);
        td_t *td = wait_for_completed_qh (dev->controller,
                                          UHCI_INST (dev->controller)->
                                          qh_data);
@@ -370,7 +357,7 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
        if (td == 0) {
                result = 0;
        } else {
-               printf ("control packet, req %x\n", req);
+               debug ("control packet, req %x\n", req);
                td_dump (td);
                result = 1;
        }
@@ -378,48 +365,6 @@ uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
        return result;
 }
 
-static int
-uhci_packet (usbdev_t *dev, int endp, int pid, int toggle, int length,
-            unsigned char *data)
-{
-       static td_t *td = 0;
-       if (td == 0)
-               td = memalign (16, sizeof (td_t));
-
-       memset (td, 0, sizeof (td_t));
-       td->ptr = 0;
-       td->terminate = 1;
-       td->queue_head = 0;
-
-       td->pid = pid;
-       td->dev_addr = dev->address;
-       td->endp = endp & 0xf;
-       td->maxlen = maxlen (length);
-       if (pid == SETUP)
-               td->counter = 3;
-       else
-               td->counter = 0;
-       td->data_toggle = toggle & 1;
-       td->lowspeed = dev->lowspeed;
-       td->bufptr = virt_to_phys (data);
-
-       td->status_active = 1;
-
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
-               virt_to_phys (td);
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
-       wait_for_completed_td (dev->controller, td);
-       if ((td->status & 0x7f) == 0) {
-               //printf("successfully sent a %x packet to %x.%x\n",pid, dev->address,endp);
-               // success
-               return 0;
-       } else {
-               td_dump (td);
-               return 1;
-       }
-}
-
 static td_t *
 create_schedule (int numpackets)
 {
@@ -429,15 +374,9 @@ create_schedule (int numpackets)
        memset (tds, 0, sizeof (td_t) * numpackets);
        int i;
        for (i = 0; i < numpackets; i++) {
-               tds[i].ptr = virt_to_phys (&tds[i + 1]);
-               tds[i].terminate = 0;
-               tds[i].queue_head = 0;
-               tds[i].depth_first = 1;
+               tds[i].ptr = virt_to_phys (&tds[i + 1]) | TD_DEPTH_FIRST;
        }
-       tds[numpackets - 1].ptr = 0;
-       tds[numpackets - 1].terminate = 1;
-       tds[numpackets - 1].queue_head = 0;
-       tds[numpackets - 1].depth_first = 0;
+       tds[numpackets - 1].ptr = 0 | TD_TERMINATE;
        return tds;
 }
 
@@ -445,29 +384,27 @@ static void
 fill_schedule (td_t *td, endpoint_t *ep, int length, unsigned char *data,
               int *toggle)
 {
-       td->pid = ep->direction;
-       td->dev_addr = ep->dev->address;
-       td->endp = ep->endpoint & 0xf;
-       td->maxlen = maxlen (length);
-       if (ep->direction == SETUP)
-               td->counter = 3;
-       else
-               td->counter = 0;
-       td->data_toggle = *toggle & 1;
-       td->lowspeed = ep->dev->lowspeed;
+       switch (ep->direction) {
+               case IN: td->token = UHCI_IN; break;
+               case OUT: td->token = UHCI_OUT; break;
+               case SETUP: td->token = UHCI_SETUP; break;
+       }
+       td->token |= ep->dev->address << TD_DEVADDR_SHIFT |
+               (ep->endpoint & 0xf) << TD_EP_SHIFT |
+               maxlen (length) << TD_MAXLEN_SHIFT |
+               (*toggle & 1) << TD_TOGGLE_SHIFT;
        td->bufptr = virt_to_phys (data);
-
-       td->status_active = 1;
+       td->ctrlsts = ((ep->direction == SETUP?3:0) << TD_COUNTER_SHIFT) |
+               ep->dev->speed?TD_LOWSPEED:0 |
+               TD_STATUS_ACTIVE;
        *toggle ^= 1;
 }
 
 static int
 run_schedule (usbdev_t *dev, td_t *td)
 {
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
-               virt_to_phys (td);
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
-       UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
+       UHCI_INST (dev->controller)->qh_data->elementlinkptr =
+               virt_to_phys (td) | ~(FLISTP_QH | FLISTP_TERMINATE);
        td = wait_for_completed_qh (dev->controller,
                                    UHCI_INST (dev->controller)->qh_data);
        if (td == 0) {
@@ -484,7 +421,7 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
 {
        int maxpsize = ep->maxpacketsize;
        if (maxpsize == 0)
-               fatal ("MaxPacketSize == 0!!!");
+               fatal("MaxPacketSize == 0!!!");
        int numpackets = (size + maxpsize - 1 + finalize) / maxpsize;
        if (numpackets == 0)
                return 0;
@@ -498,6 +435,7 @@ uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
                size -= maxpsize;
        }
        if (run_schedule (ep->dev, tds) == 1) {
+               debug("Stalled. Trying to clean up.\n");
                clear_stall (ep);
                free (tds);
                return 1;
@@ -526,15 +464,13 @@ uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming
        qh_t *qh = memalign(16, sizeof(qh_t));
 
        if (!data || !tds || !qh)
-               usb_fatal ("Not enough memory to create USB intr queue prerequisites.\n");
+               fatal("Not enough memory to create USB intr queue prerequisites.\n");
 
-       qh->elementlinkptr.ptr = virt_to_phys(tds);
-       qh->elementlinkptr.queue_head = 0;
-       qh->elementlinkptr.terminate = 0;
+       qh->elementlinkptr = virt_to_phys(tds);
 
        intr_q *q = malloc(sizeof(intr_q));
        if (!q)
-               usb_fatal ("Not enough memory to create USB intr queue.\n");
+               fatal("Not enough memory to create USB intr queue.\n");
        q->qh = qh;
        q->tds = tds;
        q->data = data;
@@ -547,33 +483,28 @@ uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming
        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;
+
+               switch (ep->direction) {
+                       case IN: tds[i].token = UHCI_IN; break;
+                       case OUT: tds[i].token = UHCI_OUT; break;
+                       case SETUP: tds[i].token = UHCI_SETUP; break;
+               }
+               tds[i].token |= ep->dev->address << TD_DEVADDR_SHIFT |
+                       (ep->endpoint & 0xf) << TD_EP_SHIFT |
+                       maxlen (reqsize) << TD_MAXLEN_SHIFT |
+                       (ep->toggle & 1) << TD_TOGGLE_SHIFT;
                tds[i].bufptr = virt_to_phys (data);
-               tds[i].status_active = 1;
+               tds[i].ctrlsts = (0 << TD_COUNTER_SHIFT) |
+                       ep->dev->speed?TD_LOWSPEED:0 |
+                       TD_STATUS_ACTIVE;
                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;
+       tds[reqcount - 1].ptr = 0 | TD_TERMINATE;
        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;
+               qh->headlinkptr = UHCI_INST (ep->dev->controller)->framelistptr[i] & ~FLISTP_TERMINATE;
+               UHCI_INST (ep->dev->controller)->framelistptr[i] = virt_to_phys(qh) | FLISTP_QH;
        }
        return q;
 }
@@ -588,15 +519,15 @@ uhci_destroy_intr_queue (endpoint_t *ep, void *q_)
        int i;
        for (i=0; i<1024; i++) {
                u32 oldptr = 0;
-               u32 ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
+               u32 ptr = UHCI_INST (ep->dev->controller)->framelistptr[i];
                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;
+                       if (((qh_t*)phys_to_virt(ptr))->elementlinkptr == val) {
+                               ((qh_t*)phys_to_virt(oldptr))->headlinkptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr;
                                free(phys_to_virt(ptr));
                                break;
                        }
                        oldptr = ptr;
-                       ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
+                       ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr;
                }
        }
        free(q->data);
@@ -613,7 +544,7 @@ static u8*
 uhci_poll_intr_queue (void *q_)
 {
        intr_q *q = (intr_q*)q_;
-       if (q->tds[q->lastread].status_active == 0) {
+       if ((q->tds[q->lastread].ctrlsts & TD_STATUS_ACTIVE) == 0) {
                /* FIXME: handle errors */
                int current = q->lastread;
                int previous;
@@ -622,15 +553,13 @@ uhci_poll_intr_queue (void *q_)
                } else {
                        previous = q->lastread - 1;
                }
-               q->tds[previous].status = 0;
-               q->tds[previous].ptr = 0;
-               q->tds[previous].terminate = 1;
+               q->tds[previous].ctrlsts &= ~TD_STATUS_MASK;
+               q->tds[previous].ptr = 0 | TD_TERMINATE;
                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->ptr = virt_to_phys(&q->tds[previous]) & ~TD_TERMINATE;
                        q->last_td = &q->tds[previous];
                }
-               q->tds[previous].status_active = 1;
+               q->tds[previous].ctrlsts |= TD_STATUS_ACTIVE;
                q->lastread = (q->lastread + 1) % q->total;
                return &q->data[current*q->reqsize];
        }
@@ -672,24 +601,3 @@ uhci_reg_read8 (hci_t *ctrl, usbreg reg)
 {
        return inb (ctrl->reg_base + reg);
 }
-
-void
-uhci_reg_mask32 (hci_t *ctrl, usbreg reg, u32 andmask, u32 ormask)
-{
-       uhci_reg_write32 (ctrl, reg,
-                         (uhci_reg_read32 (ctrl, reg) & andmask) | ormask);
-}
-
-void
-uhci_reg_mask16 (hci_t *ctrl, usbreg reg, u16 andmask, u16 ormask)
-{
-       uhci_reg_write16 (ctrl, reg,
-                         (uhci_reg_read16 (ctrl, reg) & andmask) | ormask);
-}
-
-void
-uhci_reg_mask8 (hci_t *ctrl, usbreg reg, u8 andmask, u8 ormask)
-{
-       uhci_reg_write8 (ctrl, reg,
-                        (uhci_reg_read8 (ctrl, reg) & andmask) | ormask);
-}