Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/uhci_hcd.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include <smp/apic.h>
0019 #include <drivers/usb/usb.h>
0020 #include <drivers/usb/uhci.h>
0021 #include <util/printf.h>
0022 #include <mem/virtual.h>
0023 #include <mem/pow2.h>
0024 #include <arch/i386-div64.h>
0025 #include <kernel.h>
0026 #include "sched/sched.h"
0027 
0028 #define DEBUG_UHCI
0029 //#define DEBUG_UHCI_VERBOSE
0030 
0031 #ifdef DEBUG_UHCI
0032 #define DLOG(fmt,...) DLOG_PREFIX("UHCI",fmt,##__VA_ARGS__)
0033 #else
0034 #define DLOG(fmt,...) ;
0035 #endif
0036 
0037 #ifdef DEBUG_UHCI_VERBOSE
0038 #define DLOGV(fmt,...) DLOG_PREFIX("UHCI",fmt,##__VA_ARGS__)
0039 #else
0040 #define DLOGV(fmt,...) ;
0041 #endif
0042 
0043 static int bus;                 /* set by PCI probing in uhci_init */
0044 static int dev;
0045 static int func;
0046 
0047 static uint32 uhci_irq_handler (uint8 vec);
0048 
0049 /* USB I/O space base address */
0050 static uint32_t usb_base = 0x0;
0051 
0052 /* UHCI Frame List. 1024 entries aligned to 4KB boundary */
0053 static frm_lst_ptr frame_list[1024] ALIGNED(0x1000);
0054 static UHCI_TD td[TD_POOL_SIZE] ALIGNED(0x1000);
0055 static UHCI_QH qh[QH_POOL_SIZE] ALIGNED(0x10);
0056 static frm_lst_ptr *phys_frm;
0057 static UHCI_QH *int_qh = 0;
0058 static UHCI_QH *ctl_qh = 0;
0059 static UHCI_QH *blk_qh = 0;
0060 static uint32 toggles[128];     /* endpoint toggle bit states (bulk transfer) */
0061 
0062 uint32 td_phys, qh_phys;
0063 
0064 /* Virtual-to-Physical */
0065 #define TD_V2P(ty,p) ((ty)((((uint) (p)) - ((uint) td))+td_phys))
0066 #define QH_V2P(ty,p) ((ty)((((uint) (p)) - ((uint) qh))+qh_phys))
0067 /* Physical-to-Virtual */
0068 #define TD_P2V(ty,p) ((ty)((((uint) (p)) - td_phys)+((uint) td)))
0069 #define QH_P2V(ty,p) ((ty)((((uint) (p)) - qh_phys)+((uint) qh)))
0070 
0071 static task_id uhci_waitq = 0;  /* Tasks waiting for IRQ */
0072 
0073 #define TERMINATE 1
0074 #define SELECT_TD 0
0075 #define SELECT_QH 2
0076 #define DEPTH_FIRST 4
0077 #define LINK_MASK (~0xFL)
0078 
0079 
0080 /*
0081  * This is non-reentrant! Fortunately, we do not have concurrency yet:-)
0082  * This function returns the available Queue Head or Transfer Descriptor.
0083  * It will probably be removed later.
0084  */
0085 static void *
0086 sched_alloc (int type)
0087 {
0088   int i = 0;
0089 
0090   switch (type) {
0091     case TYPE_TD:
0092       for (i = 0; i < TD_POOL_SIZE; i++) {
0093         if (td[i].link_ptr == 0) {
0094           td[i].link_ptr = TERMINATE;
0095           return &td[i];
0096         }
0097       }
0098       break;
0099 
0100     case TYPE_QH:
0101       for (i = 0; i < QH_POOL_SIZE; i++) {
0102         if (qh[i].qh_ptr == 0 && qh[i].qe_ptr == 0) {
0103           qh[i].qh_ptr = qh[i].qe_ptr = TERMINATE;
0104           return &qh[i];
0105         }
0106       }
0107       break;
0108 
0109     default:
0110       DLOG("Unsupported Descriptor Type: %d", type);
0111       return (void *) 0;
0112 
0113   }
0114 
0115   DLOG("Error! Not enough descriptor in the pool! (type=%s)",
0116        (type == TYPE_TD ? "TD" : "QH"));
0117   return (void *) 0;
0118 }
0119 
0120 static int
0121 sched_free (int type, void *res)
0122 {
0123   UHCI_TD *res_td;
0124   UHCI_QH *res_qh;
0125 
0126   switch (type) {
0127     case TYPE_TD:
0128       res_td = (UHCI_TD *) res;
0129       res_td->link_ptr = 0;
0130       res_td->raw2 = 0;
0131       res_td->raw3 = 0;
0132       res_td->buf_ptr = 0;
0133       res_td->buf_vptr = 0;
0134       res_td->call_back = 0;
0135       break;
0136 
0137     case TYPE_QH:
0138       res_qh = (UHCI_QH *) res;
0139       res_qh->qh_ptr = 0;
0140       res_qh->qe_ptr = 0;
0141       break;
0142 
0143     default:
0144       return -1;
0145   }
0146 
0147   return 0;
0148 }
0149 
0150 /* Free continuous TDs of length len */
0151 static int
0152 free_tds (UHCI_TD * tds, int len)
0153 {
0154   int count = 0, i = 0, end = 0;
0155   uint32 link_ptr;
0156 
0157   for (i = 0; i < len; i++) {
0158     link_ptr = tds->link_ptr;
0159 
0160     if (tds->link_ptr & TERMINATE) {
0161       end++;
0162     }
0163 
0164     sched_free (TYPE_TD, tds);
0165     count++;
0166 
0167     if (end)
0168       break;
0169 
0170     tds = TD_P2V (UHCI_TD *, link_ptr & LINK_MASK);
0171   }
0172 
0173   return count;
0174 }
0175 
0176 static void
0177 disable_ehci (void)
0178 {
0179   int func = 0x7;
0180   uint32_t pa_ubase = 0;
0181   unsigned long eecp = 0;
0182   uint32_t va_ubase = 0;
0183   uint32_t opregs = 0;
0184   uint32_t config_flag = 0;
0185   uint8_t hcbiossem = 0;
0186 
0187   DLOG ("EHCI: Routing all ports to companion controllers...");
0188 
0189   /* Get physical address of EHCI base */
0190   pa_ubase = pci_config_rd32 (bus, dev, func, 0x10);
0191   pa_ubase = pa_ubase & 0xFFFFFF00;
0192 
0193   /* Convert physical address to virtual address */
0194   va_ubase = (uint32_t) map_virtual_page ((pa_ubase & 0xFFFFF000) + 0x3);
0195   va_ubase += (pa_ubase & 0x0FFF);
0196 
0197 #if 0
0198   DLOG ("EHCI Base Phys=%p Base Virt=%p", pa_ubase, va_ubase);
0199 #endif
0200 
0201   eecp = (*((unsigned int *) (((char *) va_ubase) + 0x08)) & 0x0FF00) >> 8;
0202 
0203 #if 0
0204   DLOG ("EECP=%p", eecp);
0205 #endif
0206 
0207   hcbiossem = pci_config_rd8 (bus, dev, func, eecp + 0x02) & 0x01;
0208   DLOG ("HC BIOS SEM: %p", hcbiossem);
0209   pci_config_wr8 (bus, dev, func, eecp + 0x03, 0x01);
0210 
0211   for (;;) {
0212     if (((pci_config_rd8 (bus, dev, func, eecp + 0x02) & 0x01) == 0x0) &&
0213         ((pci_config_rd8 (bus, dev, func, eecp + 0x03) & 0x01)) == 0x01)
0214       break;
0215   }
0216 
0217   DLOG ("Quest got ownership of EHCI!");
0218 
0219   opregs = va_ubase + *(char *) va_ubase;
0220   config_flag = *((uint32_t *) ((char *) opregs + 0x40));
0221 
0222   /* Clear bit 0 of CONFIGFLAG to route all ports */
0223   *((uint32_t *) ((char *) opregs + 0x40)) = 0x0;
0224   delay (100);
0225 }
0226 
0227 static void
0228 init_schedule (void)
0229 {
0230   UHCI_QH *q;
0231   int i = 0;
0232 
0233   phys_frm = (frm_lst_ptr *) get_phys_addr ((void *) frame_list);
0234 
0235   for (i = 0; i < 1024; i++) {
0236     frame_list[i] = TERMINATE;
0237   }
0238 
0239   memset ((void *) td, 0, 32 * TD_POOL_SIZE);
0240   memset ((void *) qh, 0, 16 * QH_POOL_SIZE);
0241 
0242   int_qh = sched_alloc (TYPE_QH);
0243   ctl_qh = sched_alloc (TYPE_QH);
0244   blk_qh = sched_alloc (TYPE_QH);
0245 
0246   /* Points to next Queue Head (First Control QH). Set Q=1, T=0 */
0247   int_qh->qh_ptr =
0248     (((uint32_t) get_phys_addr ((void *) ctl_qh)) & LINK_MASK) + SELECT_QH;
0249   int_qh->qe_ptr = TERMINATE;
0250 
0251   /* Points to next Queue Head (First Bulk QH). Set Q=1, T=0 */
0252   ctl_qh->qh_ptr =
0253     (((uint32_t) get_phys_addr ((void *) blk_qh)) & LINK_MASK) + SELECT_QH;
0254   ctl_qh->qe_ptr = TERMINATE;
0255 
0256   /* Set this as the last Queue Head for now. T=1 */
0257   blk_qh->qh_ptr = TERMINATE;
0258   blk_qh->qe_ptr = TERMINATE;
0259 
0260   /* create 2nd level for bulk queue */
0261   q = sched_alloc (TYPE_QH);
0262   q->qh_ptr = qh->qe_ptr = TERMINATE;
0263 
0264   blk_qh->qe_ptr =
0265     (((uint32_t) get_phys_addr ((void *) q)) & LINK_MASK) + SELECT_QH;
0266 
0267   blk_qh = q;
0268 
0269 #if 0
0270   DLOG ("int_qh va=%p ctl_qh va=%p qhp va=%p",
0271       int_qh, ctl_qh, qh);
0272 #endif
0273 
0274 #if 0
0275   DLOG ("frame_list va=%p pa=%p", frame_list, phys_frm);
0276 #endif
0277 
0278   /* Link all the frame list pointers to interrupt queue. No ISO TD present now. */
0279   for (i = 0; i < 1024; i++) {
0280     frame_list[i] =
0281       (((uint32_t) get_phys_addr ((void *) int_qh)) & LINK_MASK) + SELECT_QH;
0282   }
0283 }
0284 
0285 static void
0286 debug_dump_sched (UHCI_TD * tx_tds)
0287 {
0288   // Dump the schedule for debugging
0289 
0290   for (;;) {
0291     DLOG ("TD dump: %p %p %p %p %p",
0292           tx_tds->link_ptr, tx_tds->raw2, tx_tds->raw3,
0293           tx_tds->buf_ptr, tx_tds->buf_vptr);
0294     DLOG ("  act_len=%d status=%p ioc=%d iso=%d ls=%d c_err=%d spd=%d",
0295           tx_tds->act_len, tx_tds->status, tx_tds->ioc, tx_tds->iso,
0296           tx_tds->ls, tx_tds->c_err, tx_tds->spd);
0297     DLOG ("  pid=0x%.02X addr=%d ep=%d tog=%d max_len=%d",
0298           tx_tds->pid, tx_tds->addr, tx_tds->endp, tx_tds->toggle, tx_tds->max_len);
0299 #if 0
0300     if (tx_tds->buf_vptr) {
0301       uint32 *p = (uint32 *)tx_tds->buf_vptr;
0302       DLOG ("    %.08X %.08X %.08X %.08X",
0303             p[0], p[1], p[2], p[3]);
0304     }
0305 #endif
0306     if (tx_tds->link_ptr & TERMINATE) break;
0307     if (tx_tds->link_ptr == 0) break;
0308     tx_tds = TD_P2V (UHCI_TD *, tx_tds->link_ptr & LINK_MASK);
0309   }
0310 }
0311 
0312 /* Hack that works around problem where HC does not update the
0313  * QH->qe_ptr with the current active TD.  For some reason it leaves
0314  * behind an inactive TD, which causes the HC to halt processing at
0315  * that point.  This function manually updates the QH with a physical
0316  * pointer to the next active TD. */
0317 static void
0318 fixup_tds (u32 *p_tdp)
0319 {
0320   while (!(*p_tdp & TERMINATE) && *p_tdp) {
0321     UHCI_TD *t = TD_P2V (UHCI_TD *, (*p_tdp) & LINK_MASK);
0322     if (t->status == 0)
0323       *p_tdp = t->link_ptr & (~DEPTH_FIRST);
0324     else
0325       break;
0326     p_tdp = &t->link_ptr;
0327   }
0328 }
0329 
0330 static u64 uhci_bytes = 0, uhci_timestamps = 0;
0331 
0332 extern u32
0333 uhci_sample_bps (void)
0334 {
0335   extern u32 tsc_freq_msec;
0336   u64 uhci_msec = div64_64 (uhci_timestamps, (u64) tsc_freq_msec);
0337   u32 bytes_sec = 0;
0338   if (uhci_msec)
0339     bytes_sec = (u32) div64_64 (uhci_bytes * 1000, uhci_msec);
0340   uhci_bytes = 0;
0341   uhci_timestamps = 0;
0342   return bytes_sec;
0343 }
0344 
0345 extern void
0346 debug_dump_bulk_qhs (void)
0347 {
0348   UHCI_QH *q = blk_qh;
0349   uint32 link_ptr;
0350   DLOG ("cmd=0x%.04X sts=0x%.04X frame=%d bps=%d",
0351         GET_USBCMD (usb_base), GET_USBSTS (usb_base), GET_FRNUM (usb_base),
0352         uhci_sample_bps ());
0353   for (;;) {
0354     link_ptr = q->qe_ptr;
0355     if (link_ptr & TERMINATE) {
0356       DLOG ("QH %p has no TDs", q);
0357     } else {
0358       DLOG ("QH %p has TD %p:", q, q->qe_ptr);
0359       debug_dump_sched (TD_P2V (UHCI_TD *, q->qe_ptr & LINK_MASK));
0360     }
0361     fixup_tds (&q->qe_ptr);
0362     link_ptr = q->qh_ptr;
0363     if (link_ptr & TERMINATE)
0364       break;
0365     q = QH_P2V (UHCI_QH *, link_ptr & LINK_MASK);
0366   }
0367 }
0368 
0369 static int
0370 check_tds (UHCI_QH *tx_qh, UHCI_TD *tx_tds, uint32 *act_len)
0371 {
0372   int status_count = 1;
0373   int status = 0;
0374   int len = 0;
0375 
0376   while (status_count) {
0377     UHCI_TD *tds = tx_tds;
0378     status_count = 0;
0379 
0380     fixup_tds (&tx_qh->qe_ptr);
0381 
0382     /* wait for IRQ if interrupts enabled */
0383     if (mp_enabled) {
0384       DLOGV ("wait %d", status_count);
0385       queue_append (&uhci_waitq, str ());
0386       schedule ();
0387     }
0388 
0389     len = 0;
0390     while (tds != TD_P2V (UHCI_TD *, 0)) {
0391       if (tds->status & 0x80) {
0392         status_count++;
0393       } else {
0394         len += (tds->act_len + 1) & 0x7FF;
0395         /* Check for short packet */
0396         if (tds->act_len != tds->max_len) {
0397           DLOG ("Short Packet! after %d bytes", len);
0398 #if 1
0399           *act_len = len;
0400           return status;
0401 #else
0402           debug_dump_sched (tx_tds);
0403 #endif
0404         }
0405       }
0406 
0407       /* If the TD is STALLED, we report the error */
0408       if (tds->status & 0x40) {
0409         status = tds->status & 0x7F;
0410 
0411         debug_dump_sched (tx_tds);
0412 
0413         return status;
0414       }
0415 
0416       /* If the TD is timed out */
0417       if (tds->status & 0x04) {
0418         status = tds->status & 0x7F;
0419         return status;
0420       }
0421 
0422 #if 0
0423       /* Got a NAK */
0424       if (tds->status & 0x08) {
0425         DLOG ("NAK! after %d bytes", len);
0426         *act_len = len;
0427         return status;
0428       }
0429 #endif
0430 
0431       /* move to next TD in chain */
0432       tds = TD_P2V (UHCI_TD *, tds->link_ptr & LINK_MASK);
0433     }
0434   }
0435 
0436   *act_len = len;
0437   return status;
0438 }
0439 
0440 int
0441 port_reset (uint8_t port)
0442 {
0443   uint16_t portsc = 0;
0444   switch (port) {
0445   case 0:
0446     portsc = GET_PORTSC0 (usb_base);
0447     SET_PORTSC0 (usb_base, portsc | 0x0200);
0448     delay (10);
0449     SET_PORTSC0 (usb_base, portsc & ~0x0200);
0450     delay (1);
0451     SET_PORTSC0 (usb_base, portsc | 0x0004);
0452     delay (50);
0453     break;
0454 
0455   case 1:
0456     portsc = GET_PORTSC1 (usb_base);
0457     SET_PORTSC1 (usb_base, portsc | 0x0200);
0458     delay (10);
0459     SET_PORTSC1 (usb_base, portsc & ~0x0200);
0460     delay (1);
0461     SET_PORTSC1 (usb_base, portsc | 0x0004);
0462     delay (50);
0463     break;
0464 
0465   default:
0466     return -1;
0467   }
0468 
0469   return 0;
0470 }
0471 
0472 int
0473 uhci_reset (void)
0474 {
0475   if (usb_base == 0)
0476     return -1;
0477 
0478   /* Reset UHCI host controller (Global Reset) */
0479   SET_USBCMD (usb_base, 0x0004);
0480   delay (100);                  // USB Spec specifies 10ms only
0481   SET_USBCMD (usb_base, 0x0000);
0482   delay (100);
0483 
0484   SET_USBINTR (usb_base, 0x0F);
0485   SET_PCICMD (bus, dev, func, GET_PCICMD (bus, dev, func) & 0xFBFF);
0486 
0487   /* Set up the frame list for the HC */
0488   SET_FRBASEADD (usb_base, (uint32_t) phys_frm);
0489   /* Set SOF timing */
0490   SET_SOFMOD (usb_base, 0x40);
0491   /* Set Frame Number */
0492   SET_FRNUM (usb_base, 0x0);
0493   /* Now, start the HC */
0494   SET_USBCMD (usb_base, 0x0001);
0495 
0496   return 0;
0497 }
0498 
0499 #define USB_MAX_DEVICES 32
0500 static USB_DEVICE_INFO devinfo[USB_MAX_DEVICES+1];
0501 static uint next_address = 1;
0502 
0503 #define USB_MAX_DEVICE_DRIVERS 32
0504 static USB_DRIVER drivers[USB_MAX_DEVICE_DRIVERS];
0505 static uint num_drivers = 0;
0506 
0507 void
0508 find_device_driver (USB_DEVICE_INFO *info, USB_CFG_DESC *cfgd, USB_IF_DESC *ifd)
0509 {
0510   int d;
0511   for (d=0; d<num_drivers; d++) {
0512     if (drivers[d].probe (info, cfgd, ifd))
0513       return;
0514   }
0515 }
0516 
0517 void
0518 dlog_devd (USB_DEV_DESC *devd)
0519 {
0520   DLOG ("DEVICE DESCRIPTOR len=%d type=%d bcdUSB=0x%x",
0521         devd->bLength, devd->bDescriptorType, devd->bcdUSB);
0522   DLOG ("  class=0x%x subclass=0x%x proto=0x%x maxpkt0=%d",
0523         devd->bDeviceClass, devd->bDeviceSubClass, devd->bDeviceProtocol,
0524         devd->bMaxPacketSize0);
0525   DLOG ("  vendor=0x%x product=0x%x bcdDevice=0x%x numcfgs=%d",
0526         devd->idVendor, devd->idProduct, devd->bcdDevice,
0527         devd->bNumConfigurations);
0528 }
0529 
0530 void
0531 dlog_info (USB_DEVICE_INFO *info)
0532 {
0533   DLOG ("ADDRESS %d", info->address);
0534   dlog_devd (&info->devd);
0535 
0536 #if 0
0537   uint8 strbuf[64];
0538   uint8 str[32];
0539 #define do_str(slot,label)                                              \
0540   if (info->devd.slot != 0 &&                                           \
0541       uhci_get_string (info->address, info->devd.slot, 0,               \
0542                        sizeof (strbuf), strbuf,                         \
0543                        info->devd.bMaxPacketSize0)                      \
0544       == 0) {                                                           \
0545     memset (str, 0, sizeof (str));                                      \
0546     if (uhci_interp_string ((USB_STR_DESC *)strbuf, sizeof (strbuf), 0, \
0547                             str, sizeof (str)-1) > 0) {                 \
0548       DLOG ("  "label": %s", str);                                      \
0549     }                                                                   \
0550   }
0551 
0552   do_str (iManufacturer, "Manufacturer");
0553   do_str (iProduct, "Product");
0554 #undef do_str
0555 #endif
0556 }
0557 
0558 /* figures out what device is attached as address 0 */
0559 bool
0560 uhci_enumerate (void)
0561 {
0562   USB_DEV_DESC devd;
0563   USB_CFG_DESC *cfgd;
0564   USB_IF_DESC *ifd;
0565 #define TEMPSZ 256
0566   uint8 temp[TEMPSZ], *ptr;
0567   uint curdev = next_address;
0568   sint status, c, i, total_length=0;
0569   USB_DEVICE_INFO *info;
0570 
0571   if (curdev > USB_MAX_DEVICES) {
0572     DLOG ("uhci_enumerate: too many devices");
0573     return FALSE;
0574   }
0575 
0576   DLOG ("uhci_enumerate: curdev=%d", curdev);
0577 
0578   /* clear device info */
0579   info = &devinfo[curdev];
0580   memset (info, 0, sizeof (USB_DEVICE_INFO));
0581   info->address = 0;
0582   info->host_type = USB_TYPE_HC_UHCI;
0583 
0584   /* OK, here is the deal. The spec says you should use the maximum
0585    * packet size in the data phase of control transfer if the data
0586    * is larger than one packet. Since we do not want to support low
0587    * speed device for now, the bMaxPacketSize0 is always set to 64
0588    * bytes for full speed device. So, do not be surprised if your USB
0589    * mouse does not work in Quest!
0590    */
0591   info->devd.bMaxPacketSize0 = 64;
0592 
0593   memset (&devd, 0, sizeof (USB_DEV_DESC));
0594 
0595   /* get device descriptor */
0596   status = usb_get_descriptor (info, USB_TYPE_DEV_DESC, 0, 0,
0597                                sizeof (USB_DEV_DESC), &devd);
0598   if (status != 0)
0599     goto abort;
0600 
0601   if (devd.bMaxPacketSize0 == 8) {
0602     /* get device descriptor */
0603     info->devd.bMaxPacketSize0 = 8;
0604     status = usb_get_descriptor (info, USB_TYPE_DEV_DESC, 0, 0,
0605                                  sizeof (USB_DEV_DESC), &devd);
0606     if (status != 0)
0607       goto abort;
0608   }
0609 
0610   if (devd.bNumConfigurations == 255)
0611     devd.bNumConfigurations = 1; /* hack */
0612 
0613   /* Update device info structure. Put it in USB core might be better */
0614   memcpy (&info->devd, &devd, sizeof (USB_DEV_DESC));
0615 
0616   /* assign an address */
0617   if (usb_set_address (info, curdev) != 0)
0618     goto abort;
0619   DLOG ("uhci_enumerate: set (0x%x, 0x%x, 0x%x) to addr %d",
0620         devd.bDeviceClass, devd.idVendor, devd.idProduct, curdev);
0621   delay (2);
0622 
0623   DLOG ("uhci_enumerate: num configs=%d", devd.bNumConfigurations);
0624 
0625   /* Update device info structure for new address. */
0626   info->address = curdev;
0627 
0628   dlog_info (info);
0629 
0630   for (c=0; c<devd.bNumConfigurations; c++) {
0631     /* get a config descriptor for size field */
0632     memset (temp, 0, TEMPSZ);
0633     status = usb_get_descriptor (info, USB_TYPE_CFG_DESC, c, 0,
0634                                  sizeof (USB_CFG_DESC), temp);
0635     if (status != 0) {
0636       DLOG ("uhci_enumerate: failed to get config descriptor for c=%d", c);
0637       goto abort;
0638     }
0639 
0640     cfgd = (USB_CFG_DESC *)temp;
0641     DLOG ("uhci_enumerate: c=%d cfgd->wTotalLength=%d", c, cfgd->wTotalLength);
0642     total_length += cfgd->wTotalLength;
0643   }
0644 
0645   DLOG ("uhci_enumerate: total_length=%d", total_length);
0646 
0647   /* allocate memory to hold everything */
0648   pow2_alloc (total_length, &info->raw);
0649   if (!info->raw) {
0650     DLOG ("uhci_enumerate: pow2_alloc (%d) failed", total_length);
0651     goto abort;
0652   }
0653 
0654   /* read all cfg, if, and endpoint descriptors */
0655   ptr = info->raw;
0656   for (c=0; c<devd.bNumConfigurations; c++) {
0657     /* obtain precise size info */
0658     memset (temp, 0, TEMPSZ);
0659     status = usb_get_descriptor (info, USB_TYPE_CFG_DESC, c, 0,
0660                                  sizeof (USB_CFG_DESC), temp);
0661     if (status != 0) {
0662       DLOG ("uhci_enumerate: failed to get config descriptor for c=%d", c);
0663       goto abort_mem;
0664     }
0665     cfgd = (USB_CFG_DESC *)temp;
0666 
0667     /* get cfg, if, and endp descriptors */
0668     status =
0669       usb_get_descriptor (info, USB_TYPE_CFG_DESC, c, 0, cfgd->wTotalLength, ptr);
0670     if (status != 0)
0671       goto abort_mem;
0672 
0673     cfgd = (USB_CFG_DESC *)ptr;
0674     DLOG ("uhci_enumerate: cfg %d has num_if=%d", c, cfgd->bNumInterfaces);
0675     ptr += cfgd->wTotalLength;
0676   }
0677 
0678   /* incr this here because hub drivers may recursively invoke enumerate */
0679   next_address++;
0680 
0681   /* parse cfg and if descriptors */
0682   ptr = info->raw;
0683   for (c=0; c<devd.bNumConfigurations; c++) {
0684     cfgd = (USB_CFG_DESC *) ptr;
0685     ptr += cfgd->bLength;
0686     for (i=0; i<cfgd->bNumInterfaces; i++) {
0687       /* find the next if descriptor, skipping any class-specific stuff */
0688       for (ifd = (USB_IF_DESC *) ptr;
0689            ifd->bDescriptorType != USB_TYPE_IF_DESC;
0690            ifd = (USB_IF_DESC *)((uint8 *)ifd + ifd->bLength)) {
0691         //DLOG ("ifd=%p len=%d type=0x%x", ifd, ifd->bLength, ifd->bDescriptorType);
0692       }
0693       ptr = (uint8 *) ifd;
0694       DLOG ("uhci_enumerate: examining (%d, %d) if_class=0x%X sub=0x%X proto=0x%X #endp=%d",
0695             c, i, ifd->bInterfaceClass,
0696             ifd->bInterfaceSubClass,
0697             ifd->bInterfaceProtocol,
0698             ifd->bNumEndpoints);
0699 
0700       /* find a device driver interested in this interface */
0701       find_device_driver (info, cfgd, ifd);
0702 
0703       ptr += ifd->bLength;
0704     }
0705     ptr = ((uint8 *)cfgd) + cfgd->wTotalLength;
0706   }
0707 
0708   /* --??-- what happens if more than one driver matches more than one config? */
0709 
0710   return TRUE;
0711 
0712  abort_mem:
0713   pow2_free (info->raw);
0714  abort:
0715   return FALSE;
0716 }
0717 
0718 bool
0719 usb_register_driver (USB_DRIVER *driver)
0720 {
0721   if (num_drivers >= USB_MAX_DEVICE_DRIVERS) return FALSE;
0722   memcpy (&drivers[num_drivers], driver, sizeof (USB_DRIVER));
0723   num_drivers++;
0724   return TRUE;
0725 }
0726 
0727 static bool uhci_operational = FALSE;
0728 bool
0729 usb_do_enumeration (void)
0730 {
0731   int i;
0732 #include <drivers/usb/usb_tests.h>
0733   if (!uhci_operational) return FALSE;
0734   DLOG ("begin enumeration");
0735 
0736   for (i=0;i<2;i++) {
0737     port_reset (i);
0738 
0739     uhci_enumerate ();
0740     show_usb_regs (bus, dev, func);
0741   }
0742   DLOG ("end enumeration");
0743   return TRUE;
0744 }
0745 
0746 static uint irq_line;
0747 
0748 bool
0749 uhci_init (void)
0750 {
0751   uint i, device_index, irq_pin;
0752   pci_device uhci_device;
0753   pci_irq_t irq;
0754 
0755   memset (toggles, 0, sizeof (toggles));
0756 
0757   if (mp_ISA_PC) {
0758     DLOG ("Cannot operate without PCI");
0759     return FALSE;
0760   }
0761 
0762   /* Find the UHCI device on the PCI bus */
0763   device_index = ~0;
0764   i=0;
0765   while (pci_find_device (0xFFFF, 0xFFFF, 0x0C, 0x03, i, &i)) {
0766     if (pci_get_device (i, &uhci_device)) {
0767       if (uhci_device.progIF == 0) {
0768         device_index = i;
0769         break;
0770       }
0771       i++;
0772     } else break;
0773   }
0774 
0775   if (device_index == ~0) {
0776     DLOG ("Unable to find compatible device on PCI bus");
0777     return FALSE;
0778   }
0779 
0780   if (!pci_get_device (device_index, &uhci_device)) {
0781     DLOG ("Unable to get PCI device from PCI subsystem");
0782     return FALSE;
0783   }
0784 
0785   bus = uhci_device.bus;
0786   dev = uhci_device.slot;
0787   func = uhci_device.func;
0788 
0789   DLOG ("Using PCI bus=%x dev=%x func=%x", bus, dev, func);
0790 
0791   if (!pci_get_interrupt (device_index, &irq_line, &irq_pin)) {
0792     DLOG ("Unable to get IRQ");
0793     return FALSE;
0794   }
0795 
0796   DLOG ("Using IRQ pin=%X", irq_pin);
0797 
0798   if (pci_irq_find (bus, dev, irq_pin, &irq)) {
0799     /* use PCI routing table */
0800     DLOG ("Found PCI routing entry irq.gsi=0x%x", irq.gsi);
0801     if (!pci_irq_map_handler (&irq, uhci_irq_handler, 0x01,
0802                               IOAPIC_DESTINATION_LOGICAL,
0803                               IOAPIC_DELIVERY_FIXED)) {
0804       DLOG ("Unable to map IRQ handler");
0805       return FALSE;
0806     }
0807     irq_line = irq.gsi;
0808   }
0809 
0810   td_phys = (uint32) get_phys_addr ((void *) td);
0811   qh_phys = (uint32) get_phys_addr ((void *) qh);
0812   DLOG ("td@%p td_phys@%p qh@%p qh_phys@%p",
0813         td, td_phys, qh, qh_phys);
0814 
0815 
0816   if (uhci_device.device != 0x7020)
0817     disable_ehci ();
0818 
0819   /* Disable USB Legacy Support, set PIRQ */
0820   DLOG ("UHCI LEGSUP: %p", GET_LEGACY (bus, dev, func));
0821   SET_LEGACY(bus, dev, func, 0x2000); /* PIRQ enabled */
0822   DLOG ("Set PIRQDEN");
0823 
0824   if (!pci_decode_bar (device_index, 4, NULL, &usb_base, NULL)) {
0825     DLOG ("unable to decode BAR4");
0826     return FALSE;
0827   }
0828 
0829   DLOG ("usb_base=0x%.04X", usb_base);
0830 
0831   /* Initiate UHCI internal data structure */
0832   init_schedule ();
0833   /* Perform global reset on host controller */
0834   uhci_reset ();
0835 
0836   uhci_operational = TRUE;
0837   return TRUE;
0838 }
0839 
0840 int
0841 uhci_isochronous_transfer (
0842     uint8_t address,
0843     uint8_t endpoint,
0844     addr_t data,
0845     int data_len,
0846     int *act_len,
0847     uint16_t frm,
0848     uint8_t direction,
0849     void (*func)(addr_t))
0850 {
0851   UHCI_TD *iso_td = 0;
0852   UHCI_TD *idx_td = 0;
0853   int max_packet_len = USB_MAX_LEN;
0854   frm_lst_ptr entry = 0;
0855 
0856   if ((data_len - 1) > max_packet_len)
0857     return -1;
0858 
0859   iso_td = sched_alloc (TYPE_TD);
0860   iso_td->status = 0x80;
0861   iso_td->c_err = 0;
0862   iso_td->ioc = 0; // --??-- For test, mask the interrupt
0863   iso_td->iso = 1;
0864   iso_td->spd = 0;
0865   iso_td->pid = (direction == DIR_IN) ? UHCI_PID_IN : UHCI_PID_OUT;
0866   iso_td->addr = address;
0867   iso_td->endp = endpoint;
0868   iso_td->toggle = 0;
0869   iso_td->max_len = data_len - 1;
0870   iso_td->buf_ptr = (uint32_t) get_phys_addr ((void *) data);
0871   iso_td->buf_vptr = data;
0872   iso_td->call_back = func;
0873 
0874   entry = frame_list[frm];
0875 
0876   if (!(entry & TERMINATE) && !(entry & SELECT_QH)) {
0877     idx_td = TD_P2V (UHCI_TD *, entry & LINK_MASK);
0878 
0879     while (!(idx_td->link_ptr & TERMINATE) && !(idx_td->link_ptr & SELECT_QH)) {
0880       idx_td = TD_P2V (UHCI_TD *, idx_td->link_ptr & LINK_MASK);
0881     }
0882 
0883     iso_td->link_ptr = idx_td->link_ptr;
0884     idx_td->link_ptr =
0885       (uint32_t) get_phys_addr ((void *) iso_td) & LINK_MASK;
0886   } else {
0887     iso_td->link_ptr =
0888       (((uint32_t) get_phys_addr ((void *) int_qh)) & LINK_MASK) + SELECT_QH;
0889     frame_list[frm] = (uint32_t) get_phys_addr ((void *) iso_td) & LINK_MASK;
0890   }
0891 
0892   //queue_append (&uhci_waitq, str ());
0893   //schedule ();
0894   while (iso_td->status & 0x80);
0895 
0896   *act_len = iso_td->act_len + 1;
0897   frame_list[frm] = iso_td->link_ptr;
0898   sched_free (TYPE_TD, iso_td);
0899 
0900 #if 0
0901   delay (500);
0902   delay (1000);
0903   DLOG ("The status of iso_td: %p ActLen: %p", iso_td->status, iso_td->act_len);
0904   frame_list[frm] = iso_td->link_ptr;
0905   sched_free (TYPE_TD, iso_td);
0906 #endif
0907 
0908   return 0;
0909 }
0910 
0911 /* find a free QH to queue up the TDs, or alloc a new one */
0912 static UHCI_QH *
0913 link_td_to_free_qh (UHCI_QH *q, UHCI_TD *t)
0914 {
0915   for (;;) {
0916     //DLOG ("examining QH: %p qe=%p qh=%p", q, q->qe_ptr, q->qh_ptr);
0917     if (q->qe_ptr & TERMINATE) {
0918       q->qe_ptr = TD_V2P (uint32, t) & LINK_MASK;
0919       //DLOG ("using existing QH %p", q);
0920       return q;
0921     }
0922     if (q->qh_ptr & TERMINATE) {
0923       UHCI_QH *newq = sched_alloc (TYPE_QH);
0924       if (newq == NULL) return NULL;
0925       newq->qe_ptr = (TD_V2P (uint32, t) & LINK_MASK) | SELECT_TD;
0926       newq->qh_ptr = TERMINATE;
0927       q->qh_ptr = (QH_V2P (uint32, newq) & LINK_MASK) | SELECT_QH;
0928       //DLOG ("created new QH %p", newq);
0929       return newq;
0930     }
0931 
0932     /* advance to next qh in list */
0933     q = QH_P2V (UHCI_QH *, q->qh_ptr & LINK_MASK);
0934   }
0935 }
0936 
0937 int
0938 uhci_bulk_transfer(
0939     uint8_t address,
0940     uint8_t endpoint,
0941     addr_t data,
0942     int data_len,
0943     int packet_len,
0944     uint8_t direction,
0945     uint32 *act_len)
0946 {
0947   UHCI_TD *tx_tds = 0;
0948   UHCI_TD *data_td = 0;
0949   UHCI_TD *idx_td = 0;
0950   UHCI_QH *act_qh;
0951   int max_packet_len = ((packet_len - 1) >= USB_MAX_LEN) ? USB_MAX_LEN : packet_len - 1;
0952   int i = 0, num_data_packets = 0, data_left = 0, return_status = 0, tog_idx;
0953 
0954   DLOGV ("bulk: %d %d %d %c", address, endpoint, data_len,
0955          direction == DIR_IN ? 'I' : 'O');
0956   num_data_packets = (data_len + max_packet_len) / (max_packet_len + 1);
0957   data_left = data_len;
0958 
0959   for(i = 0; i < num_data_packets; i++) {
0960     data_td = sched_alloc(TYPE_TD);
0961     data_td->link_ptr = TERMINATE;
0962     if(tx_tds == 0)
0963       tx_tds = data_td;
0964     else
0965       idx_td->link_ptr = (((uint32_t)get_phys_addr((void*)data_td)) & LINK_MASK) + DEPTH_FIRST;
0966 
0967     idx_td = data_td;
0968     data_td->status = 0x80;
0969     data_td->c_err = 3;
0970     data_td->ioc = data_td->iso = 0;
0971     data_td->spd = (direction == DIR_IN ? 1 : 0);
0972 
0973     data_td->pid = (direction == DIR_IN) ? UHCI_PID_IN : UHCI_PID_OUT;
0974     data_td->addr = address;
0975     data_td->endp = endpoint;
0976 
0977     tog_idx = (address * 32 + (endpoint + ((direction == DIR_IN) << 4)));
0978     data_td->toggle = (BITMAP_TST (toggles, tog_idx) ? 1 : 0);
0979     if (data_td->toggle)
0980       BITMAP_CLR (toggles, tog_idx);
0981     else
0982       BITMAP_SET (toggles, tog_idx);
0983 
0984     data_td->max_len = (data_left > (max_packet_len + 1)) ? max_packet_len : data_left - 1;
0985     data_td->buf_ptr = (uint32_t)get_phys_addr((void*)data);
0986     data_td->buf_vptr = data;
0987 
0988     if(data_left <= (max_packet_len + 1)) {
0989       data_td->ioc = 1;
0990       break;
0991     } else {
0992       data += (data_td->max_len + 1);
0993       data_left -= (data_td->max_len + 1);
0994     }
0995 
0996     /* set last packet IOC */
0997     if (i == num_data_packets - 1)
0998       data_td->ioc = 1;
0999   }
1000 
1001 
1002 #if 0
1003   DLOG ("Dumping tx_tds...");
1004   debug_dump_sched (tx_tds);
1005   DLOG ("... done");
1006 #endif
1007 
1008   /* Initiate our bulk transactions */
1009   act_qh = link_td_to_free_qh (blk_qh, tx_tds);
1010 
1011   if (act_qh == NULL) {
1012     DLOG ("act_qh == NULL");
1013     return -1;
1014   }
1015 
1016   u64 start, finish;
1017 
1018   RDTSC (start);
1019 
1020   /* Check the status of all the packets in the transaction */
1021   return_status = check_tds(act_qh, tx_tds, act_len);
1022   if (return_status != 0) {
1023     DLOG ("bulk: return_status != 0");
1024   } else {
1025     DLOGV ("complete: %d len %d", return_status, *act_len);
1026   }
1027 
1028   RDTSC (finish);
1029 
1030   if (return_status == 0) {
1031     uhci_bytes += *act_len;
1032     uhci_timestamps += finish - start;
1033   }
1034 
1035   /* unlink any remaining active TDs if short packet was detected */
1036   if (*act_len != data_len)
1037     act_qh->qe_ptr = TERMINATE;
1038 
1039   free_tds(tx_tds, num_data_packets);
1040 
1041   return return_status;
1042 }
1043 
1044 int
1045 uhci_control_transfer (
1046     uint8_t address,
1047     addr_t setup_req,    /* Use virtual address here */
1048     int setup_len,
1049     addr_t setup_data,   /* Use virtual address here */
1050     int data_len,
1051     int packet_len)      /* 64 bytes for Full-speed and 8 bytes for Low-speed */
1052 {
1053   UHCI_TD *tx_tds = 0;
1054   UHCI_TD *td_idx = 0;
1055   UHCI_TD *status_td = 0;
1056   UHCI_TD *data_td = 0;
1057   int i = 0, num_data_packets = 0, data_left = 0, return_status = 0;
1058   uint8_t pid = 0, toggle = 0;
1059   addr_t data = 0;
1060   /* Using the default pipe for control transfer */
1061   uint8_t endpoint = 0;
1062   uint32_t act_len;
1063 
1064   /*
1065    * USB specification max packet length :  1023 bytes
1066    * UHCI specification max packet length : 1280 bytes
1067    */
1068   /* This is encoded as n-1 */
1069   int max_packet_len =
1070     ((packet_len - 1) >= USB_MAX_LEN) ? USB_MAX_LEN : packet_len - 1;
1071   num_data_packets = (data_len + max_packet_len) / (max_packet_len + 1);
1072 
1073   /* Constructing the setup packet */
1074   tx_tds = sched_alloc (TYPE_TD);
1075   tx_tds->status = 0x80;        // Set status of the descriptor to active
1076   tx_tds->c_err = 3;            // Set counter to 3 errors
1077   tx_tds->ioc = tx_tds->iso = tx_tds->spd = 0;
1078 
1079   tx_tds->pid = UHCI_PID_SETUP;
1080   tx_tds->addr = address;
1081   tx_tds->endp = endpoint;
1082   tx_tds->toggle = toggle;      // For setup packet, it is always DATA0
1083   tx_tds->max_len = setup_len - 1;      // This field is encoded as n-1
1084 
1085   tx_tds->buf_ptr = (uint32_t) get_phys_addr ((void *) setup_req);
1086   tx_tds->buf_vptr = setup_req;
1087 
1088   /* Constructing the data packets */
1089   td_idx = tx_tds;
1090   toggle = 1;
1091   data_left = data_len;
1092   data = setup_data;
1093   pid = (*((char *) setup_req) & 0x80) ? UHCI_PID_IN : UHCI_PID_OUT;
1094 
1095   for (i = 0; i < num_data_packets; i++) {
1096     data_td = sched_alloc (TYPE_TD);
1097 
1098     /* Link TDs, depth first */
1099     td_idx->link_ptr =
1100       (((uint32_t) get_phys_addr ((void *) data_td)) & LINK_MASK) + DEPTH_FIRST;
1101     td_idx = data_td;
1102 
1103     data_td->status = 0x80;
1104     data_td->c_err = 3;
1105     data_td->ioc = data_td->iso = data_td->spd = 0;
1106     data_td->pid = pid;
1107     data_td->addr = address;
1108     data_td->endp = endpoint;
1109     data_td->toggle = toggle;
1110     data_td->max_len =
1111       (data_left > (max_packet_len + 1)) ? max_packet_len : data_left - 1;
1112     data_td->buf_ptr = (uint32_t) get_phys_addr ((void *) data);
1113     data_td->buf_vptr = data;
1114 
1115     if (data_left <= (max_packet_len + 1)) {
1116       break;
1117     } else {
1118       data += (data_td->max_len + 1);
1119       data_left -= (data_td->max_len + 1);
1120       toggle = (toggle == 1) ? 0 : 1;
1121     }
1122   }
1123 
1124   /* Constructing handshake packet */
1125   pid = (pid == UHCI_PID_IN) ? UHCI_PID_OUT : UHCI_PID_IN;
1126   toggle = 1;                   // For status stage, always use DATA1
1127   status_td = sched_alloc (TYPE_TD);
1128   td_idx->link_ptr =
1129     (((uint32_t) get_phys_addr ((void *) status_td)) & LINK_MASK) + DEPTH_FIRST;
1130 
1131   status_td->link_ptr = TERMINATE;   // Terminate
1132   status_td->status = 0x80;
1133   status_td->c_err = 3;
1134   status_td->ioc = status_td->iso = status_td->spd = 0;
1135   status_td->ioc = 1;
1136   status_td->pid = pid;
1137   status_td->addr = address;
1138   status_td->endp = endpoint;
1139   status_td->toggle = toggle;
1140   status_td->max_len = USB_NULL_PACKET;
1141 
1142   /* debug_dump_sched (tx_tds); */
1143 
1144   /* Initiate our control transaction */
1145   ctl_qh->qe_ptr =
1146     (((uint32_t) get_phys_addr ((void *) tx_tds)) & LINK_MASK) + 0x0;
1147 
1148   /* Check the status of all the packets in the transaction */
1149   return_status = check_tds (ctl_qh, tx_tds, &act_len);
1150 
1151   free_tds (tx_tds, num_data_packets + 2);
1152 
1153   return return_status;
1154 }
1155 
1156 int
1157 uhci_get_descriptor (
1158     uint8_t address,
1159     uint16_t dtype,   /* Descriptor type */
1160     uint16_t dindex,   /* Descriptor index */
1161     uint16_t index,    /* Zero or Language ID */
1162     uint16_t length,   /* Descriptor length */
1163     addr_t desc,
1164     uint8_t packet_size)
1165 {
1166   USB_DEV_REQ setup_req;
1167   setup_req.bmRequestType = 0x80;       // Characteristics of request, see spec, P183, Rev 1.1
1168   setup_req.bRequest = USB_GET_DESCRIPTOR;
1169   setup_req.wValue = (dtype << 8) + dindex;
1170   setup_req.wIndex = index;
1171   setup_req.wLength = length;
1172 
1173   return uhci_control_transfer (address,
1174       (addr_t) & setup_req, sizeof (USB_DEV_REQ),
1175       desc, length, packet_size);
1176 }
1177 
1178 sint
1179 uhci_get_string (uint8_t address, uint16_t index, uint16_t lang,
1180                  uint16_t length, void *buffer, uint8_t pktsize)
1181 {
1182   return uhci_get_descriptor (address, USB_TYPE_STR_DESC, index, lang,
1183                               length, buffer, pktsize);
1184 }
1185 
1186 sint
1187 uhci_interp_string (USB_STR_DESC *string, uint16_t length, uint16_t lang,
1188                     uint8 *output, uint16_t out_len)
1189 {
1190   sint i, j;
1191   if (lang == 0) {
1192     /* assume UTF-16 encoding */
1193     length = (length < string->bLength ? length : string->bLength);
1194     /* skip first 2 bytes */
1195     length -= 2;
1196     for (i=0, j=0; i<length && j<out_len; i+=2, j++) {
1197       output[j] = string->bString[i];
1198     }
1199     return j;
1200   } else {
1201     /* unsupported */
1202     DLOG ("unimplemented: lang!=0");
1203     return 0;
1204   }
1205 }
1206 
1207 int
1208 uhci_set_address (uint8_t old_addr, uint8_t new_addr, uint8_t packet_size)
1209 {
1210   sint status;
1211   USB_DEV_REQ setup_req;
1212   setup_req.bmRequestType = 0x0;
1213   setup_req.bRequest = USB_SET_ADDRESS;
1214   setup_req.wValue = new_addr;
1215   setup_req.wIndex = 0;
1216   setup_req.wLength = 0;
1217 
1218   status = uhci_control_transfer (old_addr,
1219       (addr_t) & setup_req, sizeof (USB_DEV_REQ), 0,
1220       0, packet_size);
1221   if (status == 0) {
1222     toggles[old_addr] = toggles[new_addr] = 0;
1223   }
1224   return status;
1225 }
1226 
1227 int
1228 uhci_get_configuration (uint8_t addr, uint8_t packet_size)
1229 {
1230   USB_DEV_REQ setup_req;
1231   uint8_t num = -1;
1232   setup_req.bmRequestType = 0x80;
1233   setup_req.bRequest = USB_GET_CONFIGURATION;
1234   setup_req.wValue = 0;
1235   setup_req.wIndex = 0;
1236   setup_req.wLength = 1;
1237 
1238   uhci_control_transfer (addr, (addr_t) & setup_req, sizeof (USB_DEV_REQ),
1239       (addr_t) & num, 1, packet_size);
1240 
1241   return num;
1242 }
1243 
1244 int
1245 uhci_set_configuration (uint8_t addr, uint8_t conf, uint8_t packet_size)
1246 {
1247   USB_DEV_REQ setup_req;
1248   setup_req.bmRequestType = 0x0;
1249   setup_req.bRequest = USB_SET_CONFIGURATION;
1250   setup_req.wValue = conf;
1251   setup_req.wIndex = 0;
1252   setup_req.wLength = 0;
1253   /*
1254    * A bulk endpoint's toggle is initialized to DATA0 when any
1255    * configuration event is experienced
1256    */
1257   toggles[addr] = 0;
1258 
1259 
1260   return uhci_control_transfer (addr,
1261       (addr_t) & setup_req, sizeof (USB_DEV_REQ), 0,
1262       0, packet_size);
1263 }
1264 
1265 int
1266 uhci_set_interface (uint8_t addr, uint16_t alt, uint16_t interface,
1267     uint8_t packet_size)
1268 {
1269   USB_DEV_REQ setup_req;
1270   setup_req.bmRequestType = 0x01;
1271   setup_req.bRequest = USB_SET_INTERFACE;
1272   setup_req.wValue = alt;
1273   setup_req.wIndex = interface;
1274   setup_req.wLength = 0;
1275 
1276   return uhci_control_transfer (addr,
1277       (addr_t) & setup_req, sizeof (USB_DEV_REQ), 0,
1278       0, packet_size);
1279 }
1280 
1281 int
1282 uhci_get_interface (uint8_t addr, uint16_t interface, uint8_t packet_size)
1283 {
1284   USB_DEV_REQ setup_req;
1285   uint8_t alt = -1;
1286   setup_req.bmRequestType = 0x81;
1287   setup_req.bRequest = USB_GET_INTERFACE;
1288   setup_req.wValue = 0;
1289   setup_req.wIndex = interface;
1290   setup_req.wLength = 1;
1291 
1292   uhci_control_transfer (addr, (addr_t) & setup_req, sizeof (USB_DEV_REQ),
1293       (addr_t) & alt, 1, packet_size);
1294 
1295   return alt;
1296 }
1297 
1298 static uint32
1299 uhci_irq_handler (uint8 vec)
1300 {
1301   uint64 v;
1302   uint16 status;
1303 
1304   lock_kernel ();
1305 
1306 #if 0
1307   v = IOAPIC_read64 (0x10 + (irq_line * 2));
1308   DLOG ("(1) IOAPIC (irq_line=0x%x) says %p %p",
1309         irq_line, (uint32) (v >> 32), (uint32) v);
1310 #endif
1311 
1312   /* mask it */
1313   //IOAPIC_map_GSI (irq_line, UHCI_VECTOR, IOAPIC_FLAGS | 0x10000);
1314 
1315   /* Check the source of the interrupt received */
1316   status = 0;
1317   status = GET_USBSTS(usb_base);
1318 
1319 #if 0
1320   DLOG ("An interrupt is caught from usb IRQ_LN! (USBSTS=0x%x PCISTS=0x%x)",
1321         status,
1322         pci_config_rd16 (bus, dev, func, 0x06));
1323 #endif
1324 
1325   if((status & 0x3F) == 0) {
1326     DLOG("Interrupt is probably not from UHCI. Nothing will be done.");
1327     goto finish;
1328   }
1329 
1330   if(status & 0x20) {
1331     /* Host Controller Halted */
1332     DLOG("HCHalted detected!");
1333     status |= 0x20; /* Clear the interrupt by writing a 1 to it */
1334     debug_dump_bulk_qhs ();
1335   }
1336 
1337   if(status & 0x10) {
1338     /* Host Controller Process Error */
1339     DLOG("HC Process Error detected!");
1340     status |= 0x10; /* Clear the interrupt by writing a 1 to it */
1341   }
1342 
1343   if(status & 0x08) {
1344     /* Host System Error */
1345     DLOG("Host System Error detected!");
1346     status |= 0x08; /* Clear the interrupt by writing a 1 to it */
1347   }
1348 
1349   if(status & 0x04) {
1350     /* Resume Detect */
1351     DLOG("Resume detected!");
1352     status |= 0x04; /* Clear the interrupt by writing a 1 to it */
1353   }
1354 
1355   if(status & 0x02) {
1356     /* USB Error Interrupt */
1357     DLOG("USB Error Interrupt detected!");
1358     status |= 0x02; /* Clear the interrupt by writing a 1 to it */
1359 
1360     /* wake-up any waiting threads */
1361     wakeup_queue (&uhci_waitq);
1362   }
1363 
1364   if(status & 0x01) {
1365     DLOGV ("IRQ");
1366     /*
1367      * This is possibly an IOC or short packet.
1368      * We need to visit the whole schedule for now
1369      * to decide what exactly happened.
1370      */
1371     status |= 0x01; /* Clear the interrupt by writing a 1 to it */
1372 
1373     /* wake-up any waiting threads */
1374     wakeup_queue (&uhci_waitq);
1375 
1376 #if 0
1377     int i;
1378     for(i = 0; i < TD_POOL_SIZE; i++) {
1379       if(td[i].link_ptr && !(td[i].status & 0x80)) {
1380         /* Is this an IOC? */
1381         if(td[i].ioc) {
1382           /* Call the call back function from user if it exists */
1383           if(td[i].call_back) {
1384             (td[i].call_back)(td[i].buf_vptr);
1385             DLOG("Call back function called: 0x%x, buf_vptr: 0x%x",
1386                 td[i].call_back, td[i].buf_vptr);
1387           }
1388           /* Release this TD if it is isochronous */
1389           if(td[i].iso) sched_free(TYPE_TD, &td[i]);
1390         }
1391 
1392         /* Short packet detected */
1393         if(td[i].spd) {
1394           /* Release this TD if it is isochronous */
1395           if(td[i].iso) sched_free(TYPE_TD, &td[i]);
1396         }
1397       }
1398     }
1399 #endif
1400   }
1401 
1402  finish:
1403 
1404   /* clear the interrupt(s) */
1405   SET_USBSTS (usb_base, status);
1406 
1407 #if 0
1408   v = IOAPIC_read64 (0x10 + (irq_line * 2));
1409   DLOG ("(2) IOAPIC (irq_line=0x%x) says %p %p",
1410         irq_line, (uint32) (v >> 32), (uint32) v);
1411 #endif
1412 
1413   /* unmask it */
1414   //IOAPIC_map_GSI (irq_line, UHCI_VECTOR, IOAPIC_FLAGS);
1415 
1416   unlock_kernel ();
1417 
1418   return 0;
1419 }
1420 
1421 #define printf com1_printf
1422 #define print com1_puts
1423 #define putx  com1_putx
1424 #define putchar com1_putc
1425 
1426 extern void
1427 uhci_show_regs (void)
1428 {
1429   uint16_t base_addr = 0;
1430   uint32_t ldata = 0;
1431   uint16_t wdata = 0;
1432   uint8_t bdata = 0;
1433 #if 1
1434   print ("\nUHCI Controller PCI Register Address Map\n\n");
1435 
1436   wdata = pci_config_rd16 (bus, dev, func, 0x00);
1437   print ("VID: 0x");
1438   putx (wdata);
1439   putchar ('\n');
1440 
1441   wdata = pci_config_rd16 (bus, dev, func, 0x02);
1442   print ("DID: 0x");
1443   putx (wdata);
1444   putchar ('\n');
1445 
1446   wdata = pci_config_rd16 (bus, dev, func, 0x04);
1447   print ("PCICMD: 0x");
1448   putx (wdata);
1449   putchar ('\n');
1450 
1451   wdata = pci_config_rd16 (bus, dev, func, 0x06);
1452   print ("PCISTS: 0x");
1453   putx (wdata);
1454   putchar ('\n');
1455 
1456   bdata = pci_config_rd8 (bus, dev, func, 0x08);
1457   print ("RID: 0x");
1458   putx (bdata);
1459   putchar ('\n');
1460 
1461   bdata = pci_config_rd8 (bus, dev, func, 0x09);
1462   print ("PI: 0x");
1463   putx (bdata);
1464   putchar ('\n');
1465 
1466   bdata = pci_config_rd8 (bus, dev, func, 0x0A);
1467   print ("SCC: 0x");
1468   putx (bdata);
1469   putchar ('\n');
1470 
1471   bdata = pci_config_rd8 (bus, dev, func, 0x0B);
1472   print ("BCC: 0x");
1473   putx (bdata);
1474   putchar ('\n');
1475 
1476   bdata = pci_config_rd8 (bus, dev, func, 0x0D);
1477   print ("MLT: 0x");
1478   putx (bdata);
1479   putchar ('\n');
1480 
1481   bdata = pci_config_rd8 (bus, dev, func, 0x0E);
1482   print ("HEADTYP: 0x");
1483   putx (bdata);
1484   putchar ('\n');
1485 
1486   wdata = pci_config_rd16 (bus, dev, func, 0x20);
1487   print ("BASE: 0x");
1488   putx (wdata);
1489   putchar ('\n');
1490 
1491   wdata = pci_config_rd16 (bus, dev, func, 0x2C);
1492   print ("SVID: 0x");
1493   putx (wdata);
1494   putchar ('\n');
1495 
1496   wdata = pci_config_rd16 (bus, dev, func, 0x2E);
1497   print ("SID: 0x");
1498   putx (wdata);
1499   putchar ('\n');
1500 
1501   bdata = pci_config_rd8 (bus, dev, func, 0x3C);
1502   print ("INT_LN: 0x");
1503   putx (bdata);
1504   putchar ('\n');
1505 
1506   bdata = pci_config_rd8 (bus, dev, func, 0x3D);
1507   print ("INT_PN: 0x");
1508   putx (bdata);
1509   putchar ('\n');
1510 
1511   bdata = pci_config_rd8 (bus, dev, func, 0x60);
1512   print ("USB_RELNUM: 0x");
1513   putx (bdata);
1514   putchar ('\n');
1515 
1516   wdata = pci_config_rd16 (bus, dev, func, 0xC0);
1517   print ("USB_LEGKEY: 0x");
1518   putx (wdata);
1519   putchar ('\n');
1520 
1521   bdata = pci_config_rd8 (bus, dev, func, 0xC4);
1522   print ("USB_RES: 0x");
1523   putx (bdata);
1524   putchar ('\n');
1525 
1526   bdata = pci_config_rd8 (bus, dev, func, 0xC8);
1527   print ("CWP: 0x");
1528   putx (bdata);
1529   putchar ('\n');
1530 #endif
1531   base_addr = pci_config_rd16 (bus, dev, func, 0x20);
1532   base_addr &= 0xFFE0;
1533 
1534   print ("\nBase address for USB I/O Registers: 0x");
1535   putx (base_addr);
1536   putchar ('\n');
1537 
1538   print ("\nUSB I/O Registers\n\n");
1539 
1540   wdata = inw (base_addr + 0x00);
1541   print ("USBCMD: 0x");
1542   putx (wdata);
1543   putchar ('\n');
1544 
1545   wdata = inw (base_addr + 0x02);
1546   print ("USBSTS: 0x");
1547   putx (wdata);
1548   putchar ('\n');
1549 
1550   wdata = inw (base_addr + 0x04);
1551   print ("USBINTR: 0x");
1552   putx (wdata);
1553   putchar ('\n');
1554 
1555   wdata = inw (base_addr + 0x06);
1556   print ("FRNUM: 0x");
1557   putx (wdata);
1558   putchar ('\n');
1559 
1560   ldata = inl (base_addr + 0x08);
1561   print ("FRBASEADD: 0x");
1562   putx (ldata);
1563   putchar ('\n');
1564 
1565   bdata = inb (base_addr + 0x0C);
1566   print ("SOFMOD: 0x");
1567   putx (bdata);
1568   putchar ('\n');
1569 
1570   wdata = inw (base_addr + 0x10);
1571   print ("PORTSC0: 0x");
1572   putx (wdata);
1573   putchar ('\n');
1574 
1575   wdata = inw (base_addr + 0x12);
1576   print ("PORTSC1: 0x");
1577   putx (wdata);
1578   putchar ('\n');
1579 
1580   bdata = pci_config_rd8 (bus, dev, func, 0x3C);
1581   print ("INT_LN: 0x");
1582   putx (bdata);
1583   putchar ('\n');
1584 
1585   bdata = pci_config_rd8 (bus, dev, func, 0x3D);
1586   print ("INT_PN: 0x");
1587   putx (bdata);
1588   putchar ('\n');
1589 
1590   return;
1591 }
1592 
1593 #include "module/header.h"
1594 
1595 static const struct module_ops mod_ops = {
1596   .init = uhci_init
1597 };
1598 
1599 //DEF_MODULE (usb___uhci, "UHCI driver", &mod_ops, {"usb", "pci"});
1600 
1601 /*
1602  * Local Variables:
1603  * indent-tabs-mode: nil
1604  * mode: C
1605  * c-file-style: "gnu"
1606  * c-basic-offset: 2
1607  * End:
1608  */
1609 
1610 /* vi: set et sw=2 sts=2: */