Rev 3816 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 3816 | Rev 4418 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | ; Code for OHCI controllers. |
1 | ; Code for OHCI 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 181... | Line 191... | ||
181 | ; to be finalized. |
191 | ; to be finalized. |
182 | DoneListEndPtr dd ? |
192 | DoneListEndPtr dd ? |
183 | ; Pointer to dword which should receive a pointer to the next item in DoneList. |
193 | ; Pointer to dword which should receive a pointer to the next item in DoneList. |
184 | ; If DoneList is empty, this is a pointer to DoneList itself; |
194 | ; If DoneList is empty, this is a pointer to DoneList itself; |
185 | ; otherwise, this is a pointer to NextTD field of the last item in DoneList. |
195 | ; otherwise, this is a pointer to NextTD field of the last item in DoneList. |
- | 196 | EhciCompanion dd ? |
|
- | 197 | ; Pointer to usb_controller for EHCI companion, if any, or NULL. |
|
186 | ends |
198 | ends |
Line 187... | Line 199... | ||
187 | 199 | ||
188 | if ohci_controller.IntEDs mod 16 |
200 | if ohci_controller.IntEDs mod 16 |
189 | .err Static endpoint descriptors must be 16-bytes aligned inside ohci_controller |
201 | .err Static endpoint descriptors must be 16-bytes aligned inside ohci_controller |
Line 288... | Line 300... | ||
288 | ; controller-independent code. |
300 | ; controller-independent code. |
289 | ; Implements the structure usb_hardware_func from hccommon.inc for OHCI. |
301 | ; Implements the structure usb_hardware_func from hccommon.inc for OHCI. |
290 | iglobal |
302 | iglobal |
291 | align 4 |
303 | align 4 |
292 | ohci_hardware_func: |
304 | ohci_hardware_func: |
- | 305 | dd USBHC_VERSION |
|
293 | dd 'OHCI' |
306 | dd 'OHCI' |
294 | dd sizeof.ohci_controller |
307 | dd sizeof.ohci_controller |
- | 308 | dd ohci_kickoff_bios |
|
295 | dd ohci_init |
309 | dd ohci_init |
296 | dd ohci_process_deferred |
310 | dd ohci_process_deferred |
297 | dd ohci_set_device_address |
311 | dd ohci_set_device_address |
298 | dd ohci_get_device_address |
312 | dd ohci_get_device_address |
299 | dd ohci_port_disable |
313 | dd ohci_port_disable |
300 | dd ohci_new_port.reset |
314 | dd ohci_new_port.reset |
301 | dd ohci_set_endpoint_packet_size |
315 | dd ohci_set_endpoint_packet_size |
302 | dd usb1_allocate_endpoint |
316 | dd ohci_alloc_pipe |
303 | dd usb1_free_endpoint |
317 | dd ohci_free_pipe |
304 | dd ohci_init_pipe |
318 | dd ohci_init_pipe |
305 | dd ohci_unlink_pipe |
319 | dd ohci_unlink_pipe |
306 | dd usb1_allocate_general_td |
320 | dd ohci_alloc_gtd |
307 | dd usb1_free_general_td |
321 | dd ohci_free_gtd |
308 | dd ohci_alloc_transfer |
322 | dd ohci_alloc_transfer |
309 | dd ohci_insert_transfer |
323 | dd ohci_insert_transfer |
310 | dd ohci_new_device |
324 | dd ohci_new_device |
- | 325 | ohci_name db 'OHCI',0 |
|
311 | endg |
326 | endg |
Line 312... | Line 327... | ||
312 | 327 | ||
313 | ; ============================================================================= |
328 | ; ============================================================================= |
314 | ; =================================== Code ==================================== |
329 | ; =================================== Code ==================================== |
Line -... | Line 330... | ||
- | 330 | ; ============================================================================= |
|
- | 331 | ||
- | 332 | ; Called once when driver is loading and once at shutdown. |
|
- | 333 | ; When loading, must initialize itself, register itself in the system |
|
- | 334 | ; and return eax = value obtained when registering. |
|
- | 335 | proc start |
|
- | 336 | virtual at esp |
|
- | 337 | dd ? ; return address |
|
- | 338 | .reason dd ? ; DRV_ENTRY or DRV_EXIT |
|
- | 339 | .cmdline dd ? ; normally NULL |
|
- | 340 | end virtual |
|
- | 341 | cmp [.reason], DRV_ENTRY |
|
- | 342 | jnz .nothing |
|
- | 343 | mov ecx, ohci_ep_mutex |
|
- | 344 | and dword [ecx-4], 0 |
|
- | 345 | invoke MutexInit |
|
- | 346 | mov ecx, ohci_gtd_mutex |
|
- | 347 | and dword [ecx-4], 0 |
|
- | 348 | invoke MutexInit |
|
- | 349 | push esi edi |
|
- | 350 | mov esi, [USBHCFunc] |
|
- | 351 | mov edi, usbhc_api |
|
- | 352 | movi ecx, sizeof.usbhc_func/4 |
|
- | 353 | rep movsd |
|
- | 354 | pop edi esi |
|
- | 355 | invoke RegUSBDriver, ohci_name, 0, ohci_hardware_func |
|
- | 356 | .nothing: |
|
- | 357 | ret |
|
315 | ; ============================================================================= |
358 | endp |
316 | 359 | ||
317 | ; Controller-specific initialization function. |
360 | ; Controller-specific initialization function. |
318 | ; Called from usb_init_controller. Initializes the hardware and |
361 | ; Called from usb_init_controller. Initializes the hardware and |
319 | ; OHCI-specific parts of software structures. |
362 | ; OHCI-specific parts of software structures. |
Line 336... | Line 379... | ||
336 | end if |
379 | end if |
337 | if ohci_controller.IntEDs >= 0x1000 |
380 | if ohci_controller.IntEDs >= 0x1000 |
338 | .err assertion failed |
381 | .err assertion failed |
339 | end if |
382 | end if |
340 | lea esi, [eax+ohci_controller.IntEDs+32*sizeof.ohci_static_ep] |
383 | lea esi, [eax+ohci_controller.IntEDs+32*sizeof.ohci_static_ep] |
341 | call get_pg_addr |
384 | invoke GetPgAddr |
342 | add eax, ohci_controller.IntEDs |
385 | add eax, ohci_controller.IntEDs |
343 | movi ecx, 32 |
386 | movi ecx, 32 |
344 | mov edx, ecx |
387 | mov edx, ecx |
345 | @@: |
388 | @@: |
346 | stosd |
389 | stosd |
Line 381... | Line 424... | ||
381 | ; 3i. Initialize the heads of Control and Bulk lists. |
424 | ; 3i. Initialize the heads of Control and Bulk lists. |
382 | call ohci_init_static_endpoint |
425 | call ohci_init_static_endpoint |
383 | call ohci_init_static_endpoint |
426 | call ohci_init_static_endpoint |
384 | ; 4. Create a virtual memory area to talk with the controller. |
427 | ; 4. Create a virtual memory area to talk with the controller. |
385 | ; 4a. Enable memory & bus master access. |
428 | ; 4a. Enable memory & bus master access. |
386 | mov ch, [.bus] |
- | |
387 | mov cl, 0 |
- | |
388 | mov eax, ecx |
- | |
389 | mov bh, [.devfn] |
429 | invoke PciRead16, dword [.bus], dword [.devfn], 4 |
390 | mov bl, 4 |
- | |
391 | call pci_read_reg |
- | |
392 | or al, 6 |
430 | or al, 6 |
393 | xchg eax, ecx |
- | |
394 | call pci_write_reg |
431 | invoke PciWrite16, dword [.bus], dword [.devfn], 4, eax |
395 | ; 4b. Read memory base address. |
432 | ; 4b. Read memory base address. |
396 | mov ah, [.bus] |
433 | invoke PciRead32, dword [.bus], dword [.devfn], 10h |
397 | mov al, 2 |
- | |
398 | mov bl, 10h |
- | |
399 | call pci_read_reg |
- | |
400 | and al, not 0Fh |
434 | and al, not 0Fh |
401 | ; 4c. Create mapping for physical memory. 256 bytes are sufficient. |
435 | ; 4c. Create mapping for physical memory. 256 bytes are sufficient. |
402 | stdcall map_io_mem, eax, 100h, PG_SW+PG_NOCACHE |
436 | invoke MapIoMem, eax, 100h, PG_SW+PG_NOCACHE |
403 | test eax, eax |
437 | test eax, eax |
404 | jz .fail |
438 | jz .fail |
405 | stosd ; fill ohci_controller.MMIOBase |
439 | stosd ; fill ohci_controller.MMIOBase |
406 | xchg eax, edi |
440 | xchg eax, edi |
407 | ; now edi = MMIOBase |
441 | ; now edi = MMIOBase |
Line 420... | Line 454... | ||
420 | movi ecx, 1 |
454 | movi ecx, 1 |
421 | movi edx, 10 |
455 | movi edx, 10 |
422 | mov [edi+OhciCommandStatusReg], ecx |
456 | mov [edi+OhciCommandStatusReg], ecx |
423 | @@: |
457 | @@: |
424 | mov esi, ecx |
458 | mov esi, ecx |
425 | call delay_ms |
459 | invoke Sleep |
426 | test [edi+OhciCommandStatusReg], ecx |
460 | test [edi+OhciCommandStatusReg], ecx |
427 | jz .resetdone |
461 | jz .resetdone |
428 | dec edx |
462 | dec edx |
429 | jnz @b |
463 | jnz @b |
430 | pop eax |
464 | pop eax |
Line 452... | Line 486... | ||
452 | .operational: |
486 | .operational: |
453 | ; 6. Setup controller registers. |
487 | ; 6. Setup controller registers. |
454 | pop esi ; restore pointer to ohci_controller saved in step 1 |
488 | pop esi ; restore pointer to ohci_controller saved in step 1 |
455 | ; 6a. Physical address of HCCA. |
489 | ; 6a. Physical address of HCCA. |
456 | mov eax, esi |
490 | mov eax, esi |
457 | call get_pg_addr |
491 | invoke GetPgAddr |
458 | mov [edi+OhciHCCAReg], eax |
492 | mov [edi+OhciHCCAReg], eax |
459 | ; 6b. Transition to operational state and clear all Enable bits. |
493 | ; 6b. Transition to operational state and clear all Enable bits. |
460 | mov cl, 2 shl 6 |
494 | mov cl, 2 shl 6 |
461 | mov [edi+OhciControlReg], ecx |
495 | mov [edi+OhciControlReg], ecx |
462 | ; 6c. Physical addresses of head of Control and Bulk lists. |
496 | ; 6c. Physical addresses of head of Control and Bulk lists. |
Line 473... | Line 507... | ||
473 | mov [edi+OhciControlCurrentEDReg], eax |
507 | mov [edi+OhciControlCurrentEDReg], eax |
474 | mov [edi+OhciBulkCurrentEDReg], eax |
508 | mov [edi+OhciBulkCurrentEDReg], eax |
475 | ; mov [edi+OhciDoneHeadReg], eax |
509 | ; mov [edi+OhciDoneHeadReg], eax |
476 | ; 6e. Enable processing of all lists with control:bulk ratio = 1:1. |
510 | ; 6e. Enable processing of all lists with control:bulk ratio = 1:1. |
477 | mov dword [edi+OhciControlReg], 10111100b |
511 | mov dword [edi+OhciControlReg], 10111100b |
478 | ; 7. Get number of ports. |
512 | ; 7. Find the EHCI companion. |
- | 513 | ; Note: this assumes that EHCI is initialized before USB1 companions. |
|
479 | add esi, sizeof.ohci_controller |
514 | add esi, sizeof.ohci_controller |
- | 515 | mov ebx, dword [.devfn] |
|
- | 516 | invoke usbhc_api.usb_find_ehci_companion |
|
- | 517 | mov [esi+ohci_controller.EhciCompanion-sizeof.ohci_controller], eax |
|
- | 518 | ; 8. Get number of ports. |
|
480 | mov eax, [edi+OhciRhDescriptorAReg] |
519 | mov eax, [edi+OhciRhDescriptorAReg] |
481 | and eax, 0xF |
520 | and eax, 0xF |
482 | mov [esi+usb_controller.NumPorts], eax |
521 | mov [esi+usb_controller.NumPorts], eax |
483 | ; 8. Initialize DoneListEndPtr to point to DoneList. |
522 | ; 9. Initialize DoneListEndPtr to point to DoneList. |
484 | lea eax, [esi+ohci_controller.DoneList-sizeof.ohci_controller] |
523 | lea eax, [esi+ohci_controller.DoneList-sizeof.ohci_controller] |
485 | mov [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller], eax |
524 | mov [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller], eax |
486 | ; 9. Hook interrupt. |
525 | ; 10. Hook interrupt. |
487 | mov ah, [.bus] |
- | |
488 | mov al, 0 |
- | |
489 | mov bh, [.devfn] |
526 | invoke PciRead8, dword [.bus], dword [.devfn], 3Ch |
490 | mov bl, 3Ch |
- | |
491 | call pci_read_reg |
- | |
492 | ; al = IRQ |
527 | ; al = IRQ |
493 | movzx eax, al |
528 | movzx eax, al |
494 | stdcall attach_int_handler, eax, ohci_irq, esi |
529 | invoke AttachIntHandler, eax, ohci_irq, esi |
495 | ; 10. Enable controller interrupt on HcDoneHead writeback and RootHubStatusChange. |
530 | ; 11. Enable controller interrupt on HcDoneHead writeback and RootHubStatusChange. |
496 | mov dword [edi+OhciInterruptEnableReg], 80000042h |
531 | mov dword [edi+OhciInterruptEnableReg], 80000042h |
497 | DEBUGF 1,'K : OHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts] |
532 | DEBUGF 1,'K : OHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts] |
498 | ; 11. Initialize ports of the controller. |
533 | ; 12. Initialize ports of the controller. |
499 | ; 11a. Initiate power up, disable all ports, clear all "changed" bits. |
534 | ; 12a. Initiate power up, disable all ports, clear all "changed" bits. |
500 | mov dword [edi+OhciRhStatusReg], 10000h ; SetGlobalPower |
535 | mov dword [edi+OhciRhStatusReg], 10000h ; SetGlobalPower |
501 | xor ecx, ecx |
536 | xor ecx, ecx |
502 | @@: |
537 | @@: |
503 | mov dword [edi+OhciRhPortStatusReg+ecx*4], 1F0101h ; SetPortPower+ClearPortEnable+clear "changed" bits |
538 | mov dword [edi+OhciRhPortStatusReg+ecx*4], 1F0101h ; SetPortPower+ClearPortEnable+clear "changed" bits |
504 | inc ecx |
539 | inc ecx |
505 | cmp ecx, [esi+usb_controller.NumPorts] |
540 | cmp ecx, [esi+usb_controller.NumPorts] |
506 | jb @b |
541 | jb @b |
507 | ; 11b. Wait for power up. |
542 | ; 12b. Wait for power up. |
508 | ; VirtualBox has AReg == 0, delay_ms doesn't like zero value; ignore zero delay |
543 | ; VirtualBox has AReg == 0, delay_ms doesn't like zero value; ignore zero delay |
509 | push esi |
544 | push esi |
510 | mov esi, [edi+OhciRhDescriptorAReg] |
545 | mov esi, [edi+OhciRhDescriptorAReg] |
511 | shr esi, 24 |
546 | shr esi, 24 |
512 | add esi, esi |
547 | add esi, esi |
513 | jz @f |
548 | jz @f |
514 | call delay_ms |
549 | invoke Sleep |
515 | @@: |
550 | @@: |
516 | pop esi |
551 | pop esi |
517 | ; 11c. Ports are powered up; now it is ok to process connect/disconnect events. |
552 | ; 12c. Ports are powered up; now it is ok to process connect/disconnect events. |
518 | mov [esi+ohci_controller.PoweredUp-sizeof.ohci_controller], 1 |
553 | mov [esi+ohci_controller.PoweredUp-sizeof.ohci_controller], 1 |
519 | ; IRQ handler doesn't accept connect/disconnect events before this point |
554 | ; IRQ handler doesn't accept connect/disconnect events before this point |
520 | ; 11d. We could miss some events while waiting for powering up; |
555 | ; 12d. We could miss some events while waiting for powering up; |
521 | ; scan all ports manually and check for connected devices. |
556 | ; scan all ports manually and check for connected devices. |
522 | xor ecx, ecx |
557 | xor ecx, ecx |
523 | .port_loop: |
558 | .port_loop: |
524 | test dword [edi+OhciRhPortStatusReg+ecx*4], 1 |
559 | test dword [edi+OhciRhPortStatusReg+ecx*4], 1 |
525 | jz .next_port |
560 | jz .next_port |
526 | ; There is a connected device; mark the port as 'connected' |
561 | ; There is a connected device; mark the port as 'connected' |
527 | ; and save the connected time. |
562 | ; and save the connected time. |
528 | ; Note that ConnectedTime must be set before 'connected' mark, |
563 | ; Note that ConnectedTime must be set before 'connected' mark, |
529 | ; otherwise the code in ohci_process_deferred could use incorrect time. |
564 | ; otherwise the code in ohci_process_deferred could use incorrect time. |
530 | mov eax, [timer_ticks] |
565 | invoke GetTimerTicks |
531 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
566 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
532 | lock bts [esi+usb_controller.NewConnected], ecx |
567 | lock bts [esi+usb_controller.NewConnected], ecx |
533 | .next_port: |
568 | .next_port: |
534 | inc ecx |
569 | inc ecx |
535 | cmp ecx, [esi+usb_controller.NumPorts] |
570 | cmp ecx, [esi+usb_controller.NumPorts] |
536 | jb .port_loop |
571 | jb .port_loop |
537 | ; 12. Return pointer to usb_controller. |
572 | ; 13. Return pointer to usb_controller. |
538 | xchg eax, esi |
573 | xchg eax, esi |
539 | ret |
574 | ret |
540 | .fail_unmap: |
575 | .fail_unmap: |
541 | ; On error after step 4, release the virtual memory area. |
576 | ; On error after step 5, release the virtual memory area. |
542 | stdcall free_kernel_space, edi |
577 | invoke FreeKernelSpace, edi |
543 | .fail: |
578 | .fail: |
544 | ; On error, free the ohci_controller structure and return zero. |
579 | ; On error, free the ohci_controller structure and return zero. |
545 | ; Note that the pointer was placed in the stack at step 1. |
580 | ; Note that the pointer was placed in the stack at step 1. |
546 | ; Note also that there can be no errors after step 8, |
581 | ; Note also that there can be no errors after step 6, |
547 | ; where that pointer is popped from the stack. |
582 | ; where that pointer is popped from the stack. |
548 | pop ecx |
583 | pop ecx |
549 | .nothing: |
584 | .nothing: |
550 | xor eax, eax |
585 | xor eax, eax |
551 | ret |
586 | ret |
Line 559... | Line 594... | ||
559 | proc ohci_init_static_endpoint |
594 | proc ohci_init_static_endpoint |
560 | mov byte [edi+ohci_static_ep.Flags+1], 1 shl (14 - 8) ; sKip this endpoint |
595 | mov byte [edi+ohci_static_ep.Flags+1], 1 shl (14 - 8) ; sKip this endpoint |
561 | mov [edi+ohci_static_ep.NextED], eax |
596 | mov [edi+ohci_static_ep.NextED], eax |
562 | mov [edi+ohci_static_ep.NextList], esi |
597 | mov [edi+ohci_static_ep.NextList], esi |
563 | add edi, ohci_static_ep.SoftwarePart |
598 | add edi, ohci_static_ep.SoftwarePart |
564 | call usb_init_static_endpoint |
599 | invoke usbhc_api.usb_init_static_endpoint |
565 | add edi, sizeof.ohci_static_ep - ohci_static_ep.SoftwarePart |
600 | add edi, sizeof.ohci_static_ep - ohci_static_ep.SoftwarePart |
566 | ret |
601 | ret |
567 | endp |
602 | endp |
Line 568... | Line 603... | ||
568 | 603 | ||
Line 589... | Line 624... | ||
589 | ; for USB keyboard and/or mice as PS/2-devices. In this case, |
624 | ; for USB keyboard and/or mice as PS/2-devices. In this case, |
590 | ; we must notify the BIOS that we don't need that emulation and know how to |
625 | ; we must notify the BIOS that we don't need that emulation and know how to |
591 | ; deal with USB devices. |
626 | ; deal with USB devices. |
592 | proc ohci_kickoff_bios |
627 | proc ohci_kickoff_bios |
593 | ; 1. Get the physical address of MMIO registers. |
628 | ; 1. Get the physical address of MMIO registers. |
594 | mov ah, [esi+PCIDEV.bus] |
- | |
595 | mov bh, [esi+PCIDEV.devfn] |
629 | invoke PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], 10h |
596 | mov al, 2 |
- | |
597 | mov bl, 10h |
- | |
598 | call pci_read_reg |
- | |
599 | and al, not 0Fh |
630 | and al, not 0Fh |
600 | ; 2. Create mapping for physical memory. 256 bytes are sufficient. |
631 | ; 2. Create mapping for physical memory. 256 bytes are sufficient. |
601 | stdcall map_io_mem, eax, 100h, PG_SW+PG_NOCACHE |
632 | invoke MapIoMem, eax, 100h, PG_SW+PG_NOCACHE |
602 | test eax, eax |
633 | test eax, eax |
603 | jz .nothing |
634 | jz .nothing |
604 | ; 3. Some BIOSes enable controller interrupts as a result of giving |
635 | ; 3. Some BIOSes enable controller interrupts as a result of giving |
605 | ; controller away. At this point the system knows nothing about how to serve |
636 | ; controller away. At this point the system knows nothing about how to serve |
606 | ; OHCI interrupts, so such an interrupt will send the system into an infinite |
637 | ; OHCI interrupts, so such an interrupt will send the system into an infinite |
Line 623... | Line 654... | ||
623 | @@: |
654 | @@: |
624 | test dword [eax+OhciControlReg], edx |
655 | test dword [eax+OhciControlReg], edx |
625 | jz .has_ownership |
656 | jz .has_ownership |
626 | push esi |
657 | push esi |
627 | movi esi, 1 |
658 | movi esi, 1 |
628 | call delay_ms |
659 | invoke Sleep |
629 | pop esi |
660 | pop esi |
630 | loop @b |
661 | loop @b |
631 | dbgstr 'warning: taking OHCI ownership from BIOS timeout' |
662 | dbgstr 'warning: taking OHCI ownership from BIOS timeout' |
632 | .has_ownership: |
663 | .has_ownership: |
633 | ; 5. Disable all controller interrupts until the system will be ready to |
664 | ; 5. Disable all controller interrupts until the system will be ready to |
634 | ; process them. |
665 | ; process them. |
635 | mov dword [eax+OhciInterruptDisableReg], 0C000007Fh |
666 | mov dword [eax+OhciInterruptDisableReg], 0C000007Fh |
636 | ; 6. Now we can unblock interrupts in the processor. |
667 | ; 6. Now we can unblock interrupts in the processor. |
637 | popf |
668 | popf |
638 | ; 7. Release memory mapping created in step 2 and return. |
669 | ; 7. Release memory mapping created in step 2 and return. |
639 | stdcall free_kernel_space, eax |
670 | invoke FreeKernelSpace, eax |
640 | .nothing: |
671 | .nothing: |
641 | ret |
672 | ret |
642 | endp |
673 | endp |
Line 643... | Line 674... | ||
643 | 674 | ||
Line 701... | Line 732... | ||
701 | ; 7b. Prepare for the reversing loop. |
732 | ; 7b. Prepare for the reversing loop. |
702 | push ebx |
733 | push ebx |
703 | xor ebx, ebx |
734 | xor ebx, ebx |
704 | test ecx, ecx |
735 | test ecx, ecx |
705 | jz .tddone |
736 | jz .tddone |
- | 737 | mov eax, [ohci_gtd_first_page] |
|
706 | call usb_td_to_virt |
738 | invoke usbhc_api.usb_td_to_virt |
707 | test eax, eax |
739 | test eax, eax |
708 | jz .tddone |
740 | jz .tddone |
709 | lea edx, [eax+ohci_gtd.NextTD] |
741 | lea edx, [eax+ohci_gtd.NextTD] |
710 | ; 7c. Reverse the list, converting physical to virtual. On every iteration: |
742 | ; 7c. Reverse the list, converting physical to virtual. On every iteration: |
711 | ; ecx = physical address of the current item |
743 | ; ecx = physical address of the current item |
Line 716... | Line 748... | ||
716 | mov ecx, [eax+ohci_gtd.NextTD] |
748 | mov ecx, [eax+ohci_gtd.NextTD] |
717 | mov [eax+ohci_gtd.NextTD], ebx |
749 | mov [eax+ohci_gtd.NextTD], ebx |
718 | lea ebx, [eax+sizeof.ohci_gtd] |
750 | lea ebx, [eax+sizeof.ohci_gtd] |
719 | test ecx, ecx |
751 | test ecx, ecx |
720 | jz .tddone |
752 | jz .tddone |
- | 753 | mov eax, [ohci_gtd_first_page] |
|
721 | call usb_td_to_virt |
754 | invoke usbhc_api.usb_td_to_virt |
722 | test eax, eax |
755 | test eax, eax |
723 | jnz .tdloop |
756 | jnz .tdloop |
724 | .tddone: |
757 | .tddone: |
725 | mov ecx, ebx |
758 | mov ecx, ebx |
726 | pop ebx |
759 | pop ebx |
Line 843... | Line 876... | ||
843 | ; after USB_CONNECT_DELAY ticks. |
876 | ; after USB_CONNECT_DELAY ticks. |
844 | test al, 1 |
877 | test al, 1 |
845 | jz .disconnect |
878 | jz .disconnect |
846 | ; Note: ConnectedTime must be stored before setting the 'connected' bit, |
879 | ; Note: ConnectedTime must be stored before setting the 'connected' bit, |
847 | ; otherwise ohci_process_deferred could use an old time. |
880 | ; otherwise ohci_process_deferred could use an old time. |
848 | mov eax, [timer_ticks] |
881 | invoke GetTimerTicks |
849 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
882 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
850 | lock bts [esi+usb_controller.NewConnected], ecx |
883 | lock bts [esi+usb_controller.NewConnected], ecx |
851 | jmp .nextport |
884 | jmp .nextport |
852 | .disconnect: |
885 | .disconnect: |
853 | lock btr [esi+usb_controller.NewConnected], ecx |
886 | lock btr [esi+usb_controller.NewConnected], ecx |
Line 856... | Line 889... | ||
856 | ; 11f. Process 'reset done' events. |
889 | ; 11f. Process 'reset done' events. |
857 | test eax, 100000h |
890 | test eax, 100000h |
858 | jz .nextport |
891 | jz .nextport |
859 | test al, 10h |
892 | test al, 10h |
860 | jnz .nextport |
893 | jnz .nextport |
861 | mov edx, [timer_ticks] |
894 | invoke GetTimerTicks |
862 | mov [esi+usb_controller.ResetTime], edx |
895 | mov [esi+usb_controller.ResetTime], eax |
863 | mov [esi+usb_controller.ResettingStatus], 2 |
896 | mov [esi+usb_controller.ResettingStatus], 2 |
864 | inc ebx |
897 | inc ebx |
865 | .nextport: |
898 | .nextport: |
866 | ; 11g. Continue the loop for the next port. |
899 | ; 11g. Continue the loop for the next port. |
867 | inc ecx |
900 | inc ecx |
Line 869... | Line 902... | ||
869 | jb .portloop |
902 | jb .portloop |
870 | .skip_roothub: |
903 | .skip_roothub: |
871 | ; 12. Restore the stack after step 6. |
904 | ; 12. Restore the stack after step 6. |
872 | pop eax |
905 | pop eax |
873 | ; 13. Notify the USB thread if some deferred processing is required. |
906 | ; 13. Notify the USB thread if some deferred processing is required. |
874 | call usb_wakeup_if_needed |
907 | invoke usbhc_api.usb_wakeup_if_needed |
875 | ; 14. Interrupt processed; return something non-zero. |
908 | ; 14. Interrupt processed; return something non-zero. |
876 | mov al, 1 |
909 | mov al, 1 |
877 | pop edi esi ebx ; restore used registers to be stdcall |
910 | pop edi esi ebx ; restore used registers to be stdcall |
878 | ret |
911 | ret |
879 | endp |
912 | endp |
Line 882... | Line 915... | ||
882 | ; and stores USB device address in the ohci_pipe structure. |
915 | ; and stores USB device address in the ohci_pipe structure. |
883 | ; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
916 | ; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
884 | proc ohci_set_device_address |
917 | proc ohci_set_device_address |
885 | mov byte [ebx+ohci_pipe.Flags-sizeof.ohci_pipe], cl |
918 | mov byte [ebx+ohci_pipe.Flags-sizeof.ohci_pipe], cl |
886 | ; Wait until the hardware will forget the old value. |
919 | ; Wait until the hardware will forget the old value. |
887 | call usb_subscribe_control |
920 | jmp [usbhc_api.usb_subscribe_control] |
888 | ret |
- | |
889 | endp |
921 | endp |
Line 890... | Line 922... | ||
890 | 922 | ||
891 | ; This procedure returns USB device address from the usb_pipe structure. |
923 | ; This procedure returns USB device address from the usb_pipe structure. |
892 | ; in: esi -> usb_controller, ebx -> usb_pipe |
924 | ; in: esi -> usb_controller, ebx -> usb_pipe |
Line 912... | Line 944... | ||
912 | ; stores the packet size in ohci_pipe structure. |
944 | ; stores the packet size in ohci_pipe structure. |
913 | ; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
945 | ; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
914 | proc ohci_set_endpoint_packet_size |
946 | proc ohci_set_endpoint_packet_size |
915 | mov byte [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe], cl |
947 | mov byte [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe], cl |
916 | ; Wait until the hardware will forget the old value. |
948 | ; Wait until the hardware will forget the old value. |
917 | call usb_subscribe_control |
949 | jmp [usbhc_api.usb_subscribe_control] |
918 | ret |
- | |
919 | endp |
950 | endp |
Line 920... | Line 951... | ||
920 | 951 | ||
921 | ; This procedure is called from API usb_open_pipe and processes |
952 | ; This procedure is called from API usb_open_pipe and processes |
922 | ; the controller-specific part of this API. See docs. |
953 | ; the controller-specific part of this API. See docs. |
Line 936... | Line 967... | ||
936 | .type dd ? |
967 | .type dd ? |
937 | .interval dd ? |
968 | .interval dd ? |
938 | end virtual |
969 | end virtual |
939 | ; 1. Initialize the queue of transfer descriptors: empty. |
970 | ; 1. Initialize the queue of transfer descriptors: empty. |
940 | sub eax, sizeof.ohci_gtd |
971 | sub eax, sizeof.ohci_gtd |
941 | call get_phys_addr |
972 | invoke GetPhysAddr |
942 | mov [edi+ohci_pipe.TailP-sizeof.ohci_pipe], eax |
973 | mov [edi+ohci_pipe.TailP-sizeof.ohci_pipe], eax |
943 | mov [edi+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
974 | mov [edi+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
944 | ; 2. Generate ohci_pipe.Flags, see the description in ohci_pipe. |
975 | ; 2. Generate ohci_pipe.Flags, see the description in ohci_pipe. |
945 | mov eax, [ecx+ohci_pipe.Flags-sizeof.ohci_pipe] |
976 | mov eax, [ecx+ohci_pipe.Flags-sizeof.ohci_pipe] |
946 | and eax, 0x207F ; keep Speed bit and FunctionAddress |
977 | and eax, 0x207F ; keep Speed bit and FunctionAddress |
Line 989... | Line 1020... | ||
989 | mov [ecx+usb_pipe.PrevVirt], edi |
1020 | mov [ecx+usb_pipe.PrevVirt], edi |
990 | mov [edx+usb_pipe.NextVirt], edi |
1021 | mov [edx+usb_pipe.NextVirt], edi |
991 | mov ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe] |
1022 | mov ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe] |
992 | mov [edi+ohci_pipe.NextED-sizeof.ohci_pipe], ecx |
1023 | mov [edi+ohci_pipe.NextED-sizeof.ohci_pipe], ecx |
993 | lea eax, [edi-sizeof.ohci_pipe] |
1024 | lea eax, [edi-sizeof.ohci_pipe] |
994 | call get_phys_addr |
1025 | invoke GetPhysAddr |
995 | mov [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax |
1026 | mov [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax |
996 | ; 4. Return something non-zero. |
1027 | ; 4. Return something non-zero. |
997 | ret |
1028 | ret |
998 | .return0: |
1029 | .return0: |
999 | xor eax, eax |
1030 | xor eax, eax |
Line 1112... | Line 1143... | ||
1112 | @@: |
1143 | @@: |
1113 | ret |
1144 | ret |
1114 | .fail: |
1145 | .fail: |
1115 | mov edi, ohci_hardware_func |
1146 | mov edi, ohci_hardware_func |
1116 | mov eax, [td] |
1147 | mov eax, [td] |
1117 | stdcall usb_undo_tds, [origTD] |
1148 | invoke usbhc_api.usb_undo_tds, [origTD] |
1118 | xor eax, eax |
1149 | xor eax, eax |
1119 | ret |
1150 | ret |
1120 | endp |
1151 | endp |
Line 1121... | Line 1152... | ||
1121 | 1152 | ||
Line 1135... | Line 1166... | ||
1135 | .Flags dd ? |
1166 | .Flags dd ? |
1136 | .td dd ? |
1167 | .td dd ? |
1137 | .direction dd ? |
1168 | .direction dd ? |
1138 | end virtual |
1169 | end virtual |
1139 | ; 1. Allocate the next TD. |
1170 | ; 1. Allocate the next TD. |
1140 | call usb1_allocate_general_td |
1171 | call ohci_alloc_gtd |
1141 | test eax, eax |
1172 | test eax, eax |
1142 | jz .nothing |
1173 | jz .nothing |
1143 | ; 2. Initialize controller-independent parts of both TDs. |
1174 | ; 2. Initialize controller-independent parts of both TDs. |
1144 | push eax |
1175 | push eax |
1145 | call usb_init_transfer |
1176 | invoke usbhc_api.usb_init_transfer |
1146 | pop eax |
1177 | pop eax |
1147 | ; 3. Save the returned value (next descriptor). |
1178 | ; 3. Save the returned value (next descriptor). |
1148 | push eax |
1179 | push eax |
1149 | ; 4. Store the physical address of the next descriptor. |
1180 | ; 4. Store the physical address of the next descriptor. |
1150 | sub eax, sizeof.ohci_gtd |
1181 | sub eax, sizeof.ohci_gtd |
1151 | call get_phys_addr |
1182 | invoke GetPhysAddr |
1152 | mov [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd], eax |
1183 | mov [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd], eax |
1153 | ; 5. For zero-length transfers, store zero in both fields for buffer addresses. |
1184 | ; 5. For zero-length transfers, store zero in both fields for buffer addresses. |
1154 | ; Otherwise, fill them with real values. |
1185 | ; Otherwise, fill them with real values. |
1155 | xor eax, eax |
1186 | xor eax, eax |
1156 | mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
1187 | mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
1157 | mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
1188 | mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
1158 | cmp [.packetSize], eax |
1189 | cmp [.packetSize], eax |
1159 | jz @f |
1190 | jz @f |
1160 | mov eax, [.buffer] |
1191 | mov eax, [.buffer] |
1161 | call get_phys_addr |
1192 | invoke GetPhysAddr |
1162 | mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
1193 | mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
1163 | mov eax, [.buffer] |
1194 | mov eax, [.buffer] |
1164 | add eax, [.packetSize] |
1195 | add eax, [.packetSize] |
1165 | dec eax |
1196 | dec eax |
1166 | call get_phys_addr |
1197 | invoke GetPhysAddr |
1167 | mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
1198 | mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
1168 | @@: |
1199 | @@: |
1169 | ; 6. Generate Flags field: |
1200 | ; 6. Generate Flags field: |
1170 | ; - set bufferRounding (bit 18) to zero = disallow short transfers; |
1201 | ; - set bufferRounding (bit 18) to zero = disallow short transfers; |
1171 | ; for the last transfer in a row, ohci_alloc_transfer would set the real value; |
1202 | ; for the last transfer in a row, ohci_alloc_transfer would set the real value; |
Line 1223... | Line 1254... | ||
1223 | ; If reset has been failed (device disconnected during reset), |
1254 | ; If reset has been failed (device disconnected during reset), |
1224 | ; continue to next device (if there is one). |
1255 | ; continue to next device (if there is one). |
1225 | xor eax, eax |
1256 | xor eax, eax |
1226 | xchg al, [esi+usb_controller.ResettingStatus] |
1257 | xchg al, [esi+usb_controller.ResettingStatus] |
1227 | test al, al |
1258 | test al, al |
- | 1259 | jns @f |
|
1228 | js usb_test_pending_port |
1260 | jmp [usbhc_api.usb_test_pending_port] |
- | 1261 | @@: |
|
1229 | ; If the controller has disabled the port (e.g. overcurrent), |
1262 | ; If the controller has disabled the port (e.g. overcurrent), |
1230 | ; continue to next device (if there is one). |
1263 | ; continue to next device (if there is one). |
1231 | movzx ecx, [esi+usb_controller.ResettingPort] |
1264 | movzx ecx, [esi+usb_controller.ResettingPort] |
1232 | mov eax, [edi+OhciRhPortStatusReg+ecx*4] |
1265 | mov eax, [edi+OhciRhPortStatusReg+ecx*4] |
1233 | test al, 2 |
1266 | test al, 2 |
1234 | jnz @f |
1267 | jnz @f |
1235 | DEBUGF 1,'K : USB port disabled after reset, status=%x\n',eax |
1268 | DEBUGF 1,'K : USB port disabled after reset, status=%x\n',eax |
1236 | jmp usb_test_pending_port |
1269 | jmp [usbhc_api.usb_test_pending_port] |
1237 | @@: |
1270 | @@: |
1238 | push ecx |
1271 | push ecx |
1239 | ; 2. Get LowSpeed bit to bit 0 of eax and call the worker procedure |
1272 | ; 2. Get LowSpeed bit to bit 0 of eax and call the worker procedure |
1240 | ; to notify the protocol layer about new OHCI device. |
1273 | ; to notify the protocol layer about new OHCI device. |
1241 | mov eax, [edi+OhciRhPortStatusReg+ecx*4] |
1274 | mov eax, [edi+OhciRhPortStatusReg+ecx*4] |
1242 | DEBUGF 1,'K : port_after_reset [%d] status of port %d is %x\n',[timer_ticks],ecx,eax |
1275 | DEBUGF 1,'K : port_after_reset, status of port %d is %x\n',ecx,eax |
1243 | shr eax, 9 |
1276 | shr eax, 9 |
1244 | call ohci_new_device |
1277 | call ohci_new_device |
1245 | pop ecx |
1278 | pop ecx |
1246 | ; 3. If something at the protocol layer has failed |
1279 | ; 3. If something at the protocol layer has failed |
1247 | ; (no memory, no bus address), disable the port and stop the initialization. |
1280 | ; (no memory, no bus address), disable the port and stop the initialization. |
1248 | test eax, eax |
1281 | test eax, eax |
1249 | jnz .nothing |
1282 | jnz .nothing |
1250 | .disable_exit: |
1283 | .disable_exit: |
1251 | mov dword [edi+OhciRhPortStatusReg+ecx*4], 1 |
1284 | mov dword [edi+OhciRhPortStatusReg+ecx*4], 1 |
1252 | jmp usb_test_pending_port |
1285 | jmp [usbhc_api.usb_test_pending_port] |
1253 | .nothing: |
1286 | .nothing: |
1254 | ret |
1287 | ret |
1255 | endp |
1288 | endp |
Line 1256... | Line 1289... | ||
1256 | 1289 | ||
Line 1270... | Line 1303... | ||
1270 | push esi ; .Controller |
1303 | push esi ; .Controller |
1271 | mov ecx, esp |
1304 | mov ecx, esp |
1272 | sub esp, 12 ; ignored fields |
1305 | sub esp, 12 ; ignored fields |
1273 | push eax ; .Flags |
1306 | push eax ; .Flags |
1274 | ; 4. Notify the protocol layer. |
1307 | ; 4. Notify the protocol layer. |
1275 | call usb_new_device |
1308 | invoke usbhc_api.usb_new_device |
1276 | ; 5. Cleanup the stack after step 3 and return. |
1309 | ; 5. Cleanup the stack after step 3 and return. |
1277 | add esp, 20 |
1310 | add esp, 20 |
1278 | ret |
1311 | ret |
1279 | endp |
1312 | endp |
Line 1285... | Line 1318... | ||
1285 | proc ohci_process_deferred |
1318 | proc ohci_process_deferred |
1286 | push ebx edi ; save used registers to be stdcall |
1319 | push ebx edi ; save used registers to be stdcall |
1287 | ; 1. Initialize the return value. |
1320 | ; 1. Initialize the return value. |
1288 | push -1 |
1321 | push -1 |
1289 | ; 2. Process disconnect events. |
1322 | ; 2. Process disconnect events. |
1290 | call usb_disconnect_stage2 |
1323 | invoke usbhc_api.usb_disconnect_stage2 |
1291 | ; 3. Check for connected devices. |
1324 | ; 3. Check for connected devices. |
1292 | ; If there is a connected device which was connected less than |
1325 | ; If there is a connected device which was connected less than |
1293 | ; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over. |
1326 | ; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over. |
1294 | ; Otherwise, call ohci_new_port. |
1327 | ; Otherwise, call ohci_new_port. |
1295 | mov edi, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller] |
1328 | mov edi, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller] |
Line 1297... | Line 1330... | ||
1297 | cmp [esi+usb_controller.NewConnected], ecx |
1330 | cmp [esi+usb_controller.NewConnected], ecx |
1298 | jz .skip_newconnected |
1331 | jz .skip_newconnected |
1299 | .portloop: |
1332 | .portloop: |
1300 | bt [esi+usb_controller.NewConnected], ecx |
1333 | bt [esi+usb_controller.NewConnected], ecx |
1301 | jnc .noconnect |
1334 | jnc .noconnect |
- | 1335 | ; If this port is shared with the EHCI companion and we see the connect event, |
|
- | 1336 | ; then the device is USB1 dropped by EHCI, |
|
- | 1337 | ; so EHCI has already waited for debounce delay, we can proceed immediately. |
|
- | 1338 | cmp [esi+ohci_controller.EhciCompanion-sizeof.ohci_controller], 0 |
|
- | 1339 | jz .portloop.test_time |
|
- | 1340 | dbgstr 'port is shared with EHCI, skipping initial debounce' |
|
- | 1341 | jmp .connected |
|
- | 1342 | .portloop.test_time: |
|
1302 | mov eax, [timer_ticks] |
1343 | invoke GetTimerTicks |
1303 | sub eax, [esi+usb_controller.ConnectedTime+ecx*4] |
1344 | sub eax, [esi+usb_controller.ConnectedTime+ecx*4] |
1304 | sub eax, USB_CONNECT_DELAY |
1345 | sub eax, USB_CONNECT_DELAY |
1305 | jge .connected |
1346 | jge .connected |
1306 | neg eax |
1347 | neg eax |
1307 | cmp [esp], eax |
1348 | cmp [esp], eax |
Line 1319... | Line 1360... | ||
1319 | jb .portloop |
1360 | jb .portloop |
1320 | .skip_newconnected: |
1361 | .skip_newconnected: |
1321 | ; 4. Check for end of reset signalling. If so, call ohci_port_after_reset. |
1362 | ; 4. Check for end of reset signalling. If so, call ohci_port_after_reset. |
1322 | cmp [esi+usb_controller.ResettingStatus], 2 |
1363 | cmp [esi+usb_controller.ResettingStatus], 2 |
1323 | jnz .no_reset_recovery |
1364 | jnz .no_reset_recovery |
1324 | mov eax, [timer_ticks] |
1365 | invoke GetTimerTicks |
1325 | sub eax, [esi+usb_controller.ResetTime] |
1366 | sub eax, [esi+usb_controller.ResetTime] |
1326 | sub eax, USB_RESET_RECOVERY_TIME |
1367 | sub eax, USB_RESET_RECOVERY_TIME |
1327 | jge .reset_done |
1368 | jge .reset_done |
1328 | neg eax |
1369 | neg eax |
1329 | cmp [esp], eax |
1370 | cmp [esp], eax |
Line 1351... | Line 1392... | ||
1351 | jmp .tdloop |
1392 | jmp .tdloop |
1352 | .tddone: |
1393 | .tddone: |
1353 | ; 6. Process wait-done notifications, test for new wait requests. |
1394 | ; 6. Process wait-done notifications, test for new wait requests. |
1354 | ; Note: that must be done after steps 2 and 5 which could create new requests. |
1395 | ; Note: that must be done after steps 2 and 5 which could create new requests. |
1355 | ; 6a. Call the worker function from main USB code. |
1396 | ; 6a. Call the worker function from main USB code. |
1356 | call usb_process_wait_lists |
1397 | invoke usbhc_api.usb_process_wait_lists |
1357 | ; 6b. If no new requests, skip the rest of this step. |
1398 | ; 6b. If no new requests, skip the rest of this step. |
1358 | test eax, eax |
1399 | test eax, eax |
1359 | jz @f |
1400 | jz @f |
1360 | ; 6c. OHCI is not allowed to cache anything; we don't know what is |
1401 | ; 6c. OHCI is not allowed to cache anything; we don't know what is |
1361 | ; processed right now, but we can be sure that the controller will not |
1402 | ; processed right now, but we can be sure that the controller will not |
Line 1400... | Line 1441... | ||
1400 | lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
1441 | lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
1401 | xor ebx, ebx |
1442 | xor ebx, ebx |
1402 | jmp .next_td2 |
1443 | jmp .next_td2 |
1403 | @@: |
1444 | @@: |
1404 | ; 2. Remove the descriptor from the descriptors queue. |
1445 | ; 2. Remove the descriptor from the descriptors queue. |
1405 | call usb_unlink_td |
1446 | invoke usbhc_api.usb_unlink_td |
1406 | ; 3. Get number of bytes that remain to be transferred. |
1447 | ; 3. Get number of bytes that remain to be transferred. |
1407 | ; If CurBufPtr is zero, everything was transferred. |
1448 | ; If CurBufPtr is zero, everything was transferred. |
1408 | xor edx, edx |
1449 | xor edx, edx |
1409 | cmp [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], edx |
1450 | cmp [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], edx |
1410 | jz .gotlen |
1451 | jz .gotlen |
Line 1427... | Line 1468... | ||
1427 | ; The actual length is Length - (remaining length). |
1468 | ; The actual length is Length - (remaining length). |
1428 | sub edx, [ebx+usb_gtd.Length] |
1469 | sub edx, [ebx+usb_gtd.Length] |
1429 | neg edx |
1470 | neg edx |
1430 | ; 4. Check for error. If so, go to 7. |
1471 | ; 4. Check for error. If so, go to 7. |
1431 | push ebx |
1472 | push ebx |
1432 | mov eax, [ebx+ohci_gtd.Flags-sizeof.ohci_gtd] |
1473 | mov ecx, [ebx+ohci_gtd.Flags-sizeof.ohci_gtd] |
1433 | shr eax, 28 |
1474 | shr ecx, 28 |
1434 | jnz .error |
1475 | jnz .error |
1435 | .notify: |
1476 | .notify: |
1436 | ; 5. Successful completion. |
1477 | ; 5. Successful completion. |
1437 | ; 5a. Check whether this descriptor has an associated callback. |
- | |
1438 | mov ecx, [ebx+usb_gtd.Callback] |
- | |
1439 | test ecx, ecx |
- | |
1440 | jz .ok_nocallback |
- | |
1441 | ; 5b. If so, call the callback. |
- | |
1442 | stdcall_verify ecx, [ebx+usb_gtd.Pipe], eax, \ |
- | |
1443 | [ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData] |
- | |
1444 | jmp .next_td |
- | |
1445 | .ok_nocallback: |
- | |
1446 | ; 5c. Otherwise, add length of the current descriptor to the next descriptor. |
- | |
1447 | mov eax, [ebx+usb_gtd.NextVirt] |
1478 | invoke usbhc_api.usb_process_gtd |
1448 | add [eax+usb_gtd.Length], edx |
- | |
1449 | .next_td: |
1479 | .next_td: |
1450 | ; 6. Free the current descriptor and advance to the next item. |
1480 | ; 6. Free the current descriptor and advance to the next item. |
1451 | ; If the current item is the last in the list, |
1481 | ; If the current item is the last in the list, |
1452 | ; set DoneListEndPtr to pointer to DoneList. |
1482 | ; set DoneListEndPtr to pointer to DoneList. |
1453 | cmp ebx, [esp] |
1483 | cmp ebx, [esp] |
1454 | jz @f |
1484 | jz @f |
1455 | stdcall usb1_free_general_td, ebx |
1485 | stdcall ohci_free_gtd, ebx |
1456 | @@: |
1486 | @@: |
1457 | pop ebx |
1487 | pop ebx |
1458 | lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
1488 | lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
1459 | .next_td2: |
1489 | .next_td2: |
1460 | push ebx |
1490 | push ebx |
Line 1475... | Line 1505... | ||
1475 | ; ecx = the next item |
1505 | ; ecx = the next item |
1476 | push ecx |
1506 | push ecx |
1477 | ; Free the current item, set ebx to the next item, continue to 5a. |
1507 | ; Free the current item, set ebx to the next item, continue to 5a. |
1478 | test ebx, ebx |
1508 | test ebx, ebx |
1479 | jz @f |
1509 | jz @f |
1480 | stdcall usb1_free_general_td, ebx |
1510 | stdcall ohci_free_gtd, ebx |
1481 | @@: |
1511 | @@: |
1482 | pop ebx |
1512 | pop ebx |
1483 | ret |
1513 | ret |
1484 | .error: |
1514 | .error: |
1485 | ; 7. There was an error while processing this descriptor. |
1515 | ; 7. There was an error while processing this descriptor. |
1486 | ; The hardware has stopped processing the queue. |
1516 | ; The hardware has stopped processing the queue. |
1487 | ; 7a. Save status and length. |
1517 | ; 7a. Save status and length. |
1488 | push eax |
1518 | push ecx |
1489 | push edx |
1519 | push edx |
1490 | ; DEBUGF 1,'K : TD failed:\n' |
1520 | ; DEBUGF 1,'K : TD failed:\n' |
1491 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd],[ebx-sizeof.ohci_gtd+4],[ebx-sizeof.ohci_gtd+8],[ebx-sizeof.ohci_gtd+12] |
1521 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd],[ebx-sizeof.ohci_gtd+4],[ebx-sizeof.ohci_gtd+8],[ebx-sizeof.ohci_gtd+12] |
1492 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd+16],[ebx-sizeof.ohci_gtd+20],[ebx-sizeof.ohci_gtd+24],[ebx-sizeof.ohci_gtd+28] |
1522 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd+16],[ebx-sizeof.ohci_gtd+20],[ebx-sizeof.ohci_gtd+24],[ebx-sizeof.ohci_gtd+28] |
1493 | ; mov eax, [ebx+usb_gtd.Pipe] |
1523 | ; mov eax, [ebx+usb_gtd.Pipe] |
1494 | ; DEBUGF 1,'K : pipe: %x %x %x %x\n',[eax-sizeof.ohci_pipe],[eax-sizeof.ohci_pipe+4],[eax-sizeof.ohci_pipe+8],[eax-sizeof.ohci_pipe+12] |
1524 | ; DEBUGF 1,'K : pipe: %x %x %x %x\n',[eax-sizeof.ohci_pipe],[eax-sizeof.ohci_pipe+4],[eax-sizeof.ohci_pipe+8],[eax-sizeof.ohci_pipe+12] |
1495 | ; 7b. Traverse the list of descriptors looking for the final packet |
1525 | ; 7b. Traverse the list of descriptors looking for the final packet |
1496 | ; for this transfer. |
1526 | ; for this transfer. |
1497 | ; Free and unlink non-final descriptors, except the current one. |
1527 | ; Free and unlink non-final descriptors, except the current one. |
1498 | ; Final descriptor will be freed in step 6. |
1528 | ; Final descriptor will be freed in step 6. |
1499 | call usb_is_final_packet |
1529 | invoke usbhc_api.usb_is_final_packet |
1500 | jnc .found_final |
1530 | jnc .found_final |
1501 | mov ebx, [ebx+usb_gtd.NextVirt] |
1531 | mov ebx, [ebx+usb_gtd.NextVirt] |
1502 | virtual at esp |
1532 | virtual at esp |
1503 | .length dd ? |
1533 | .length dd ? |
1504 | .error_code dd ? |
1534 | .error_code dd ? |
1505 | .current_item dd ? |
1535 | .current_item dd ? |
1506 | end virtual |
1536 | end virtual |
1507 | .look_final: |
1537 | .look_final: |
1508 | call usb_unlink_td |
1538 | invoke usbhc_api.usb_unlink_td |
1509 | call usb_is_final_packet |
1539 | invoke usbhc_api.usb_is_final_packet |
1510 | jnc .found_final |
1540 | jnc .found_final |
1511 | push [ebx+usb_gtd.NextVirt] |
1541 | push [ebx+usb_gtd.NextVirt] |
1512 | stdcall usb1_free_general_td, ebx |
1542 | stdcall ohci_free_gtd, ebx |
1513 | pop ebx |
1543 | pop ebx |
1514 | jmp .look_final |
1544 | jmp .look_final |
1515 | .found_final: |
1545 | .found_final: |
1516 | ; 7c. If error code is USB_STATUS_UNDERRUN and the last TD allows short packets, |
1546 | ; 7c. If error code is USB_STATUS_UNDERRUN and the last TD allows short packets, |
1517 | ; it is not an error. |
1547 | ; it is not an error. |
Line 1528... | Line 1558... | ||
1528 | mov edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe] |
1558 | mov edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe] |
1529 | and edx, 2 |
1559 | and edx, 2 |
1530 | .advance_queue: |
1560 | .advance_queue: |
1531 | mov eax, [ebx+usb_gtd.NextVirt] |
1561 | mov eax, [ebx+usb_gtd.NextVirt] |
1532 | sub eax, sizeof.ohci_gtd |
1562 | sub eax, sizeof.ohci_gtd |
1533 | call get_phys_addr |
1563 | invoke GetPhysAddr |
1534 | or eax, edx |
1564 | or eax, edx |
1535 | mov [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
1565 | mov [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
1536 | push ebx |
1566 | push ebx |
1537 | mov ebx, ecx |
1567 | mov ebx, ecx |
1538 | call ohci_notify_new_work |
1568 | call ohci_notify_new_work |
1539 | pop ebx |
1569 | pop ebx |
1540 | pop edx eax |
1570 | pop edx ecx |
1541 | jmp .notify |
1571 | jmp .notify |
1542 | ; 7d. Abort the entire transfer. |
1572 | ; 7d. Abort the entire transfer. |
1543 | ; There are two cases: either there is only one transfer stage |
1573 | ; There are two cases: either there is only one transfer stage |
1544 | ; (everything except control transfers), then ebx points to the last TD and |
1574 | ; (everything except control transfers), then ebx points to the last TD and |
1545 | ; all previous TD were unlinked and dismissed (if possible), |
1575 | ; all previous TD were unlinked and dismissed (if possible), |
Line 1551... | Line 1581... | ||
1551 | cmp [ebx+usb_gtd.Callback], 0 |
1581 | cmp [ebx+usb_gtd.Callback], 0 |
1552 | jnz .halted |
1582 | jnz .halted |
1553 | cmp ebx, [.current_item] |
1583 | cmp ebx, [.current_item] |
1554 | push [ebx+usb_gtd.NextVirt] |
1584 | push [ebx+usb_gtd.NextVirt] |
1555 | jz @f |
1585 | jz @f |
1556 | stdcall usb1_free_general_td, ebx |
1586 | stdcall ohci_free_gtd, ebx |
1557 | @@: |
1587 | @@: |
1558 | pop ebx |
1588 | pop ebx |
1559 | call usb_unlink_td |
1589 | invoke usbhc_api.usb_unlink_td |
1560 | .halted: |
1590 | .halted: |
1561 | ; 7e. For bulk/interrupt transfers we have no choice but halt the queue, |
1591 | ; 7e. For bulk/interrupt transfers we have no choice but halt the queue, |
1562 | ; the driver should intercede (through some API which is not written yet). |
1592 | ; the driver should intercede (through some API which is not written yet). |
1563 | ; Control pipes normally recover at the next SETUP transaction (first stage |
1593 | ; Control pipes normally recover at the next SETUP transaction (first stage |
1564 | ; of any control transfer), so we hope on the best and just advance the queue |
1594 | ; of any control transfer), so we hope on the best and just advance the queue |
Line 1595... | Line 1625... | ||
1595 | mov [eax+usb_pipe.NextVirt], edx |
1625 | mov [eax+usb_pipe.NextVirt], edx |
1596 | mov edx, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe] |
1626 | mov edx, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe] |
1597 | mov [eax+ohci_pipe.NextED-sizeof.ohci_pipe], edx |
1627 | mov [eax+ohci_pipe.NextED-sizeof.ohci_pipe], edx |
1598 | ret |
1628 | ret |
1599 | endp>=>> |
1629 | endp |
- | 1630 | ||
- | 1631 | ; Allocates one endpoint structure for OHCI. |
|
- | 1632 | ; Returns pointer to software part (usb_pipe) in eax. |
|
- | 1633 | proc ohci_alloc_pipe |
|
- | 1634 | push ebx |
|
- | 1635 | mov ebx, ohci_ep_mutex |
|
- | 1636 | invoke usbhc_api.usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh |
|
- | 1637 | test eax, eax |
|
- | 1638 | jz @f |
|
- | 1639 | add eax, sizeof.ohci_pipe |
|
- | 1640 | @@: |
|
- | 1641 | pop ebx |
|
- | 1642 | ret |
|
- | 1643 | endp |
|
- | 1644 | ||
- | 1645 | ; Free one endpoint structure for OHCI. |
|
- | 1646 | ; Stdcall with one argument, pointer to software part (usb_pipe). |
|
- | 1647 | proc ohci_free_pipe |
|
- | 1648 | sub dword [esp+4], sizeof.ohci_pipe |
|
- | 1649 | jmp [usbhc_api.usb_free_common] |
|
- | 1650 | endp |
|
- | 1651 | ||
- | 1652 | ; Allocates one general transfer descriptor structure for OHCI. |
|
- | 1653 | ; Returns pointer to software part (usb_gtd) in eax. |
|
- | 1654 | proc ohci_alloc_gtd |
|
- | 1655 | push ebx |
|
- | 1656 | mov ebx, ohci_gtd_mutex |
|
- | 1657 | invoke usbhc_api.usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh |
|
- | 1658 | test eax, eax |
|
- | 1659 | jz @f |
|
- | 1660 | add eax, sizeof.ohci_gtd |
|
- | 1661 | @@: |
|
- | 1662 | pop ebx |
|
- | 1663 | ret |
|
- | 1664 | endp |
|
- | 1665 | ||
- | 1666 | ; Free one general transfer descriptor structure for OHCI. |
|
- | 1667 | ; Stdcall with one argument, pointer to software part (usb_gtd). |
|
- | 1668 | proc ohci_free_gtd |
|
- | 1669 | sub dword [esp+4], sizeof.ohci_gtd |
|
- | 1670 | jmp [usbhc_api.usb_free_common] |
|
- | 1671 | endp |
|
- | 1672 | ||
- | 1673 | include 'usb1_scheduler.inc' |
|
- | 1674 | define_controller_name ohci |
|
- | 1675 | ||
- | 1676 | section '.data' readable writable |
|
- | 1677 | include '../peimport.inc' |
|
- | 1678 | include_debug_strings |
|
- | 1679 | IncludeIGlobals |
|
- | 1680 | IncludeUGlobals |
|
- | 1681 | align 4 |
|
- | 1682 | usbhc_api usbhc_func |
|
- | 1683 | ohci_ep_first_page dd ? |
|
- | 1684 | ohci_ep_mutex MUTEX |
|
- | 1685 | ohci_gtd_first_page dd ? |
|
- | 1686 | ohci_gtd_mutex MUTEX>=>> |