Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 3652 → Rev 3653

/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