/drivers/usb/ehci.asm |
---|
156,8 → 156,6 |
; Working area for the current TD, if there is any. |
; When TD is retired, it is written to that TD and Overlay is loaded |
; from the new TD, if any. |
BaseList dd ? |
; Pointer to head of the corresponding pipe list. |
ends |
; This structure describes the static head of every list of pipes. |
293,6 → 291,8 |
dd ehci_alloc_transfer |
dd ehci_insert_transfer |
dd ehci_new_device |
dd ehci_disable_pipe |
dd ehci_enable_pipe |
ehci_name db 'EHCI',0 |
endg |
998,7 → 998,7 |
jz .return0 |
mov word [edi+ehci_pipe.Flags-sizeof.ehci_pipe], ax |
.insert: |
mov [edi+ehci_pipe.BaseList-sizeof.ehci_pipe], edx |
mov [edi+usb_pipe.BaseList], edx |
; Insert to the head of the corresponding list. |
; Note: inserting to the head guarantees that the list traverse in |
; ehci_process_updated_schedule, once started, will not interact with new pipes. |
1912,22 → 1912,61 |
call ehci_fs_interrupt_list_unlink |
.interrupt_common: |
@@: |
mov edx, [ebx+usb_pipe.NextVirt] |
mov eax, [ebx+usb_pipe.PrevVirt] |
mov [edx+usb_pipe.PrevVirt], eax |
mov [eax+usb_pipe.NextVirt], edx |
ret |
endp |
; This procedure temporarily removes the given pipe from hardware queue. |
; esi -> usb_controller, ebx -> usb_pipe |
proc ehci_disable_pipe |
mov eax, [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe] |
mov ecx, [ebx+usb_pipe.PrevVirt] |
mov edx, esi |
sub edx, eax |
sub edx, ecx |
cmp edx, sizeof.ehci_controller |
mov edx, [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe] |
jb .prev_is_static |
mov [eax+ehci_pipe.NextQH-sizeof.ehci_pipe], edx |
mov [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax |
ret |
.prev_is_static: |
mov [eax+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], edx |
mov [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax |
ret |
endp |
; This procedure reinserts the given pipe to hardware queue |
; after ehci_disable_pipe, with clearing transfer queue. |
; esi -> usb_controller, ebx -> usb_pipe |
; edx -> current descriptor, eax -> new last descriptor |
proc ehci_enable_pipe |
; 1. Clear transfer queue. |
; 1a. Clear status bits so that the controller will try to advance the queue |
; without doing anything, keep DataToggle and PID bits. |
and [ebx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 80000000h |
; 1b. Set [Alternate]NextTD to physical address of the new last descriptor. |
sub eax, sizeof.ehci_gtd |
invoke GetPhysAddr |
mov [ebx+ehci_pipe.HeadTD-sizeof.ehci_pipe], eax |
mov [ebx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax |
mov [ebx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax |
; 2. Reinsert the pipe to hardware queue. |
lea eax, [ebx-sizeof.ehci_pipe] |
invoke GetPhysAddr |
inc eax |
inc eax |
mov ecx, [ebx+usb_pipe.PrevVirt] |
mov edx, esi |
sub edx, ecx |
cmp edx, sizeof.ehci_controller |
jb .prev_is_static |
mov edx, [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe] |
mov [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx |
mov [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax |
ret |
.prev_is_static: |
mov edx, [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart] |
mov [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx |
mov [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax |
ret |
endp |
proc ehci_alloc_td |
push ebx |
mov ebx, ehci_gtd_mutex |
/drivers/usb/ehci_scheduler.inc |
---|
298,7 → 298,7 |
imul eax, ecx |
movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
; get target list |
mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
mov edx, [ebx+usb_pipe.BaseList] |
; update bandwidth |
.dec_bandwidth: |
shr ecx, 1 |
732,7 → 732,7 |
mov edi, esp |
call tt_fill_split_info |
; get target list |
mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
mov edx, [ebx+usb_pipe.BaseList] |
; update bandwidth for Start-Split |
mov eax, [edi+usb_split_info.ssplit_bandwidth] |
xor ecx, ecx |
/drivers/usb/ohci.asm |
---|
64,7 → 64,7 |
; 2. Next 4 bits (bits 7-10) are EndpointNumber. This is the USB address of |
; the endpoint within the function. |
; 3. Next 2 bits (bits 11-12) are Direction. This 2-bit field indicates the |
; direction of data flow: 1 = IN, 2 = OUT. If neither IN nor OUT is |
; direction of data flow: 1 = OUT, 2 = IN. If neither IN nor OUT is |
; specified, then the direction is determined from the PID field of the TD. |
; For CONTROL endpoints, the transfer direction is different |
; for different transfers, so the value of this field is 0 |
322,6 → 322,8 |
dd ohci_alloc_transfer |
dd ohci_insert_transfer |
dd ohci_new_device |
dd ohci_disable_pipe |
dd ohci_enable_pipe |
ohci_name db 'OHCI',0 |
endg |
1014,6 → 1016,7 |
; Inserting to tail would work as well, |
; but let's be consistent with other controllers. |
.insert: |
mov [edi+usb_pipe.BaseList], edx |
mov ecx, [edx+usb_pipe.NextVirt] |
mov [edi+usb_pipe.NextVirt], ecx |
mov [edi+usb_pipe.PrevVirt], edx |
1614,20 → 1617,44 |
mov eax, [ebx+ohci_pipe.Flags-sizeof.ohci_pipe] |
bt eax, 13 |
setc cl |
bt eax, 11 |
bt eax, 12 |
setc ch |
shr eax, 16 |
stdcall usb1_interrupt_list_unlink, eax, ecx |
@@: |
mov edx, [ebx+usb_pipe.NextVirt] |
mov eax, [ebx+usb_pipe.PrevVirt] |
mov [edx+usb_pipe.PrevVirt], eax |
mov [eax+usb_pipe.NextVirt], edx |
mov edx, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe] |
mov [eax+ohci_pipe.NextED-sizeof.ohci_pipe], edx |
ret |
endp |
; This procedure temporarily removes the given pipe from hardware queue, |
; keeping it in software lists. |
; esi -> usb_controller, ebx -> usb_pipe |
proc ohci_disable_pipe |
mov eax, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe] |
mov edx, [ebx+usb_pipe.PrevVirt] |
mov [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax |
ret |
endp |
; This procedure reinserts the given pipe from hardware queue |
; after ehci_disable_pipe, with clearing transfer queue. |
; esi -> usb_controller, ebx -> usb_pipe |
; edx -> current descriptor, eax -> new last descriptor |
proc ohci_enable_pipe |
sub eax, sizeof.ohci_gtd |
invoke GetPhysAddr |
mov edx, [ebx+ohci_pipe.HeadP-sizeof.ohci_pipe] |
and edx, 2 |
or eax, edx |
mov [ebx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
lea eax, [ebx-sizeof.ohci_pipe] |
invoke GetPhysAddr |
mov edx, [ebx+usb_pipe.PrevVirt] |
mov ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe] |
mov [ebx+ohci_pipe.NextED-sizeof.ohci_pipe], ecx |
mov [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax |
ret |
endp |
; Allocates one endpoint structure for OHCI. |
; Returns pointer to software part (usb_pipe) in eax. |
proc ohci_alloc_pipe |
/drivers/usb/uhci.asm |
---|
274,6 → 274,8 |
dd uhci_alloc_transfer |
dd uhci_insert_transfer |
dd uhci_new_device |
dd uhci_disable_pipe |
dd uhci_enable_pipe |
uhci_name db 'UHCI',0 |
endg |
1133,7 → 1135,6 |
jnz .loop |
; 5. Flip the toggle bit in uhci_pipe structure. |
xor byte [ecx+uhci_pipe.Token-sizeof.uhci_pipe-usb_pipe.Lock+2], 1 shl (19-16) |
or dword [ecx+uhci_pipe.Token-sizeof.uhci_pipe-usb_pipe.Lock], eax |
; 6. Unlock the transfer queue. |
invoke MutexUnlock |
.nothing: |
1461,6 → 1462,7 |
test edx, edx |
jz .return0 |
.insert: |
mov [edi+usb_pipe.BaseList], edx |
; Insert to the head of the corresponding list. |
; Note: inserting to the head guarantees that the list traverse in |
; uhci_process_updated_schedule, once started, will not interact with new pipes. |
1505,20 → 1507,47 |
shr eax, 21 |
stdcall usb1_interrupt_list_unlink, eax, ecx |
@@: |
; Note: we need to ensure that NextVirt field of the pipe is not modified; |
; this procedure can be called while uhci_process_updated_schedule processes |
; the same pipe, and it needs a correct NextVirt field to continue. |
mov edx, [ebx+usb_pipe.NextVirt] |
mov eax, [ebx+usb_pipe.PrevVirt] |
mov [edx+usb_pipe.PrevVirt], eax |
mov [eax+usb_pipe.NextVirt], edx |
; Note: eax could be either usb_pipe or usb_static_ep; |
ret |
endp |
; This procedure temporarily removes the given pipe from hardware queue, |
; keeping it in software lists. |
; esi -> usb_controller, ebx -> usb_pipe |
proc uhci_disable_pipe |
mov eax, [ebx+uhci_pipe.NextQH-sizeof.uhci_pipe] |
mov edx, [ebx+usb_pipe.PrevVirt] |
; Note: edx could be either usb_pipe or usb_static_ep; |
; fortunately, NextQH and SoftwarePart have same offsets in both. |
mov edx, [ebx+uhci_pipe.NextQH-sizeof.uhci_pipe] |
mov [eax+uhci_pipe.NextQH-sizeof.uhci_pipe], edx |
mov [edx+uhci_pipe.NextQH-sizeof.uhci_pipe], eax |
ret |
endp |
; This procedure reinserts the given pipe from hardware queue |
; after ehci_disable_pipe, with clearing transfer queue. |
; esi -> usb_controller, ebx -> usb_pipe |
; edx -> current descriptor, eax -> new last descriptor |
proc uhci_enable_pipe |
; 1. Copy DataToggle bit from edx to pipe. |
mov ecx, [edx+uhci_gtd.Token-sizeof.uhci_gtd] |
xor ecx, [ebx+uhci_pipe.Token-sizeof.uhci_pipe] |
and ecx, 1 shl 19 |
xor [ebx+uhci_pipe.Token-sizeof.uhci_pipe], ecx |
; 2. Store new last descriptor as the current HeadTD. |
sub eax, sizeof.uhci_gtd |
invoke GetPhysAddr |
mov [ebx+uhci_pipe.HeadTD-sizeof.uhci_pipe], eax |
; 3. Reinsert the pipe to hardware queue. |
lea eax, [ebx-sizeof.uhci_pipe] |
invoke GetPhysAddr |
inc eax |
inc eax |
mov edx, [ebx+usb_pipe.PrevVirt] |
mov ecx, [edx+uhci_pipe.NextQH-sizeof.uhci_pipe] |
mov [ebx+uhci_pipe.NextQH-sizeof.uhci_pipe], ecx |
mov [edx+uhci_pipe.NextQH-sizeof.uhci_pipe], eax |
ret |
endp |
; This procedure is called from the several places in main USB code |
; and allocates required packets for the given transfer stage. |
; ebx = pipe, other parameters are passed through the stack |
/drivers/usb/usb1_scheduler.inc |
---|
167,12 → 167,7 |
mov eax, [.maxpacket] |
mov ecx, dword [.lowspeed] |
call calc_usb1_bandwidth |
; find list header |
mov edx, ebx |
@@: |
mov edx, [edx+usb_pipe.NextVirt] |
cmp [edx+usb_pipe.Controller], esi |
jz @b |
mov edx, [ebx+usb_pipe.BaseList] |
; subtract pipe bandwidth |
sub [edx+usb_static_ep.Bandwidth], eax |
ret 8 |