1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2005, Jan-Rixt Van Hoye 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // explanation of this file: 23 // ------------------------- 24 // 25 // This is the implementation of the OHCI module for the Haiku USB stack 26 // It is bases on the hcir1_0a documentation that can be found on www.usb.org 27 // Some parts are derive from source-files from openbsd, netbsd and linux. 28 // 29 // ------------------------------------------------------------------------ 30 31 // --------------------------- 32 // OHCI:: Includes 33 // --------------------------- 34 #include <module.h> 35 #include <PCI.h> 36 #include <USB.h> 37 #include <KernelExport.h> 38 #include <stdlib.h> 39 40 // --------------------------- 41 // OHCI:: Local includes 42 // --------------------------- 43 44 #include "ohci.h" 45 #include "ohci_hardware.h" 46 #include "usb_p.h" 47 48 //------------------------------------------------------ 49 // OHCI:: Reverse the bits in a value between 0 and 31 50 // (Section 3.3.2) 51 //------------------------------------------------------ 52 53 static uint8 revbits[OHCI_NO_INTRS] = 54 { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 55 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 56 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 57 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; 58 59 //------------------------------------------------------------------------ 60 // OHCI:: These are the OHCI operations that can be done. 61 // 62 // parameters: 63 // - op: operation 64 //------------------------------------------------------------------------ 65 66 static int32 67 ohci_std_ops( int32 op , ... ) 68 { 69 switch (op) 70 { 71 case B_MODULE_INIT: 72 TRACE( "ohci_module: init the module\n" ); 73 return B_OK; 74 case B_MODULE_UNINIT: 75 TRACE( "ohci_module: uninit the module\n" ); 76 break; 77 default: 78 return EINVAL; 79 } 80 return B_OK; 81 } 82 83 //------------------------------------------------------------------------ 84 // OHCI:: Give an reference of a stack instance to the OHCI module 85 // 86 // parameters: 87 // - &stack: reference to a stack instance form stack.cpp 88 //------------------------------------------------------------------------ 89 90 static bool 91 ohci_add_to( Stack &stack ) 92 { 93 status_t status; 94 pci_info *item; 95 bool found = false; 96 int i; 97 98 #ifdef OHCI_DEBUG 99 set_dprintf_enabled( true ); 100 load_driver_symbols( "ohci" ); 101 #endif 102 // 103 // Try if the PCI module is loaded 104 // 105 if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK) 106 { 107 TRACE( "USB_ OHCI: init_hardware(): Get PCI module failed! %lu \n", status); 108 return status; 109 } 110 TRACE( "usb_ohci init_hardware(): Setting up hardware\n" ); 111 // 112 // TODO: in the future we might want to support multiple host controllers. 113 // 114 item = new pci_info; 115 for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) 116 { 117 // 118 // class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 10 (OHCI) 119 // 120 if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) && 121 ( item->class_api == 0x10 ) ) 122 { 123 if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) 124 { 125 TRACE( "USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"); 126 continue; 127 } 128 TRACE("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line); 129 OHCI *bus = new OHCI( item , &stack ); 130 if ( bus->InitCheck() != B_OK ) 131 { 132 delete bus; 133 break; 134 } 135 136 stack.AddBusManager( bus ); 137 bus->Start(); 138 found = true; 139 break; 140 } 141 } 142 143 if ( found == false ) 144 { 145 TRACE( "USB OHCI: init hardware(): no devices found\n" ); 146 free( item ); 147 put_module( B_PCI_MODULE_NAME ); 148 return ENODEV; 149 } 150 return B_OK; //Hardware found 151 } 152 153 //------------------------------------------------------------------------ 154 // OHCI:: Host controller information 155 // 156 // parameters: none 157 //------------------------------------------------------------------------ 158 159 host_controller_info ohci_module = { 160 { 161 "busses/usb/ohci/jixt", 162 NULL, // No flag like B_KEEP_LOADED : the usb module does that 163 ohci_std_ops 164 }, 165 NULL , 166 ohci_add_to 167 }; 168 169 //------------------------------------------------------------------------ 170 // OHCI:: Module information 171 // 172 // parameters: none 173 //------------------------------------------------------------------------ 174 175 module_info *modules[] = 176 { 177 (module_info *) &ohci_module, 178 NULL 179 }; 180 181 //------------------------------------------------------------------------ 182 // OHCI:: Constructor/Initialisation 183 // 184 // parameters: 185 // - info: pointer to a pci information structure 186 // - stack: pointer to a stack instance 187 //------------------------------------------------------------------------ 188 189 OHCI::OHCI( pci_info *info , Stack *stack ) 190 { 191 m_pcii = info; 192 m_stack = stack; 193 uint32 rev=0; 194 int i; 195 hcd_soft_endpoint *sed, *psed; 196 dprintf( "OHCI: constructing new BusManager\n" ); 197 m_opreg_base = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, 0x20, 4); 198 m_opreg_base &= PCI_address_io_mask; 199 TRACE( "OHCI: iospace offset: %lx\n" , m_opreg_base ); 200 m_roothub_base = 255; //Invalidate the Root Hub address 201 { 202 // enable pci address access 203 unsigned char cmd; 204 cmd = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2); 205 cmd = cmd | PCI_command_io | PCI_command_master | PCI_command_memory; 206 OHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd ); 207 } 208 209 // Get the revision of the controller 210 211 OHCI::pci_module->read_io_16( m_opreg_base + OHCI_REVISION ); 212 213 // Check the revision of the controller. The revision should be 10xh 214 215 dprintf(" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); 216 217 if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) 218 { 219 dprintf("OHCI: Unsupported OHCI revision of the ohci device\n"); 220 return; 221 } 222 // Set the revision of the controller 223 m_revision = rev; 224 // Set the product description of the controller 225 m_product_descr = "Open Host Controller Interface"; 226 // Initialize the transfer descriptors and the interupt transfer descriptors 227 // 228 /* +++++++++++++++++++ */ 229 // 230 // Allocate the HCCA area. 231 void *phy; 232 m_hcca_area = stack->AllocateArea( (void **)&(hcca) , &(phy) ,OHCI_HCCA_SIZE , "ohci hcca area" ); 233 m_hcca_base = reinterpret_cast<addr_t>(phy); 234 235 // Allocate dummy Endpoint Descriptor that starts the control list. 236 ed_control_tail = ohci_alloc_soft_endpoint(); 237 ed_control_tail->ed.ed_flags |= OHCI_ED_SKIP; 238 239 // Allocate dummy Endpoint Descriptor that starts the bulk list. 240 ed_bulk_tail = ohci_alloc_soft_endpoint(); 241 ed_bulk_tail->ed.ed_flags |= OHCI_ED_SKIP; 242 243 // Allocate dummy Endpoint Descriptor that starts the isochronous list. 244 ed_isoch_tail = ohci_alloc_soft_endpoint(); 245 ed_isoch_tail->ed.ed_flags |= OHCI_ED_SKIP; 246 247 // Allocate all the dummy Endpoint Desriptors that make up the interrupt tree. 248 for (i = 0; i < OHCI_NO_EDS; i++) 249 { 250 sed = ohci_alloc_soft_endpoint(); 251 if (sed == NULL) 252 { 253 return; 254 } 255 /* All ED fields are set to 0. */ 256 sc_eds[i] = sed; 257 sed->ed.ed_flags |= OHCI_ED_SKIP; 258 if (i != 0) 259 psed = sc_eds[(i-1) / 2]; 260 else 261 psed= ed_isoch_tail; 262 sed->next = psed; 263 sed->ed.ed_nexted = psed->physaddr; 264 } 265 266 // Fill HCCA interrupt table. The bit reversal is to get 267 // the tree set up properly to spread the interrupts. 268 for (i = 0; i < OHCI_NO_INTRS; i++) 269 hcca->hcca_interrupt_table[revbits[i]] = sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr; 270 271 // Determine in what context we are running. 272 uint32 ctrlmsg,statusmsg; 273 ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL); 274 if (ctrlmsg & OHCI_IR) 275 { 276 /// SMM active, request change 277 dprintf(("OHCI: SMM active, request owner change\n")); 278 statusmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_COMMAND_STATUS); 279 OHCI::pci_module->write_io_16( m_opreg_base + OHCI_COMMAND_STATUS,statusmsg | OHCI_OCR); 280 for (i = 0; i < 100 && (ctrlmsg & OHCI_IR); i++) 281 { 282 snooze(100); 283 ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL); 284 } 285 if ((ctrlmsg & OHCI_IR) == 0) 286 { 287 dprintf("OHCI: SMM does not respond, resetting\n"); 288 OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_RESET); 289 goto reset; 290 } 291 // Don't bother trying to reuse the BIOS init, we'll reset it anyway. 292 } 293 else if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) 294 { 295 // BIOS started controller 296 dprintf("OHCI: BIOS active\n"); 297 if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) 298 { 299 OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_OPERATIONAL); 300 snooze(250000); 301 } 302 } 303 else 304 { 305 dprintf("OHCI: cold started\n"); 306 reset: 307 // Controller was cold started. 308 snooze(100000); 309 } 310 311 // This reset should not be necessary according to the OHCI spec, but 312 // without it some controllers do not start. 313 // 314 /* +++++++++++++++++++ */ 315 // 316 // We now own the host controller and the bus has been reset. 317 // 318 /* +++++++++++++++++++ */ 319 // 320 // Reset the Host Controller 321 // 322 /* +++++++++++++++++++ */ 323 // 324 // Nominal time for a reset is 10 us. 325 // 326 /* +++++++++++++++++++ */ 327 // 328 // The controller is now in SUSPEND state, we have 2ms to finish. 329 // 330 // Set up the Host Controler registers. 331 // 332 /* +++++++++++++++++++ */ 333 // 334 // Disable all interrupts and then switch on all desired interrupts. 335 // 336 /* +++++++++++++++++++ */ 337 // 338 // Switch on desired functional features. 339 // 340 /* +++++++++++++++++++ */ 341 // 342 // And finally start it! 343 // 344 /* +++++++++++++++++++ */ 345 // 346 // The controller is now OPERATIONAL. Set a some final 347 // registers that should be set earlier, but that the 348 // controller ignores when in the SUSPEND state. 349 // 350 /* +++++++++++++++++++ */ 351 // 352 // Fiddle the No OverCurrent Protection bit to avoid chip bug. 353 // 354 /* +++++++++++++++++++ */ 355 // 356 // The AMD756 requires a delay before re-reading the register, 357 // otherwise it will occasionally report 0 ports. 358 // 359 /* +++++++++++++++++++ */ 360 // 361 // Set up the bus structure 362 // 363 /* +++++++++++++++++++ */ 364 //return B_OK; 365 } 366 367 hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint() 368 { 369 hcd_soft_endpoint *sed; 370 int i; 371 void *phy; 372 if (sc_freeeds == NULL) 373 { 374 dprintf("OHCI: ohci_alloc_soft_endpoint(): allocating chunk\n"); 375 for(i = 0; i < OHCI_SED_CHUNK; i++) 376 { 377 if(m_stack->AllocateChunk( (void **)&(sed) ,&phy , OHCI_ED_ALIGN )!= B_OK) 378 { 379 dprintf( "USB OHCI: ohci_alloc_soft_endpoint(): failed allocation of skeleton qh %i, aborting\n", i ); 380 return (0); 381 } 382 // chunk has been allocated 383 sed->physaddr = reinterpret_cast<addr_t>(phy); 384 sed->next = sc_freeeds; 385 sc_freeeds = sed; 386 } 387 } 388 sed = sc_freeeds; 389 sc_freeeds = sed->next; 390 memset(&sed->ed, 0, sizeof(hc_endpoint_descriptor)); 391 sed->next = 0; 392 return (sed); 393 } 394 395 //------------------------------------------------------------------------ 396 // OHCI:: Submit a transfer 397 // 398 // parameters: 399 // - t: pointer to a transfer instance 400 //------------------------------------------------------------------------ 401 402 status_t OHCI::SubmitTransfer( Transfer *t ) 403 { 404 return B_OK; 405 } 406 pci_module_info *OHCI::pci_module = 0; 407