1/* 2 * Copyright (c) 2007-2013 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <barrelfish/barrelfish.h> 14 15#include "ohci_device.h" 16 17#include <usb/usb.h> 18#include <usb/usb_error.h> 19 20#include <usb_controller.h> 21#include "usb_ohci.h" 22#include "usb_ohci_memory.h" 23#include "usb_ohci_bus.h" 24#include "usb_ohci_root_hub.h" 25 26/* 27 * our mackerel base 28 */ 29static struct ohci_t ohci_base; 30 31static struct usb_ohci_ed *usb_ohci_init_ed(struct usb_ohci_ed **list) 32{ 33 struct usb_ohci_ed *ed = usb_ohci_ed_alloc(); 34 if (ed == NULL) { 35 return NULL; 36 } 37 ed->ed_control.skip=1; 38 39 if (list != NULL) { 40 *list = ed; 41 } 42 return ed; 43} 44 45/** 46 * \brief initializes the host controller hardware 47 * 48 * \param hc the host controller 49 * \param suspend flag the host controller should be suspended 50 */ 51static usb_error_t usb_ohci_init_controller(usb_ohci_hc_t *hc, uint8_t suspend) 52{ 53 USB_DEBUG("usb_ohci_init_controller()\n"); 54 55 char status[512]; 56 ohci_control_pr(status, 512, hc->ohci_base); 57 puts(status); 58 59 /* 60 * check the ownership of the host controller 61 */ 62 if (ohci_control_ir_rdf(hc->ohci_base)) { 63 assert(!"REQEUST OWER CHANGE. "); 64 } 65 66 // reset the device 67 ohci_control_hcfs_wrf(hc->ohci_base, 0); 68 69 /* 70 * TODO: Wait till reset is done 71 */ 72 for(uint32_t i = 0; i < 2000000000; i++); 73 74 USB_DEBUG("usb_ohci_init_controller(): Device Reset done.\n"); 75 76 77 ohci_fm_interval_t ival = ohci_fm_interval_rd(hc->ohci_base); 78 79 ohci_cmdstatus_hcr_wrf(hc->ohci_base, 1); 80 81 for (uint16_t i = 0; i < 10; i++) { 82 /* 83 * TODO: Wait 10 us 84 */ 85 for(uint32_t j = 0; j < 2000000000; j++); 86 87 if (!ohci_cmdstatus_hcr_rdf(hc->ohci_base)) { 88 break; 89 } 90 } 91 if (ohci_cmdstatus_hcr_rdf(hc->ohci_base)) { 92 debug_printf("OHCI host controller reset timeout."); 93 return USB_ERR_IOERROR; 94 } 95 96 if (suspend) { 97 ohci_control_hcfs_wrf(hc->ohci_base, 3); 98 return USB_ERR_OK; 99 } 100 101 /* 102 * Setting up register values 103 */ 104 // HCCA pointer 105 ohci_hcca_wr(hc->ohci_base, usb_ohci_hcca_physaddr()); 106 107 // Control ED head pointer 108 ohci_ctrl_head_wr(hc->ohci_base, hc->qh_ctrl_first->ed_self); 109 110 // Bulk ED head pointer 111 ohci_bulk_head_wr(hc->ohci_base, hc->qh_bulk_first->ed_self); 112 113 USB_DEBUG("usb_ohci_init() - reset and enable interrupts\n"); 114 // reset the interrupts 115 ohci_intdisable_rawwr(hc->ohci_base, 0x0); 116 ohci_interrupt_t enabled_intrs = ohci_intenable_rd(hc->ohci_base); 117 enabled_intrs= ohci_interrupt_mie_insert(enabled_intrs, 1); 118 enabled_intrs= ohci_interrupt_wdh_insert(enabled_intrs, 1); 119 enabled_intrs= ohci_interrupt_rd_insert(enabled_intrs, 1); 120 enabled_intrs= ohci_interrupt_ue_insert(enabled_intrs, 1); 121 enabled_intrs= ohci_interrupt_oc_insert(enabled_intrs, 1); 122 enabled_intrs= ohci_interrupt_rhsc_insert(enabled_intrs, 1); 123 ohci_intenable_wr(hc->ohci_base, enabled_intrs); 124 125 hc->enabled_intrs = enabled_intrs; 126 127 // setting the desired features 128 ohci_control_t ctrl = ohci_control_rd(hc->ohci_base); 129 ctrl = ohci_control_ie_insert(ctrl, 1); 130 ctrl = ohci_control_ir_insert(ctrl,0); 131 ctrl = ohci_control_cle_insert(ctrl, 1); 132 ctrl = ohci_control_ble_insert(ctrl, 1); 133 ctrl = ohci_control_cbsr_insert(ctrl, 3); 134 ctrl = ohci_control_hcfs_insert(ctrl, 2); 135 ctrl = ohci_control_pe_insert(ctrl, 1); 136 ctrl = ohci_control_rwe_insert(ctrl, 1); 137 ctrl = ohci_control_rwc_insert(ctrl, 1); 138 ohci_control_wr(hc->ohci_base, ctrl); 139 140 /* 141 * the controller is now OPERATIONAL and running. 142 */ 143 debug_printf("OHCI host controller operational now!\n"); 144 // setting some remaining registers 145 ival = ohci_fm_interval_fit_insert(ival, 0); 146 ival = ohci_fm_interval_fsmps_insert(ival, (ival-210)*6/7); 147 ohci_fm_interval_wr(hc->ohci_base, ival); 148 ohci_period_start_wr(hc->ohci_base, (ival)*9/10); 149 150 // setting some root hub fields 151 ohci_rh_descra_nocp_wrf(hc->ohci_base, 1); 152 ohci_rh_status_lpsc_wrf(hc->ohci_base, 1); 153 154 /* 155 * getting the port numbers 156 */ 157 hc->root_hub_num_ports = 0; 158 for (uint8_t i = 0; (i < 10) && (hc->root_hub_num_ports == 0); i++) { 159 /* 160 * TODO: delay 161 */ 162 for(uint32_t j = 0; j < 100000000; j++); 163 hc->root_hub_num_ports = ohci_rh_descra_ndp_rdf(hc->ohci_base); 164 } 165 debug_printf("OHCI CONTROLLER INTIALIZED. Having %"PRIu8" ports\n", 166 hc->root_hub_num_ports ); 167 168 //char buf[8001]; 169 // ohci_rh_descra_pr(buf, 15999, hc->ohci_base); 170 // printf(buf); 171 //ohci_pr(buf, 5000, hc->ohci_base); 172 //printf(buf); 173 174 //ohci_cmdstatus_ocr_wrf(hc->ohci_base, 0x1); 175 usb_ohci_root_hub_interrupt(hc); 176 177 return USB_ERR_OK; 178} 179 180/* 181 * ------------------------------------------------------------------------ 182 * Exported Functions 183 * ------------------------------------------------------------------------ 184 */ 185 186 187 188/** 189 * \brief initializes the OHCI controller hardware 190 */ 191usb_error_t usb_ohci_init(usb_ohci_hc_t *hc, uintptr_t base) 192{ 193 /* 194 * initialize the mackerel framework 195 */ 196// TODO: Why does 32-bit expect mackerel_io_t? 197#ifdef __x86__ 198 ohci_initialize(&ohci_base, (mackerel_io_t)base); 199#else 200 ohci_initialize(&ohci_base, (mackerel_addr_t)base); 201#endif 202 hc->ohci_base = &ohci_base; 203 204 /* 205 * setup the endpoint descriptors 206 */ 207 hc->qh_bulk_last = usb_ohci_init_ed(&hc->qh_bulk_first); 208 hc->qh_ctrl_last = usb_ohci_init_ed(&hc->qh_ctrl_first); 209 hc->qh_isoc_last = usb_ohci_init_ed(NULL); 210 211 for (uint16_t i = 0; i<USB_OHCI_NO_EP_DESCRIPTORS; i++) { 212 hc->qh_intr_last[i] = usb_ohci_init_ed(NULL); 213 } 214 215 /** 216 * setup the interrupt transfer type tree 217 */ 218 uint16_t bit = USB_OHCI_NO_EP_DESCRIPTORS / 2; 219 uint16_t current; 220 uint16_t next; 221 while (bit) { 222 current = bit; 223 while (current & bit) { 224 next = (current ^ bit) | (bit / 2); 225 226 usb_ohci_ed_t *ed_current = hc->qh_intr_last[current]; 227 usb_ohci_ed_t *ed_next = hc->qh_intr_last[next]; 228 ed_current->next = NULL; 229 ed_current->ed_nextED = ed_next->ed_self; 230 231 current++; 232 } 233 bit >>= 1; 234 } 235 236 /* 237 * after the last interrupt endpoint the isochronus follows 238 */ 239 usb_ohci_ed_t *intr_ed = hc->qh_intr_last[0]; 240 intr_ed->next = hc->qh_isoc_last; 241 intr_ed->ed_nextED = hc->qh_isoc_last->ed_self; 242 /* 243 * allocate and initiate the HCCA memory region 244 */ 245 hc->hcca = usb_ohci_hcca_alloc(); 246 247 for (uint16_t i = 0; i < USB_OHCI_NO_IRQS; i++) { 248 hc->hcca->hcca_interrupt_table[i] = hc->qh_intr_last[i 249 | USB_OHCI_NO_EP_DESCRIPTORS / 2]->ed_self; 250 } 251 252 hc->controller->hcdi_bus_fn = usb_ohci_get_bus_fn(); 253 hc->controller->usb_revision = USB_REV_1_0; 254 255 256 /* 257 * initialize the hardware 258 */ 259 if (usb_ohci_init_controller(hc, 0) != USB_ERR_OK) { 260 return USB_ERR_INVAL; 261 } 262 263 USB_DEBUG("usb_ohci_init() - calling usb_ohci_do_poll\n"); 264 //usb_ohci_do_poll(hc->controller); 265 266 return USB_ERR_OK; 267 268} 269 270/** 271 * \brief this function shuts down the controller 272 * 273 * 274 */ 275void usb_ohci_detach(usb_ohci_hc_t *hc) 276{ 277 ohci_intdisable_wr(hc->ohci_base, 0xFFFFFFFF); 278 ohci_control_hcfs_wrf(hc->ohci_base, 0); 279} 280 281/** 282 * \brief the interrupt handler for this host controller 283 */ 284void usb_ohci_interrupt(usb_ohci_hc_t *hc) 285{ 286 struct usb_ohci_hcca *hcca = hc->hcca; 287 ohci_interrupt_t status = 0; 288 usb_paddr_t done = hcca->hcca_done_head; 289 290 /* 291 * check if we have some completed transfers 292 */ 293 if (!done) { 294 status = 0; 295 /* 296 * we have other interrupts at the time hcca done head 297 * was written. read status register 298 */ 299 if (USB_OHCI_HCCA_UNMASKED_IRQ(hcca)) { 300 status = ohci_intstatus_rd(hc->ohci_base); 301 } 302 /* 303 * we have just the WriteDoneHead interrupt 304 */ 305 if ((hcca - USB_OHCI_HCCA_UNMASKED_IRQ(hcca))) { 306 status = ohci_interrupt_wdh_insert(status, 1); 307 } 308 } else { 309 /* 310 * the done head has not been written, so read the interrupt status 311 * and clear the WriteDoneHead 312 */ 313 status = ohci_intstatus_rd(hc->ohci_base); 314 status = ohci_interrupt_wdh_insert(status, 0); 315 } 316 317 /* 318 * Master Interrupt Enable bit is always set on, so clear it 319 */ 320 status = ohci_interrupt_mie_insert(status, 0); 321 322 if (status == 0) { 323 /* 324 * there are no interrupts to process, just return 325 */ 326 return; 327 } 328 329 // acknowledge the interrupts 330 ohci_intstatus_wr(hc->ohci_base, status); 331 332 // get the enabled interrupts and clear the others 333 status &= hc->enabled_intrs; 334 335 if (status == 0) { 336 /* 337 * there are no interrupts to be enabled, so 338 * nothing to do left 339 */ 340 return; 341 } 342 343 /* 344 * ScheduleOverrun Interrupt 345 * 346 * This bit is set when the USB schedule for the current Frame 347 * overruns and after the update of HccaFrameNumber. A scheduling 348 * overrun will also cause the SchedulingOverrunCount of HcCommandStatus 349 * to be incremented. 350 */ 351 if (ohci_interrupt_so_extract(status)) { 352 debug_printf("ScheduleOverrun interrupt...\n"); 353 } 354 355 /* 356 * ResumeDetected 357 * This bit is set when HC detects that a device on the USB is 358 * asserting resume signaling. It is the transition from no resume 359 * signaling to resume signaling causing this bit to be set. This bit 360 * is not set when HCD sets the USBRESUME state 361 */ 362 if (ohci_interrupt_rd_extract(status)) { 363 debug_printf("ResumeDetected interrupt...\n"); 364 } 365 366 /* 367 * UnrecoverableError 368 * This bit is set when HC detects a system error not related to 369 * USB. HC should not proceed with any processing nor signaling 370 * before the system error has been corrected. HCD clears this bit 371 * after HC has been reset. 372 */ 373 if (ohci_interrupt_ue_extract(status)) { 374 debug_printf("UnrecoverableError interrupt...\n"); 375 376 } 377 378 /* 379 * RootHubStatusChange 380 * 381 * This bit is set when the content of HcRhStatus or the content of 382 * any of HcRhPortStatus[NumberofDownstreamPort] has changed. 383 */ 384 if (ohci_interrupt_rhsc_extract(status)) { 385 debug_printf("RootHubStatusChange interrupt...\n"); 386 387 hc->enabled_intrs = ohci_interrupt_rhsc_insert(hc->enabled_intrs, 0); 388 ohci_intdisable_rhsc_wrf(hc->ohci_base, 1); 389 390 usb_ohci_root_hub_interrupt(hc); 391 } 392 393 status = ohci_interrupt_rhsc_insert(status, 0); 394 status = ohci_interrupt_wdh_insert(status, 0); 395 status = ohci_interrupt_so_insert(status, 0); 396 397 if (status) { 398 ohci_intdisable_wr(hc->ohci_base, status); 399 hc->enabled_intrs &= ~status; 400 } 401 402 usb_ohci_do_poll(hc->controller); 403} 404