static void uhci_reset (hci_t *controller) { /* reset */ uhci_reg_write16 (controller, USBCMD, 4); mdelay (50); uhci_reg_write16 (controller, USBCMD, 0); mdelay (10); uhci_reg_write16 (controller, USBCMD, 2); while ((uhci_reg_read16 (controller, USBCMD) & 2) != 0) mdelay (1); uhci_reg_write32 (controller, FLBASEADD, (u32) virt_to_phys (UHCI_INST (controller)-> framelistptr)); //debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr); /* disable irqs */ uhci_reg_write16 (controller, USBINTR, 0); /* reset framelist index */ uhci_reg_write16 (controller, FRNUM, 0); uhci_reg_mask16 (controller, USBCMD, ~0, 0xc0); // max packets, configure flag uhci_start (controller); }
/* disable root hub */ static void uhci_rh_disable_port (usbdev_t *dev, int port) { hci_t *controller = dev->controller; if (port == 1) port = PORTSC1; else if (port == 2) port = PORTSC2; else { usb_debug("Invalid port %d\n", port); return; } uhci_reg_write16(controller, port, uhci_reg_read16(controller, port) & ~4); u16 value; /* wait for controller to disable port */ /* TOTEST: how long to wait? 100ms for now */ int timeout = 200; /* time out after 200 * 500us == 100ms */ do { value = uhci_reg_read16 (controller, port); udelay(500); timeout--; } while (((value & (1 << 2)) != 0) && timeout); if (!timeout) usb_debug("Warning: uhci_rh: port disabling timed out.\n"); }
static void uhci_rh_scanport (usbdev_t *dev, int port) { int portsc, offset; if (port == 1) { portsc = PORTSC1; offset = 0; } else if (port == 2) { portsc = PORTSC2; offset = 1; } else { usb_debug("Invalid port %d\n", port); return; } int devno = RH_INST (dev)->port[offset]; if ((dev->controller->devices[devno] != 0) && (devno != -1)) { usb_detach_device(dev->controller, devno); RH_INST (dev)->port[offset] = -1; } uhci_reg_write16(dev->controller, portsc, uhci_reg_read16(dev->controller, portsc) | (1 << 3) | (1 << 2)); // clear port state change, enable port mdelay(100); // wait for signal to stabilize if ((uhci_reg_read16 (dev->controller, portsc) & 1) != 0) { // device attached uhci_rh_disable_port (dev, port); uhci_rh_enable_port (dev, port); int speed = ((uhci_reg_read16 (dev->controller, portsc) >> 8) & 1); RH_INST (dev)->port[offset] = usb_attach_device(dev->controller, dev->address, portsc, speed); }
static void uhci_reset (hci_t *controller) { /* reset */ uhci_reg_write16 (controller, USBCMD, 4); /* Global Reset */ mdelay (50); /* uhci spec 2.1.1: at least 10ms */ uhci_reg_write16 (controller, USBCMD, 0); mdelay (10); uhci_reg_write16 (controller, USBCMD, 2); /* Host Controller Reset */ /* wait for controller to finish reset */ /* TOTEST: how long to wait? 100ms for now */ int timeout = 200; /* time out after 200 * 500us == 100ms */ while (((uhci_reg_read16 (controller, USBCMD) & 2) != 0) && timeout--) udelay (500); if (timeout < 0) usb_debug ("Warning: uhci: host controller reset timed out.\n"); }
static void uhci_reinit (hci_t *controller) { uhci_reg_write32 (controller, FLBASEADD, (u32) virt_to_phys (UHCI_INST (controller)-> framelistptr)); //usb_debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr); /* disable irqs */ uhci_reg_write16 (controller, USBINTR, 0); /* reset framelist index */ uhci_reg_write16 (controller, FRNUM, 0); uhci_reg_write16(controller, USBCMD, uhci_reg_read16(controller, USBCMD) | 0xc0); // max packets, configure flag uhci_start (controller); }
static void uhci_rh_enable_port (usbdev_t *dev, int port) { u16 value; hci_t *controller = dev->controller; if (port == 1) port = PORTSC1; else if (port == 2) port = PORTSC2; else { usb_debug("Invalid port %d\n", port); return; } uhci_reg_write16(controller, port, uhci_reg_read16(controller, port) & ~(1 << 12)); /* wakeup */ uhci_reg_write16(controller, port, uhci_reg_read16(controller, port) | 1 << 9); /* reset */ mdelay (30); // >10ms uhci_reg_write16(controller, port, uhci_reg_read16(controller, port) & ~(1 << 9)); mdelay (1); // >5.3us per spec, <3ms because some devices make trouble uhci_reg_write16(controller, port, uhci_reg_read16(controller, port) | 1 << 2); /* enable */ /* wait for controller to enable port */ /* TOTEST: how long to wait? 100ms for now */ int timeout = 200; /* time out after 200 * 500us == 100ms */ do { value = uhci_reg_read16 (controller, port); udelay(500); timeout--; } while (((value & (1 << 2)) == 0) && (value & 0x01) && timeout); if (!timeout) usb_debug("Warning: uhci_rh: port enabling timed out.\n"); }
static td_t * wait_for_completed_qh (hci_t *controller, qh_t *qh) { int timeout = 1000; /* max 30 ms. */ 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 = 1000; } uhci_reg_write16(controller, USBSTS, uhci_reg_read16(controller, USBSTS) | 0); // clear resettable registers udelay (30); } return (GET_TD (qh->elementlinkptr) == 0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr)); }
static void uhci_shutdown (hci_t *controller) { if (controller == 0) return; detach_controller (controller); UHCI_INST (controller)->roothub->destroy (UHCI_INST (controller)-> roothub); 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); free (UHCI_INST (controller)->qh_data); free (UHCI_INST (controller)->qh_last); free (UHCI_INST (controller)); free (controller); }
static void uhci_stop (hci_t *controller) { uhci_reg_write16(controller, USBCMD, uhci_reg_read16(controller, USBCMD) & ~1); // stop work on schedule }
hci_t * uhci_init (pcidev_t addr) { int i; u16 reg16; hci_t *controller = new_controller (); if (!controller) fatal("Could not create USB controller instance.\n"); controller->instance = malloc (sizeof (uhci_t)); if(!controller->instance) fatal("Not enough memory creating USB controller instance.\n"); controller->type = UHCI; controller->start = uhci_start; controller->stop = uhci_stop; controller->reset = uhci_reset; controller->init = uhci_reinit; controller->shutdown = uhci_shutdown; controller->bulk = uhci_bulk; controller->control = uhci_control; controller->set_address = generic_set_address; controller->finish_device_config = NULL; controller->destroy_device = NULL; 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 = 0; 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 */ /* kill legacy support handler */ uhci_stop (controller); mdelay (1); uhci_reg_write16 (controller, USBSTS, 0x3f); 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) fatal("Not enough memory for USB frame list pointer.\n"); 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)); if (!antiberserk) fatal("Not enough memory for chipset workaround.\n"); 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)); if (! UHCI_INST (controller)->qh_prei || ! UHCI_INST (controller)->qh_intr || ! UHCI_INST (controller)->qh_data || ! UHCI_INST (controller)->qh_last) 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] = virt_to_phys (UHCI_INST (controller)->qh_prei) | FLISTP_QH; } controller->devices[0]->controller = controller; controller->devices[0]->init = uhci_rh_init; controller->devices[0]->init (controller->devices[0]); uhci_reset (controller); uhci_reinit (controller); return controller; }
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); }