Changes in uspace/drv/ohci/hc.c [d6522dd:049eb87] in mainline
- File:
-
- 1 edited
-
uspace/drv/ohci/hc.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ohci/hc.c
rd6522dd r049eb87 43 43 44 44 #include "hc.h" 45 #include "hcd_endpoint.h"46 45 47 46 static int interrupt_emulator(hc_t *instance); 48 47 static void hc_gain_control(hc_t *instance); 49 48 static void hc_init_hw(hc_t *instance); 50 static int hc_init_transfer_lists(hc_t *instance);51 static int hc_init_memory(hc_t *instance);52 49 /*----------------------------------------------------------------------------*/ 53 50 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun) … … 55 52 assert(instance); 56 53 assert(hub_fun); 57 58 int ret;59 54 60 55 usb_address_t hub_address = 61 56 device_keeper_get_free_address(&instance->manager, USB_SPEED_FULL); 62 if (hub_address <= 0) {63 usb_log_error("Failed to get OHCI root hub address.\n");64 return hub_address;65 }66 57 instance->rh.address = hub_address; 67 58 usb_device_keeper_bind( 68 59 &instance->manager, hub_address, hub_fun->handle); 69 60 70 ret = hc_add_endpoint(instance, hub_address, 0, USB_SPEED_FULL,71 USB_TRANSFER_CONTROL, USB_DIRECTION_BOTH, 64, 0, 0);72 if (ret != EOK) {73 usb_log_error("Failed to add OHCI rh endpoint 0.\n");74 usb_device_keeper_release(&instance->manager, hub_address);75 return ret;76 }77 78 61 char *match_str = NULL; 79 /* DDF needs heap allocated string */80 ret = asprintf(&match_str, "usb&class=hub");62 int ret = asprintf(&match_str, "usb&class=hub"); 63 ret = (match_str == NULL) ? ret : EOK; 81 64 if (ret < 0) { 82 usb_log_error( 83 "Failed(%d) to create root hub match-id string.\n", ret); 84 usb_device_keeper_release(&instance->manager, hub_address); 65 usb_log_error("Failed to create root hub match-id string.\n"); 85 66 return ret; 86 67 } … … 88 69 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 89 70 if (ret != EOK) { 90 usb_log_error("Failed add root hub match-id.\n");71 usb_log_error("Failed add create root hub match-id.\n"); 91 72 } 92 73 return ret; … … 109 90 ret, str_error(ret)); 110 91 92 instance->ddf_instance = fun; 111 93 usb_device_keeper_init(&instance->manager); 112 94 ret = usb_endpoint_manager_init(&instance->ep_manager, … … 115 97 ret, str_error(ret)); 116 98 117 hc_gain_control(instance);118 ret = hc_init_memory(instance);119 CHECK_RET_RETURN(ret, "Failed to create OHCI memory structures:%s.\n",120 ret, str_error(ret));121 hc_init_hw(instance);122 fibril_mutex_initialize(&instance->guard);123 124 rh_init(&instance->rh, instance->registers);125 126 99 if (!interrupts) { 127 100 instance->interrupt_emulator = … … 130 103 } 131 104 132 list_initialize(&instance->pending_batches); 133 #undef CHECK_RET_RETURN 105 hc_gain_control(instance); 106 107 rh_init(&instance->rh, dev, instance->registers); 108 109 hc_init_hw(instance); 110 111 /* TODO: implement */ 134 112 return EOK; 135 113 } 136 114 /*----------------------------------------------------------------------------*/ 137 int hc_add_endpoint(138 hc_t *instance, usb_address_t address, usb_endpoint_t endpoint,139 usb_speed_t speed, usb_transfer_type_t type, usb_direction_t direction,140 size_t mps, size_t size, unsigned interval)141 {142 endpoint_t *ep = malloc(sizeof(endpoint_t));143 if (ep == NULL)144 return ENOMEM;145 int ret =146 endpoint_init(ep, address, endpoint, direction, type, speed, mps);147 if (ret != EOK) {148 free(ep);149 return ret;150 }151 152 hcd_endpoint_t *hcd_ep = hcd_endpoint_assign(ep);153 if (hcd_ep == NULL) {154 endpoint_destroy(ep);155 return ENOMEM;156 }157 158 ret = usb_endpoint_manager_register_ep(&instance->ep_manager, ep, size);159 if (ret != EOK) {160 hcd_endpoint_clear(ep);161 endpoint_destroy(ep);162 return ret;163 }164 165 /* Enqueue hcd_ep */166 switch (ep->transfer_type) {167 case USB_TRANSFER_CONTROL:168 instance->registers->control &= ~C_CLE;169 endpoint_list_add_ep(170 &instance->lists[ep->transfer_type], hcd_ep);171 instance->registers->control_current = 0;172 instance->registers->control |= C_CLE;173 break;174 case USB_TRANSFER_BULK:175 instance->registers->control &= ~C_BLE;176 endpoint_list_add_ep(177 &instance->lists[ep->transfer_type], hcd_ep);178 instance->registers->control |= C_BLE;179 break;180 case USB_TRANSFER_ISOCHRONOUS:181 case USB_TRANSFER_INTERRUPT:182 instance->registers->control &= (~C_PLE & ~C_IE);183 endpoint_list_add_ep(184 &instance->lists[ep->transfer_type], hcd_ep);185 instance->registers->control |= C_PLE | C_IE;186 break;187 default:188 break;189 }190 191 return EOK;192 }193 /*----------------------------------------------------------------------------*/194 int hc_remove_endpoint(hc_t *instance, usb_address_t address,195 usb_endpoint_t endpoint, usb_direction_t direction)196 {197 assert(instance);198 fibril_mutex_lock(&instance->guard);199 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,200 address, endpoint, direction, NULL);201 if (ep == NULL) {202 usb_log_error("Endpoint unregister failed: No such EP.\n");203 fibril_mutex_unlock(&instance->guard);204 return ENOENT;205 }206 207 hcd_endpoint_t *hcd_ep = hcd_endpoint_get(ep);208 if (hcd_ep) {209 /* Dequeue hcd_ep */210 switch (ep->transfer_type) {211 case USB_TRANSFER_CONTROL:212 instance->registers->control &= ~C_CLE;213 endpoint_list_remove_ep(214 &instance->lists[ep->transfer_type], hcd_ep);215 instance->registers->control_current = 0;216 instance->registers->control |= C_CLE;217 break;218 case USB_TRANSFER_BULK:219 instance->registers->control &= ~C_BLE;220 endpoint_list_remove_ep(221 &instance->lists[ep->transfer_type], hcd_ep);222 instance->registers->control |= C_BLE;223 break;224 case USB_TRANSFER_ISOCHRONOUS:225 case USB_TRANSFER_INTERRUPT:226 instance->registers->control &= (~C_PLE & ~C_IE);227 endpoint_list_remove_ep(228 &instance->lists[ep->transfer_type], hcd_ep);229 instance->registers->control |= C_PLE | C_IE;230 break;231 default:232 break;233 }234 hcd_endpoint_clear(ep);235 } else {236 usb_log_warning("Endpoint without hcd equivalent structure.\n");237 }238 int ret = usb_endpoint_manager_unregister_ep(&instance->ep_manager,239 address, endpoint, direction);240 fibril_mutex_unlock(&instance->guard);241 return ret;242 }243 /*----------------------------------------------------------------------------*/244 endpoint_t * hc_get_endpoint(hc_t *instance, usb_address_t address,245 usb_endpoint_t endpoint, usb_direction_t direction, size_t *bw)246 {247 assert(instance);248 fibril_mutex_lock(&instance->guard);249 endpoint_t *ep = usb_endpoint_manager_get_ep(&instance->ep_manager,250 address, endpoint, direction, bw);251 fibril_mutex_unlock(&instance->guard);252 return ep;253 }254 /*----------------------------------------------------------------------------*/255 115 int hc_schedule(hc_t *instance, usb_transfer_batch_t *batch) 256 116 { 257 117 assert(instance); 258 118 assert(batch); 259 assert(batch->ep); 260 261 /* check for root hub communication */ 262 if (batch->ep->address == instance->rh.address) { 119 if (batch->target.address == instance->rh.address) { 263 120 return rh_request(&instance->rh, batch); 264 121 } 265 266 fibril_mutex_lock(&instance->guard); 267 list_append(&batch->link, &instance->pending_batches); 268 batch_commit(batch); 269 switch (batch->ep->transfer_type) { 270 case USB_TRANSFER_CONTROL: 271 instance->registers->command_status |= CS_CLF; 272 break; 273 case USB_TRANSFER_BULK: 274 instance->registers->command_status |= CS_BLF; 275 break; 276 default: 277 break; 278 } 279 280 fibril_mutex_unlock(&instance->guard); 281 return EOK; 122 /* TODO: implement */ 123 return ENOTSUP; 282 124 } 283 125 /*----------------------------------------------------------------------------*/ … … 285 127 { 286 128 assert(instance); 287 if ( (status & ~IS_SF) == 0) /* ignore sof status */129 if (status == 0) 288 130 return; 289 131 if (status & IS_RHSC) 290 132 rh_interrupt(&instance->rh); 291 133 292 usb_log_debug("OHCI interrupt: %x.\n", status); 293 294 if (status & IS_WDH) { 295 fibril_mutex_lock(&instance->guard); 296 usb_log_debug2("HCCA: %p-%p(%p).\n", instance->hcca, 297 instance->registers->hcca, addr_to_phys(instance->hcca)); 298 usb_log_debug2("Periodic current: %p.\n", 299 instance->registers->periodic_current); 300 301 link_t *current = instance->pending_batches.next; 302 while (current != &instance->pending_batches) { 303 link_t *next = current->next; 304 usb_transfer_batch_t *batch = 305 usb_transfer_batch_from_link(current); 306 307 if (batch_is_complete(batch)) { 308 list_remove(current); 309 usb_transfer_batch_finish(batch); 310 } 311 current = next; 312 } 313 fibril_mutex_unlock(&instance->guard); 314 } 134 usb_log_info("OHCI interrupt: %x.\n", status); 135 136 /* TODO: Check for further interrupt causes */ 137 /* TODO: implement */ 315 138 } 316 139 /*----------------------------------------------------------------------------*/ … … 323 146 instance->registers->interrupt_status = status; 324 147 hc_interrupt(instance, status); 325 async_usleep( 50000);148 async_usleep(1000); 326 149 } 327 150 return EOK; … … 331 154 { 332 155 assert(instance); 333 /* Turn off legacy emulation */334 volatile uint32_t *ohci_emulation_reg =335 (uint32_t*)((char*)instance->registers + 0x100);336 usb_log_debug("OHCI legacy register %p: %x.\n",337 ohci_emulation_reg, *ohci_emulation_reg);338 *ohci_emulation_reg = 0;339 340 156 /* Interrupt routing enabled => smm driver is active */ 341 157 if (instance->registers->control & C_IR) { 342 usb_log_ debug("SMM driver: requestownership change.\n");158 usb_log_info("Found SMM driver requesting ownership change.\n"); 343 159 instance->registers->command_status |= CS_OCR; 344 160 while (instance->registers->control & C_IR) { 345 161 async_usleep(1000); 346 162 } 347 usb_log_info(" SMM driver: Ownership taken.\n");163 usb_log_info("Ownership taken from SMM driver.\n"); 348 164 return; 349 165 } … … 353 169 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 354 170 if (hc_status != C_HCFS_RESET) { 355 usb_log_ debug("BIOS driver found.\n");171 usb_log_info("Found BIOS driver.\n"); 356 172 if (hc_status == C_HCFS_OPERATIONAL) { 357 usb_log_info(" BIOS driver: HC operational.\n");173 usb_log_info("HC operational(BIOS).\n"); 358 174 return; 359 175 } … … 361 177 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT); 362 178 async_usleep(20000); 363 usb_log_info("BIOS driver: HC resumed.\n");364 179 return; 365 180 } … … 367 182 /* HC is in reset (hw startup) => no other driver 368 183 * maintain reset for at least the time specified in USB spec (50 ms)*/ 369 usb_log_info("HC found in reset.\n");370 184 async_usleep(50000); 185 186 /* turn off legacy emulation */ 187 volatile uint32_t *ohci_emulation_reg = 188 (uint32_t*)((char*)instance->registers + 0x100); 189 usb_log_info("OHCI legacy register status %p: %x.\n", 190 ohci_emulation_reg, *ohci_emulation_reg); 191 *ohci_emulation_reg = 0; 192 371 193 } 372 194 /*----------------------------------------------------------------------------*/ 373 195 void hc_init_hw(hc_t *instance) 374 196 { 375 /* OHCI guide page 42 */ 376 assert(instance); 377 usb_log_debug2("Started hc initialization routine.\n"); 378 379 /* Save contents of fm_interval register */ 197 assert(instance); 380 198 const uint32_t fm_interval = instance->registers->fm_interval; 381 usb_log_debug2("Old value of HcFmInterval: %x.\n", fm_interval);382 383 /* Reset hc */384 usb_log_debug2("HC reset.\n");385 size_t time = 0;386 199 instance->registers->command_status = CS_HCR; 387 while (instance->registers->command_status & CS_HCR) { 388 async_usleep(10); 389 time += 10; 390 } 391 usb_log_debug2("HC reset complete in %zu us.\n", time); 392 393 /* Restore fm_interval */ 200 async_usleep(10); 394 201 instance->registers->fm_interval = fm_interval; 395 202 assert((instance->registers->command_status & CS_HCR) == 0); 396 397 203 /* hc is now in suspend state */ 398 usb_log_debug2("HC should be in suspend state(%x).\n", 399 instance->registers->control); 400 401 /* Use HCCA */ 402 instance->registers->hcca = addr_to_phys(instance->hcca); 403 404 /* Use queues */ 405 instance->registers->bulk_head = 406 instance->lists[USB_TRANSFER_BULK].list_head_pa; 407 usb_log_debug2("Bulk HEAD set to: %p(%p).\n", 408 instance->lists[USB_TRANSFER_BULK].list_head, 409 instance->lists[USB_TRANSFER_BULK].list_head_pa); 410 411 instance->registers->control_head = 412 instance->lists[USB_TRANSFER_CONTROL].list_head_pa; 413 usb_log_debug2("Control HEAD set to: %p(%p).\n", 414 instance->lists[USB_TRANSFER_CONTROL].list_head, 415 instance->lists[USB_TRANSFER_CONTROL].list_head_pa); 416 417 /* Enable queues */ 418 instance->registers->control |= (C_PLE | C_IE | C_CLE | C_BLE); 419 usb_log_debug2("All queues enabled(%x).\n", 420 instance->registers->control); 421 422 /* Disable interrupts */ 423 instance->registers->interrupt_disable = I_SF | I_OC; 424 usb_log_debug2("Disabling interrupts: %x.\n", 425 instance->registers->interrupt_disable); 426 instance->registers->interrupt_disable = I_MI; 427 usb_log_debug2("Enabled interrupts: %x.\n", 428 instance->registers->interrupt_enable); 429 430 /* Set periodic start to 90% */ 431 uint32_t frame_length = ((fm_interval >> FMI_FI_SHIFT) & FMI_FI_MASK); 432 instance->registers->periodic_start = (frame_length / 10) * 9; 433 usb_log_debug2("All periodic start set to: %x(%u - 90%% of %d).\n", 434 instance->registers->periodic_start, 435 instance->registers->periodic_start, frame_length); 204 /* TODO: init HCCA block */ 205 /* TODO: init queues */ 206 /* TODO: enable queues */ 207 /* TODO: enable interrupts */ 208 /* TODO: set periodic start to 90% */ 436 209 437 210 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT); 438 usb_log_info("OHCI HC up and running(%x).\n", 439 instance->registers->control); 440 } 441 /*----------------------------------------------------------------------------*/ 442 int hc_init_transfer_lists(hc_t *instance) 443 { 444 assert(instance); 445 446 #define SETUP_ENDPOINT_LIST(type) \ 447 do { \ 448 const char *name = usb_str_transfer_type(type); \ 449 int ret = endpoint_list_init(&instance->lists[type], name); \ 450 if (ret != EOK) { \ 451 usb_log_error("Failed(%d) to setup %s endpoint list.\n", \ 452 ret, name); \ 453 endpoint_list_fini(&instance->lists[USB_TRANSFER_ISOCHRONOUS]); \ 454 endpoint_list_fini(&instance->lists[USB_TRANSFER_INTERRUPT]); \ 455 endpoint_list_fini(&instance->lists[USB_TRANSFER_CONTROL]); \ 456 endpoint_list_fini(&instance->lists[USB_TRANSFER_BULK]); \ 457 } \ 458 } while (0) 459 460 SETUP_ENDPOINT_LIST(USB_TRANSFER_ISOCHRONOUS); 461 SETUP_ENDPOINT_LIST(USB_TRANSFER_INTERRUPT); 462 SETUP_ENDPOINT_LIST(USB_TRANSFER_CONTROL); 463 SETUP_ENDPOINT_LIST(USB_TRANSFER_BULK); 464 #undef SETUP_ENDPOINT_LIST 465 endpoint_list_set_next(&instance->lists[USB_TRANSFER_INTERRUPT], 466 &instance->lists[USB_TRANSFER_ISOCHRONOUS]); 467 468 return EOK; 469 } 470 /*----------------------------------------------------------------------------*/ 471 int hc_init_memory(hc_t *instance) 472 { 473 assert(instance); 474 /* Init queues */ 475 hc_init_transfer_lists(instance); 476 477 /*Init HCCA */ 478 instance->hcca = malloc32(sizeof(hcca_t)); 479 if (instance->hcca == NULL) 480 return ENOMEM; 481 bzero(instance->hcca, sizeof(hcca_t)); 482 usb_log_debug2("OHCI HCCA initialized at %p.\n", instance->hcca); 483 484 unsigned i = 0; 485 for (; i < 32; ++i) { 486 instance->hcca->int_ep[i] = 487 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa; 488 } 489 usb_log_debug2("Interrupt HEADs set to: %p(%p).\n", 490 instance->lists[USB_TRANSFER_INTERRUPT].list_head, 491 instance->lists[USB_TRANSFER_INTERRUPT].list_head_pa); 492 493 return EOK; 211 usb_log_info("OHCI HC up and running.\n"); 494 212 } 495 213 /**
Note:
See TracChangeset
for help on using the changeset viewer.
