Rev 4300 | Rev 4547 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4300 | Rev 4418 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | ; Code for EHCI controllers. |
1 | ; Code for EHCI controllers. |
- | 2 | ||
- | 3 | ; Standard driver stuff |
|
- | 4 | format PE DLL native |
|
- | 5 | entry start |
|
- | 6 | __DEBUG__ equ 1 |
|
- | 7 | __DEBUG_LEVEL__ equ 1 |
|
2 | ; Note: it should be moved to an external driver, |
8 | section '.reloc' data readable discardable fixups |
3 | ; it was convenient to have this code compiled into the kernel during initial |
9 | section '.text' code readable executable |
- | 10 | include '../proc32.inc' |
|
- | 11 | include '../struct.inc' |
|
- | 12 | include '../macros.inc' |
|
- | 13 | include '../fdo.inc' |
|
4 | ; development, but there are no reasons to keep it here. |
14 | include '../../kernel/trunk/bus/usb/common.inc' |
Line 5... | Line 15... | ||
5 | 15 | ||
6 | ; ============================================================================= |
16 | ; ============================================================================= |
7 | ; ================================= Constants ================================= |
17 | ; ================================= Constants ================================= |
8 | ; ============================================================================= |
18 | ; ============================================================================= |
Line 244... | Line 254... | ||
244 | CapabilityParams dd ? |
254 | CapabilityParams dd ? |
245 | ; Copy of EhciCapParamsReg value. |
255 | ; Copy of EhciCapParamsReg value. |
246 | DeferredActions dd ? |
256 | DeferredActions dd ? |
247 | ; Bitmask of events from EhciStatusReg which were observed by the IRQ handler |
257 | ; Bitmask of events from EhciStatusReg which were observed by the IRQ handler |
248 | ; and needs to be processed in the IRQ thread. |
258 | ; and needs to be processed in the IRQ thread. |
- | 259 | PortRoutes rb 16 |
|
- | 260 | ; Companion port route description. |
|
- | 261 | ; Each byte describes routing of one port, value = PCI function. |
|
- | 262 | ; This field must be the last one: |
|
- | 263 | ; UHCI/OHCI code uses this field without knowing the entire structure. |
|
249 | ends |
264 | ends |
Line 250... | Line 265... | ||
250 | 265 | ||
251 | if ehci_controller.IntEDs mod 32 |
266 | if ehci_controller.IntEDs mod 32 |
252 | .err Static endpoint descriptors must be 32-bytes aligned inside ehci_controller |
267 | .err Static endpoint descriptors must be 32-bytes aligned inside ehci_controller |
Line 256... | Line 271... | ||
256 | ; controller-independent code. |
271 | ; controller-independent code. |
257 | ; Implements the structure usb_hardware_func from hccommon.inc for EHCI. |
272 | ; Implements the structure usb_hardware_func from hccommon.inc for EHCI. |
258 | iglobal |
273 | iglobal |
259 | align 4 |
274 | align 4 |
260 | ehci_hardware_func: |
275 | ehci_hardware_func: |
- | 276 | dd USBHC_VERSION |
|
261 | dd 'EHCI' |
277 | dd 'EHCI' |
262 | dd sizeof.ehci_controller |
278 | dd sizeof.ehci_controller |
- | 279 | dd ehci_kickoff_bios |
|
263 | dd ehci_init |
280 | dd ehci_init |
264 | dd ehci_process_deferred |
281 | dd ehci_process_deferred |
265 | dd ehci_set_device_address |
282 | dd ehci_set_device_address |
266 | dd ehci_get_device_address |
283 | dd ehci_get_device_address |
267 | dd ehci_port_disable |
284 | dd ehci_port_disable |
Line 274... | Line 291... | ||
274 | dd ehci_alloc_td |
291 | dd ehci_alloc_td |
275 | dd ehci_free_td |
292 | dd ehci_free_td |
276 | dd ehci_alloc_transfer |
293 | dd ehci_alloc_transfer |
277 | dd ehci_insert_transfer |
294 | dd ehci_insert_transfer |
278 | dd ehci_new_device |
295 | dd ehci_new_device |
- | 296 | ehci_name db 'EHCI',0 |
|
279 | endg |
297 | endg |
Line 280... | Line 298... | ||
280 | 298 | ||
281 | ; ============================================================================= |
299 | ; ============================================================================= |
282 | ; =================================== Code ==================================== |
300 | ; =================================== Code ==================================== |
Line -... | Line 301... | ||
- | 301 | ; ============================================================================= |
|
- | 302 | ||
- | 303 | ; Called once when driver is loading and once at shutdown. |
|
- | 304 | ; When loading, must initialize itself, register itself in the system |
|
- | 305 | ; and return eax = value obtained when registering. |
|
- | 306 | proc start |
|
- | 307 | virtual at esp |
|
- | 308 | dd ? ; return address |
|
- | 309 | .reason dd ? ; DRV_ENTRY or DRV_EXIT |
|
- | 310 | .cmdline dd ? ; normally NULL |
|
- | 311 | end virtual |
|
- | 312 | cmp [.reason], DRV_ENTRY |
|
- | 313 | jnz .nothing |
|
- | 314 | mov ecx, ehci_ep_mutex |
|
- | 315 | invoke MutexInit |
|
- | 316 | mov ecx, ehci_gtd_mutex |
|
- | 317 | invoke MutexInit |
|
- | 318 | push esi edi |
|
- | 319 | mov esi, [USBHCFunc] |
|
- | 320 | mov edi, usbhc_api |
|
- | 321 | movi ecx, sizeof.usbhc_func/4 |
|
- | 322 | rep movsd |
|
- | 323 | pop edi esi |
|
- | 324 | invoke RegUSBDriver, ehci_name, 0, ehci_hardware_func |
|
- | 325 | .nothing: |
|
- | 326 | ret |
|
283 | ; ============================================================================= |
327 | endp |
284 | 328 | ||
285 | ; Controller-specific initialization function. |
329 | ; Controller-specific initialization function. |
286 | ; Called from usb_init_controller. Initializes the hardware and |
330 | ; Called from usb_init_controller. Initializes the hardware and |
287 | ; EHCI-specific parts of software structures. |
331 | ; EHCI-specific parts of software structures. |
Line 311... | Line 355... | ||
311 | end if |
355 | end if |
312 | if (ehci_controller.IntEDs mod 0x1000) <> 0 |
356 | if (ehci_controller.IntEDs mod 0x1000) <> 0 |
313 | .err assertion failed |
357 | .err assertion failed |
314 | end if |
358 | end if |
315 | add eax, ehci_controller.IntEDs |
359 | add eax, ehci_controller.IntEDs |
316 | call get_phys_addr |
360 | call [GetPhysAddr] |
317 | ; 2b. Fill first 32 entries. |
361 | ; 2b. Fill first 32 entries. |
318 | inc eax |
362 | inc eax |
319 | inc eax ; set Type to EHCI_TYPE_QH |
363 | inc eax ; set Type to EHCI_TYPE_QH |
320 | movi ecx, 32 |
364 | movi ecx, 32 |
321 | mov edx, ecx |
365 | mov edx, ecx |
Line 370... | Line 414... | ||
370 | ; 3j. Initialize the head of Bulk list. |
414 | ; 3j. Initialize the head of Bulk list. |
371 | sub esi, sizeof.ehci_static_ep |
415 | sub esi, sizeof.ehci_static_ep |
372 | call ehci_init_static_endpoint |
416 | call ehci_init_static_endpoint |
373 | ; 4. Create a virtual memory area to talk with the controller. |
417 | ; 4. Create a virtual memory area to talk with the controller. |
374 | ; 4a. Enable memory & bus master access. |
418 | ; 4a. Enable memory & bus master access. |
375 | mov ch, [.bus] |
- | |
376 | mov cl, 1 |
- | |
377 | mov eax, ecx |
- | |
378 | mov bh, [.devfn] |
419 | invoke PciRead16, dword [.bus], dword [.devfn], 4 |
379 | mov bl, 4 |
- | |
380 | call pci_read_reg |
- | |
381 | or al, 6 |
420 | or al, 6 |
382 | xchg eax, ecx |
- | |
383 | call pci_write_reg |
421 | invoke PciWrite16, dword [.bus], dword [.devfn], 4, eax |
384 | ; 4b. Read memory base address. |
422 | ; 4b. Read memory base address. |
385 | mov ah, [.bus] |
423 | invoke PciRead32, dword [.bus], dword [.devfn], 10h |
386 | mov al, 2 |
- | |
387 | mov bl, 10h |
- | |
388 | call pci_read_reg |
- | |
389 | ; DEBUGF 1,'K : phys MMIO %x\n',eax |
424 | ; DEBUGF 1,'K : phys MMIO %x\n',eax |
390 | and al, not 0Fh |
425 | and al, not 0Fh |
391 | ; 4c. Create mapping for physical memory. 200h bytes are always sufficient. |
426 | ; 4c. Create mapping for physical memory. 200h bytes are always sufficient. |
392 | stdcall map_io_mem, eax, 200h, PG_SW+PG_NOCACHE |
427 | invoke MapIoMem, eax, 200h, PG_SW+PG_NOCACHE |
393 | test eax, eax |
428 | test eax, eax |
394 | jz .fail |
429 | jz .fail |
395 | ; DEBUGF 1,'K : MMIO %x\n',eax |
430 | ; DEBUGF 1,'K : MMIO %x\n',eax |
396 | if ehci_controller.MMIOBase1 <> ehci_controller.BulkED + sizeof.ehci_static_ep |
431 | if ehci_controller.MMIOBase1 <> ehci_controller.BulkED + sizeof.ehci_static_ep |
397 | .err assertion failed |
432 | .err assertion failed |
398 | end if |
433 | end if |
399 | stosd ; fill ehci_controller.MMIOBase1 |
434 | stosd ; fill ehci_controller.MMIOBase1 |
- | 435 | ; 5. Read basic parameters of the controller. |
|
- | 436 | ; 5a. Structural parameters. |
|
- | 437 | mov ebx, [eax+EhciStructParamsReg] |
|
- | 438 | ; 5b. Port routing rules. |
|
- | 439 | ; If bit 7 in HCSPARAMS is set, read and unpack EhciPortRouteReg. |
|
- | 440 | ; Otherwise, bits 11:8 are N_PCC = number of ports per companion, |
|
- | 441 | ; bits 15:12 are number of companions, maybe zero, |
|
- | 442 | ; first N_PCC ports are routed to the first companion and so on. |
|
- | 443 | xor esi, esi |
|
- | 444 | test bl, bl |
|
- | 445 | js .read_routes |
|
- | 446 | test bh, 0x0F |
|
- | 447 | jz .no_companions |
|
- | 448 | test bh, 0xF0 |
|
- | 449 | jz .no_companions |
|
- | 450 | xor edx, edx |
|
- | 451 | .fill_routes: |
|
- | 452 | movzx ecx, bh |
|
- | 453 | and ecx, 15 |
|
- | 454 | @@: |
|
- | 455 | mov byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl |
|
- | 456 | inc esi |
|
- | 457 | cmp esi, 16 |
|
- | 458 | jz .routes_filled |
|
- | 459 | dec ecx |
|
- | 460 | jnz @b |
|
- | 461 | movzx ecx, bh |
|
- | 462 | shr ecx, 4 |
|
- | 463 | inc edx |
|
- | 464 | cmp edx, ecx |
|
- | 465 | jb .fill_routes |
|
- | 466 | .no_companions: |
|
- | 467 | mov byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], 0xFF |
|
- | 468 | inc esi |
|
- | 469 | cmp esi, 16 |
|
- | 470 | jnz .no_companions |
|
- | 471 | jmp .routes_filled |
|
- | 472 | .read_routes: |
|
- | 473 | rept 2 counter |
|
- | 474 | { |
|
- | 475 | mov ecx, [eax+EhciPortRouteReg+(counter-1)*4] |
|
- | 476 | @@: |
|
- | 477 | mov edx, ecx |
|
- | 478 | shr ecx, 4 |
|
- | 479 | and edx, 15 |
|
- | 480 | mov byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl |
|
- | 481 | inc esi |
|
- | 482 | cmp esi, 8*counter |
|
- | 483 | jnz @b |
|
- | 484 | } |
|
- | 485 | .routes_filled: |
|
- | 486 | ; DEBUGF 1,'K : EhciPortRouteReg: %x %x\n',[eax+EhciPortRouteReg],[eax+EhciPortRouteReg+4] |
|
- | 487 | ; DEBUGF 1,'K : routes:\nK : ' |
|
- | 488 | ;rept 8 counter |
|
- | 489 | ;{ |
|
- | 490 | ; DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)+counter-1]:2 |
|
- | 491 | ;} |
|
- | 492 | ; DEBUGF 1,'\nK : ' |
|
- | 493 | ;rept 8 counter |
|
- | 494 | ;{ |
|
- | 495 | ; DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes+8-(ehci_controller.MMIOBase1+4)+counter-1]:2 |
|
- | 496 | ;} |
|
- | 497 | ; DEBUGF 1,'\n' |
|
400 | movzx ecx, byte [eax+EhciCapLengthReg] |
498 | movzx ecx, byte [eax+EhciCapLengthReg] |
401 | mov edx, [eax+EhciCapParamsReg] |
499 | mov edx, [eax+EhciCapParamsReg] |
402 | mov ebx, [eax+EhciStructParamsReg] |
- | |
403 | add eax, ecx |
500 | add eax, ecx |
404 | if ehci_controller.MMIOBase2 <> ehci_controller.MMIOBase1 + 4 |
501 | if ehci_controller.MMIOBase2 <> ehci_controller.MMIOBase1 + 4 |
405 | .err assertion failed |
502 | .err assertion failed |
406 | end if |
503 | end if |
407 | stosd ; fill ehci_controller.MMIOBase2 |
504 | stosd ; fill ehci_controller.MMIOBase2 |
Line 424... | Line 521... | ||
424 | test dword [edi+EhciStatusReg], 1 shl 12 |
521 | test dword [edi+EhciStatusReg], 1 shl 12 |
425 | jnz .stopped |
522 | jnz .stopped |
426 | and dword [edi+EhciCommandReg], not 1 |
523 | and dword [edi+EhciCommandReg], not 1 |
427 | @@: |
524 | @@: |
428 | movi esi, 1 |
525 | movi esi, 1 |
429 | call delay_ms |
526 | invoke Sleep |
430 | test dword [edi+EhciStatusReg], 1 shl 12 |
527 | test dword [edi+EhciStatusReg], 1 shl 12 |
431 | jnz .stopped |
528 | jnz .stopped |
432 | loop @b |
529 | loop @b |
433 | dbgstr 'Failed to stop EHCI controller' |
530 | dbgstr 'Failed to stop EHCI controller' |
434 | jmp .fail_unmap |
531 | jmp .fail_unmap |
Line 436... | Line 533... | ||
436 | ; 6c. Reset the controller. Wait up to 50 ms checking status every 1 ms. |
533 | ; 6c. Reset the controller. Wait up to 50 ms checking status every 1 ms. |
437 | or dword [edi+EhciCommandReg], 2 |
534 | or dword [edi+EhciCommandReg], 2 |
438 | movi ecx, 50 |
535 | movi ecx, 50 |
439 | @@: |
536 | @@: |
440 | movi esi, 1 |
537 | movi esi, 1 |
441 | call delay_ms |
538 | invoke Sleep |
442 | test dword [edi+EhciCommandReg], 2 |
539 | test dword [edi+EhciCommandReg], 2 |
443 | jz .reset_ok |
540 | jz .reset_ok |
444 | loop @b |
541 | loop @b |
445 | dbgstr 'Failed to reset EHCI controller' |
542 | dbgstr 'Failed to reset EHCI controller' |
446 | jmp .fail_unmap |
543 | jmp .fail_unmap |
Line 453... | Line 550... | ||
453 | test byte [esi+ehci_controller.CapabilityParams-sizeof.ehci_controller], 1 |
550 | test byte [esi+ehci_controller.CapabilityParams-sizeof.ehci_controller], 1 |
454 | jz @f |
551 | jz @f |
455 | mov dword [edi+EhciCtrlDataSegReg], 0 |
552 | mov dword [edi+EhciCtrlDataSegReg], 0 |
456 | @@: |
553 | @@: |
457 | ; 7b. Hook interrupt and enable appropriate interrupt sources. |
554 | ; 7b. Hook interrupt and enable appropriate interrupt sources. |
458 | mov ah, [.bus] |
- | |
459 | mov al, 0 |
- | |
460 | mov bh, [.devfn] |
555 | invoke PciRead8, dword [.bus], dword [.devfn], 3Ch |
461 | mov bl, 3Ch |
- | |
462 | call pci_read_reg |
- | |
463 | ; al = IRQ |
556 | ; al = IRQ |
464 | DEBUGF 1,'K : attaching to IRQ %x\n',al |
557 | ; DEBUGF 1,'K : attaching to IRQ %x\n',al |
465 | movzx eax, al |
558 | movzx eax, al |
466 | stdcall attach_int_handler, eax, ehci_irq, esi |
559 | invoke AttachIntHandler, eax, ehci_irq, esi |
467 | ; mov dword [edi+EhciStatusReg], 111111b ; clear status |
560 | ; mov dword [edi+EhciStatusReg], 111111b ; clear status |
468 | ; disable Frame List Rollover interrupt, enable all other sources |
561 | ; disable Frame List Rollover interrupt, enable all other sources |
469 | mov dword [edi+EhciInterruptReg], 110111b |
562 | mov dword [edi+EhciInterruptReg], 110111b |
470 | ; 7c. Inform the controller of the address of periodic lists head. |
563 | ; 7c. Inform the controller of the address of periodic lists head. |
471 | lea eax, [esi-sizeof.ehci_controller] |
564 | lea eax, [esi-sizeof.ehci_controller] |
472 | call get_phys_addr |
565 | invoke GetPhysAddr |
473 | mov dword [edi+EhciPeriodicListReg], eax |
566 | mov dword [edi+EhciPeriodicListReg], eax |
474 | ; 7d. Inform the controller of the address of asynchronous lists head. |
567 | ; 7d. Inform the controller of the address of asynchronous lists head. |
475 | lea eax, [esi+ehci_controller.ControlED-sizeof.ehci_controller] |
568 | lea eax, [esi+ehci_controller.ControlED-sizeof.ehci_controller] |
476 | call get_phys_addr |
569 | invoke GetPhysAddr |
477 | mov dword [edi+EhciAsyncListReg], eax |
570 | mov dword [edi+EhciAsyncListReg], eax |
478 | ; 7e. Configure operational details and run the controller. |
571 | ; 7e. Configure operational details and run the controller. |
479 | mov dword [edi+EhciCommandReg], \ |
572 | mov dword [edi+EhciCommandReg], \ |
480 | (1 shl 16) + \ ; interrupt threshold = 1 microframe = 0.125ms |
573 | (1 shl 16) + \ ; interrupt threshold = 1 microframe = 0.125ms |
481 | (0 shl 11) + \ ; disable Async Park Mode |
574 | (0 shl 11) + \ ; disable Async Park Mode |
Line 496... | Line 589... | ||
496 | jb @b |
589 | jb @b |
497 | test byte [esi+ehci_controller.StructuralParams-sizeof.ehci_controller], 10h |
590 | test byte [esi+ehci_controller.StructuralParams-sizeof.ehci_controller], 10h |
498 | jz @f |
591 | jz @f |
499 | push esi |
592 | push esi |
500 | movi esi, 20 |
593 | movi esi, 20 |
501 | call delay_ms |
594 | invoke Sleep |
502 | pop esi |
595 | pop esi |
503 | @@: |
596 | @@: |
504 | ; 9. Return pointer to usb_controller. |
597 | ; 9. Return pointer to usb_controller. |
505 | xchg eax, esi |
598 | xchg eax, esi |
506 | ret |
599 | ret |
Line 508... | Line 601... | ||
508 | ; Note that the main code branch restores the stack at step 7 and never fails |
601 | ; Note that the main code branch restores the stack at step 7 and never fails |
509 | ; after step 7. |
602 | ; after step 7. |
510 | .fail_unmap: |
603 | .fail_unmap: |
511 | pop eax |
604 | pop eax |
512 | push eax |
605 | push eax |
513 | stdcall free_kernel_space, [eax+ehci_controller.MMIOBase1] |
606 | invoke FreeKernelSpace, [eax+ehci_controller.MMIOBase1] |
514 | .fail: |
607 | .fail: |
515 | pop ecx |
608 | pop ecx |
516 | xor eax, eax |
609 | xor eax, eax |
517 | ret |
610 | ret |
518 | endp |
611 | endp |
Line 527... | Line 620... | ||
527 | mov [edi+ehci_static_ep.NextTD], eax |
620 | mov [edi+ehci_static_ep.NextTD], eax |
528 | mov [edi+ehci_static_ep.AlternateNextTD], eax |
621 | mov [edi+ehci_static_ep.AlternateNextTD], eax |
529 | test esi, esi |
622 | test esi, esi |
530 | jz @f |
623 | jz @f |
531 | mov eax, esi |
624 | mov eax, esi |
532 | call get_phys_addr |
625 | invoke GetPhysAddr |
533 | inc eax |
626 | inc eax |
534 | inc eax ; set Type to EHCI_TYPE_QH |
627 | inc eax ; set Type to EHCI_TYPE_QH |
535 | @@: |
628 | @@: |
536 | mov [edi+ehci_static_ep.NextQH], eax |
629 | mov [edi+ehci_static_ep.NextQH], eax |
537 | mov [edi+ehci_static_ep.NextList], esi |
630 | mov [edi+ehci_static_ep.NextList], esi |
538 | mov byte [edi+ehci_static_ep.OverlayToken], 1 shl 6 ; halted |
631 | mov byte [edi+ehci_static_ep.OverlayToken], 1 shl 6 ; halted |
539 | add edi, ehci_static_ep.SoftwarePart |
632 | add edi, ehci_static_ep.SoftwarePart |
- | 633 | mov eax, [USBHCFunc] |
|
540 | call usb_init_static_endpoint |
634 | call [eax+usbhc_func.usb_init_static_endpoint] |
541 | add edi, sizeof.ehci_static_ep - ehci_static_ep.SoftwarePart |
635 | add edi, sizeof.ehci_static_ep - ehci_static_ep.SoftwarePart |
542 | ret |
636 | ret |
543 | endp |
637 | endp |
Line 544... | Line 638... | ||
544 | 638 | ||
Line 563... | Line 657... | ||
563 | ; to support USB flash drives. In this case, |
657 | ; to support USB flash drives. In this case, |
564 | ; we must notify the BIOS that we don't need that emulation and know how to |
658 | ; we must notify the BIOS that we don't need that emulation and know how to |
565 | ; deal with USB devices. |
659 | ; deal with USB devices. |
566 | proc ehci_kickoff_bios |
660 | proc ehci_kickoff_bios |
567 | ; 1. Get the physical address of MMIO registers. |
661 | ; 1. Get the physical address of MMIO registers. |
568 | mov ah, [esi+PCIDEV.bus] |
- | |
569 | mov bh, [esi+PCIDEV.devfn] |
662 | invoke PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], 10h |
570 | mov al, 2 |
- | |
571 | mov bl, 10h |
- | |
572 | call pci_read_reg |
- | |
573 | and al, not 0Fh |
663 | and al, not 0Fh |
574 | ; 2. Create mapping for physical memory. 200h bytes are always sufficient. |
664 | ; 2. Create mapping for physical memory. 200h bytes are always sufficient. |
575 | stdcall map_io_mem, eax, 200h, PG_SW+PG_NOCACHE |
665 | invoke MapIoMem, eax, 200h, PG_SW+PG_NOCACHE |
576 | test eax, eax |
666 | test eax, eax |
577 | jz .nothing |
667 | jz .nothing |
578 | push eax ; push argument for step 8 |
668 | push eax ; push argument for step 8 |
579 | ; 3. Some BIOSes enable controller interrupts as a result of giving |
669 | ; 3. Some BIOSes enable controller interrupts as a result of giving |
580 | ; controller away. At this point the system knows nothing about how to serve |
670 | ; controller away. At this point the system knows nothing about how to serve |
Line 602... | Line 692... | ||
602 | jb .no_capability |
692 | jb .no_capability |
603 | .look_bios_handoff: |
693 | .look_bios_handoff: |
604 | test bl, 3 |
694 | test bl, 3 |
605 | jnz .no_capability |
695 | jnz .no_capability |
606 | ; In each iteration, read the current dword, |
696 | ; In each iteration, read the current dword, |
607 | mov ah, [esi+PCIDEV.bus] |
- | |
608 | mov al, 2 |
- | |
609 | mov bh, [esi+PCIDEV.devfn] |
697 | invoke PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx |
610 | call pci_read_reg |
- | |
611 | ; check, whether the capability ID is take-ownership ID = 1, |
698 | ; check, whether the capability ID is take-ownership ID = 1, |
612 | cmp al, 1 |
699 | cmp al, 1 |
613 | jz .found_bios_handoff |
700 | jz .found_bios_handoff |
614 | ; if not, advance to next-capability link and continue loop. |
701 | ; if not, advance to next-capability link and continue loop. |
615 | dec byte [esp] |
702 | dec byte [esp] |
Line 630... | Line 717... | ||
630 | inc ebx |
717 | inc ebx |
631 | test eax, 0x10000 |
718 | test eax, 0x10000 |
632 | jz .has_ownership |
719 | jz .has_ownership |
633 | ; 4c. Request ownership. |
720 | ; 4c. Request ownership. |
634 | inc ebx |
721 | inc ebx |
635 | mov cl, 1 |
- | |
636 | mov ah, [esi+PCIDEV.bus] |
722 | invoke PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 1 |
637 | mov al, 0 |
- | |
638 | call pci_write_reg |
- | |
639 | ; 4d. Some BIOSes set ownership flag, but forget to watch for change-ownership |
723 | ; 4d. Some BIOSes set ownership flag, but forget to watch for change-ownership |
640 | ; requests; if so, there is no sense in waiting. |
724 | ; requests; if so, there is no sense in waiting. |
641 | inc ebx |
725 | inc ebx |
642 | mov ah, [esi+PCIDEV.bus] |
726 | invoke PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx |
643 | mov al, 2 |
- | |
644 | call pci_read_reg |
- | |
645 | dec ebx |
727 | dec ebx |
646 | dec ebx |
728 | dec ebx |
647 | test ah, 20h |
729 | test ah, 20h |
648 | jz .force_ownership |
730 | jz .force_ownership |
649 | ; 4e. Wait for result no more than 1 s, checking for status every 1 ms. |
731 | ; 4e. Wait for result no more than 1 s, checking for status every 1 ms. |
650 | ; If successful, go to 5. |
732 | ; If successful, go to 5. |
651 | mov dword [esp], 1000 |
733 | mov dword [esp], 1000 |
652 | @@: |
734 | @@: |
653 | mov ah, [esi+PCIDEV.bus] |
735 | invoke PciRead8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx |
654 | mov al, 0 |
- | |
655 | call pci_read_reg |
- | |
656 | test al, 1 |
736 | test al, 1 |
657 | jz .has_ownership |
737 | jz .has_ownership |
658 | push esi |
738 | push esi |
659 | movi esi, 1 |
739 | movi esi, 1 |
660 | call delay_ms |
740 | invoke Sleep |
661 | pop esi |
741 | pop esi |
662 | dec dword [esp] |
742 | dec dword [esp] |
663 | jnz @b |
743 | jnz @b |
664 | dbgstr 'warning: taking EHCI ownership from BIOS timeout' |
744 | dbgstr 'warning: taking EHCI ownership from BIOS timeout' |
665 | .force_ownership: |
745 | .force_ownership: |
666 | ; 4f. BIOS has not responded within the timeout. |
746 | ; 4f. BIOS has not responded within the timeout. |
667 | ; Let's just clear BIOS ownership flag and hope that everything will be ok. |
747 | ; Let's just clear BIOS ownership flag and hope that everything will be ok. |
668 | mov ah, [esi+PCIDEV.bus] |
748 | invoke PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 0 |
669 | mov al, 0 |
- | |
670 | mov cl, 0 |
- | |
671 | call pci_write_reg |
- | |
672 | .has_ownership: |
749 | .has_ownership: |
673 | ; 5. Just in case clear all SMI event sources except change-ownership. |
750 | ; 5. Just in case clear all SMI event sources except change-ownership. |
674 | dbgstr 'has_ownership' |
751 | dbgstr 'has_ownership' |
675 | inc ebx |
752 | inc ebx |
676 | inc ebx |
753 | inc ebx |
677 | mov ah, [esi+PCIDEV.bus] |
754 | invoke PciRead16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx |
678 | mov al, 2 |
- | |
679 | mov ecx, eax |
- | |
680 | call pci_read_reg |
- | |
681 | and ax, 2000h |
755 | and ax, 2000h |
682 | xchg eax, ecx |
- | |
683 | call pci_write_reg |
756 | invoke PciWrite16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, eax |
684 | .has_ownership2: |
757 | .has_ownership2: |
685 | pop ecx |
758 | pop ecx |
686 | ; 6. Disable all controller interrupts until the system will be ready to |
759 | ; 6. Disable all controller interrupts until the system will be ready to |
687 | ; process them. |
760 | ; process them. |
688 | mov dword [edi+EhciInterruptReg], 0 |
761 | mov dword [edi+EhciInterruptReg], 0 |
689 | ; 7. Now we can unblock interrupts in the processor. |
762 | ; 7. Now we can unblock interrupts in the processor. |
690 | popf |
763 | popf |
691 | ; 8. Release memory mapping created in step 2 and return. |
764 | ; 8. Release memory mapping created in step 2 and return. |
692 | call free_kernel_space |
765 | invoke FreeKernelSpace |
693 | .nothing: |
766 | .nothing: |
694 | ret |
767 | ret |
695 | endp |
768 | endp |
Line 696... | Line 769... | ||
696 | 769 | ||
Line 715... | Line 788... | ||
715 | ; 2. Get the mask of events which should be processed. |
788 | ; 2. Get the mask of events which should be processed. |
716 | mov esi, [.controller] |
789 | mov esi, [.controller] |
717 | mov edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller] |
790 | mov edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller] |
718 | spin_lock_irqsave [esi+usb_controller.WaitSpinlock] |
791 | spin_lock_irqsave [esi+usb_controller.WaitSpinlock] |
719 | mov eax, [edi+EhciStatusReg] |
792 | mov eax, [edi+EhciStatusReg] |
720 | ; DEBUGF 1,'K : [%d] EHCI status %x\n',[timer_ticks],eax |
- | |
721 | ; 3. Check whether that interrupt has been generated by our controller. |
793 | ; 3. Check whether that interrupt has been generated by our controller. |
722 | ; (One IRQ can be shared by several devices.) |
794 | ; (One IRQ can be shared by several devices.) |
723 | and eax, [edi+EhciInterruptReg] |
795 | and eax, [edi+EhciInterruptReg] |
724 | jz .noint |
796 | jz .noint |
725 | ; 4. Clear the events we know of. |
797 | ; 4. Clear the events we know of. |
Line 737... | Line 809... | ||
737 | ; We can't do too much from an interrupt handler. Inform the processing thread |
809 | ; We can't do too much from an interrupt handler. Inform the processing thread |
738 | ; that it should perform appropriate actions. |
810 | ; that it should perform appropriate actions. |
739 | or [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], eax |
811 | or [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], eax |
740 | spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock] |
812 | spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock] |
741 | inc ebx |
813 | inc ebx |
742 | call usb_wakeup_if_needed |
814 | invoke usbhc_api.usb_wakeup_if_needed |
743 | ; 6. Interrupt processed; return non-zero. |
815 | ; 6. Interrupt processed; return non-zero. |
744 | mov al, 1 |
816 | mov al, 1 |
745 | pop edi esi ebx ; restore used registers to be cdecl |
817 | pop edi esi ebx ; restore used registers to be cdecl |
746 | ret |
818 | ret |
747 | endp |
819 | endp |
Line 749... | Line 821... | ||
749 | ; This procedure is called from usb_set_address_callback |
821 | ; This procedure is called from usb_set_address_callback |
750 | ; and stores USB device address in the ehci_pipe structure. |
822 | ; and stores USB device address in the ehci_pipe structure. |
751 | ; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
823 | ; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
752 | proc ehci_set_device_address |
824 | proc ehci_set_device_address |
753 | mov byte [ebx+ehci_pipe.Token-sizeof.ehci_pipe], cl |
825 | mov byte [ebx+ehci_pipe.Token-sizeof.ehci_pipe], cl |
754 | call usb_subscribe_control |
826 | jmp [usbhc_api.usb_subscribe_control] |
755 | ret |
- | |
756 | endp |
827 | endp |
Line 757... | Line 828... | ||
757 | 828 | ||
758 | ; This procedure returns USB device address from the ehci_pipe structure. |
829 | ; This procedure returns USB device address from the ehci_pipe structure. |
759 | ; in: esi -> usb_controller, ebx -> usb_pipe |
830 | ; in: esi -> usb_controller, ebx -> usb_pipe |
Line 783... | Line 854... | ||
783 | and eax, not (0x7FF shl 16) |
854 | and eax, not (0x7FF shl 16) |
784 | shl ecx, 16 |
855 | shl ecx, 16 |
785 | or eax, ecx |
856 | or eax, ecx |
786 | mov [ebx+ehci_pipe.Token-sizeof.ehci_pipe], eax |
857 | mov [ebx+ehci_pipe.Token-sizeof.ehci_pipe], eax |
787 | ; Wait until hardware cache is evicted. |
858 | ; Wait until hardware cache is evicted. |
788 | call usb_subscribe_control |
859 | jmp [usbhc_api.usb_subscribe_control] |
789 | ret |
- | |
790 | endp |
860 | endp |
Line 791... | Line 861... | ||
791 | 861 | ||
792 | uglobal |
862 | uglobal |
793 | align 4 |
863 | align 4 |
Line 802... | Line 872... | ||
802 | ; Both hardware+software parts must be allocated, returns pointer to usb_pipe |
872 | ; Both hardware+software parts must be allocated, returns pointer to usb_pipe |
803 | ; (software part). |
873 | ; (software part). |
804 | proc ehci_alloc_pipe |
874 | proc ehci_alloc_pipe |
805 | push ebx |
875 | push ebx |
806 | mov ebx, ehci_ep_mutex |
876 | mov ebx, ehci_ep_mutex |
807 | stdcall usb_allocate_common, (sizeof.ehci_pipe + sizeof.usb_pipe + 1Fh) and not 1Fh |
877 | invoke usbhc_api.usb_allocate_common, (sizeof.ehci_pipe + sizeof.usb_pipe + 1Fh) and not 1Fh |
808 | test eax, eax |
878 | test eax, eax |
809 | jz @f |
879 | jz @f |
810 | add eax, sizeof.ehci_pipe |
880 | add eax, sizeof.ehci_pipe |
811 | @@: |
881 | @@: |
812 | pop ebx |
882 | pop ebx |
Line 819... | Line 889... | ||
819 | virtual at esp |
889 | virtual at esp |
820 | dd ? ; return address |
890 | dd ? ; return address |
821 | .ptr dd ? |
891 | .ptr dd ? |
822 | end virtual |
892 | end virtual |
823 | sub [.ptr], sizeof.ehci_pipe |
893 | sub [.ptr], sizeof.ehci_pipe |
824 | jmp usb_free_common |
894 | jmp [usbhc_api.usb_free_common] |
825 | endp |
895 | endp |
Line 826... | Line 896... | ||
826 | 896 | ||
827 | ; This procedure is called from API usb_open_pipe and processes |
897 | ; This procedure is called from API usb_open_pipe and processes |
828 | ; the controller-specific part of this API. See docs. |
898 | ; the controller-specific part of this API. See docs. |
Line 851... | Line 921... | ||
851 | mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
921 | mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
852 | mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
922 | mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
853 | mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
923 | mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
854 | ; 3. Store physical address of the first TD. |
924 | ; 3. Store physical address of the first TD. |
855 | sub eax, sizeof.ehci_gtd |
925 | sub eax, sizeof.ehci_gtd |
856 | call get_phys_addr |
926 | call [GetPhysAddr] |
857 | mov [edi+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax |
927 | mov [edi+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax |
858 | ; 4. Fill ehci_pipe.Flags except for S- and C-masks. |
928 | ; 4. Fill ehci_pipe.Flags except for S- and C-masks. |
859 | ; Copy location from the config pipe. |
929 | ; Copy location from the config pipe. |
860 | mov eax, [ecx+ehci_pipe.Flags-sizeof.ehci_pipe] |
930 | mov eax, [ecx+ehci_pipe.Flags-sizeof.ehci_pipe] |
861 | and eax, 3FFF0000h |
931 | and eax, 3FFF0000h |
Line 943... | Line 1013... | ||
943 | ; 5d. Insert in the hardware list: copy previous NextQH to the new pipe, |
1013 | ; 5d. Insert in the hardware list: copy previous NextQH to the new pipe, |
944 | ; store the physical address of the new pipe to previous NextQH. |
1014 | ; store the physical address of the new pipe to previous NextQH. |
945 | mov ecx, [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart] |
1015 | mov ecx, [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart] |
946 | mov [edi+ehci_pipe.NextQH-sizeof.ehci_pipe], ecx |
1016 | mov [edi+ehci_pipe.NextQH-sizeof.ehci_pipe], ecx |
947 | lea eax, [edi-sizeof.ehci_pipe] |
1017 | lea eax, [edi-sizeof.ehci_pipe] |
948 | call get_phys_addr |
1018 | call [GetPhysAddr] |
949 | inc eax |
1019 | inc eax |
950 | inc eax |
1020 | inc eax |
951 | mov [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax |
1021 | mov [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax |
952 | ; 6. Return with nonzero eax. |
1022 | ; 6. Return with nonzero eax. |
953 | ret |
1023 | ret |
Line 961... | Line 1031... | ||
961 | ; and therefore is ready to be configured. |
1031 | ; and therefore is ready to be configured. |
962 | ; ecx = port, esi -> ehci_controller, edi -> EHCI MMIO |
1032 | ; ecx = port, esi -> ehci_controller, edi -> EHCI MMIO |
963 | proc ehci_new_port |
1033 | proc ehci_new_port |
964 | ; 1. If the device operates at low-speed, just release it to a companion. |
1034 | ; 1. If the device operates at low-speed, just release it to a companion. |
965 | mov eax, [edi+EhciPortsReg+ecx*4] |
1035 | mov eax, [edi+EhciPortsReg+ecx*4] |
966 | DEBUGF 1,'K : [%d] EHCI %x port %d state is %x\n',[timer_ticks],esi,ecx,eax |
1036 | DEBUGF 1,'K : EHCI %x port %d state is %x\n',esi,ecx,eax |
967 | mov edx, eax |
1037 | mov edx, eax |
968 | and ah, 0Ch |
1038 | and ah, 0Ch |
969 | cmp ah, 4 |
1039 | cmp ah, 4 |
970 | jz .low_speed |
1040 | jz .low_speed |
971 | ; 2. Devices operating at full-speed and high-speed must now have ah == 8. |
1041 | ; 2. Devices operating at full-speed and high-speed must now have ah == 8. |
Line 994... | Line 1064... | ||
994 | ; 2. Initiate reset signalling. |
1064 | ; 2. Initiate reset signalling. |
995 | or ah, 1 |
1065 | or ah, 1 |
996 | and al, not (4 or 2Ah) |
1066 | and al, not (4 or 2Ah) |
997 | mov [edi+EhciPortsReg+ecx*4], eax |
1067 | mov [edi+EhciPortsReg+ecx*4], eax |
998 | ; 3. Store the current time and set status to 1 = reset signalling active. |
1068 | ; 3. Store the current time and set status to 1 = reset signalling active. |
999 | mov eax, [timer_ticks] |
1069 | invoke GetTimerTicks |
1000 | mov [esi+usb_controller.ResetTime], eax |
1070 | mov [esi+usb_controller.ResetTime], eax |
1001 | mov [esi+usb_controller.ResettingStatus], 1 |
1071 | mov [esi+usb_controller.ResettingStatus], 1 |
1002 | ; dbgstr 'high-speed or full-speed device, resetting' |
1072 | ; dbgstr 'high-speed or full-speed device, resetting' |
1003 | DEBUGF 1,'K : [%d] EHCI %x: port %d has HS or FS device, resetting\n',[timer_ticks],esi,ecx |
1073 | DEBUGF 1,'K : EHCI %x: port %d has HS or FS device, resetting\n',esi,ecx |
1004 | pop edi |
1074 | pop edi |
1005 | .nothing: |
1075 | .nothing: |
1006 | ret |
1076 | ret |
1007 | .low_speed: |
1077 | .low_speed: |
1008 | ; dbgstr 'low-speed device, releasing' |
1078 | ; dbgstr 'low-speed device, releasing' |
1009 | DEBUGF 1,'K : [%d] EHCI %x: port %d has LS device, releasing\n',[timer_ticks],esi,ecx |
1079 | DEBUGF 1,'K : EHCI %x: port %d has LS device, releasing\n',esi,ecx |
1010 | or dh, 20h |
1080 | or dh, 20h |
1011 | and dl, not 2Ah |
1081 | and dl, not 2Ah |
1012 | mov [edi+EhciPortsReg+ecx*4], edx |
1082 | mov [edi+EhciPortsReg+ecx*4], edx |
1013 | ret |
1083 | ret |
1014 | .se1: |
1084 | .se1: |
Line 1049... | Line 1119... | ||
1049 | jbe .lastpacket |
1119 | jbe .lastpacket |
1050 | ; 2. While the remaining data cannot fit in one descriptor, |
1120 | ; 2. While the remaining data cannot fit in one descriptor, |
1051 | ; allocate full descriptors (of maximal possible size). |
1121 | ; allocate full descriptors (of maximal possible size). |
1052 | ; 2a. Calculate size of one descriptor: must be a multiple of transfer size |
1122 | ; 2a. Calculate size of one descriptor: must be a multiple of transfer size |
1053 | ; and must be not greater than 4001h. |
1123 | ; and must be not greater than 4001h. |
1054 | movzx ecx, word [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe] |
1124 | movzx ecx, word [ebx+ehci_pipe.Token+2-sizeof.ehci_pipe] |
- | 1125 | and ecx, (1 shl 11) - 1 |
|
1055 | mov eax, 4001h |
1126 | mov eax, 4001h |
1056 | xor edx, edx |
1127 | xor edx, edx |
1057 | mov edi, eax |
1128 | mov edi, eax |
1058 | div ecx |
1129 | div ecx |
1059 | sub edi, edx |
1130 | sub edi, edx |
Line 1090... | Line 1161... | ||
1090 | jmp @f |
1161 | jmp @f |
1091 | .disable_short: |
1162 | .disable_short: |
1092 | mov eax, [ebx+usb_pipe.Controller] |
1163 | mov eax, [ebx+usb_pipe.Controller] |
1093 | add eax, ehci_controller.StopQueueTD - sizeof.ehci_controller |
1164 | add eax, ehci_controller.StopQueueTD - sizeof.ehci_controller |
1094 | @@: |
1165 | @@: |
1095 | call get_phys_addr |
1166 | call [GetPhysAddr] |
1096 | mov edx, [origTD] |
1167 | mov edx, [origTD] |
1097 | @@: |
1168 | @@: |
1098 | cmp edx, [esp] |
1169 | cmp edx, [esp] |
1099 | jz @f |
1170 | jz @f |
1100 | mov [edx+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], eax |
1171 | mov [edx+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], eax |
Line 1104... | Line 1175... | ||
1104 | pop eax |
1175 | pop eax |
1105 | ret |
1176 | ret |
1106 | .fail: |
1177 | .fail: |
1107 | mov edi, ehci_hardware_func |
1178 | mov edi, ehci_hardware_func |
1108 | mov eax, [td] |
1179 | mov eax, [td] |
1109 | stdcall usb_undo_tds, [origTD] |
1180 | invoke usbhc_api.usb_undo_tds, [origTD] |
1110 | xor eax, eax |
1181 | xor eax, eax |
1111 | ret |
1182 | ret |
1112 | endp |
1183 | endp |
Line 1113... | Line 1184... | ||
1113 | 1184 | ||
Line 1132... | Line 1203... | ||
1132 | call ehci_alloc_td |
1203 | call ehci_alloc_td |
1133 | test eax, eax |
1204 | test eax, eax |
1134 | jz .nothing |
1205 | jz .nothing |
1135 | ; 2. Initialize controller-independent parts of both TDs. |
1206 | ; 2. Initialize controller-independent parts of both TDs. |
1136 | push eax |
1207 | push eax |
1137 | call usb_init_transfer |
1208 | invoke usbhc_api.usb_init_transfer |
1138 | pop eax |
1209 | pop eax |
1139 | ; 3. Copy PID to the new descriptor. |
1210 | ; 3. Copy PID to the new descriptor. |
1140 | mov edx, [ecx+ehci_gtd.Token-sizeof.ehci_gtd] |
1211 | mov edx, [ecx+ehci_gtd.Token-sizeof.ehci_gtd] |
1141 | mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
1212 | mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
1142 | mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
1213 | mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
1143 | mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
1214 | mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
1144 | ; 4. Save the returned value (next descriptor). |
1215 | ; 4. Save the returned value (next descriptor). |
1145 | push eax |
1216 | push eax |
1146 | ; 5. Store the physical address of the next descriptor. |
1217 | ; 5. Store the physical address of the next descriptor. |
1147 | sub eax, sizeof.ehci_gtd |
1218 | sub eax, sizeof.ehci_gtd |
1148 | call get_phys_addr |
1219 | call [GetPhysAddr] |
1149 | mov [ecx+ehci_gtd.NextTD-sizeof.ehci_gtd], eax |
1220 | mov [ecx+ehci_gtd.NextTD-sizeof.ehci_gtd], eax |
1150 | ; 6. For zero-length transfers, store zero in all fields for buffer addresses. |
1221 | ; 6. For zero-length transfers, store zero in all fields for buffer addresses. |
1151 | ; Otherwise, fill them with real values. |
1222 | ; Otherwise, fill them with real values. |
1152 | xor eax, eax |
1223 | xor eax, eax |
1153 | mov [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], eax |
1224 | mov [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], eax |
Line 1155... | Line 1226... | ||
1155 | mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd+(%-1)*4], eax |
1226 | mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd+(%-1)*4], eax |
1156 | end repeat |
1227 | end repeat |
1157 | cmp [.packetSize], eax |
1228 | cmp [.packetSize], eax |
1158 | jz @f |
1229 | jz @f |
1159 | mov eax, [.buffer] |
1230 | mov eax, [.buffer] |
1160 | call get_phys_addr |
1231 | call [GetPhysAddr] |
1161 | mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd], eax |
1232 | mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd], eax |
1162 | and eax, 0xFFF |
1233 | and eax, 0xFFF |
1163 | mov edx, [.packetSize] |
1234 | mov edx, [.packetSize] |
1164 | add edx, eax |
1235 | add edx, eax |
1165 | sub edx, 0x1000 |
1236 | sub edx, 0x1000 |
1166 | jbe @f |
1237 | jbe @f |
1167 | mov eax, [.buffer] |
1238 | mov eax, [.buffer] |
1168 | add eax, 0x1000 |
1239 | add eax, 0x1000 |
1169 | call get_pg_addr |
1240 | call [GetPgAddr] |
1170 | mov [ecx+ehci_gtd.BufferPointers+4-sizeof.ehci_gtd], eax |
1241 | mov [ecx+ehci_gtd.BufferPointers+4-sizeof.ehci_gtd], eax |
1171 | sub edx, 0x1000 |
1242 | sub edx, 0x1000 |
1172 | jbe @f |
1243 | jbe @f |
1173 | mov eax, [.buffer] |
1244 | mov eax, [.buffer] |
1174 | add eax, 0x2000 |
1245 | add eax, 0x2000 |
1175 | call get_pg_addr |
1246 | call [GetPgAddr] |
1176 | mov [ecx+ehci_gtd.BufferPointers+8-sizeof.ehci_gtd], eax |
1247 | mov [ecx+ehci_gtd.BufferPointers+8-sizeof.ehci_gtd], eax |
1177 | sub edx, 0x1000 |
1248 | sub edx, 0x1000 |
1178 | jbe @f |
1249 | jbe @f |
1179 | mov eax, [.buffer] |
1250 | mov eax, [.buffer] |
1180 | add eax, 0x3000 |
1251 | add eax, 0x3000 |
1181 | call get_pg_addr |
1252 | call [GetPgAddr] |
1182 | mov [ecx+ehci_gtd.BufferPointers+12-sizeof.ehci_gtd], eax |
1253 | mov [ecx+ehci_gtd.BufferPointers+12-sizeof.ehci_gtd], eax |
1183 | sub edx, 0x1000 |
1254 | sub edx, 0x1000 |
1184 | jbe @f |
1255 | jbe @f |
1185 | mov eax, [.buffer] |
1256 | mov eax, [.buffer] |
1186 | add eax, 0x4000 |
1257 | add eax, 0x4000 |
1187 | call get_pg_addr |
1258 | call [GetPgAddr] |
1188 | mov [ecx+ehci_gtd.BufferPointers+16-sizeof.ehci_gtd], eax |
1259 | mov [ecx+ehci_gtd.BufferPointers+16-sizeof.ehci_gtd], eax |
1189 | @@: |
1260 | @@: |
1190 | ; 7. Fill Token field: |
1261 | ; 7. Fill Token field: |
1191 | ; set Status = 0 (inactive, ehci_insert_transfer would mark everything active); |
1262 | ; set Status = 0 (inactive, ehci_insert_transfer would mark everything active); |
1192 | ; keep current PID if [.direction] is zero, use two lower bits of [.direction] |
1263 | ; keep current PID if [.direction] is zero, use two lower bits of [.direction] |
Line 1240... | Line 1311... | ||
1240 | ; This function is called from ehci_process_deferred when |
1311 | ; This function is called from ehci_process_deferred when |
1241 | ; reset signalling for a new device needs to be finished. |
1312 | ; reset signalling for a new device needs to be finished. |
1242 | proc ehci_port_reset_done |
1313 | proc ehci_port_reset_done |
1243 | movzx ecx, [esi+usb_controller.ResettingPort] |
1314 | movzx ecx, [esi+usb_controller.ResettingPort] |
1244 | and dword [edi+EhciPortsReg+ecx*4], not 12Ah |
1315 | and dword [edi+EhciPortsReg+ecx*4], not 12Ah |
1245 | mov eax, [timer_ticks] |
1316 | invoke GetTimerTicks |
1246 | mov [esi+usb_controller.ResetTime], eax |
1317 | mov [esi+usb_controller.ResetTime], eax |
1247 | mov [esi+usb_controller.ResettingStatus], 2 |
1318 | mov [esi+usb_controller.ResettingStatus], 2 |
1248 | DEBUGF 1,'K : [%d] EHCI %x: reset port %d done\n',[timer_ticks],esi,ecx |
1319 | ; DEBUGF 1,'K : EHCI %x: reset port %d done\n',esi,ecx |
1249 | ret |
1320 | ret |
1250 | endp |
1321 | endp |
Line 1251... | Line 1322... | ||
1251 | 1322 | ||
1252 | ; This function is called from ehci_process_deferred when |
1323 | ; This function is called from ehci_process_deferred when |
Line 1256... | Line 1327... | ||
1256 | ; If reset has been failed (device disconnected during reset), |
1327 | ; If reset has been failed (device disconnected during reset), |
1257 | ; continue to next device (if there is one). |
1328 | ; continue to next device (if there is one). |
1258 | xor eax, eax |
1329 | xor eax, eax |
1259 | xchg al, [esi+usb_controller.ResettingStatus] |
1330 | xchg al, [esi+usb_controller.ResettingStatus] |
1260 | test al, al |
1331 | test al, al |
- | 1332 | jns @f |
|
1261 | js usb_test_pending_port |
1333 | jmp [usbhc_api.usb_test_pending_port] |
- | 1334 | @@: |
|
1262 | ; 2. Get the port status. High-speed devices should be now enabled, |
1335 | ; 2. Get the port status. High-speed devices should be now enabled, |
1263 | ; full-speed devices are left disabled; |
1336 | ; full-speed devices are left disabled; |
1264 | ; if the port is disabled, release it to a companion and continue to |
1337 | ; if the port is disabled, release it to a companion and continue to |
1265 | ; next device (if there is one). |
1338 | ; next device (if there is one). |
1266 | movzx ecx, [esi+usb_controller.ResettingPort] |
1339 | movzx ecx, [esi+usb_controller.ResettingPort] |
1267 | mov eax, [edi+EhciPortsReg+ecx*4] |
1340 | mov eax, [edi+EhciPortsReg+ecx*4] |
1268 | DEBUGF 1,'K : [%d] EHCI %x status of port %d is %x\n',[timer_ticks],esi,ecx,eax |
1341 | DEBUGF 1,'K : EHCI %x status of port %d is %x\n',esi,ecx,eax |
1269 | test al, 4 |
1342 | test al, 4 |
1270 | jnz @f |
1343 | jnz @f |
1271 | ; DEBUGF 1,'K : USB port disabled after reset, status = %x\n',eax |
1344 | ; DEBUGF 1,'K : USB port disabled after reset, status = %x\n',eax |
1272 | dbgstr 'releasing to companion' |
1345 | dbgstr 'releasing to companion' |
1273 | or ah, 20h |
1346 | or ah, 20h |
1274 | mov [edi+EhciPortsReg+ecx*4], eax |
1347 | mov [edi+EhciPortsReg+ecx*4], eax |
1275 | jmp usb_test_pending_port |
1348 | jmp [usbhc_api.usb_test_pending_port] |
1276 | @@: |
1349 | @@: |
1277 | ; 3. Call the worker procedure to notify the protocol layer |
1350 | ; 3. Call the worker procedure to notify the protocol layer |
1278 | ; about new EHCI device. It is high-speed. |
1351 | ; about new EHCI device. It is high-speed. |
1279 | movi eax, USB_SPEED_HS |
1352 | movi eax, USB_SPEED_HS |
1280 | call ehci_new_device |
1353 | call ehci_new_device |
Line 1282... | Line 1355... | ||
1282 | jnz .nothing |
1355 | jnz .nothing |
1283 | ; 4. If something at the protocol layer has failed |
1356 | ; 4. If something at the protocol layer has failed |
1284 | ; (no memory, no bus address), disable the port and stop the initialization. |
1357 | ; (no memory, no bus address), disable the port and stop the initialization. |
1285 | .disable_exit: |
1358 | .disable_exit: |
1286 | and dword [edi+EhciPortsReg+ecx*4], not (4 or 2Ah) |
1359 | and dword [edi+EhciPortsReg+ecx*4], not (4 or 2Ah) |
1287 | jmp usb_test_pending_port |
1360 | jmp [usbhc_api.usb_test_pending_port] |
1288 | .nothing: |
1361 | .nothing: |
1289 | ret |
1362 | ret |
1290 | endp |
1363 | endp |
Line 1291... | Line 1364... | ||
1291 | 1364 | ||
Line 1305... | Line 1378... | ||
1305 | jz .common |
1378 | jz .common |
1306 | ; 4. For low-speed and full-speed devices, fill address:port |
1379 | ; 4. For low-speed and full-speed devices, fill address:port |
1307 | ; of the last high-speed hub (the closest to the device hub) |
1380 | ; of the last high-speed hub (the closest to the device hub) |
1308 | ; for split transactions, and set ControlEndpoint bit in eax; |
1381 | ; for split transactions, and set ControlEndpoint bit in eax; |
1309 | ; ehci_init_pipe assumes that the parent pipe is a control pipe. |
1382 | ; ehci_init_pipe assumes that the parent pipe is a control pipe. |
- | 1383 | push eax |
|
1310 | movzx ecx, [esi+usb_controller.ResettingPort] |
1384 | movzx ecx, [esi+usb_controller.ResettingPort] |
1311 | mov edx, [esi+usb_controller.ResettingHub] |
1385 | mov edx, [esi+usb_controller.ResettingHub] |
1312 | ; If the parent hub is high-speed, it is TT for the device. |
- | |
1313 | ; Otherwise, the parent hub itself is behind TT, and the device |
- | |
1314 | ; has the same TT hub+port as the parent hub. |
- | |
1315 | push eax |
- | |
1316 | mov eax, [edx+usb_hub.ConfigPipe] |
- | |
1317 | mov eax, [eax+usb_pipe.DeviceData] |
- | |
1318 | cmp [eax+usb_device_data.Speed], USB_SPEED_HS |
- | |
1319 | jz @f |
- | |
1320 | movzx ecx, [eax+usb_device_data.TTPort] |
1386 | invoke usbhc_api.usb_get_tt |
1321 | mov edx, [eax+usb_device_data.TTHub] |
- | |
1322 | @@: |
- | |
1323 | mov edx, [edx+usb_hub.ConfigPipe] |
- | |
1324 | inc ecx |
1387 | inc ecx |
1325 | mov edx, [edx+ehci_pipe.Token-sizeof.ehci_pipe] |
1388 | mov edx, [edx+ehci_pipe.Token-sizeof.ehci_pipe] |
1326 | shl ecx, 23 |
1389 | shl ecx, 23 |
1327 | and edx, 7Fh |
1390 | and edx, 7Fh |
1328 | shl edx, 16 |
1391 | shl edx, 16 |
Line 1336... | Line 1399... | ||
1336 | mov ecx, esp |
1399 | mov ecx, esp |
1337 | sub esp, sizeof.ehci_pipe - ehci_pipe.Flags - 4 |
1400 | sub esp, sizeof.ehci_pipe - ehci_pipe.Flags - 4 |
1338 | push edx ; ehci_pipe.Flags |
1401 | push edx ; ehci_pipe.Flags |
1339 | push eax ; ehci_pipe.Token |
1402 | push eax ; ehci_pipe.Token |
1340 | ; 6. Notify the protocol layer. |
1403 | ; 6. Notify the protocol layer. |
1341 | call usb_new_device |
1404 | invoke usbhc_api.usb_new_device |
1342 | ; 7. Cleanup the stack after step 5 and return. |
1405 | ; 7. Cleanup the stack after step 5 and return. |
1343 | add esp, sizeof.ehci_pipe - ehci_pipe.Flags + 8 |
1406 | add esp, sizeof.ehci_pipe - ehci_pipe.Flags + 8 |
1344 | pop ecx ebx ; restore used registers |
1407 | pop ecx ebx ; restore used registers |
1345 | ret |
1408 | ret |
1346 | endp |
1409 | endp |
Line 1376... | Line 1439... | ||
1376 | ; the first read and the clearing, invalidating the old status. If an event |
1439 | ; the first read and the clearing, invalidating the old status. If an event |
1377 | ; occurs after the clearing, we will not miss it, looking in the next scan. |
1440 | ; occurs after the clearing, we will not miss it, looking in the next scan. |
1378 | mov [edi+EhciPortsReg+ecx*4], eax |
1441 | mov [edi+EhciPortsReg+ecx*4], eax |
1379 | mov ebx, eax |
1442 | mov ebx, eax |
1380 | mov eax, [edi+EhciPortsReg+ecx*4] |
1443 | mov eax, [edi+EhciPortsReg+ecx*4] |
1381 | DEBUGF 1,'K : [%d] EHCI %x: status of port %d changed to %x\n',[timer_ticks],esi,ecx,ebx |
1444 | DEBUGF 1,'K : EHCI %x: status of port %d changed to %x\n',esi,ecx,ebx |
1382 | ; 3e. Handle overcurrent. |
1445 | ; 3e. Handle overcurrent. |
1383 | ; Note: that needs work. |
1446 | ; Note: that needs work. |
1384 | test bl, 20h ; overcurrent change |
1447 | test bl, 20h ; overcurrent change |
1385 | jz .noovercurrent |
1448 | jz .noovercurrent |
1386 | test al, 10h ; overcurrent active |
1449 | test al, 10h ; overcurrent active |
Line 1409... | Line 1472... | ||
1409 | ; 3h. Change connected status. For the connection event, also store |
1472 | ; 3h. Change connected status. For the connection event, also store |
1410 | ; the connection time; any further processing is permitted only after |
1473 | ; the connection time; any further processing is permitted only after |
1411 | ; USB_CONNECT_DELAY ticks. |
1474 | ; USB_CONNECT_DELAY ticks. |
1412 | test al, 1 |
1475 | test al, 1 |
1413 | jz .disconnect |
1476 | jz .disconnect |
1414 | mov eax, [timer_ticks] |
1477 | invoke GetTimerTicks |
1415 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
1478 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
1416 | bts [esi+usb_controller.NewConnected], ecx |
1479 | bts [esi+usb_controller.NewConnected], ecx |
1417 | jmp .nextport |
1480 | jmp .nextport |
1418 | .disconnect: |
1481 | .disconnect: |
1419 | btr [esi+usb_controller.NewConnected], ecx |
1482 | btr [esi+usb_controller.NewConnected], ecx |
Line 1433... | Line 1496... | ||
1433 | cmp ecx, [esi+usb_controller.NumPorts] |
1496 | cmp ecx, [esi+usb_controller.NumPorts] |
1434 | jb .portloop |
1497 | jb .portloop |
1435 | .skip_roothub: |
1498 | .skip_roothub: |
1436 | ; 4. Process disconnect events. This should be done after step 3 |
1499 | ; 4. Process disconnect events. This should be done after step 3 |
1437 | ; (which includes the first stage of disconnect processing). |
1500 | ; (which includes the first stage of disconnect processing). |
1438 | call usb_disconnect_stage2 |
1501 | invoke usbhc_api.usb_disconnect_stage2 |
1439 | ; 5. Check for previously connected devices. |
1502 | ; 5. Check for previously connected devices. |
1440 | ; If there is a connected device which was connected less than |
1503 | ; If there is a connected device which was connected less than |
1441 | ; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over. |
1504 | ; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over. |
1442 | ; Otherwise, call ehci_new_port. |
1505 | ; Otherwise, call ehci_new_port. |
1443 | ; This should be done after step 3. |
1506 | ; This should be done after step 3. |
Line 1445... | Line 1508... | ||
1445 | cmp [esi+usb_controller.NewConnected], ecx |
1508 | cmp [esi+usb_controller.NewConnected], ecx |
1446 | jz .skip_newconnected |
1509 | jz .skip_newconnected |
1447 | .portloop2: |
1510 | .portloop2: |
1448 | bt [esi+usb_controller.NewConnected], ecx |
1511 | bt [esi+usb_controller.NewConnected], ecx |
1449 | jnc .noconnect |
1512 | jnc .noconnect |
1450 | mov eax, [timer_ticks] |
1513 | invoke GetTimerTicks |
1451 | sub eax, [esi+usb_controller.ConnectedTime+ecx*4] |
1514 | sub eax, [esi+usb_controller.ConnectedTime+ecx*4] |
1452 | sub eax, USB_CONNECT_DELAY |
1515 | sub eax, USB_CONNECT_DELAY |
1453 | jge .connected |
1516 | jge .connected |
1454 | neg eax |
1517 | neg eax |
1455 | cmp [esp], eax |
1518 | cmp [esp], eax |
Line 1486... | Line 1549... | ||
1486 | .noperiodic: |
1549 | .noperiodic: |
1487 | ; 6b. Asynchronous endpoints. |
1550 | ; 6b. Asynchronous endpoints. |
1488 | ; Satisfy a request when InterruptOnAsyncAdvance fired. |
1551 | ; Satisfy a request when InterruptOnAsyncAdvance fired. |
1489 | test byte [esp+4], 20h |
1552 | test byte [esp+4], 20h |
1490 | jz @f |
1553 | jz @f |
1491 | dbgstr 'async advance int' |
1554 | ; dbgstr 'async advance int' |
1492 | mov eax, [esi+usb_controller.WaitPipeRequestAsync] |
1555 | mov eax, [esi+usb_controller.WaitPipeRequestAsync] |
1493 | mov [esi+usb_controller.ReadyPipeHeadAsync], eax |
1556 | mov [esi+usb_controller.ReadyPipeHeadAsync], eax |
1494 | @@: |
1557 | @@: |
1495 | ; Some hardware in some (rarely) conditions set the status bit, |
1558 | ; Some hardware in some (rarely) conditions set the status bit, |
1496 | ; but just does not generate the corresponding interrupt. |
1559 | ; but just does not generate the corresponding interrupt. |
Line 1529... | Line 1592... | ||
1529 | .test_reset: |
1592 | .test_reset: |
1530 | ; 8a. Test whether reset signalling is active. |
1593 | ; 8a. Test whether reset signalling is active. |
1531 | cmp [esi+usb_controller.ResettingStatus], 1 |
1594 | cmp [esi+usb_controller.ResettingStatus], 1 |
1532 | jnz .no_reset_in_progress |
1595 | jnz .no_reset_in_progress |
1533 | ; 8b. Yep. Test whether it should be stopped. |
1596 | ; 8b. Yep. Test whether it should be stopped. |
1534 | mov eax, [timer_ticks] |
1597 | invoke GetTimerTicks |
1535 | sub eax, [esi+usb_controller.ResetTime] |
1598 | sub eax, [esi+usb_controller.ResetTime] |
1536 | sub eax, USB_RESET_TIME |
1599 | sub eax, USB_RESET_TIME |
1537 | jge .reset_done |
1600 | jge .reset_done |
1538 | ; 8c. Not yet, but initiate wakeup in -eax ticks and exit this step. |
1601 | ; 8c. Not yet, but initiate wakeup in -eax ticks and exit this step. |
1539 | neg eax |
1602 | neg eax |
Line 1547... | Line 1610... | ||
1547 | .no_reset_in_progress: |
1610 | .no_reset_in_progress: |
1548 | ; 8e. Test whether reset process is done, either successful or failed. |
1611 | ; 8e. Test whether reset process is done, either successful or failed. |
1549 | cmp [esi+usb_controller.ResettingStatus], 0 |
1612 | cmp [esi+usb_controller.ResettingStatus], 0 |
1550 | jz .skip_reset |
1613 | jz .skip_reset |
1551 | ; 8f. Yep. Test whether it should be stopped. |
1614 | ; 8f. Yep. Test whether it should be stopped. |
1552 | mov eax, [timer_ticks] |
1615 | invoke GetTimerTicks |
1553 | sub eax, [esi+usb_controller.ResetTime] |
1616 | sub eax, [esi+usb_controller.ResetTime] |
1554 | sub eax, USB_RESET_RECOVERY_TIME |
1617 | sub eax, USB_RESET_RECOVERY_TIME |
1555 | jge .reset_recovery_done |
1618 | jge .reset_recovery_done |
1556 | ; 8g. Not yet, but initiate wakeup in -eax ticks and exit this step. |
1619 | ; 8g. Not yet, but initiate wakeup in -eax ticks and exit this step. |
1557 | neg eax |
1620 | neg eax |
Line 1566... | Line 1629... | ||
1566 | jmp .test_reset |
1629 | jmp .test_reset |
1567 | .skip_reset: |
1630 | .skip_reset: |
1568 | ; 9. Process wait-done notifications, test for new wait requests. |
1631 | ; 9. Process wait-done notifications, test for new wait requests. |
1569 | ; Note: that must be done after steps 4 and 7 which could create new requests. |
1632 | ; Note: that must be done after steps 4 and 7 which could create new requests. |
1570 | ; 9a. Call the worker function. |
1633 | ; 9a. Call the worker function. |
1571 | call usb_process_wait_lists |
1634 | invoke usbhc_api.usb_process_wait_lists |
1572 | ; 9b. If it reports that an asynchronous endpoint should be removed, |
1635 | ; 9b. If it reports that an asynchronous endpoint should be removed, |
1573 | ; doorbell InterruptOnAsyncAdvance and schedule wakeup in 1s |
1636 | ; doorbell InterruptOnAsyncAdvance and schedule wakeup in 1s |
1574 | ; (sometimes it just does not fire). |
1637 | ; (sometimes it just does not fire). |
1575 | test al, 1 shl CONTROL_PIPE |
1638 | test al, 1 shl CONTROL_PIPE |
1576 | jz @f |
1639 | jz @f |
1577 | mov edx, [esi+usb_controller.WaitPipeListAsync] |
1640 | mov edx, [esi+usb_controller.WaitPipeListAsync] |
1578 | mov [esi+usb_controller.WaitPipeRequestAsync], edx |
1641 | mov [esi+usb_controller.WaitPipeRequestAsync], edx |
1579 | or dword [edi+EhciCommandReg], 1 shl 6 |
1642 | or dword [edi+EhciCommandReg], 1 shl 6 |
1580 | dbgstr 'async advance doorbell' |
1643 | ; dbgstr 'async advance doorbell' |
1581 | cmp dword [esp], 100 |
1644 | cmp dword [esp], 100 |
1582 | jb @f |
1645 | jb @f |
1583 | mov dword [esp], 100 |
1646 | mov dword [esp], 100 |
1584 | @@: |
1647 | @@: |
1585 | ; 9c. If it reports that a periodic endpoint should be removed, |
1648 | ; 9c. If it reports that a periodic endpoint should be removed, |
Line 1647... | Line 1710... | ||
1647 | ; 2. For every pipe, perform the internal loop over all descriptors. |
1710 | ; 2. For every pipe, perform the internal loop over all descriptors. |
1648 | ; All descriptors are organized in the queue; we process items from the start |
1711 | ; All descriptors are organized in the queue; we process items from the start |
1649 | ; of the queue until a) the last descriptor (not the part of the queue itself) |
1712 | ; of the queue until a) the last descriptor (not the part of the queue itself) |
1650 | ; or b) an active (not yet processed by the hardware) descriptor is reached. |
1713 | ; or b) an active (not yet processed by the hardware) descriptor is reached. |
1651 | lea ecx, [ebx+usb_pipe.Lock] |
1714 | lea ecx, [ebx+usb_pipe.Lock] |
1652 | call mutex_lock |
1715 | invoke MutexLock |
1653 | mov ebx, [ebx+usb_pipe.LastTD] |
1716 | mov ebx, [ebx+usb_pipe.LastTD] |
1654 | push ebx |
1717 | push ebx |
1655 | mov ebx, [ebx+usb_gtd.NextVirt] |
1718 | mov ebx, [ebx+usb_gtd.NextVirt] |
1656 | .tdloop: |
1719 | .tdloop: |
1657 | ; 3. For every descriptor, test active flag and check for end-of-queue; |
1720 | ; 3. For every descriptor, test active flag and check for end-of-queue; |
Line 1661... | Line 1724... | ||
1661 | cmp byte [ebx+ehci_gtd.Token-sizeof.ehci_gtd], 0 |
1724 | cmp byte [ebx+ehci_gtd.Token-sizeof.ehci_gtd], 0 |
1662 | js .tddone |
1725 | js .tddone |
1663 | ; Release the queue lock while processing one descriptor: |
1726 | ; Release the queue lock while processing one descriptor: |
1664 | ; callback function could (and often would) schedule another transfer. |
1727 | ; callback function could (and often would) schedule another transfer. |
1665 | push ecx |
1728 | push ecx |
1666 | call mutex_unlock |
1729 | invoke MutexUnlock |
1667 | call ehci_process_updated_td |
1730 | call ehci_process_updated_td |
1668 | pop ecx |
1731 | pop ecx |
1669 | call mutex_lock |
1732 | invoke MutexLock |
1670 | jmp .tdloop |
1733 | jmp .tdloop |
1671 | .tddone: |
1734 | .tddone: |
1672 | call mutex_unlock |
1735 | invoke MutexUnlock |
1673 | pop ebx |
1736 | pop ebx |
1674 | ; End of internal loop, restore pointer to the next pipe |
1737 | ; End of internal loop, restore pointer to the next pipe |
1675 | ; and continue the external loop. |
1738 | ; and continue the external loop. |
1676 | pop ebx |
1739 | pop ebx |
1677 | jmp .loop |
1740 | jmp .loop |
Line 1693... | Line 1756... | ||
1693 | ; lea eax, [ebx-sizeof.ehci_gtd] |
1756 | ; lea eax, [ebx-sizeof.ehci_gtd] |
1694 | ; DEBUGF 1,'K : %x %x %x %x\n',[eax],[eax+4],[eax+8],[eax+12] |
1757 | ; DEBUGF 1,'K : %x %x %x %x\n',[eax],[eax+4],[eax+8],[eax+12] |
1695 | ; DEBUGF 1,'K : %x %x %x %x\n',[eax+16],[eax+20],[eax+24],[eax+28] |
1758 | ; DEBUGF 1,'K : %x %x %x %x\n',[eax+16],[eax+20],[eax+24],[eax+28] |
1696 | ;@@: |
1759 | ;@@: |
1697 | ; 1. Remove this descriptor from the list of descriptors for this pipe. |
1760 | ; 1. Remove this descriptor from the list of descriptors for this pipe. |
1698 | call usb_unlink_td |
1761 | invoke usbhc_api.usb_unlink_td |
1699 | ; 2. Calculate actual number of bytes transferred. |
1762 | ; 2. Calculate actual number of bytes transferred. |
1700 | mov eax, [ebx+ehci_gtd.Token-sizeof.ehci_gtd] |
1763 | mov eax, [ebx+ehci_gtd.Token-sizeof.ehci_gtd] |
1701 | lea edx, [eax+eax] |
1764 | lea edx, [eax+eax] |
1702 | shr edx, 17 |
1765 | shr edx, 17 |
1703 | sub edx, [ebx+usb_gtd.Length] |
1766 | sub edx, [ebx+usb_gtd.Length] |
Line 1721... | Line 1784... | ||
1721 | jnz .special |
1784 | jnz .special |
1722 | .notify: |
1785 | .notify: |
1723 | ; 4. Either the descriptor in ebx was processed without errors, |
1786 | ; 4. Either the descriptor in ebx was processed without errors, |
1724 | ; or all necessary error actions were taken and ebx points to the last |
1787 | ; or all necessary error actions were taken and ebx points to the last |
1725 | ; related descriptor. |
1788 | ; related descriptor. |
1726 | ; 4a. Test whether it is the last descriptor in the transfer |
- | |
1727 | ; <=> it has an associated callback. |
- | |
1728 | mov eax, [ebx+usb_gtd.Callback] |
- | |
1729 | test eax, eax |
- | |
1730 | jz .nocallback |
- | |
1731 | ; 4b. It has an associated callback; call it with corresponding parameters. |
- | |
1732 | stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \ |
- | |
1733 | [ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData] |
- | |
1734 | jmp .callback |
- | |
1735 | .nocallback: |
- | |
1736 | ; 4c. It is an intermediate descriptor. Add its length to the length |
- | |
1737 | ; in the following descriptor. |
- | |
1738 | mov eax, [ebx+usb_gtd.NextVirt] |
1789 | invoke usbhc_api.usb_process_gtd |
1739 | add [eax+usb_gtd.Length], edx |
- | |
1740 | .callback: |
- | |
1741 | ; 5. Free the current descriptor and return the next one. |
1790 | ; 5. Free the current descriptor and return the next one. |
1742 | push [ebx+usb_gtd.NextVirt] |
1791 | push [ebx+usb_gtd.NextVirt] |
1743 | stdcall ehci_free_td, ebx |
1792 | stdcall ehci_free_td, ebx |
1744 | pop ebx |
1793 | pop ebx |
1745 | ret |
1794 | ret |
Line 1763... | Line 1812... | ||
1763 | push eax |
1812 | push eax |
1764 | ; 6b. Traverse the list of descriptors looking for the final descriptor |
1813 | ; 6b. Traverse the list of descriptors looking for the final descriptor |
1765 | ; for this transfer. Free and unlink non-final descriptors. |
1814 | ; for this transfer. Free and unlink non-final descriptors. |
1766 | ; Final descriptor will be freed in step 5. |
1815 | ; Final descriptor will be freed in step 5. |
1767 | .look_final: |
1816 | .look_final: |
1768 | call usb_is_final_packet |
1817 | invoke usbhc_api.usb_is_final_packet |
1769 | jnc .found_final |
1818 | jnc .found_final |
1770 | push [ebx+usb_gtd.NextVirt] |
1819 | push [ebx+usb_gtd.NextVirt] |
1771 | stdcall ehci_free_td, ebx |
1820 | stdcall ehci_free_td, ebx |
1772 | pop ebx |
1821 | pop ebx |
1773 | call usb_unlink_td |
1822 | invoke usbhc_api.usb_unlink_td |
1774 | jmp .look_final |
1823 | jmp .look_final |
1775 | .found_final: |
1824 | .found_final: |
1776 | ; 6c. Restore the status saved in 6a and transform it to the error code. |
1825 | ; 6c. Restore the status saved in 6a and transform it to the error code. |
1777 | ; Notes: |
1826 | ; Notes: |
1778 | ; * any USB transaction error results in Halted bit; if it is not set, |
1827 | ; * any USB transaction error results in Halted bit; if it is not set, |
Line 1820... | Line 1869... | ||
1820 | jnz .normal |
1869 | jnz .normal |
1821 | push ecx |
1870 | push ecx |
1822 | push [ebx+usb_gtd.NextVirt] |
1871 | push [ebx+usb_gtd.NextVirt] |
1823 | stdcall ehci_free_td, ebx |
1872 | stdcall ehci_free_td, ebx |
1824 | pop ebx |
1873 | pop ebx |
1825 | call usb_unlink_td |
1874 | invoke usbhc_api.usb_unlink_td |
1826 | pop ecx |
1875 | pop ecx |
1827 | .normal: |
1876 | .normal: |
1828 | ; 6f. For bulk/interrupt transfers we have no choice but halt the queue, |
1877 | ; 6f. For bulk/interrupt transfers we have no choice but halt the queue, |
1829 | ; the driver should intercede (through some API which is not written yet). |
1878 | ; the driver should intercede (through some API which is not written yet). |
1830 | ; Control pipes normally recover at the next SETUP transaction (first stage |
1879 | ; Control pipes normally recover at the next SETUP transaction (first stage |
Line 1880... | Line 1929... | ||
1880 | endp |
1929 | endp |
Line 1881... | Line 1930... | ||
1881 | 1930 | ||
1882 | proc ehci_alloc_td |
1931 | proc ehci_alloc_td |
1883 | push ebx |
1932 | push ebx |
1884 | mov ebx, ehci_gtd_mutex |
1933 | mov ebx, ehci_gtd_mutex |
1885 | stdcall usb_allocate_common, (sizeof.ehci_gtd + sizeof.usb_gtd + 1Fh) and not 1Fh |
1934 | invoke usbhc_api.usb_allocate_common, (sizeof.ehci_gtd + sizeof.usb_gtd + 1Fh) and not 1Fh |
1886 | test eax, eax |
1935 | test eax, eax |
1887 | jz @f |
1936 | jz @f |
1888 | add eax, sizeof.ehci_gtd |
1937 | add eax, sizeof.ehci_gtd |
1889 | @@: |
1938 | @@: |
Line 1894... | Line 1943... | ||
1894 | ; This procedure is called from several places from main USB code and |
1943 | ; This procedure is called from several places from main USB code and |
1895 | ; frees all additional data associated with the transfer descriptor. |
1944 | ; frees all additional data associated with the transfer descriptor. |
1896 | ; EHCI has no additional data, so just free ehci_gtd structure. |
1945 | ; EHCI has no additional data, so just free ehci_gtd structure. |
1897 | proc ehci_free_td |
1946 | proc ehci_free_td |
1898 | sub dword [esp+4], sizeof.ehci_gtd |
1947 | sub dword [esp+4], sizeof.ehci_gtd |
1899 | jmp usb_free_common |
1948 | jmp [usbhc_api.usb_free_common] |
1900 | endp=>=8>>>>>>>>>=>=> |
1949 | endp |
- | 1950 | ||
- | 1951 | include 'ehci_scheduler.inc' |
|
- | 1952 | ||
- | 1953 | section '.data' readable writable |
|
- | 1954 | include '../peimport.inc' |
|
- | 1955 | include_debug_strings |
|
- | 1956 | IncludeIGlobals |
|
- | 1957 | IncludeUGlobals |
|
- | 1958 | align 4 |
|
- | 1959 | usbhc_api usbhc_func=8>>>>>>>>>=>=> |