Changeset e50cd7f in mainline for uspace/drv/ohci/hc.c
- Timestamp:
- 2011-04-17T19:17:55Z (14 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 63517c2, cfbbe1d3
- Parents:
- ef354b6 (diff), 8595577b (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)
links above to see all the changes relative to each parent. - File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/drv/ohci/hc.c
ref354b6 re50cd7f 43 43 44 44 #include "hc.h" 45 #include "hcd_endpoint.h" 45 46 46 47 static int interrupt_emulator(hc_t *instance); 47 48 static void hc_gain_control(hc_t *instance); 48 49 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); 49 52 /*----------------------------------------------------------------------------*/ 50 53 int hc_register_hub(hc_t *instance, ddf_fun_t *hub_fun) … … 52 55 assert(instance); 53 56 assert(hub_fun); 57 58 int ret; 54 59 55 60 usb_address_t hub_address = 56 61 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 } 57 66 instance->rh.address = hub_address; 58 67 usb_device_keeper_bind( 59 68 &instance->manager, hub_address, hub_fun->handle); 60 69 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 61 78 char *match_str = NULL; 62 int ret = asprintf(&match_str, "usb&class=hub");63 ret = (match_str == NULL) ? ret : EOK;79 /* DDF needs heap allocated string */ 80 ret = asprintf(&match_str, "usb&class=hub"); 64 81 if (ret < 0) { 65 usb_log_error("Failed to create root hub match-id string.\n"); 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); 66 85 return ret; 67 86 } … … 69 88 ret = ddf_fun_add_match_id(hub_fun, match_str, 100); 70 89 if (ret != EOK) { 71 usb_log_error("Failed add createroot hub match-id.\n");90 usb_log_error("Failed add root hub match-id.\n"); 72 91 } 73 92 return ret; … … 90 109 ret, str_error(ret)); 91 110 92 instance->ddf_instance = fun;93 111 usb_device_keeper_init(&instance->manager); 94 112 ret = usb_endpoint_manager_init(&instance->ep_manager, … … 97 115 ret, str_error(ret)); 98 116 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 99 126 if (!interrupts) { 100 127 instance->interrupt_emulator = … … 103 130 } 104 131 105 hc_gain_control(instance); 106 107 rh_init(&instance->rh, dev, instance->registers); 108 109 hc_init_hw(instance); 110 111 /* TODO: implement */ 112 return EOK; 132 list_initialize(&instance->pending_batches); 133 #undef CHECK_RET_RETURN 134 return EOK; 135 } 136 /*----------------------------------------------------------------------------*/ 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; 113 253 } 114 254 /*----------------------------------------------------------------------------*/ … … 117 257 assert(instance); 118 258 assert(batch); 119 if (batch->target.address == instance->rh.address) { 259 assert(batch->ep); 260 261 /* check for root hub communication */ 262 if (batch->ep->address == instance->rh.address) { 120 263 return rh_request(&instance->rh, batch); 121 264 } 122 /* TODO: implement */ 123 return ENOTSUP; 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; 124 282 } 125 283 /*----------------------------------------------------------------------------*/ … … 127 285 { 128 286 assert(instance); 129 if ( status == 0)287 if ((status & ~IS_SF) == 0) /* ignore sof status */ 130 288 return; 131 289 if (status & IS_RHSC) 132 290 rh_interrupt(&instance->rh); 133 291 134 usb_log_info("OHCI interrupt: %x.\n", status); 135 136 /* TODO: Check for further interrupt causes */ 137 /* TODO: implement */ 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 } 138 315 } 139 316 /*----------------------------------------------------------------------------*/ … … 146 323 instance->registers->interrupt_status = status; 147 324 hc_interrupt(instance, status); 148 async_usleep( 1000);325 async_usleep(50000); 149 326 } 150 327 return EOK; … … 154 331 { 155 332 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 156 340 /* Interrupt routing enabled => smm driver is active */ 157 341 if (instance->registers->control & C_IR) { 158 usb_log_ info("Found SMM driver requestingownership change.\n");342 usb_log_debug("SMM driver: request ownership change.\n"); 159 343 instance->registers->command_status |= CS_OCR; 160 344 while (instance->registers->control & C_IR) { 161 345 async_usleep(1000); 162 346 } 163 usb_log_info(" Ownership taken from SMM driver.\n");347 usb_log_info("SMM driver: Ownership taken.\n"); 164 348 return; 165 349 } … … 169 353 /* Interrupt routing disabled && status != USB_RESET => BIOS active */ 170 354 if (hc_status != C_HCFS_RESET) { 171 usb_log_ info("Found BIOS driver.\n");355 usb_log_debug("BIOS driver found.\n"); 172 356 if (hc_status == C_HCFS_OPERATIONAL) { 173 usb_log_info(" HC operational(BIOS).\n");357 usb_log_info("BIOS driver: HC operational.\n"); 174 358 return; 175 359 } … … 177 361 instance->registers->control &= (C_HCFS_RESUME << C_HCFS_SHIFT); 178 362 async_usleep(20000); 363 usb_log_info("BIOS driver: HC resumed.\n"); 179 364 return; 180 365 } … … 182 367 /* HC is in reset (hw startup) => no other driver 183 368 * maintain reset for at least the time specified in USB spec (50 ms)*/ 369 usb_log_info("HC found in reset.\n"); 184 370 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 193 371 } 194 372 /*----------------------------------------------------------------------------*/ 195 373 void hc_init_hw(hc_t *instance) 196 374 { 197 assert(instance); 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 */ 198 380 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; 199 386 instance->registers->command_status = CS_HCR; 200 async_usleep(10); 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 */ 201 394 instance->registers->fm_interval = fm_interval; 202 395 assert((instance->registers->command_status & CS_HCR) == 0); 396 203 397 /* hc is now in suspend state */ 204 /* TODO: init HCCA block */ 205 /* TODO: init queues */ 206 /* TODO: enable queues */ 207 /* TODO: enable interrupts */ 208 /* TODO: set periodic start to 90% */ 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); 209 436 210 437 instance->registers->control &= (C_HCFS_OPERATIONAL << C_HCFS_SHIFT); 211 usb_log_info("OHCI HC up and running.\n"); 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; 212 494 } 213 495 /**
Note:
See TracChangeset
for help on using the changeset viewer.