static void xhci_shutdown(hci_t *const controller) { int i; if (controller == 0) return; xhci_t *const xhci = XHCI_INST(controller); detach_controller(controller); /* Detach device hierarchy (starting at root hub) */ usb_detach_device(controller, 0); xhci_stop(controller); if (controller->pcidev) xhci_switchback_ppt_ports(controller->pcidev); if (xhci->sp_ptrs) { const size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs; for (i = 0; i < max_sp_bufs; ++i) { if (xhci->sp_ptrs[i]) free(phys_to_virt(xhci->sp_ptrs[i])); } } free(xhci->sp_ptrs); free(xhci->dcbaa); free(xhci->dev); free((void *)xhci->ev_ring_table); free((void *)xhci->er.ring); free((void *)xhci->cr.ring); free(xhci); free(controller); }
static void ohci_shutdown (hci_t *controller) { if (controller == 0) return; detach_controller (controller); ohci_stop(controller); OHCI_INST (controller)->roothub->destroy (OHCI_INST (controller)-> roothub); free (OHCI_INST (controller)); free (controller); }
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_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); free (UHCI_INST (controller)); free (controller); }
hci_t * xhci_init (unsigned long physical_bar) { int i; /* First, allocate and initialize static controller structures */ hci_t *const controller = new_controller(); if (!controller) { xhci_debug("Could not create USB controller instance\n"); return controller; } controller->type = XHCI; controller->start = xhci_start; controller->stop = xhci_stop; controller->reset = xhci_reset; controller->init = xhci_reinit; controller->shutdown = xhci_shutdown; controller->bulk = xhci_bulk; controller->control = xhci_control; controller->set_address = xhci_set_address; controller->finish_device_config= xhci_finish_device_config; controller->destroy_device = xhci_destroy_dev; controller->create_intr_queue = xhci_create_intr_queue; controller->destroy_intr_queue = xhci_destroy_intr_queue; controller->poll_intr_queue = xhci_poll_intr_queue; controller->pcidev = 0; for (i = 0; i < 128; ++i) { controller->devices[i] = NULL; } controller->instance = malloc(sizeof(xhci_t)); if (!controller->instance) { xhci_debug("Out of memory creating xHCI controller instance\n"); goto _free_controller; } xhci_t *const xhci = (xhci_t *)controller->instance; memset(xhci, 0x00, sizeof(*xhci)); init_device_entry(controller, 0); xhci->roothub = controller->devices[0]; xhci->cr.ring = xhci_align(64, COMMAND_RING_SIZE * sizeof(trb_t)); xhci->er.ring = xhci_align(64, EVENT_RING_SIZE * sizeof(trb_t)); xhci->ev_ring_table = xhci_align(64, sizeof(erst_entry_t)); if (!xhci->roothub || !xhci->cr.ring || !xhci->er.ring || !xhci->ev_ring_table) { xhci_debug("Out of memory\n"); goto _free_xhci; } xhci->capreg = phys_to_virt(physical_bar); xhci->opreg = ((void *)xhci->capreg) + xhci->capreg->caplength; xhci->hcrreg = ((void *)xhci->capreg) + xhci->capreg->rtsoff; xhci->dbreg = ((void *)xhci->capreg) + xhci->capreg->dboff; xhci_debug("regbase: 0x%"PRIx32"\n", physical_bar); xhci_debug("caplen: 0x%"PRIx32"\n", xhci->capreg->caplength); xhci_debug("rtsoff: 0x%"PRIx32"\n", xhci->capreg->rtsoff); xhci_debug("dboff: 0x%"PRIx32"\n", xhci->capreg->dboff); xhci_debug("hciversion: %"PRIx8".%"PRIx8"\n", xhci->capreg->hciver_hi, xhci->capreg->hciver_lo); if ((xhci->capreg->hciversion < 0x96) || (xhci->capreg->hciversion > 0x100)) { xhci_debug("Unsupported xHCI version\n"); goto _free_xhci; } xhci_debug("context size: %dB\n", CTXSIZE(xhci)); xhci_debug("maxslots: 0x%02lx\n", xhci->capreg->MaxSlots); xhci_debug("maxports: 0x%02lx\n", xhci->capreg->MaxPorts); const unsigned pagesize = xhci->opreg->pagesize << 12; xhci_debug("pagesize: 0x%04x\n", pagesize); /* * We haven't touched the hardware yet. So we allocate all dynamic * structures at first and can still chicken out easily if we run out * of memory. */ xhci->max_slots_en = xhci->capreg->MaxSlots & CONFIG_LP_MASK_MaxSlotsEn; xhci->dcbaa = xhci_align(64, (xhci->max_slots_en + 1) * sizeof(u64)); xhci->dev = malloc((xhci->max_slots_en + 1) * sizeof(*xhci->dev)); if (!xhci->dcbaa || !xhci->dev) { xhci_debug("Out of memory\n"); goto _free_xhci; } memset(xhci->dcbaa, 0x00, (xhci->max_slots_en + 1) * sizeof(u64)); memset(xhci->dev, 0x00, (xhci->max_slots_en + 1) * sizeof(*xhci->dev)); /* * Let dcbaa[0] point to another array of pointers, sp_ptrs. * The pointers therein point to scratchpad buffers (pages). */ const size_t max_sp_bufs = xhci->capreg->Max_Scratchpad_Bufs; xhci_debug("max scratchpad bufs: 0x%zx\n", max_sp_bufs); if (max_sp_bufs) { const size_t sp_ptrs_size = max_sp_bufs * sizeof(u64); xhci->sp_ptrs = xhci_align(64, sp_ptrs_size); if (!xhci->sp_ptrs) { xhci_debug("Out of memory\n"); goto _free_xhci_structs; } memset(xhci->sp_ptrs, 0x00, sp_ptrs_size); for (i = 0; i < max_sp_bufs; ++i) { /* Could use mmap() here if we had it. Maybe there is another way. */ void *const page = memalign(pagesize, pagesize); if (!page) { xhci_debug("Out of memory\n"); goto _free_xhci_structs; } xhci->sp_ptrs[i] = virt_to_phys(page); } xhci->dcbaa[0] = virt_to_phys(xhci->sp_ptrs); } if (dma_initialized()) { xhci->dma_buffer = dma_memalign(64 * 1024, DMA_SIZE); if (!xhci->dma_buffer) { xhci_debug("Not enough memory for DMA bounce buffer\n"); goto _free_xhci_structs; } } /* Now start working on the hardware */ if (xhci_wait_ready(xhci)) goto _free_xhci_structs; /* TODO: Check if BIOS claims ownership (and hand over) */ xhci_reset(controller); xhci_reinit(controller); xhci->roothub->controller = controller; xhci->roothub->init = xhci_rh_init; xhci->roothub->init(xhci->roothub); return controller; _free_xhci_structs: if (xhci->sp_ptrs) { for (i = 0; i < max_sp_bufs; ++i) { if (xhci->sp_ptrs[i]) free(phys_to_virt(xhci->sp_ptrs[i])); } } free(xhci->sp_ptrs); free(xhci->dcbaa); _free_xhci: free((void *)xhci->ev_ring_table); free((void *)xhci->er.ring); free((void *)xhci->cr.ring); free(xhci->roothub); free(xhci->dev); free(xhci); _free_controller: detach_controller(controller); free(controller); return NULL; }