Changeset cddcc4a3 in mainline for uspace/drv/bus/usb/ohci/root_hub.c
- Timestamp:
- 2012-08-14T18:16:39Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 669f5cae
- Parents:
- 76d92db1 (diff), 4802dd7 (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/bus/usb/ohci/root_hub.c
r76d92db1 rcddcc4a3 33 33 */ 34 34 #include <assert.h> 35 #include <byteorder.h> 35 36 #include <errno.h> 36 37 #include <str_error.h> 37 38 #include <fibril_synch.h> 38 39 40 #include <usb/usb.h> 39 41 #include <usb/debug.h> 40 42 #include <usb/dev/request.h> 41 43 #include <usb/classes/hub.h> 42 44 43 #include "root_hub.h"44 45 #include <usb/classes/classes.h> 45 46 #include <usb/classes/hub.h> 46 47 #include <usb/dev/driver.h> 47 48 #include "ohci_regs.h" 49 #include "root_hub.h" 48 50 49 51 /** … … 122 124 { 123 125 assert(request); 126 usb_log_debug("Sending interrupt vector(%zu) %hhx:%hhx.\n", 127 size, ((uint8_t*)&mask)[0], ((uint8_t*)&mask)[1]); 124 128 usb_transfer_batch_finish_error(request, &mask, size, EOK); 125 129 usb_transfer_batch_destroy(request); … … 150 154 151 155 instance->registers = regs; 152 instance->port_count = 153 (instance->registers->rh_desc_a >> RHDA_NDS_SHIFT) & RHDA_NDS_MASK;156 instance->port_count = OHCI_RD(regs->rh_desc_a) & RHDA_NDS_MASK; 157 usb_log_debug2("rh_desc_a: %x.\n", OHCI_RD(regs->rh_desc_a)); 154 158 if (instance->port_count > 15) { 155 159 usb_log_warning("OHCI specification does not allow more than 15" … … 163 167 164 168 #if defined OHCI_POWER_SWITCH_no 169 usb_log_debug("OHCI rh: Set power mode to no power switching.\n"); 165 170 /* Set port power mode to no power-switching. (always on) */ 166 instance->registers->rh_desc_a |= RHDA_NPS_FLAG;171 OHCI_SET(regs->rh_desc_a, RHDA_NPS_FLAG); 167 172 168 173 /* Set to no over-current reporting */ 169 instance->registers->rh_desc_a |= RHDA_NOCP_FLAG;174 OHCI_SET(regs->rh_desc_a, RHDA_NOCP_FLAG); 170 175 171 176 #elif defined OHCI_POWER_SWITCH_ganged 172 /* Set port power mode to no ganged power-switching. */ 173 instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG; 174 instance->registers->rh_desc_a &= ~RHDA_PSM_FLAG; 175 instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER; 177 usb_log_debug("OHCI rh: Set power mode to ganged power switching.\n"); 178 /* Set port power mode to ganged power-switching. */ 179 OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG); 180 OHCI_CLR(regs->rh_desc_a, RHDA_PSM_FLAG); 181 182 /* Turn off power (hub driver will turn this back on)*/ 183 OHCI_WR(regs->rh_status, RHS_CLEAR_GLOBAL_POWER); 176 184 177 185 /* Set to global over-current */ 178 instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;179 instance->registers->rh_desc_a &= ~RHDA_OCPM_FLAG;186 OHCI_CLR(regs->rh_desc_a, RHDA_NOCP_FLAG); 187 OHCI_CLR(regs->rh_desc_a, RHDA_OCPM_FLAG); 180 188 #else 181 /* Set port power mode to no per port power-switching. */ 182 instance->registers->rh_desc_a &= ~RHDA_NPS_FLAG; 183 instance->registers->rh_desc_a |= RHDA_PSM_FLAG; 189 usb_log_debug("OHCI rh: Set power mode to per-port power switching.\n"); 190 /* Set port power mode to per port power-switching. */ 191 OHCI_CLR(regs->rh_desc_a, RHDA_NPS_FLAG); 192 OHCI_SET(regs->rh_desc_a, RHDA_PSM_FLAG); 184 193 185 194 /* Control all ports by global switch and turn them off */ 186 instance->registers->rh_desc_b &= (RHDB_PCC_MASK << RHDB_PCC_SHIFT);187 instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER;195 OHCI_CLR(regs->rh_desc_b, RHDB_PCC_MASK << RHDB_PCC_SHIFT); 196 OHCI_WR(regs->rh_status, RHS_CLEAR_GLOBAL_POWER); 188 197 189 198 /* Return control to per port state */ 190 instance->registers->rh_desc_b |= 191 ((1 << (instance->port_count + 1)) - 1) << RHDB_PCC_SHIFT; 199 OHCI_SET(regs->rh_desc_b, RHDB_PCC_MASK << RHDB_PCC_SHIFT); 192 200 193 201 /* Set per port over-current */ 194 instance->registers->rh_desc_a &= ~RHDA_NOCP_FLAG;195 instance->registers->rh_desc_a |= RHDA_OCPM_FLAG;202 OHCI_CLR(regs->rh_desc_a, RHDA_NOCP_FLAG); 203 OHCI_SET(regs->rh_desc_a, RHDA_OCPM_FLAG); 196 204 #endif 197 205 … … 202 210 instance->port_count); 203 211 } 204 /*----------------------------------------------------------------------------*/ 212 205 213 /** 206 214 * Process root hub request. … … 226 234 fibril_mutex_lock(&instance->guard); 227 235 assert(instance->unfinished_interrupt_transfer == NULL); 228 uint16_t mask = create_interrupt_mask(instance);236 const uint16_t mask = create_interrupt_mask(instance); 229 237 if (mask == 0) { 230 usb_log_debug("No changes ...\n");238 usb_log_debug("No changes(%hx)...\n", mask); 231 239 instance->unfinished_interrupt_transfer = request; 232 240 } else { … … 243 251 } 244 252 } 245 /*----------------------------------------------------------------------------*/ 253 246 254 /** 247 255 * Process interrupt on a hub device. … … 257 265 if (instance->unfinished_interrupt_transfer) { 258 266 usb_log_debug("Finalizing interrupt transfer\n"); 259 uint16_t mask = create_interrupt_mask(instance);267 const uint16_t mask = create_interrupt_mask(instance); 260 268 interrupt_request(instance->unfinished_interrupt_transfer, 261 269 mask, instance->interrupt_mask_size); … … 264 272 fibril_mutex_unlock(&instance->guard); 265 273 } 266 /*----------------------------------------------------------------------------*/ 274 267 275 /** 268 276 * Create hub descriptor. … … 282 290 instance->hub_descriptor_size = size; 283 291 284 uint32_t hub_desc = instance->registers->rh_desc_a;285 uint32_t port_desc = instance->registers->rh_desc_b;292 const uint32_t hub_desc = OHCI_RD(instance->registers->rh_desc_a); 293 const uint32_t port_desc = OHCI_RD(instance->registers->rh_desc_b); 286 294 287 295 /* bDescLength */ … … 305 313 instance->descriptors.hub[4] = 0; 306 314 /* bPwrOn2PwrGood */ 307 instance->descriptors.hub[5] = 308 (hub_desc >> RHDA_POTPGT_SHIFT) & RHDA_POTPGT_MASK; 315 instance->descriptors.hub[5] = hub_desc >> RHDA_POTPGT_SHIFT; 309 316 /* bHubContrCurrent, root hubs don't need no power. */ 310 317 instance->descriptors.hub[6] = 0; 311 318 312 319 /* Device Removable and some legacy 1.0 stuff*/ 313 instance->descriptors.hub[7] = 314 (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK & 0xff; 320 instance->descriptors.hub[7] = (port_desc >> RHDB_DR_SHIFT) & 0xff; 315 321 instance->descriptors.hub[8] = 0xff; 316 322 if (instance->interrupt_mask_size == 2) { 317 323 instance->descriptors.hub[8] = 318 (port_desc >> RHDB_DR_SHIFT) & RHDB_DR_MASK>> 8;324 (port_desc >> RHDB_DR_SHIFT) >> 8; 319 325 instance->descriptors.hub[9] = 0xff; 320 326 instance->descriptors.hub[10] = 0xff; 321 327 } 322 328 } 323 /*----------------------------------------------------------------------------*/ 329 324 330 /** Initialize hub descriptors. 325 331 * … … 341 347 instance->interrupt_mask_size; 342 348 343 instance->descriptors.configuration.total_length = 349 instance->descriptors.configuration.total_length = uint16_host2usb( 344 350 sizeof(usb_standard_configuration_descriptor_t) + 345 351 sizeof(usb_standard_endpoint_descriptor_t) + 346 352 sizeof(usb_standard_interface_descriptor_t) + 347 instance->hub_descriptor_size ;348 } 349 /*----------------------------------------------------------------------------*/ 353 instance->hub_descriptor_size); 354 } 355 350 356 /** 351 357 * Create bitmap of changes to answer status interrupt. … … 364 370 365 371 /* Only local power source change and over-current change can happen */ 366 if (instance->registers->rh_status & (RHS_LPSC_FLAG | RHS_OCIC_FLAG)) { 372 if (OHCI_RD(instance->registers->rh_status) 373 & (RHS_LPSC_FLAG | RHS_OCIC_FLAG)) { 367 374 mask |= 1; 368 375 } 369 376 for (size_t port = 1; port <= instance->port_count; ++port) { 370 377 /* Write-clean bits are those that indicate change */ 371 if (RHPS_CHANGE_WC_MASK 372 & instance->registers->rh_port_status[port - 1]) { 373 378 if (OHCI_RD(instance->registers->rh_port_status[port - 1]) 379 & RHPS_CHANGE_WC_MASK) { 374 380 mask |= (1 << port); 375 381 } 376 382 } 377 /* USB is little endian */378 return host2uint32_t_le(mask);379 } 380 /*----------------------------------------------------------------------------*/ 383 usb_log_debug2("OHCI root hub interrupt mask: %hx.\n", mask); 384 return uint16_host2usb(mask); 385 } 386 381 387 /** 382 388 * Create answer to status request. … … 396 402 usb_device_request_setup_packet_t *request_packet = 397 403 (usb_device_request_setup_packet_t*)request->setup_buffer; 404 405 const uint16_t index = uint16_usb2host(request_packet->index); 398 406 399 407 switch (request_packet->request_type) … … 406 414 TRANSFER_END(request, EOVERFLOW); 407 415 } else { 408 uint32_t data = instance->registers->rh_status & 409 (RHS_LPS_FLAG | RHS_LPSC_FLAG 410 | RHS_OCI_FLAG | RHS_OCIC_FLAG); 416 const uint32_t data = 417 OHCI_RD(instance->registers->rh_status) & 418 (RHS_LPS_FLAG | RHS_LPSC_FLAG 419 | RHS_OCI_FLAG | RHS_OCIC_FLAG); 411 420 TRANSFER_END_DATA(request, &data, sizeof(data)); 412 421 } … … 420 429 TRANSFER_END(request, EOVERFLOW); 421 430 } else { 422 unsigned port = request_packet->index;431 const unsigned port = index; 423 432 if (port < 1 || port > instance->port_count) 424 433 TRANSFER_END(request, EINVAL); 425 426 uint32_t data = 427 instance->registers->rh_port_status[port - 1]; 434 /* Register format matches the format of port status 435 * field */ 436 const uint32_t data = uint32_host2usb(OHCI_RD( 437 instance->registers->rh_port_status[port - 1])); 428 438 TRANSFER_END_DATA(request, &data, sizeof(data)); 429 439 } … … 434 444 TRANSFER_END(request, EOVERFLOW); 435 445 } else { 436 uint16_t data =446 const uint16_t data = 437 447 uint16_host2usb(USB_DEVICE_STATUS_SELF_POWERED); 438 448 TRANSFER_END_DATA(request, &data, sizeof(data)); … … 441 451 case SETUP_REQUEST_TO_HOST(USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_INTERFACE): 442 452 /* Hubs are allowed to have only one interface */ 443 if ( request_packet->index != 0)453 if (index != 0) 444 454 TRANSFER_END(request, EINVAL); 445 455 /* Fall through, as the answer will be the same: 0x0000 */ 446 456 case SETUP_REQUEST_TO_HOST(USB_REQUEST_TYPE_STANDARD, USB_REQUEST_RECIPIENT_ENDPOINT): 447 457 /* Endpoint 0 (default control) and 1 (interrupt) */ 448 if ( request_packet->index >= 2)458 if (index >= 2) 449 459 TRANSFER_END(request, EINVAL); 450 460 … … 455 465 } else { 456 466 /* Endpoints are OK. (We don't halt) */ 457 uint16_t data = 0;467 const uint16_t data = 0; 458 468 TRANSFER_END_DATA(request, &data, sizeof(data)); 459 469 } … … 465 475 466 476 } 467 /*----------------------------------------------------------------------------*/ 477 468 478 /** 469 479 * Create answer to a descriptor request. … … 482 492 usb_device_request_setup_packet_t *setup_request = 483 493 (usb_device_request_setup_packet_t *) request->setup_buffer; 484 uint16_t setup_request_value = setup_request->value_high; 485 switch (setup_request_value) 494 /* "The wValue field specifies the descriptor type in the high byte 495 * and the descriptor index in the low byte (refer to Table 9-5)." */ 496 const int desc_type = uint16_usb2host(setup_request->value) >> 8; 497 switch (desc_type) 486 498 { 487 499 case USB_DESCTYPE_HUB: … … 530 542 setup_request->value, 531 543 setup_request->request_type, setup_request->request, 532 setup_request_value, setup_request->index,544 desc_type, setup_request->index, 533 545 setup_request->length); 534 546 TRANSFER_END(request, EINVAL); … … 537 549 TRANSFER_END(request, ENOTSUP); 538 550 } 539 /*----------------------------------------------------------------------------*/ 551 540 552 /** 541 553 * process feature-enabling request on hub … … 554 566 return EINVAL; 555 567 556 switch (feature) 557 { 558 case USB_HUB_FEATURE_PORT_POWER: //8 559 /* No power switching */ 560 if (instance->registers->rh_desc_a & RHDA_NPS_FLAG) 561 return EOK; 562 /* Ganged power switching */ 563 if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) { 564 instance->registers->rh_status = RHS_SET_GLOBAL_POWER; 565 return EOK; 568 switch (feature) { 569 case USB_HUB_FEATURE_PORT_POWER: /*8*/ 570 { 571 const uint32_t rhda = 572 OHCI_RD(instance->registers->rh_desc_a); 573 /* No power switching */ 574 if (rhda & RHDA_NPS_FLAG) 575 return EOK; 576 /* Ganged power switching, one port powers all */ 577 if (!(rhda & RHDA_PSM_FLAG)) { 578 OHCI_WR(instance->registers->rh_status, 579 RHS_SET_GLOBAL_POWER); 580 return EOK; 581 } 566 582 } 567 case USB_HUB_FEATURE_PORT_ENABLE: //1 568 case USB_HUB_FEATURE_PORT_SUSPEND: //2 569 case USB_HUB_FEATURE_PORT_RESET: //4 570 /* Nice thing is that these shifts correspond to the position 571 * of control bits in register */ 572 instance->registers->rh_port_status[port - 1] = (1 << feature); 583 /* Fall through */ 584 case USB_HUB_FEATURE_PORT_ENABLE: /*1*/ 585 case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/ 586 case USB_HUB_FEATURE_PORT_RESET: /*4*/ 587 usb_log_debug2("Setting port POWER, ENABLE, SUSPEND or RESET " 588 "on port %"PRIu16".\n", port); 589 OHCI_WR(instance->registers->rh_port_status[port - 1], 590 1 << feature); 573 591 return EOK; 574 592 default: … … 576 594 } 577 595 } 578 /*----------------------------------------------------------------------------*/ 596 579 597 /** 580 598 * Process feature clear request. … … 596 614 switch (feature) 597 615 { 598 case USB_HUB_FEATURE_PORT_POWER: //8 599 /* No power switching */ 600 if (instance->registers->rh_desc_a & RHDA_NPS_FLAG) 601 return ENOTSUP; 602 /* Ganged power switching */ 603 if (!(instance->registers->rh_desc_a & RHDA_PSM_FLAG)) { 604 instance->registers->rh_status = RHS_CLEAR_GLOBAL_POWER; 616 case USB_HUB_FEATURE_PORT_POWER: /*8*/ 617 { 618 const uint32_t rhda = 619 OHCI_RD(instance->registers->rh_desc_a); 620 /* No power switching */ 621 if (rhda & RHDA_NPS_FLAG) 622 return ENOTSUP; 623 /* Ganged power switching, one port powers all */ 624 if (!(rhda & RHDA_PSM_FLAG)) { 625 OHCI_WR(instance->registers->rh_status, 626 RHS_CLEAR_GLOBAL_POWER); 627 return EOK; 628 } 629 OHCI_WR(instance->registers->rh_port_status[port - 1], 630 RHPS_CLEAR_PORT_POWER); 605 631 return EOK; 606 632 } 607 instance->registers->rh_port_status[port - 1] = 608 RHPS_CLEAR_PORT_POWER; 633 634 case USB_HUB_FEATURE_PORT_ENABLE: /*1*/ 635 OHCI_WR(instance->registers->rh_port_status[port - 1], 636 RHPS_CLEAR_PORT_ENABLE); 609 637 return EOK; 610 638 611 case USB_HUB_FEATURE_PORT_ ENABLE: //1612 instance->registers->rh_port_status[port - 1] =613 RHPS_CLEAR_PORT_ENABLE;639 case USB_HUB_FEATURE_PORT_SUSPEND: /*2*/ 640 OHCI_WR(instance->registers->rh_port_status[port - 1], 641 RHPS_CLEAR_PORT_SUSPEND); 614 642 return EOK; 615 643 616 case USB_HUB_FEATURE_PORT_SUSPEND: //2 617 instance->registers->rh_port_status[port - 1] = 618 RHPS_CLEAR_PORT_SUSPEND; 619 return EOK; 620 621 case USB_HUB_FEATURE_C_PORT_CONNECTION: //16 622 case USB_HUB_FEATURE_C_PORT_ENABLE: //17 623 case USB_HUB_FEATURE_C_PORT_SUSPEND: //18 624 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: //19 625 case USB_HUB_FEATURE_C_PORT_RESET: //20 626 /* Nice thing is that these shifts correspond to the position 627 * of control bits in register */ 628 instance->registers->rh_port_status[port - 1] = (1 << feature); 644 case USB_HUB_FEATURE_C_PORT_CONNECTION: /*16*/ 645 case USB_HUB_FEATURE_C_PORT_ENABLE: /*17*/ 646 case USB_HUB_FEATURE_C_PORT_SUSPEND: /*18*/ 647 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: /*19*/ 648 case USB_HUB_FEATURE_C_PORT_RESET: /*20*/ 649 usb_log_debug2("Clearing port C_CONNECTION, C_ENABLE, " 650 "C_SUSPEND, C_OC or C_RESET on port %"PRIu16".\n", port); 651 /* Bit offsets correspond to the feature number */ 652 OHCI_WR(instance->registers->rh_port_status[port - 1], 653 1 << feature); 629 654 return EOK; 630 655 … … 633 658 } 634 659 } 635 /*----------------------------------------------------------------------------*/ 660 636 661 /** 637 662 * process one of requests that do not request nor carry additional data … … 654 679 case USB_HUB_REQ_TYPE_SET_PORT_FEATURE: 655 680 usb_log_debug("USB_HUB_REQ_TYPE_SET_PORT_FEATURE\n"); 656 int ret = set_feature_port(instance,681 const int ret = set_feature_port(instance, 657 682 setup_request->value, setup_request->index); 658 683 TRANSFER_END(request, ret); … … 671 696 } 672 697 } 673 /*----------------------------------------------------------------------------*/ 698 674 699 /** 675 700 * process one of requests that do not request nor carry additional data … … 693 718 case USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE: 694 719 usb_log_debug("USB_HUB_REQ_TYPE_CLEAR_PORT_FEATURE\n"); 695 int ret = clear_feature_port(instance,720 const int ret = clear_feature_port(instance, 696 721 setup_request->value, setup_request->index); 697 722 TRANSFER_END(request, ret); … … 706 731 * as root hubs do not support local power status feature. 707 732 * (OHCI pg. 127) */ 708 if (setup_request->value == USB_HUB_FEATURE_C_HUB_OVER_CURRENT) { 709 instance->registers->rh_status = RHS_OCIC_FLAG; 733 if (uint16_usb2host(setup_request->value) 734 == USB_HUB_FEATURE_C_HUB_OVER_CURRENT) { 735 OHCI_WR(instance->registers->rh_status, RHS_OCIC_FLAG); 710 736 TRANSFER_END(request, EOK); 711 737 } … … 717 743 } 718 744 } 719 /*----------------------------------------------------------------------------*/ 745 720 746 /** 721 747 * Process hub control request. … … 771 797 if (request->buffer_size == 0) 772 798 TRANSFER_END(request, EOVERFLOW); 773 uint8_t config = 1;799 const uint8_t config = 1; 774 800 TRANSFER_END_DATA(request, &config, sizeof(config)); 775 801 … … 790 816 TRANSFER_END(request, EINVAL); 791 817 792 instance->address = setup_request->value;818 instance->address = uint16_usb2host(setup_request->value); 793 819 TRANSFER_END(request, EOK); 794 820 795 821 case USB_DEVREQ_SET_CONFIGURATION: 796 822 usb_log_debug("USB_DEVREQ_SET_CONFIGURATION: %u\n", 797 setup_request->value);823 uint16_usb2host(setup_request->value)); 798 824 /* We have only one configuration, it's number is 1 */ 799 825 if (uint16_usb2host(setup_request->value) != 1)
Note:
See TracChangeset
for help on using the changeset viewer.