/kernel/trunk/bus/usb/ehci.inc |
---|
81,27 → 81,21 |
; * The hardware requires 32-bytes alignment of the hardware part, so |
; the entire descriptor must be 32-bytes aligned. Since the allocator |
; (usb_allocate_common) allocates memory sequentially from page start |
; (aligned on 0x1000 bytes), size of the structure must be divisible by 32. |
; (aligned on 0x1000 bytes), block size for the allocator must be divisible |
; by 32; ehci_alloc_td ensures this. |
; * The hardware also requires that the hardware part must not cross page |
; boundary; the allocator satisfies this automatically. |
struct ehci_gtd ehci_hardware_td |
Flags dd ? |
; Copy of flags from the call to usb_*_transfer_async. |
SoftwarePart rd sizeof.usb_gtd/4 |
; Software part, common for all controllers. |
rd 3 ; padding |
ends |
if sizeof.ehci_gtd mod 32 |
.err ehci_gtd must be 32-bytes aligned |
end if |
; EHCI-specific part of a pipe descriptor. |
; * This structure corresponds to the Queue Head from the EHCI specification. |
; * The hardware requires 32-bytes alignment of the hardware part. |
; Since the allocator (usb_allocate_common) allocates memory sequentially |
; from page start (aligned on 0x1000 bytes), size of the structure must be |
; divisible by 32. |
; from page start (aligned on 0x1000 bytes), block size for the allocator |
; must be divisible by 32; ehci_alloc_pipe ensures this. |
; * The hardware requires also that the hardware part must not cross page |
; boundary; the allocator satisfies this automatically. |
struct ehci_pipe |
154,15 → 148,8 |
; from the new TD, if any. |
BaseList dd ? |
; Pointer to head of the corresponding pipe list. |
SoftwarePart rd sizeof.usb_pipe/4 |
; Software part, common for all controllers. |
rd 2 ; padding |
ends |
if sizeof.ehci_pipe mod 32 |
.err ehci_pipe must be 32-bytes aligned |
end if |
; This structure describes the static head of every list of pipes. |
; The hardware requires 32-bytes alignment of this structure. |
; All instances of this structure are located sequentially in ehci_controller, |
764,7 → 751,7 |
; and stores USB device address in the ehci_pipe structure. |
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
proc ehci_set_device_address |
mov byte [ebx+ehci_pipe.Token-ehci_pipe.SoftwarePart], cl |
mov byte [ebx+ehci_pipe.Token-sizeof.ehci_pipe], cl |
call usb_subscribe_control |
ret |
endp |
773,7 → 760,7 |
; in: esi -> usb_controller, ebx -> usb_pipe |
; out: eax = endpoint address |
proc ehci_get_device_address |
mov eax, [ebx+ehci_pipe.Token-ehci_pipe.SoftwarePart] |
mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
and eax, 7Fh |
ret |
endp |
793,11 → 780,11 |
; stores the packet size in ehci_pipe structure. |
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
proc ehci_set_endpoint_packet_size |
mov eax, [ebx+ehci_pipe.Token-ehci_pipe.SoftwarePart] |
mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
and eax, not (0x7FF shl 16) |
shl ecx, 16 |
or eax, ecx |
mov [ebx+ehci_pipe.Token-ehci_pipe.SoftwarePart], eax |
mov [ebx+ehci_pipe.Token-sizeof.ehci_pipe], eax |
; Wait until hardware cache is evicted. |
call usb_subscribe_control |
ret |
818,10 → 805,10 |
proc ehci_alloc_pipe |
push ebx |
mov ebx, ehci_ep_mutex |
stdcall usb_allocate_common, sizeof.ehci_pipe |
stdcall usb_allocate_common, (sizeof.ehci_pipe + sizeof.usb_pipe + 1Fh) and not 1Fh |
test eax, eax |
jz @f |
add eax, ehci_pipe.SoftwarePart |
add eax, sizeof.ehci_pipe |
@@: |
pop ebx |
ret |
834,7 → 821,7 |
dd ? ; return address |
.ptr dd ? |
end virtual |
sub [.ptr], ehci_pipe.SoftwarePart |
sub [.ptr], sizeof.ehci_pipe |
jmp usb_free_common |
endp |
853,9 → 840,9 |
end virtual |
; 1. Zero all fields in the hardware part. |
push eax ecx |
sub edi, ehci_pipe.SoftwarePart |
sub edi, sizeof.ehci_pipe |
xor eax, eax |
movi ecx, ehci_pipe.SoftwarePart/4 |
movi ecx, sizeof.ehci_pipe/4 |
rep stosd |
pop ecx eax |
; 2. Setup PID in the first TD and make sure that the it is not active. |
862,16 → 849,16 |
xor edx, edx |
test byte [.endpoint], 80h |
setnz dh |
mov [eax+ehci_gtd.Token-ehci_gtd.SoftwarePart], edx |
mov [eax+ehci_gtd.NextTD-ehci_gtd.SoftwarePart], 1 |
mov [eax+ehci_gtd.AlternateNextTD-ehci_gtd.SoftwarePart], 1 |
mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
; 3. Store physical address of the first TD. |
sub eax, ehci_gtd.SoftwarePart |
sub eax, sizeof.ehci_gtd |
call get_phys_addr |
mov [edi+ehci_pipe.Overlay.NextTD-ehci_pipe.SoftwarePart], eax |
mov [edi+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax |
; 4. Fill ehci_pipe.Flags except for S- and C-masks. |
; Copy location from the config pipe. |
mov eax, [ecx+ehci_pipe.Flags-ehci_pipe.SoftwarePart] |
mov eax, [ecx+ehci_pipe.Flags-sizeof.ehci_pipe] |
and eax, 3FFF0000h |
; Use 1 requests per microframe for control/bulk endpoints, |
; use value from the endpoint descriptor for periodic endpoints |
884,9 → 871,9 |
@@: |
shl edx, 30 |
or eax, edx |
mov [edi+ehci_pipe.Flags-ehci_pipe.SoftwarePart], eax |
mov [edi+ehci_pipe.Flags-sizeof.ehci_pipe], eax |
; 5. Fill ehci_pipe.Token. |
mov eax, [ecx+ehci_pipe.Token-ehci_pipe.SoftwarePart] |
mov eax, [ecx+ehci_pipe.Token-sizeof.ehci_pipe] |
; copy following fields from the config pipe: |
; DeviceAddress, EndpointSpeed, ControlEndpoint if new type is control |
mov ecx, eax |
915,7 → 902,7 |
@@: |
or eax, 40000000h |
.nonak: |
mov [edi+ehci_pipe.Token-ehci_pipe.SoftwarePart], eax |
mov [edi+ehci_pipe.Token-sizeof.ehci_pipe], eax |
; 5. Select the corresponding list and insert to the list. |
; 5a. Use Control list for control pipes, Bulk list for bulk pipes. |
lea edx, [esi+ehci_controller.ControlED.SoftwarePart-sizeof.ehci_controller] |
931,7 → 918,7 |
; another for split transactions. |
; This could fail if the requested bandwidth is not available; |
; if so, return an error. |
test word [edi+ehci_pipe.Flags-ehci_pipe.SoftwarePart+2], 3FFFh |
test word [edi+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh |
jnz .interrupt_fs |
call ehci_select_hs_interrupt_list |
jmp .interrupt_common |
940,9 → 927,9 |
.interrupt_common: |
test edx, edx |
jz .return0 |
mov word [edi+ehci_pipe.Flags-ehci_pipe.SoftwarePart], ax |
mov word [edi+ehci_pipe.Flags-sizeof.ehci_pipe], ax |
.insert: |
mov [edi+ehci_pipe.BaseList-ehci_pipe.SoftwarePart], edx |
mov [edi+ehci_pipe.BaseList-sizeof.ehci_pipe], 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. |
957,8 → 944,8 |
; 5d. Insert in the hardware list: copy previous NextQH to the new pipe, |
; store the physical address of the new pipe to previous NextQH. |
mov ecx, [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart] |
mov [edi+ehci_pipe.NextQH-ehci_pipe.SoftwarePart], ecx |
lea eax, [edi-ehci_pipe.SoftwarePart] |
mov [edi+ehci_pipe.NextQH-sizeof.ehci_pipe], ecx |
lea eax, [edi-sizeof.ehci_pipe] |
call get_phys_addr |
inc eax |
inc eax |
1084,7 → 1071,7 |
jz .fail |
; 9. Update flags in the last packet. |
mov edx, [flags] |
mov [ecx+ehci_gtd.Flags-ehci_gtd.SoftwarePart], edx |
mov [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], edx |
; 10. Fill AlternateNextTD field in all allocated TDs. |
; If the caller says that short transfer is ok, the queue must advance to |
; the next descriptor, which is in eax. |
1093,7 → 1080,7 |
push eax |
test dl, 1 |
jz .disable_short |
sub eax, ehci_gtd.SoftwarePart |
sub eax, sizeof.ehci_gtd |
jmp @f |
.disable_short: |
mov eax, [ebx+usb_pipe.Controller] |
1104,7 → 1091,7 |
@@: |
cmp edx, [esp] |
jz @f |
mov [edx+ehci_gtd.AlternateNextTD-ehci_gtd.SoftwarePart], eax |
mov [edx+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], eax |
mov edx, [edx+usb_gtd.NextVirt] |
jmp @b |
@@: |
1144,28 → 1131,28 |
call usb_init_transfer |
pop eax |
; 3. Copy PID to the new descriptor. |
mov edx, [ecx+ehci_gtd.Token-ehci_gtd.SoftwarePart] |
mov [eax+ehci_gtd.Token-ehci_gtd.SoftwarePart], edx |
mov [eax+ehci_gtd.NextTD-ehci_gtd.SoftwarePart], 1 |
mov [eax+ehci_gtd.AlternateNextTD-ehci_gtd.SoftwarePart], 1 |
mov edx, [ecx+ehci_gtd.Token-sizeof.ehci_gtd] |
mov [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx |
mov [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1 |
mov [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1 |
; 4. Save the returned value (next descriptor). |
push eax |
; 5. Store the physical address of the next descriptor. |
sub eax, ehci_gtd.SoftwarePart |
sub eax, sizeof.ehci_gtd |
call get_phys_addr |
mov [ecx+ehci_gtd.NextTD-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.NextTD-sizeof.ehci_gtd], eax |
; 6. For zero-length transfers, store zero in all fields for buffer addresses. |
; Otherwise, fill them with real values. |
xor eax, eax |
mov [ecx+ehci_gtd.Flags-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], eax |
repeat 10 |
mov [ecx+ehci_gtd.BufferPointers-ehci_gtd.SoftwarePart+(%-1)*4], eax |
mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd+(%-1)*4], eax |
end repeat |
cmp [.packetSize], eax |
jz @f |
mov eax, [.buffer] |
call get_phys_addr |
mov [ecx+ehci_gtd.BufferPointers-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd], eax |
and eax, 0xFFF |
mov edx, [.packetSize] |
add edx, eax |
1174,25 → 1161,25 |
mov eax, [.buffer] |
add eax, 0x1000 |
call get_pg_addr |
mov [ecx+ehci_gtd.BufferPointers+4-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.BufferPointers+4-sizeof.ehci_gtd], eax |
sub edx, 0x1000 |
jbe @f |
mov eax, [.buffer] |
add eax, 0x2000 |
call get_pg_addr |
mov [ecx+ehci_gtd.BufferPointers+8-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.BufferPointers+8-sizeof.ehci_gtd], eax |
sub edx, 0x1000 |
jbe @f |
mov eax, [.buffer] |
add eax, 0x3000 |
call get_pg_addr |
mov [ecx+ehci_gtd.BufferPointers+12-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.BufferPointers+12-sizeof.ehci_gtd], eax |
sub edx, 0x1000 |
jbe @f |
mov eax, [.buffer] |
add eax, 0x4000 |
call get_pg_addr |
mov [ecx+ehci_gtd.BufferPointers+16-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.BufferPointers+16-sizeof.ehci_gtd], eax |
@@: |
; 7. Fill Token field: |
; set Status = 0 (inactive, ehci_insert_transfer would mark everything active); |
1202,7 → 1189,7 |
; set current page to 0; |
; do not interrupt on complete (ehci_insert_transfer sets this bit where needed); |
; set DataToggle to bit 2 of [.direction]. |
mov eax, [ecx+ehci_gtd.Token-ehci_gtd.SoftwarePart] |
mov eax, [ecx+ehci_gtd.Token-sizeof.ehci_gtd] |
and eax, 300h ; keep PID code |
mov edx, [.direction] |
test edx, edx |
1222,7 → 1209,7 |
mov edx, [.packetSize] |
shl edx, 16 |
or eax, edx |
mov [ecx+ehci_gtd.Token-ehci_gtd.SoftwarePart], eax |
mov [ecx+ehci_gtd.Token-sizeof.ehci_gtd], eax |
; 4. Restore the returned value saved in step 2. |
pop eax |
.nothing: |
1234,10 → 1221,10 |
; ehci_alloc_transfer. |
; ecx -> last descriptor for the transfer, ebx -> usb_pipe |
proc ehci_insert_transfer |
or byte [ecx+ehci_gtd.Token+1-ehci_gtd.SoftwarePart], 80h ; set IOC bit |
or byte [ecx+ehci_gtd.Token+1-sizeof.ehci_gtd], 80h ; set IOC bit |
mov eax, [esp+4] |
.activate: |
or byte [eax+ehci_gtd.Token-ehci_gtd.SoftwarePart], 80h ; set Active bit |
or byte [eax+ehci_gtd.Token-sizeof.ehci_gtd], 80h ; set Active bit |
cmp eax, ecx |
mov eax, [eax+usb_gtd.NextVirt] |
jnz .activate |
1328,7 → 1315,7 |
.found_hs_hub: |
mov edx, [edx+usb_hub.ConfigPipe] |
inc ecx |
mov edx, [edx+ehci_pipe.Token-ehci_pipe.SoftwarePart] |
mov edx, [edx+ehci_pipe.Token-sizeof.ehci_pipe] |
shl ecx, 23 |
and edx, 7Fh |
shl edx, 16 |
1338,15 → 1325,15 |
.common: |
; 5. Create pseudo-pipe in the stack. |
; See ehci_init_pipe: only .Controller, .Token, .Flags fields are used. |
push esi ; ehci_pipe.SoftwarePart.Controller |
push esi ; usb_pipe.Controller |
mov ecx, esp |
sub esp, ehci_pipe.SoftwarePart - ehci_pipe.Flags - 4 |
sub esp, sizeof.ehci_pipe - ehci_pipe.Flags - 4 |
push edx ; ehci_pipe.Flags |
push eax ; ehci_pipe.Token |
; 6. Notify the protocol layer. |
call usb_new_device |
; 7. Cleanup the stack after step 5 and return. |
add esp, ehci_pipe.SoftwarePart - ehci_pipe.Flags + 8 |
add esp, sizeof.ehci_pipe - ehci_pipe.Flags + 8 |
pop ecx ebx ; restore used registers |
ret |
endp |
1658,7 → 1645,7 |
; if either of conditions holds, exit from the internal loop. |
cmp ebx, [esp] |
jz .tddone |
cmp byte [ebx+ehci_gtd.Token-ehci_gtd.SoftwarePart], 0 |
cmp byte [ebx+ehci_gtd.Token-sizeof.ehci_gtd], 0 |
js .tddone |
; Release the queue lock while processing one descriptor: |
; callback function could (and often would) schedule another transfer. |
1690,7 → 1677,7 |
; cmp [eax+usb_pipe.Type], INTERRUPT_PIPE |
; jnz @f |
; DEBUGF 1,'K : finalized TD for pipe %x:\n',eax |
; lea eax, [ebx-ehci_gtd.SoftwarePart] |
; lea eax, [ebx-sizeof.ehci_gtd] |
; DEBUGF 1,'K : %x %x %x %x\n',[eax],[eax+4],[eax+8],[eax+12] |
; DEBUGF 1,'K : %x %x %x %x\n',[eax+16],[eax+20],[eax+24],[eax+28] |
;@@: |
1697,7 → 1684,7 |
; 1. Remove this descriptor from the list of descriptors for this pipe. |
call usb_unlink_td |
; 2. Calculate actual number of bytes transferred. |
mov eax, [ebx+ehci_gtd.Token-ehci_gtd.SoftwarePart] |
mov eax, [ebx+ehci_gtd.Token-sizeof.ehci_gtd] |
lea edx, [eax+eax] |
shr edx, 17 |
sub edx, [ebx+usb_gtd.Length] |
1715,7 → 1702,7 |
xor ecx, ecx |
test al, 40h |
jnz .error |
test byte [ebx+ehci_gtd.Flags-ehci_gtd.SoftwarePart], 1 |
test byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1 |
jnz .notify |
cmp edx, [ebx+usb_gtd.Length] |
jnz .special |
1745,7 → 1732,7 |
ret |
.error: |
push ebx |
sub ebx, ehci_gtd.SoftwarePart |
sub ebx, sizeof.ehci_gtd |
DEBUGF 1,'K : TD failed:\n' |
DEBUGF 1,'K : %x %x %x %x\n',[ebx],[ebx+4],[ebx+8],[ebx+12] |
DEBUGF 1,'K : %x %x %x %x\n',[ebx+16],[ebx+20],[ebx+24],[ebx+28] |
1752,7 → 1739,7 |
pop ebx |
DEBUGF 1,'K : pipe now:\n' |
mov ecx, [ebx+usb_gtd.Pipe] |
sub ecx, ehci_pipe.SoftwarePart |
sub ecx, sizeof.ehci_pipe |
DEBUGF 1,'K : %x %x %x %x\n',[ecx],[ecx+4],[ecx+8],[ecx+12] |
DEBUGF 1,'K : %x %x %x %x\n',[ecx+16],[ecx+20],[ecx+24],[ecx+28] |
DEBUGF 1,'K : %x %x %x %x\n',[ecx+32],[ecx+36],[ecx+40],[ecx+44] |
1802,7 → 1789,7 |
; it is not an error; in this case, go to 4 with ecx = 0. |
cmp ecx, USB_STATUS_UNDERRUN |
jnz @f |
test byte [ebx+ehci_gtd.Flags-ehci_gtd.SoftwarePart], 1 |
test byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1 |
jz @f |
xor ecx, ecx |
pop edx ; length |
1832,20 → 1819,20 |
; to the next transfer. (According to the standard, "A control pipe may also |
; support functional stall as well, but this is not recommended."). |
mov edx, [ebx+usb_gtd.Pipe] |
mov eax, [ebx+ehci_gtd.NextTD-ehci_gtd.SoftwarePart] |
mov eax, [ebx+ehci_gtd.NextTD-sizeof.ehci_gtd] |
or al, 1 |
mov [edx+ehci_pipe.Overlay.NextTD-ehci_pipe.SoftwarePart], eax |
mov [edx+ehci_pipe.Overlay.AlternateNextTD-ehci_pipe.SoftwarePart], eax |
mov [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax |
mov [edx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax |
cmp [edx+usb_pipe.Type], CONTROL_PIPE |
jz .control |
; Bulk/interrupt transfer; halt the queue. |
mov [edx+ehci_pipe.Overlay.Token-ehci_pipe.SoftwarePart], 40h |
mov [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 40h |
pop edx |
jmp .notify |
; Control transfer. |
.control: |
and [edx+ehci_pipe.Overlay.Token-ehci_pipe.SoftwarePart], 0 |
dec [edx+ehci_pipe.Overlay.NextTD-ehci_pipe.SoftwarePart] |
and [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 0 |
dec [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe] |
pop edx |
jmp .notify |
endp |
1855,7 → 1842,7 |
proc ehci_unlink_pipe |
cmp [ebx+usb_pipe.Type], INTERRUPT_PIPE |
jnz @f |
test word [ebx+ehci_pipe.Flags-ehci_pipe.SoftwarePart+2], 3FFFh |
test word [ebx+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh |
jnz .interrupt_fs |
call ehci_hs_interrupt_list_unlink |
jmp .interrupt_common |
1870,9 → 1857,9 |
mov edx, esi |
sub edx, eax |
cmp edx, sizeof.ehci_controller |
mov edx, [ebx+ehci_pipe.NextQH-ehci_pipe.SoftwarePart] |
mov edx, [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe] |
jb .prev_is_static |
mov [eax+ehci_pipe.NextQH-ehci_pipe.SoftwarePart], edx |
mov [eax+ehci_pipe.NextQH-sizeof.ehci_pipe], edx |
ret |
.prev_is_static: |
mov [eax+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], edx |
1882,10 → 1869,10 |
proc ehci_alloc_td |
push ebx |
mov ebx, ehci_gtd_mutex |
stdcall usb_allocate_common, sizeof.ehci_gtd |
stdcall usb_allocate_common, (sizeof.ehci_gtd + sizeof.usb_gtd + 1Fh) and not 1Fh |
test eax, eax |
jz @f |
add eax, ehci_gtd.SoftwarePart |
add eax, sizeof.ehci_gtd |
@@: |
pop ebx |
ret |
1895,6 → 1882,6 |
; frees all additional data associated with the transfer descriptor. |
; EHCI has no additional data, so just free ehci_gtd structure. |
proc ehci_free_td |
sub dword [esp+4], ehci_gtd.SoftwarePart |
sub dword [esp+4], sizeof.ehci_gtd |
jmp usb_free_common |
endp |
/kernel/trunk/bus/usb/memory.inc |
---|
26,7 → 26,7 |
endg |
; sanity check: structures in UHCI and OHCI should be the same for allocation |
if (sizeof.ohci_pipe=sizeof.uhci_pipe)&(ohci_pipe.SoftwarePart=uhci_pipe.SoftwarePart) |
if (sizeof.ohci_pipe = sizeof.uhci_pipe) |
; Allocates one endpoint structure for UHCI/OHCI. |
; Returns pointer to software part (usb_pipe) in eax. |
33,10 → 33,10 |
proc usb1_allocate_endpoint |
push ebx |
mov ebx, usb1_ep_mutex |
stdcall usb_allocate_common, sizeof.ohci_pipe |
stdcall usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh |
test eax, eax |
jz @f |
add eax, ohci_pipe.SoftwarePart |
add eax, sizeof.ohci_pipe |
@@: |
pop ebx |
ret |
45,7 → 45,7 |
; Free one endpoint structure for UHCI/OHCI. |
; Stdcall with one argument, pointer to software part (usb_pipe). |
proc usb1_free_endpoint |
sub dword [esp+4], ohci_pipe.SoftwarePart |
sub dword [esp+4], sizeof.ohci_pipe |
jmp usb_free_common |
endp |
55,7 → 55,7 |
end if |
; sanity check: structures in UHCI and OHCI should be the same for allocation |
if (sizeof.ohci_gtd=sizeof.uhci_gtd)&(ohci_gtd.SoftwarePart=uhci_gtd.SoftwarePart) |
if (sizeof.ohci_gtd = sizeof.uhci_gtd) |
; Allocates one general transfer descriptor structure for UHCI/OHCI. |
; Returns pointer to software part (usb_gtd) in eax. |
62,10 → 62,10 |
proc usb1_allocate_general_td |
push ebx |
mov ebx, usb_gtd_mutex |
stdcall usb_allocate_common, sizeof.ohci_gtd |
stdcall usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh |
test eax, eax |
jz @f |
add eax, ohci_gtd.SoftwarePart |
add eax, sizeof.ohci_gtd |
@@: |
pop ebx |
ret |
74,7 → 74,7 |
; Free one general transfer descriptor structure for UHCI/OHCI. |
; Stdcall with one argument, pointer to software part (usb_gtd). |
proc usb1_free_general_td |
sub dword [esp+4], ohci_gtd.SoftwarePart |
sub dword [esp+4], sizeof.ohci_gtd |
jmp usb_free_common |
endp |
/kernel/trunk/bus/usb/ohci.inc |
---|
44,8 → 44,8 |
; specification. |
; * The hardware requires 16-bytes alignment of the hardware part. |
; Since the allocator (usb_allocate_common) allocates memory sequentially |
; from page start (aligned on 0x1000 bytes), size of the structure must be |
; divisible by 16. |
; from page start (aligned on 0x1000 bytes), block size for the allocator |
; must be divisible by 16; usb1_allocate_endpoint ensures this. |
struct ohci_pipe |
; All addresses are physical. |
Flags dd ? |
95,14 → 95,8 |
; * There is no "next" list for Bulk and Control lists, they are processed |
; separately from others. |
; * There is no "next" list for Periodic list for 1ms interval. |
SoftwarePart rd sizeof.usb_pipe/4 |
; Software part, common for all controllers. |
ends |
if sizeof.ohci_pipe mod 16 |
.err ohci_pipe must be 16-bytes aligned |
end if |
; This structure describes the static head of every list of pipes. |
; The hardware requires 16-bytes alignment of this structure. |
; All instances of this structure are located sequentially in uhci_controller, |
204,7 → 198,8 |
; * The hardware requires 16-bytes alignment of the hardware part, so |
; the entire descriptor must be 16-bytes aligned. Since the allocator |
; (usb_allocate_common) allocates memory sequentially from page start |
; (aligned on 0x1000 bytes), size of the structure must be divisible by 16. |
; (aligned on 0x1000 bytes), block size for the allocator must be |
; divisible by 16; usb1_allocate_generic_td ensures this. |
struct ohci_gtd |
; ------------------------------ hardware fields ------------------------------ |
; All addresses in this part are physical. |
248,15 → 243,9 |
; Virtual pointer to the next processed TD. |
BufEnd dd ? |
; Physical address of the last byte in the buffer for this TD. |
dd ? ; padding for 16-bytes alignment |
SoftwarePart rd sizeof.usb_gtd/4 |
; Common part for all controllers. |
dd ? ; padding to align with uhci_gtd |
ends |
if sizeof.ohci_gtd mod 16 |
.err ohci_gtd must be 16-bytes aligned |
end if |
; OHCI isochronous transfer descriptor. |
; * The structure describes transfers to be performed on Isochronous endpoints. |
; * The structure includes two parts, the hardware part and the software part. |
726,7 → 715,7 |
.tdloop: |
mov ecx, [eax+ohci_gtd.NextTD] |
mov [eax+ohci_gtd.NextTD], ebx |
lea ebx, [eax+ohci_gtd.SoftwarePart] |
lea ebx, [eax+sizeof.ohci_gtd] |
test ecx, ecx |
jz .tddone |
call usb_td_to_virt |
893,7 → 882,7 |
; and stores USB device address in the ohci_pipe structure. |
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
proc ohci_set_device_address |
mov byte [ebx+ohci_pipe.Flags-ohci_pipe.SoftwarePart], cl |
mov byte [ebx+ohci_pipe.Flags-sizeof.ohci_pipe], cl |
; Wait until the hardware will forget the old value. |
call usb_subscribe_control |
ret |
903,7 → 892,7 |
; in: esi -> usb_controller, ebx -> usb_pipe |
; out: eax = endpoint address |
proc ohci_get_device_address |
mov eax, [ebx+ohci_pipe.Flags-ohci_pipe.SoftwarePart] |
mov eax, [ebx+ohci_pipe.Flags-sizeof.ohci_pipe] |
and eax, 7Fh |
ret |
endp |
923,7 → 912,7 |
; stores the packet size in ohci_pipe structure. |
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
proc ohci_set_endpoint_packet_size |
mov byte [ebx+ohci_pipe.Flags+2-ohci_pipe.SoftwarePart], cl |
mov byte [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe], cl |
; Wait until the hardware will forget the old value. |
call usb_subscribe_control |
ret |
943,20 → 932,20 |
.interval dd ? |
end virtual |
; 1. Initialize the queue of transfer descriptors: empty. |
sub eax, ohci_gtd.SoftwarePart |
sub eax, sizeof.ohci_gtd |
call get_phys_addr |
mov [edi+ohci_pipe.TailP-ohci_pipe.SoftwarePart], eax |
mov [edi+ohci_pipe.HeadP-ohci_pipe.SoftwarePart], eax |
mov [edi+ohci_pipe.TailP-sizeof.ohci_pipe], eax |
mov [edi+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
; 2. Generate ohci_pipe.Flags, see the description in ohci_pipe. |
mov eax, [ecx+ohci_pipe.Flags-ohci_pipe.SoftwarePart] |
mov eax, [ecx+ohci_pipe.Flags-sizeof.ohci_pipe] |
and eax, 0x207F ; keep Speed bit and FunctionAddress |
mov edx, [.endpoint] |
and edx, 15 |
shl edx, 7 |
or eax, edx |
mov [edi+ohci_pipe.Flags-ohci_pipe.SoftwarePart], eax |
mov [edi+ohci_pipe.Flags-sizeof.ohci_pipe], eax |
mov eax, [.maxpacket] |
mov word [edi+ohci_pipe.Flags+2-ohci_pipe.SoftwarePart], ax |
mov word [edi+ohci_pipe.Flags+2-sizeof.ohci_pipe], ax |
cmp [.type], CONTROL_PIPE |
jz @f |
test byte [.endpoint], 80h |
963,7 → 952,7 |
setnz al |
inc eax |
shl al, 3 |
or byte [edi+ohci_pipe.Flags+1-ohci_pipe.SoftwarePart], al |
or byte [edi+ohci_pipe.Flags+1-sizeof.ohci_pipe], al |
@@: |
; 3. Insert the new pipe to the corresponding list of endpoints. |
; 3a. Use Control list for control pipes, Bulk list for bulk pipes. |
992,11 → 981,11 |
mov [edi+usb_pipe.PrevVirt], edx |
mov [ecx+usb_pipe.PrevVirt], edi |
mov [edx+usb_pipe.NextVirt], edi |
mov ecx, [edx+ohci_pipe.NextED-ohci_pipe.SoftwarePart] |
mov [edi+ohci_pipe.NextED-ohci_pipe.SoftwarePart], ecx |
lea eax, [edi-ohci_pipe.SoftwarePart] |
mov ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe] |
mov [edi+ohci_pipe.NextED-sizeof.ohci_pipe], ecx |
lea eax, [edi-sizeof.ohci_pipe] |
call get_phys_addr |
mov [edx+ohci_pipe.NextED-ohci_pipe.SoftwarePart], eax |
mov [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax |
; 4. Return something non-zero. |
ret |
.return0: |
1094,7 → 1083,7 |
test eax, eax |
jz .fail |
; 4. Enable an immediate interrupt on completion of the last packet. |
and byte [ecx+ohci_gtd.Flags+2-ohci_gtd.SoftwarePart], not (7 shl (21-16)) |
and byte [ecx+ohci_gtd.Flags+2-sizeof.ohci_gtd], not (7 shl (21-16)) |
; 5. If a short transfer is ok for a caller, set the corresponding bit in |
; the last descriptor, but not in others. |
; Note: even if the caller says that short transfers are ok, |
1104,7 → 1093,7 |
; transparently to the caller. |
test [flags], 1 |
jz @f |
or byte [ecx+ohci_gtd.Flags+2-ohci_gtd.SoftwarePart], 1 shl (18-16) |
or byte [ecx+ohci_gtd.Flags+2-sizeof.ohci_gtd], 1 shl (18-16) |
@@: |
ret |
.fail: |
1143,24 → 1132,24 |
; 3. Save the returned value (next descriptor). |
push eax |
; 4. Store the physical address of the next descriptor. |
sub eax, ohci_gtd.SoftwarePart |
sub eax, sizeof.ohci_gtd |
call get_phys_addr |
mov [ecx+ohci_gtd.NextTD-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd], eax |
; 5. For zero-length transfers, store zero in both fields for buffer addresses. |
; Otherwise, fill them with real values. |
xor eax, eax |
mov [ecx+ohci_gtd.CurBufPtr-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.BufEnd-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
cmp [.packetSize], eax |
jz @f |
mov eax, [.buffer] |
call get_phys_addr |
mov [ecx+ohci_gtd.CurBufPtr-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax |
mov eax, [.buffer] |
add eax, [.packetSize] |
dec eax |
call get_phys_addr |
mov [ecx+ohci_gtd.BufEnd-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax |
@@: |
; 6. Generate Flags field: |
; - set bufferRounding (bit 18) to zero = disallow short transfers; |
1179,7 → 1168,7 |
and edx, (3 shl 2) |
shl edx, 24 - 2 |
lea eax, [eax + edx + (7 shl 21) + (15 shl 28)] |
mov [ecx+ohci_gtd.Flags-ohci_gtd.SoftwarePart], eax |
mov [ecx+ohci_gtd.Flags-sizeof.ohci_gtd], eax |
; 7. Restore the returned value saved in step 3. |
pop eax |
.nothing: |
1192,8 → 1181,8 |
; ecx -> last descriptor for the transfer, ebx -> usb_pipe |
proc ohci_insert_transfer |
; 1. Advance the queue of transfer descriptors. |
mov eax, [ecx+ohci_gtd.NextTD-ohci_gtd.SoftwarePart] |
mov [ebx+ohci_pipe.TailP-ohci_pipe.SoftwarePart], eax |
mov eax, [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
mov [ebx+ohci_pipe.TailP-sizeof.ohci_pipe], eax |
; 2. For control and bulk pipes, notify the controller that |
; there is new work in control/bulk queue respectively. |
ohci_notify_new_work: |
1393,7 → 1382,7 |
mov edx, [ebx+usb_gtd.Pipe] |
test [edx+usb_pipe.Flags], USB_FLAG_CLOSED |
jz @f |
lea eax, [ebx+ohci_gtd.NextTD-ohci_gtd.SoftwarePart] |
lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
xor ebx, ebx |
jmp .next_td2 |
@@: |
1402,13 → 1391,13 |
; 3. Get number of bytes that remain to be transferred. |
; If CurBufPtr is zero, everything was transferred. |
xor edx, edx |
cmp [ebx+ohci_gtd.CurBufPtr-ohci_gtd.SoftwarePart], edx |
cmp [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], edx |
jz .gotlen |
; Otherwise, the remaining length is |
; (BufEnd and 0xFFF) - (CurBufPtr and 0xFFF) + 1, |
; plus 0x1000 if BufEnd and CurBufPtr are in different pages. |
mov edx, [ebx+ohci_gtd.BufEnd-ohci_gtd.SoftwarePart] |
mov eax, [ebx+ohci_gtd.CurBufPtr-ohci_gtd.SoftwarePart] |
mov edx, [ebx+ohci_gtd.BufEnd-sizeof.ohci_gtd] |
mov eax, [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd] |
mov ecx, edx |
and edx, 0xFFF |
inc edx |
1425,7 → 1414,7 |
neg edx |
; 4. Check for error. If so, go to 7. |
push ebx |
mov eax, [ebx+ohci_gtd.Flags-ohci_gtd.SoftwarePart] |
mov eax, [ebx+ohci_gtd.Flags-sizeof.ohci_gtd] |
shr eax, 28 |
jnz .error |
.notify: |
1451,7 → 1440,7 |
stdcall usb1_free_general_td, ebx |
@@: |
pop ebx |
lea eax, [ebx+ohci_gtd.NextTD-ohci_gtd.SoftwarePart] |
lea eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd] |
.next_td2: |
push ebx |
mov ebx, eax |
1484,10 → 1473,10 |
push eax |
push edx |
; DEBUGF 1,'K : TD failed:\n' |
; DEBUGF 1,'K : %x %x %x %x\n',[ebx-ohci_gtd.SoftwarePart],[ebx-ohci_gtd.SoftwarePart+4],[ebx-ohci_gtd.SoftwarePart+8],[ebx-ohci_gtd.SoftwarePart+12] |
; DEBUGF 1,'K : %x %x %x %x\n',[ebx-ohci_gtd.SoftwarePart+16],[ebx-ohci_gtd.SoftwarePart+20],[ebx-ohci_gtd.SoftwarePart+24],[ebx-ohci_gtd.SoftwarePart+28] |
; 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] |
; 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] |
; mov eax, [ebx+usb_gtd.Pipe] |
; DEBUGF 1,'K : pipe: %x %x %x %x\n',[eax-ohci_pipe.SoftwarePart],[eax-ohci_pipe.SoftwarePart+4],[eax-ohci_pipe.SoftwarePart+8],[eax-ohci_pipe.SoftwarePart+12] |
; 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] |
; 7b. Traverse the list of descriptors looking for the final packet |
; for this transfer. |
; Free and unlink non-final descriptors, except the current one. |
1517,18 → 1506,18 |
; After that, go to step 5 with eax = 0 (no error). |
cmp dword [.error_code], USB_STATUS_UNDERRUN |
jnz .no_underrun |
test byte [ebx+ohci_gtd.Flags+2-ohci_gtd.SoftwarePart], 1 shl (18-16) |
test byte [ebx+ohci_gtd.Flags+2-sizeof.ohci_gtd], 1 shl (18-16) |
jz .no_underrun |
and dword [.error_code], 0 |
mov ecx, [ebx+usb_gtd.Pipe] |
mov edx, [ecx+ohci_pipe.HeadP-ohci_pipe.SoftwarePart] |
mov edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe] |
and edx, 2 |
.advance_queue: |
mov eax, [ebx+usb_gtd.NextVirt] |
sub eax, ohci_gtd.SoftwarePart |
sub eax, sizeof.ohci_gtd |
call get_phys_addr |
or eax, edx |
mov [ecx+ohci_pipe.HeadP-ohci_pipe.SoftwarePart], eax |
mov [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax |
push ebx |
mov ebx, ecx |
call ohci_notify_new_work |
1562,7 → 1551,7 |
; support functional stall as well, but this is not recommended."). |
; Advance the transfer queue to the next descriptor. |
mov ecx, [ebx+usb_gtd.Pipe] |
mov edx, [ecx+ohci_pipe.HeadP-ohci_pipe.SoftwarePart] |
mov edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe] |
and edx, 2 ; keep toggleCarry bit |
cmp [ecx+usb_pipe.Type], CONTROL_PIPE |
jnz @f |
1577,7 → 1566,7 |
proc ohci_unlink_pipe |
cmp [ebx+usb_pipe.Type], INTERRUPT_PIPE |
jnz @f |
mov eax, [ebx+ohci_pipe.Flags-ohci_pipe.SoftwarePart] |
mov eax, [ebx+ohci_pipe.Flags-sizeof.ohci_pipe] |
bt eax, 13 |
setc cl |
bt eax, 11 |
1589,7 → 1578,7 |
mov eax, [ebx+usb_pipe.PrevVirt] |
mov [edx+usb_pipe.PrevVirt], eax |
mov [eax+usb_pipe.NextVirt], edx |
mov edx, [ebx+ohci_pipe.NextED-ohci_pipe.SoftwarePart] |
mov [eax+ohci_pipe.NextED-ohci_pipe.SoftwarePart], edx |
mov edx, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe] |
mov [eax+ohci_pipe.NextED-sizeof.ohci_pipe], edx |
ret |
endp |
/kernel/trunk/bus/usb/scheduler.inc |
---|
432,14 → 432,14 |
; in the list header. |
proc ehci_hs_interrupt_list_unlink |
; get target list |
mov edx, [ebx+ehci_pipe.BaseList-ehci_pipe.SoftwarePart] |
mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
; TODO: calculate real bandwidth |
movzx eax, word [ebx+ehci_pipe.Token-ehci_pipe.SoftwarePart+2] |
mov ecx, [ebx+ehci_pipe.Flags-ehci_pipe.SoftwarePart] |
movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
and eax, (1 shl 11) - 1 |
shr ecx, 30 |
imul eax, ecx |
movzx ecx, byte [ebx+ehci_pipe.Flags-ehci_pipe.SoftwarePart] |
movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
add edx, ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart |
; update bandwidth |
.dec_bandwidth: |
/kernel/trunk/bus/usb/uhci.inc |
---|
42,8 → 42,8 |
; software book-keeping. |
; * The hardware requires 16-bytes alignment of the hardware part. |
; Since the allocator (usb_allocate_common) allocates memory sequentially |
; from page start (aligned on 0x1000 bytes), size of the structure must be |
; divisible by 16. |
; from page start (aligned on 0x1000 bytes), block size for the allocator |
; must be divisible by 16; usb1_allocate_endpoint ensures this. |
struct uhci_pipe |
NextQH dd ? |
; 1. First bit (bit 0) is Terminate bit. 1 = there is no next QH. |
81,14 → 81,8 |
ErrorTD dd ? |
; Usually NULL. If nonzero, it is a pointer to descriptor which was error'd |
; and should be freed sometime in the future (the hardware could still use it). |
SoftwarePart rd sizeof.usb_pipe/4 |
; Common part for all controllers, described by usb_pipe structure. |
ends |
if sizeof.uhci_pipe mod 16 |
.err uhci_pipe must be 16-bytes aligned |
end if |
; This structure describes the static head of every list of pipes. |
; The hardware requires 16-bytes alignment of this structure. |
; All instances of this structure are located sequentially in uhci_controller, |
167,7 → 161,8 |
; * The hardware requires 16-bytes alignment of the hardware part, so |
; the entire descriptor must be 16-bytes aligned. Since the allocator |
; (uhci_allocate_common) allocates memory sequentially from page start |
; (aligned on 0x1000 bytes), size of the structure must be divisible by 16. |
; (aligned on 0x1000 bytes), block size for the allocator must be |
; divisible by 16; usb1_allocate_general_td ensures this. |
struct uhci_gtd |
NextTD dd ? |
; 1. First bit (bit 0) is Terminate bit. 1 = there is no next TD. |
231,14 → 226,8 |
; bit 0: 1 = short packet is NOT allowed |
; (before the TD is processed, it is the copy of bit 29 of ControlStatus; |
; some controllers modify that bit, so we need a copy in a safe place) |
SoftwarePart rd sizeof.usb_gtd/4 |
; Software part, common for all controllers. |
ends |
if sizeof.uhci_gtd mod 16 |
.err uhci_gtd must be 16-bytes aligned |
end if |
; UHCI requires that the entire transfer buffer should be on one page. |
; If the actual buffer crosses page boundary, uhci_alloc_packet |
; allocates additional memory for buffer for hardware. |
853,7 → 842,7 |
; if either of conditions holds, exit from the internal loop. |
cmp ebx, [esp] |
jz .tddone |
mov eax, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
mov eax, [ebx+uhci_gtd.ControlStatus-sizeof.uhci_gtd] |
test eax, 1 shl 23 ; active? |
jnz .tddone |
; Release the queue lock while processing one descriptor: |
889,10 → 878,10 |
; DEBUGF 1,'K : %x %x %x %x\n',[ebx-4],[ebx],[ebx+4],[ebx+8] |
; 2. If this is IN transfer into special buffer, copy the data |
; to target location. |
mov edx, [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
mov edx, [ebx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd] |
and edx, not 1 ; clear lsb (used for another goal) |
jz .nocopy |
cmp byte [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart], USB_PID_IN |
cmp byte [ebx+uhci_gtd.Token-sizeof.uhci_gtd], USB_PID_IN |
jnz .nocopy |
; Note: we assume that pointer to buffer is valid in the memory space of |
; the USB thread. This means that buffer must reside in kernel memory |
900,7 → 889,7 |
push esi edi |
mov esi, [edx+uhci_original_buffer.UsedBuffer] |
mov edi, [edx+uhci_original_buffer.OrigBuffer] |
mov ecx, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
mov ecx, [ebx+uhci_gtd.ControlStatus-sizeof.uhci_gtd] |
inc ecx |
and ecx, 7FFh |
mov edx, ecx |
913,8 → 902,8 |
.nocopy: |
; 3. Calculate actual number of bytes transferred. |
; 3a. Read the state. |
mov eax, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
mov ecx, [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
mov eax, [ebx+uhci_gtd.ControlStatus-sizeof.uhci_gtd] |
mov ecx, [ebx+uhci_gtd.Token-sizeof.uhci_gtd] |
; 3b. Get number of bytes processed. |
lea edx, [eax+1] |
and edx, 7FFh |
938,7 → 927,7 |
xor ecx, ecx |
test eax, 1 shl 22 |
jnz .error |
test byte [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
test byte [ebx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd], 1 |
jz .notify |
cmp edx, [ebx+usb_gtd.Length] |
jz .notify |
946,7 → 935,7 |
; 5. There was an error while processing this packet. |
; The hardware has stopped processing the queue. |
DEBUGF 1,'K : TD failed:\n' |
if uhci_gtd.SoftwarePart <> 20 |
if sizeof.uhci_gtd <> 20 |
.err modify offsets for debug output |
end if |
DEBUGF 1,'K : %x %x %x %x\n',[ebx-20],[ebx-16],[ebx-12],[ebx-8] |
955,17 → 944,17 |
push edx |
push eax |
mov eax, [ebx+usb_gtd.Pipe] |
DEBUGF 1,'K : pipe: %x %x\n',[eax+0-uhci_pipe.SoftwarePart],[eax+4-uhci_pipe.SoftwarePart] |
DEBUGF 1,'K : pipe: %x %x\n',[eax+0-sizeof.uhci_pipe],[eax+4-sizeof.uhci_pipe] |
; 5b. Store the current TD as an error packet. |
; If an error packet is already stored for this pipe, |
; it is definitely not used already, so free the old packet. |
mov eax, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
mov eax, [eax+uhci_pipe.ErrorTD-sizeof.uhci_pipe] |
test eax, eax |
jz @f |
stdcall uhci_free_td, eax |
@@: |
mov eax, [ebx+usb_gtd.Pipe] |
mov [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], ebx |
mov [eax+uhci_pipe.ErrorTD-sizeof.uhci_pipe], ebx |
; 5c. Traverse the list of descriptors looking for the final packet |
; for this transfer. |
; Free and unlink non-final descriptors, except the current one. |
1019,7 → 1008,7 |
; After that, go to step 6 with ecx = 0 (no error). |
cmp ecx, USB_STATUS_UNDERRUN |
jnz @f |
test byte [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
test byte [ebx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd], 1 |
jnz @f |
; The controller has stopped this queue on the error packet. |
; Update uhci_pipe.HeadTD to point to the next packet in the queue. |
1026,10 → 1015,10 |
call uhci_fix_toggle |
xor ecx, ecx |
.control: |
mov eax, [ebx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart] |
mov eax, [ebx+uhci_gtd.NextTD-sizeof.uhci_gtd] |
and al, not 0xF |
mov edx, [ebx+usb_gtd.Pipe] |
mov [edx+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
mov [edx+uhci_pipe.HeadTD-sizeof.uhci_pipe], eax |
pop edx ; length |
jmp .notify |
@@: |
1047,7 → 1036,7 |
push ecx |
mov eax, [ebx+usb_gtd.Pipe] |
push [ebx+usb_gtd.NextVirt] |
cmp ebx, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
cmp ebx, [eax+uhci_pipe.ErrorTD-sizeof.uhci_pipe] |
jz @f |
stdcall uhci_free_td, ebx |
@@: |
1065,10 → 1054,10 |
cmp [edx+usb_pipe.Type], CONTROL_PIPE |
jz .control |
; Bulk/interrupt transfer; halt the queue. |
mov eax, [ebx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart] |
mov eax, [ebx+uhci_gtd.NextTD-sizeof.uhci_gtd] |
and al, not 0xF |
inc eax ; set Halted bit |
mov [edx+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
mov [edx+uhci_pipe.HeadTD-sizeof.uhci_pipe], eax |
pop edx ; restore length saved in step 5a |
.notify: |
; 6. Either the descriptor in ebx was processed without errors, |
1094,7 → 1083,7 |
push [ebx+usb_gtd.NextVirt] |
; 7b. Free the descriptor, unless it is saved as ErrorTD. |
mov eax, [ebx+usb_gtd.Pipe] |
cmp [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], ebx |
cmp [eax+uhci_pipe.ErrorTD-sizeof.uhci_pipe], ebx |
jz @f |
stdcall uhci_free_td, ebx |
@@: |
1118,9 → 1107,9 |
; 2. The hardware expects next packet with toggle = (ErrorTD.toggle xor 1), |
; the current value in next packet is (ebx.toggle xor 1). |
; Nothing to do if ErrorTD.toggle == ebx.toggle. |
mov eax, [ecx+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
mov eax, [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
xor eax, [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
mov eax, [ecx+uhci_pipe.ErrorTD-sizeof.uhci_pipe] |
mov eax, [eax+uhci_gtd.Token-sizeof.uhci_gtd] |
xor eax, [ebx+uhci_gtd.Token-sizeof.uhci_gtd] |
test eax, 1 shl 19 |
jz .nothing |
; 3. Lock the transfer queue. |
1130,13 → 1119,13 |
; (inclusive). |
mov eax, [ebx+usb_gtd.NextVirt] |
.loop: |
xor byte [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart+2], 1 shl (19-16) |
xor byte [eax+uhci_gtd.Token-sizeof.uhci_gtd+2], 1 shl (19-16) |
cmp eax, [ecx+usb_pipe.LastTD-usb_pipe.Lock] |
mov eax, [eax+usb_gtd.NextVirt] |
jnz .loop |
; 5. Flip the toggle bit in uhci_pipe structure. |
xor byte [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart-usb_pipe.Lock+2], 1 shl (19-16) |
or dword [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart-usb_pipe.Lock], eax |
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. |
call mutex_unlock |
.nothing: |
1338,7 → 1327,7 |
; and stores USB device address in the uhci_pipe structure. |
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
proc uhci_set_device_address |
mov byte [ebx+uhci_pipe.Token+1-uhci_pipe.SoftwarePart], cl |
mov byte [ebx+uhci_pipe.Token+1-sizeof.uhci_pipe], cl |
call usb_subscription_done |
ret |
endp |
1347,7 → 1336,7 |
; in: esi -> usb_controller, ebx -> usb_pipe |
; out: eax = endpoint address |
proc uhci_get_device_address |
mov al, byte [ebx+uhci_pipe.Token+1-uhci_pipe.SoftwarePart] |
mov al, byte [ebx+uhci_pipe.Token+1-sizeof.uhci_pipe] |
and eax, 7Fh |
ret |
endp |
1372,8 → 1361,8 |
proc uhci_set_endpoint_packet_size |
dec ecx |
shl ecx, 21 |
and [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], (1 shl 21) - 1 |
or [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], ecx |
and [ebx+uhci_pipe.Token-sizeof.uhci_pipe], (1 shl 21) - 1 |
or [ebx+uhci_pipe.Token-sizeof.uhci_pipe], ecx |
; uhci_pipe.Token field is purely for software bookkeeping and does not affect |
; the hardware; thus, we can continue initialization immediately. |
call usb_subscription_done |
1395,18 → 1384,18 |
.interval dd ? |
end virtual |
; 1. Initialize ErrorTD to zero. |
and [edi+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], 0 |
and [edi+uhci_pipe.ErrorTD-sizeof.uhci_pipe], 0 |
; 2. Initialize HeadTD to the physical address of the first TD. |
push eax ; store pointer to the first TD for step ? |
sub eax, uhci_gtd.SoftwarePart |
sub eax, sizeof.uhci_gtd |
call get_phys_addr |
mov [edi+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
mov [edi+uhci_pipe.HeadTD-sizeof.uhci_pipe], eax |
; 3. Initialize Token field: |
; take DeviceAddress and LowSpeedDevice from the parent pipe, |
; take Endpoint and MaximumLength fields from API arguments, |
; set PID depending on pipe type and provided pipe direction, |
; set DataToggle to zero. |
mov eax, [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
mov eax, [ecx+uhci_pipe.Token-sizeof.uhci_pipe] |
and eax, 0x107F00 ; keep DeviceAddress and LowSpeedDevice |
mov edx, [.endpoint] |
and edx, 15 |
1424,20 → 1413,20 |
jz @f |
mov al, USB_PID_IN |
@@: |
mov [edi+uhci_pipe.Token-uhci_pipe.SoftwarePart], eax |
mov [edi+uhci_pipe.Token-sizeof.uhci_pipe], eax |
; 4. Initialize the first TD: |
; copy Token from uhci_pipe.Token zeroing reserved bit 20, |
; set ControlStatus for future transfers, bit make it inactive, |
; set bit 0 in NextTD = "no next TD". |
pop edx ; restore pointer saved in step 2 |
mov [edx+uhci_gtd.Token-uhci_gtd.SoftwarePart], eax |
and byte [edx+uhci_gtd.Token+2-uhci_gtd.SoftwarePart], not (1 shl (20-16)) |
mov [edx+uhci_gtd.Token-sizeof.uhci_gtd], eax |
and byte [edx+uhci_gtd.Token+2-sizeof.uhci_gtd], not (1 shl (20-16)) |
and eax, 1 shl 20 |
shl eax, 6 |
or eax, UHCI_INVALID_LENGTH + (3 shl 27) |
; not processed, inactive, allow 3 errors |
mov [edx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart], eax |
mov [edx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 1 |
mov [edx+uhci_gtd.ControlStatus-sizeof.uhci_gtd], eax |
mov [edx+uhci_gtd.NextTD-sizeof.uhci_gtd], 1 |
; 5. Select the corresponding list and insert to the list. |
; 5a. Use Control list for control pipes, Bulk list for bulk pipes. |
lea edx, [esi+uhci_controller.ControlED.SoftwarePart-sizeof.uhci_controller] |
1471,8 → 1460,8 |
; 5d. Insert in the hardware list: copy previous NextQH to the new pipe, |
; store the physical address of the new pipe to previous NextQH. |
mov ecx, [edx+uhci_static_ep.NextQH-uhci_static_ep.SoftwarePart] |
mov [edi+uhci_pipe.NextQH-uhci_pipe.SoftwarePart], ecx |
lea eax, [edi-uhci_pipe.SoftwarePart] |
mov [edi+uhci_pipe.NextQH-sizeof.uhci_pipe], ecx |
lea eax, [edi-sizeof.uhci_pipe] |
call get_phys_addr |
inc eax |
inc eax |
1486,13 → 1475,13 |
; This procedure is called when a pipe is closing (either due to API call |
; or due to disconnect); it unlinks a pipe from the corresponding list. |
if uhci_static_ep.SoftwarePart <> uhci_pipe.SoftwarePart |
.err uhci_unlink_pipe assumes that uhci_static_ep.SoftwarePart == uhci_pipe.SoftwarePart |
if uhci_static_ep.SoftwarePart <> sizeof.uhci_pipe |
.err uhci_unlink_pipe assumes that uhci_static_ep.SoftwarePart == sizeof.uhci_pipe |
end if |
proc uhci_unlink_pipe |
cmp [ebx+usb_pipe.Type], INTERRUPT_PIPE |
jnz @f |
mov eax, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
mov eax, [ebx+uhci_pipe.Token-sizeof.uhci_pipe] |
cmp al, USB_PID_IN |
setz ch |
bt eax, 20 |
1510,8 → 1499,8 |
mov [eax+usb_pipe.NextVirt], edx |
; Note: eax could be either usb_pipe or usb_static_ep; |
; fortunately, NextQH and SoftwarePart have same offsets in both. |
mov edx, [ebx+uhci_pipe.NextQH-uhci_pipe.SoftwarePart] |
mov [eax+uhci_pipe.NextQH-uhci_pipe.SoftwarePart], edx |
mov edx, [ebx+uhci_pipe.NextQH-sizeof.uhci_pipe] |
mov [eax+uhci_pipe.NextQH-sizeof.uhci_pipe], edx |
ret |
endp |
1519,7 → 1508,7 |
; For UHCI, this includes usb_pipe structure and ErrorTD, if present. |
proc uhci_free_pipe |
mov eax, [esp+4] |
mov eax, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
mov eax, [eax+uhci_pipe.ErrorTD-sizeof.uhci_pipe] |
test eax, eax |
jz @f |
stdcall uhci_free_td, eax |
1544,7 → 1533,7 |
; with size <= endpoint max packet size. |
; 2. Get the maximum packet size for endpoint from uhci_pipe.Token |
; and generate Token field for TDs. |
mov edi, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
mov edi, [ebx+uhci_pipe.Token-sizeof.uhci_pipe] |
mov eax, edi |
shr edi, 21 |
inc edi |
1602,14 → 1591,14 |
; transparently to the caller. |
test [flags], 1 |
jz @f |
and byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], not (1 shl (29-24)) |
and byte [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], not 1 |
and byte [ecx+uhci_gtd.ControlStatus+3-sizeof.uhci_gtd], not (1 shl (29-24)) |
and byte [ecx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd], not 1 |
@@: |
; 6. Update toggle bit in uhci_pipe structure from current value of [token]. |
mov edx, [token] |
xor edx, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
xor edx, [ebx+uhci_pipe.Token-sizeof.uhci_pipe] |
and edx, 1 shl 19 |
xor [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], edx |
xor [ebx+uhci_pipe.Token-sizeof.uhci_pipe], edx |
.nothing: |
ret |
.fail: |
1713,21 → 1702,21 |
; allocated), copy Token field from uhci_pipe.Token zeroing bit 20, |
; generate ControlStatus field, mark as Active |
; (for last descriptor, this will be changed by uhci_insert_transfer). |
mov [eax+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 1 ; no next TD |
mov edx, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
mov [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart], edx |
and byte [eax+uhci_gtd.Token+2-uhci_gtd.SoftwarePart], not (1 shl (20-16)) |
mov [eax+uhci_gtd.NextTD-sizeof.uhci_gtd], 1 ; no next TD |
mov edx, [ebx+uhci_pipe.Token-sizeof.uhci_pipe] |
mov [eax+uhci_gtd.Token-sizeof.uhci_gtd], edx |
and byte [eax+uhci_gtd.Token+2-sizeof.uhci_gtd], not (1 shl (20-16)) |
and edx, 1 shl 20 |
shl edx, 6 |
or edx, UHCI_INVALID_LENGTH + (1 shl 23) + (3 shl 27) |
; not processed, active, allow 3 errors |
mov [eax+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart], edx |
mov [eax+uhci_gtd.ControlStatus-sizeof.uhci_gtd], edx |
; 5. Initialize remaining fields of the current TD. |
; 5a. Store pointer to the buffer allocated in step 1 (or zero). |
pop [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
pop [ecx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd] |
; 5b. Store physical address of the next TD. |
push eax |
sub eax, uhci_gtd.SoftwarePart |
sub eax, sizeof.uhci_gtd |
call get_phys_addr |
; use Depth traversal unless this is the first TD in the transfer stage; |
; uhci_insert_transfer will set Depth traversal for the first TD and clear |
1736,7 → 1725,7 |
jz @f |
or eax, 4 |
@@: |
mov [ecx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], eax |
mov [ecx+uhci_gtd.NextTD-sizeof.uhci_gtd], eax |
; 5c. Store physical address of the buffer: zero if no data present, |
; the temporary buffer if it was allocated, the given buffer otherwise. |
xor eax, eax |
1743,7 → 1732,7 |
cmp [.packetSize], eax |
jz .hasphysbuf |
mov eax, [.buffer] |
mov edx, [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
mov edx, [ecx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd] |
test edx, edx |
jz @f |
mov eax, [edx+uhci_original_buffer.UsedBuffer] |
1750,7 → 1739,7 |
@@: |
call get_phys_addr |
.hasphysbuf: |
mov [ecx+uhci_gtd.Buffer-uhci_gtd.SoftwarePart], eax |
mov [ecx+uhci_gtd.Buffer-sizeof.uhci_gtd], eax |
; 5d. For IN transfers, disallow short packets. |
; This will be overridden, if needed, by uhci_alloc_transfer. |
mov eax, [.token] |
1758,13 → 1747,13 |
dec edx |
cmp al, USB_PID_IN |
jnz @f |
or byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], 1 shl (29-24) ; disallow short packets |
or byte [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
or byte [ecx+uhci_gtd.ControlStatus+3-sizeof.uhci_gtd], 1 shl (29-24) ; disallow short packets |
or byte [ecx+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd], 1 |
@@: |
; 5e. Get Token field: combine [.token] with [.packetSize]. |
shl edx, 21 |
or edx, eax |
mov [ecx+uhci_gtd.Token-uhci_gtd.SoftwarePart], edx |
mov [ecx+uhci_gtd.Token-sizeof.uhci_gtd], edx |
; 6. Flip toggle bit in [.token]. |
xor eax, 1 shl 19 |
mov [.token], eax |
1785,11 → 1774,11 |
; ecx -> last descriptor for the transfer, ebx -> usb_pipe |
proc uhci_insert_transfer |
; DEBUGF 1,'K : uhci_insert_transfer: eax=%x, ecx=%x, [esp+4]=%x\n',eax,ecx,[esp+4] |
and byte [eax+uhci_gtd.ControlStatus+2-uhci_gtd.SoftwarePart], not (1 shl (23-16)) ; clear Active bit |
or byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], 1 shl (24-24) ; set InterruptOnComplete bit |
and byte [eax+uhci_gtd.ControlStatus+2-sizeof.uhci_gtd], not (1 shl (23-16)) ; clear Active bit |
or byte [ecx+uhci_gtd.ControlStatus+3-sizeof.uhci_gtd], 1 shl (24-24) ; set InterruptOnComplete bit |
mov eax, [esp+4] |
or byte [eax+uhci_gtd.ControlStatus+2-uhci_gtd.SoftwarePart], 1 shl (23-16) ; set Active bit |
or byte [eax+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 4 ; set Depth bit |
or byte [eax+uhci_gtd.ControlStatus+2-sizeof.uhci_gtd], 1 shl (23-16) ; set Active bit |
or byte [eax+uhci_gtd.NextTD-sizeof.uhci_gtd], 4 ; set Depth bit |
ret |
endp |
1798,7 → 1787,7 |
; and the temporary buffer, if present. |
proc uhci_free_td |
mov eax, [esp+4] |
mov eax, [eax+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
mov eax, [eax+uhci_gtd.OrigBufferInfo-sizeof.uhci_gtd] |
and eax, not 1 |
jz .nobuf |
push ebx |
1805,6 → 1794,6 |
call free |
pop ebx |
.nobuf: |
sub dword [esp+4], uhci_gtd.SoftwarePart |
sub dword [esp+4], sizeof.uhci_gtd |
jmp usb_free_common |
endp |