Subversion Repositories Kolibri OS

Rev

Rev 4547 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4547 Rev 4577
1
; Code for EHCI controllers.
1
; Code for EHCI controllers.
2
 
2
 
3
; Standard driver stuff
3
; Standard driver stuff
4
format PE DLL native
4
format PE DLL native
5
entry start
5
entry start
6
__DEBUG__ equ 1
6
__DEBUG__ equ 1
7
__DEBUG_LEVEL__ equ 1
7
__DEBUG_LEVEL__ equ 1
8
section '.reloc' data readable discardable fixups
8
section '.reloc' data readable discardable fixups
9
section '.text' code readable executable
9
section '.text' code readable executable
10
include '../proc32.inc'
10
include '../proc32.inc'
11
include '../struct.inc'
11
include '../struct.inc'
12
include '../macros.inc'
12
include '../macros.inc'
13
include '../fdo.inc'
13
include '../fdo.inc'
14
include '../../kernel/trunk/bus/usb/common.inc'
14
include '../../kernel/trunk/bus/usb/common.inc'
15
 
15
 
16
; =============================================================================
16
; =============================================================================
17
; ================================= Constants =================================
17
; ================================= Constants =================================
18
; =============================================================================
18
; =============================================================================
19
; EHCI register declarations.
19
; EHCI register declarations.
20
; Part 1. Capability registers.
20
; Part 1. Capability registers.
21
; Base is MMIO from the PCI space.
21
; Base is MMIO from the PCI space.
22
EhciCapLengthReg    = 0
22
EhciCapLengthReg    = 0
23
EhciVersionReg      = 2
23
EhciVersionReg      = 2
24
EhciStructParamsReg = 4
24
EhciStructParamsReg = 4
25
EhciCapParamsReg    = 8
25
EhciCapParamsReg    = 8
26
EhciPortRouteReg    = 0Ch
26
EhciPortRouteReg    = 0Ch
27
; Part 2. Operational registers.
27
; Part 2. Operational registers.
28
; Base is (base for part 1) + (value of EhciCapLengthReg).
28
; Base is (base for part 1) + (value of EhciCapLengthReg).
29
EhciCommandReg      = 0
29
EhciCommandReg      = 0
30
EhciStatusReg       = 4
30
EhciStatusReg       = 4
31
EhciInterruptReg    = 8
31
EhciInterruptReg    = 8
32
EhciFrameIndexReg   = 0Ch
32
EhciFrameIndexReg   = 0Ch
33
EhciCtrlDataSegReg  = 10h
33
EhciCtrlDataSegReg  = 10h
34
EhciPeriodicListReg = 14h
34
EhciPeriodicListReg = 14h
35
EhciAsyncListReg    = 18h
35
EhciAsyncListReg    = 18h
36
EhciConfigFlagReg   = 40h
36
EhciConfigFlagReg   = 40h
37
EhciPortsReg        = 44h
37
EhciPortsReg        = 44h
38
 
38
 
39
; Possible values of ehci_pipe.NextQH.Type bitfield.
39
; Possible values of ehci_pipe.NextQH.Type bitfield.
40
EHCI_TYPE_ITD  = 0 ; isochronous transfer descriptor
40
EHCI_TYPE_ITD  = 0 ; isochronous transfer descriptor
41
EHCI_TYPE_QH   = 1 ; queue head
41
EHCI_TYPE_QH   = 1 ; queue head
42
EHCI_TYPE_SITD = 2 ; split-transaction isochronous TD
42
EHCI_TYPE_SITD = 2 ; split-transaction isochronous TD
43
EHCI_TYPE_FSTN = 3 ; frame span traversal node
43
EHCI_TYPE_FSTN = 3 ; frame span traversal node
44
 
44
 
45
; =============================================================================
45
; =============================================================================
46
; ================================ Structures =================================
46
; ================================ Structures =================================
47
; =============================================================================
47
; =============================================================================
48
 
48
 
49
; Hardware part of EHCI general transfer descriptor.
49
; Hardware part of EHCI general transfer descriptor.
50
struct ehci_hardware_td
50
struct ehci_hardware_td
51
NextTD          dd      ?
51
NextTD          dd      ?
52
; Bit 0 is Terminate bit, 1 = there is no next TD.
52
; Bit 0 is Terminate bit, 1 = there is no next TD.
53
; Bits 1-4 must be zero.
53
; Bits 1-4 must be zero.
54
; With masked 5 lower bits, this is the physical address of the next TD, if any.
54
; With masked 5 lower bits, this is the physical address of the next TD, if any.
55
AlternateNextTD dd      ?
55
AlternateNextTD dd      ?
56
; Similar to NextTD, used if the transfer terminates with a short packet.
56
; Similar to NextTD, used if the transfer terminates with a short packet.
57
Token           dd      ?
57
Token           dd      ?
58
; 1. Lower byte is Status field:
58
; 1. Lower byte is Status field:
59
; bit 0 = ping state for USB2 endpoints, ERR handshake signal for USB1 endpoints
59
; bit 0 = ping state for USB2 endpoints, ERR handshake signal for USB1 endpoints
60
; bit 1 = split transaction state, meaningless for USB2 endpoints
60
; bit 1 = split transaction state, meaningless for USB2 endpoints
61
; bit 2 = missed micro-frame
61
; bit 2 = missed micro-frame
62
; bit 3 = transaction error
62
; bit 3 = transaction error
63
; bit 4 = babble detected
63
; bit 4 = babble detected
64
; bit 5 = data buffer error
64
; bit 5 = data buffer error
65
; bit 6 = halted
65
; bit 6 = halted
66
; bit 7 = active
66
; bit 7 = active
67
; 2. Next two bits (bits 8-9) are PID code, 0 = OUT, 1 = IN, 2 = SETUP.
67
; 2. Next two bits (bits 8-9) are PID code, 0 = OUT, 1 = IN, 2 = SETUP.
68
; 3. Next two bits (bits 10-11) is ErrorCounter. Initialized as 3, decremented
68
; 3. Next two bits (bits 10-11) is ErrorCounter. Initialized as 3, decremented
69
;    on each error; if it goes to zero, transaction is stopped.
69
;    on each error; if it goes to zero, transaction is stopped.
70
; 4. Next 3 bits (bits 12-14) are CurrentPage field.
70
; 4. Next 3 bits (bits 12-14) are CurrentPage field.
71
; 5. Next bit (bit 15) is InterruptOnComplete bit.
71
; 5. Next bit (bit 15) is InterruptOnComplete bit.
72
; 6. Next 15 bits (bits 16-30) are TransferLength field,
72
; 6. Next 15 bits (bits 16-30) are TransferLength field,
73
;    number of bytes to transfer.
73
;    number of bytes to transfer.
74
; 7. Upper bit (bit 31) is DataToggle bit.
74
; 7. Upper bit (bit 31) is DataToggle bit.
75
BufferPointers  rd      5
75
BufferPointers  rd      5
76
; The buffer to be transferred can be spanned on up to 5 physical pages.
76
; The buffer to be transferred can be spanned on up to 5 physical pages.
77
; The first item of this array is the physical address of the first byte in
77
; The first item of this array is the physical address of the first byte in
78
; the buffer, other items are physical addresses of next pages. Lower 12 bits
78
; the buffer, other items are physical addresses of next pages. Lower 12 bits
79
; in other items must be set to zero; ehci_pipe.Overlay reuses some of them.
79
; in other items must be set to zero; ehci_pipe.Overlay reuses some of them.
80
BufferPointersHigh      rd      5
80
BufferPointersHigh      rd      5
81
; Upper dwords of BufferPointers for controllers with 64-bit memory access.
81
; Upper dwords of BufferPointers for controllers with 64-bit memory access.
82
; Always zero.
82
; Always zero.
83
ends
83
ends
84
 
84
 
85
; EHCI general transfer descriptor.
85
; EHCI general transfer descriptor.
86
; * The structure describes transfers to be performed on Control, Bulk or
86
; * The structure describes transfers to be performed on Control, Bulk or
87
;   Interrupt endpoints.
87
;   Interrupt endpoints.
88
; * The structure includes two parts, the hardware part and the software part.
88
; * The structure includes two parts, the hardware part and the software part.
89
; * The hardware part consists of first 52 bytes and corresponds to
89
; * The hardware part consists of first 52 bytes and corresponds to
90
;   the Queue Element Transfer Descriptor from EHCI specification.
90
;   the Queue Element Transfer Descriptor from EHCI specification.
91
; * The hardware requires 32-bytes alignment of the hardware part, so
91
; * The hardware requires 32-bytes alignment of the hardware part, so
92
;   the entire descriptor must be 32-bytes aligned. Since the allocator
92
;   the entire descriptor must be 32-bytes aligned. Since the allocator
93
;   (usb_allocate_common) allocates memory sequentially from page start
93
;   (usb_allocate_common) allocates memory sequentially from page start
94
;   (aligned on 0x1000 bytes), block size for the allocator must be divisible
94
;   (aligned on 0x1000 bytes), block size for the allocator must be divisible
95
;   by 32; ehci_alloc_td ensures this.
95
;   by 32; ehci_alloc_td ensures this.
96
; * The hardware also requires that the hardware part must not cross page
96
; * The hardware also requires that the hardware part must not cross page
97
;   boundary; the allocator satisfies this automatically.
97
;   boundary; the allocator satisfies this automatically.
98
struct ehci_gtd ehci_hardware_td
98
struct ehci_gtd ehci_hardware_td
99
Flags                   dd      ?
99
Flags                   dd      ?
100
; Copy of flags from the call to usb_*_transfer_async.
100
; Copy of flags from the call to usb_*_transfer_async.
101
ends
101
ends
102
 
102
 
103
; EHCI-specific part of a pipe descriptor.
103
; EHCI-specific part of a pipe descriptor.
104
; * This structure corresponds to the Queue Head from the EHCI specification.
104
; * This structure corresponds to the Queue Head from the EHCI specification.
105
; * The hardware requires 32-bytes alignment of the hardware part.
105
; * The hardware requires 32-bytes alignment of the hardware part.
106
;   Since the allocator (usb_allocate_common) allocates memory sequentially
106
;   Since the allocator (usb_allocate_common) allocates memory sequentially
107
;   from page start (aligned on 0x1000 bytes), block size for the allocator
107
;   from page start (aligned on 0x1000 bytes), block size for the allocator
108
;   must be divisible by 32; ehci_alloc_pipe ensures this.
108
;   must be divisible by 32; ehci_alloc_pipe ensures this.
109
; * The hardware requires also that the hardware part must not cross page
109
; * The hardware requires also that the hardware part must not cross page
110
;   boundary; the allocator satisfies this automatically.
110
;   boundary; the allocator satisfies this automatically.
111
struct ehci_pipe
111
struct ehci_pipe
112
NextQH                  dd      ?
112
NextQH                  dd      ?
113
; 1. First bit (bit 0) is Terminate bit, 1 = there is no next QH.
113
; 1. First bit (bit 0) is Terminate bit, 1 = there is no next QH.
114
; 2. Next two bits (bits 1-2) are Type field of the next QH,
114
; 2. Next two bits (bits 1-2) are Type field of the next QH,
115
;    one of EHCI_TYPE_* constants.
115
;    one of EHCI_TYPE_* constants.
116
; 3. Next two bits (bits 3-4) are reserved, must be zero.
116
; 3. Next two bits (bits 3-4) are reserved, must be zero.
117
; 4. With masked 5 lower bits, this is the physical address of the next object
117
; 4. With masked 5 lower bits, this is the physical address of the next object
118
;    to be processed, usually next QH.
118
;    to be processed, usually next QH.
119
Token                   dd      ?
119
Token                   dd      ?
120
; 1. Lower 7 bits are DeviceAddress field. This is the address of the
120
; 1. Lower 7 bits are DeviceAddress field. This is the address of the
121
;    target device on the USB bus.
121
;    target device on the USB bus.
122
; 2. Next bit (bit 7) is Inactivate-on-next-transaction bit. Can be nonzero
122
; 2. Next bit (bit 7) is Inactivate-on-next-transaction bit. Can be nonzero
123
;    only for interrupt/isochronous USB1 endpoints.
123
;    only for interrupt/isochronous USB1 endpoints.
124
; 3. Next 4 bits (bits 8-11) are Endpoint field. This is the target endpoint
124
; 3. Next 4 bits (bits 8-11) are Endpoint field. This is the target endpoint
125
;    number.
125
;    number.
126
; 4. Next 2 bits (bits 12-13) are EndpointSpeed field, one of EHCI_SPEED_*.
126
; 4. Next 2 bits (bits 12-13) are EndpointSpeed field, one of EHCI_SPEED_*.
127
; 5. Next bit (bit 14) is DataToggleControl bit,
127
; 5. Next bit (bit 14) is DataToggleControl bit,
128
;    0 = use DataToggle bit from QH, 1 = from TD.
128
;    0 = use DataToggle bit from QH, 1 = from TD.
129
; 6. Next bit (bit 15) is Head-of-reclamation-list. The head of Control list
129
; 6. Next bit (bit 15) is Head-of-reclamation-list. The head of Control list
130
;    has 1 here, all other QHs have zero.
130
;    has 1 here, all other QHs have zero.
131
; 7. Next 11 bits (bits 16-26) are MaximumPacketLength field for the target
131
; 7. Next 11 bits (bits 16-26) are MaximumPacketLength field for the target
132
;    endpoint.
132
;    endpoint.
133
; 8. Next bit (bit 27) is ControlEndpoint bit, must be 1 for USB1 control
133
; 8. Next bit (bit 27) is ControlEndpoint bit, must be 1 for USB1 control
134
;    endpoints and 0 for all others.
134
;    endpoints and 0 for all others.
135
; 9. Upper 4 bits (bits 28-31) are NakCountReload field.
135
; 9. Upper 4 bits (bits 28-31) are NakCountReload field.
136
;    Zero for USB1 endpoints, zero for periodic endpoints.
136
;    Zero for USB1 endpoints, zero for periodic endpoints.
137
;    For control/bulk USB2 endpoints, the code sets it to 4,
137
;    For control/bulk USB2 endpoints, the code sets it to 4,
138
;    which is rather arbitrary.
138
;    which is rather arbitrary.
139
Flags                   dd      ?
139
Flags                   dd      ?
140
; 1. Lower byte is S-mask, each bit corresponds to one microframe per frame;
140
; 1. Lower byte is S-mask, each bit corresponds to one microframe per frame;
141
;    bit is set <=> enable transactions in this microframe.
141
;    bit is set <=> enable transactions in this microframe.
142
; 2. Next byte is C-mask, each bit corresponds to one microframe per frame;
142
; 2. Next byte is C-mask, each bit corresponds to one microframe per frame;
143
;    bit is set <=> enable complete-split transactions in this microframe.
143
;    bit is set <=> enable complete-split transactions in this microframe.
144
;    Meaningful only for USB1 endpoints.
144
;    Meaningful only for USB1 endpoints.
145
; 3. Next 14 bits give address of the target device as hub:port, bits 16-22
145
; 3. Next 14 bits give address of the target device as hub:port, bits 16-22
146
;    are the USB address of the hub, bits 23-29 are the port number.
146
;    are the USB address of the hub, bits 23-29 are the port number.
147
;    Meaningful only for USB1 endpoints.
147
;    Meaningful only for USB1 endpoints.
148
; 4. Upper 2 bits define number of consequetive transactions per micro-frame
148
; 4. Upper 2 bits define number of consequetive transactions per micro-frame
149
;    which host is allowed to permit for this endpoint.
149
;    which host is allowed to permit for this endpoint.
150
;    For control/bulk endpoints, it must be 1.
150
;    For control/bulk endpoints, it must be 1.
151
;    For periodic endpoints, the value is taken from the endpoint descriptor.
151
;    For periodic endpoints, the value is taken from the endpoint descriptor.
152
HeadTD                  dd      ?
152
HeadTD                  dd      ?
153
; The physical address of the first TD for this pipe.
153
; The physical address of the first TD for this pipe.
154
; Lower 5 bits must be zero.
154
; Lower 5 bits must be zero.
155
Overlay                 ehci_hardware_td        ?
155
Overlay                 ehci_hardware_td        ?
156
; Working area for the current TD, if there is any.
156
; Working area for the current TD, if there is any.
157
; When TD is retired, it is written to that TD and Overlay is loaded
157
; When TD is retired, it is written to that TD and Overlay is loaded
158
; from the new TD, if any.
158
; from the new TD, if any.
159
ends
159
ends
160
 
160
 
161
; This structure describes the static head of every list of pipes.
161
; This structure describes the static head of every list of pipes.
162
; The hardware requires 32-bytes alignment of this structure.
162
; The hardware requires 32-bytes alignment of this structure.
163
; All instances of this structure are located sequentially in ehci_controller,
163
; All instances of this structure are located sequentially in ehci_controller,
164
; ehci_controller is page-aligned, so it is sufficient to make this structure
164
; ehci_controller is page-aligned, so it is sufficient to make this structure
165
; 32-bytes aligned and verify that the first instance is 32-bytes aligned
165
; 32-bytes aligned and verify that the first instance is 32-bytes aligned
166
; inside ehci_controller.
166
; inside ehci_controller.
167
; The hardware also requires that 44h bytes (size of 64-bit Queue Head
167
; The hardware also requires that 44h bytes (size of 64-bit Queue Head
168
; Descriptor) starting at the beginning of this structure must not cross page
168
; Descriptor) starting at the beginning of this structure must not cross page
169
; boundary. If not, most hardware still behaves correctly (in fact, the last
169
; boundary. If not, most hardware still behaves correctly (in fact, the last
170
; dword can have any value and this structure is never written), but on some
170
; dword can have any value and this structure is never written), but on some
171
; hardware some things just break in mysterious ways.
171
; hardware some things just break in mysterious ways.
172
struct ehci_static_ep
172
struct ehci_static_ep
173
; Hardware fields are the same as in ehci_pipe.
173
; Hardware fields are the same as in ehci_pipe.
174
; Only NextQH and Overlay.Token are actually used.
174
; Only NextQH and Overlay.Token are actually used.
175
; NB: some emulators ignore Token.Halted bit (probably assuming that it is set
175
; NB: some emulators ignore Token.Halted bit (probably assuming that it is set
176
; only when device fails and emulation never fails) and always follow
176
; only when device fails and emulation never fails) and always follow
177
; [Alternate]NextTD when they see that OverlayToken.Active bit is zero;
177
; [Alternate]NextTD when they see that OverlayToken.Active bit is zero;
178
; so it is important to also set [Alternate]NextTD to 1.
178
; so it is important to also set [Alternate]NextTD to 1.
179
NextQH          dd      ?
179
NextQH          dd      ?
180
Token           dd      ?
180
Token           dd      ?
181
Flags           dd      ?
181
Flags           dd      ?
182
HeadTD          dd      ?
182
HeadTD          dd      ?
183
NextTD          dd      ?
183
NextTD          dd      ?
184
AlternateNextTD dd      ?
184
AlternateNextTD dd      ?
185
OverlayToken    dd      ?
185
OverlayToken    dd      ?
186
NextList        dd      ?
186
NextList        dd      ?
187
SoftwarePart    rd      sizeof.usb_static_ep/4
187
SoftwarePart    rd      sizeof.usb_static_ep/4
188
Bandwidths      rw      8
188
Bandwidths      rw      8
189
                dd      ?
189
                dd      ?
190
ends
190
ends
191
 
191
 
192
if sizeof.ehci_static_ep mod 32
192
if sizeof.ehci_static_ep mod 32
193
.err ehci_static_ep must be 32-bytes aligned
193
.err ehci_static_ep must be 32-bytes aligned
194
end if
194
end if
195
 
195
 
196
if ehci_static_ep.OverlayToken <> ehci_pipe.Overlay.Token
196
if ehci_static_ep.OverlayToken <> ehci_pipe.Overlay.Token
197
.err ehci_static_ep.OverlayToken misplaced
197
.err ehci_static_ep.OverlayToken misplaced
198
end if
198
end if
199
 
199
 
200
; EHCI-specific part of controller data.
200
; EHCI-specific part of controller data.
201
; * The structure includes two parts, the hardware part and the software part.
201
; * The structure includes two parts, the hardware part and the software part.
202
; * The hardware part consists of first 4096 bytes and corresponds to
202
; * The hardware part consists of first 4096 bytes and corresponds to
203
;   the Periodic Frame List from the EHCI specification.
203
;   the Periodic Frame List from the EHCI specification.
204
; * The hardware requires page-alignment of the hardware part, so
204
; * The hardware requires page-alignment of the hardware part, so
205
;   the entire descriptor must be page-aligned.
205
;   the entire descriptor must be page-aligned.
206
;   This structure is allocated with kernel_alloc (see usb_init_controller),
206
;   This structure is allocated with kernel_alloc (see usb_init_controller),
207
;   this gives page-aligned data.
207
;   this gives page-aligned data.
208
; * The controller is described by both ehci_controller and usb_controller
208
; * The controller is described by both ehci_controller and usb_controller
209
;   structures, for each controller there is one ehci_controller and one
209
;   structures, for each controller there is one ehci_controller and one
210
;   usb_controller structure. These structures are located sequentially
210
;   usb_controller structure. These structures are located sequentially
211
;   in the memory: beginning from some page start, there is ehci_controller
211
;   in the memory: beginning from some page start, there is ehci_controller
212
;   structure - this enforces hardware alignment requirements - and then
212
;   structure - this enforces hardware alignment requirements - and then
213
;   usb_controller structure.
213
;   usb_controller structure.
214
; * The code keeps pointer to usb_controller structure. The ehci_controller
214
; * The code keeps pointer to usb_controller structure. The ehci_controller
215
;   structure is addressed as [ptr + ehci_controller.field - sizeof.ehci_controller].
215
;   structure is addressed as [ptr + ehci_controller.field - sizeof.ehci_controller].
216
struct ehci_controller
216
struct ehci_controller
217
; ------------------------------ hardware fields ------------------------------
217
; ------------------------------ hardware fields ------------------------------
218
FrameList               rd      1024
218
FrameList               rd      1024
219
; Entry n corresponds to the head of the frame list to be executed in
219
; Entry n corresponds to the head of the frame list to be executed in
220
; the frames n,n+1024,n+2048,n+3072,...
220
; the frames n,n+1024,n+2048,n+3072,...
221
; The first bit of each entry is Terminate bit, 1 = the frame is empty.
221
; The first bit of each entry is Terminate bit, 1 = the frame is empty.
222
; Bits 1-2 are Type field, one of EHCI_TYPE_* constants.
222
; Bits 1-2 are Type field, one of EHCI_TYPE_* constants.
223
; Bits 3-4 must be zero.
223
; Bits 3-4 must be zero.
224
; With masked 5 lower bits, the entry is a physical address of the first QH/TD
224
; With masked 5 lower bits, the entry is a physical address of the first QH/TD
225
; to be executed.
225
; to be executed.
226
; ------------------------------ software fields ------------------------------
226
; ------------------------------ software fields ------------------------------
227
; Every list has the static head, which is an always halted QH.
227
; Every list has the static head, which is an always halted QH.
228
; The following fields are static heads, one per list:
228
; The following fields are static heads, one per list:
229
; 32+16+8+4+2+1 = 63 for Periodic lists, 1 for Control list and 1 for Bulk list.
229
; 32+16+8+4+2+1 = 63 for Periodic lists, 1 for Control list and 1 for Bulk list.
230
IntEDs                  ehci_static_ep
230
IntEDs                  ehci_static_ep
231
                        rb      62 * sizeof.ehci_static_ep
231
                        rb      62 * sizeof.ehci_static_ep
232
; Beware.
232
; Beware.
233
; Two following strings ensure that 44h bytes at any static head
233
; Two following strings ensure that 44h bytes at any static head
234
; do not cross page boundary. Without that, the code "works on my machine"...
234
; do not cross page boundary. Without that, the code "works on my machine"...
235
; but fails on some hardware in seemingly unrelated ways.
235
; but fails on some hardware in seemingly unrelated ways.
236
; One hardware TD (without any software fields) fit in the rest of the page.
236
; One hardware TD (without any software fields) fit in the rest of the page.
237
ehci_controller.ControlDelta = 2000h - (ehci_controller.IntEDs + 63 * sizeof.ehci_static_ep)
237
ehci_controller.ControlDelta = 2000h - (ehci_controller.IntEDs + 63 * sizeof.ehci_static_ep)
238
StopQueueTD             ehci_hardware_td
238
StopQueueTD             ehci_hardware_td
239
; Used as AlternateNextTD for transfers when short packet is considered
239
; Used as AlternateNextTD for transfers when short packet is considered
240
; as an error; short packet must stop the queue in this case, not advance
240
; as an error; short packet must stop the queue in this case, not advance
241
; to the next transfer.
241
; to the next transfer.
242
                        rb      ehci_controller.ControlDelta - sizeof.ehci_hardware_td
242
                        rb      ehci_controller.ControlDelta - sizeof.ehci_hardware_td
243
; Padding for page-alignment.
243
; Padding for page-alignment.
244
ControlED               ehci_static_ep
244
ControlED               ehci_static_ep
245
BulkED                  ehci_static_ep
245
BulkED                  ehci_static_ep
246
MMIOBase1               dd      ?
246
MMIOBase1               dd      ?
247
; Virtual address of memory-mapped area with part 1 of EHCI registers EhciXxxReg.
247
; Virtual address of memory-mapped area with part 1 of EHCI registers EhciXxxReg.
248
MMIOBase2               dd      ?
248
MMIOBase2               dd      ?
249
; Pointer inside memory-mapped area MMIOBase1; points to part 2 of EHCI registers.
249
; Pointer inside memory-mapped area MMIOBase1; points to part 2 of EHCI registers.
250
StructuralParams        dd      ?
250
StructuralParams        dd      ?
251
; Copy of EhciStructParamsReg value.
251
; Copy of EhciStructParamsReg value.
252
CapabilityParams        dd      ?
252
CapabilityParams        dd      ?
253
; Copy of EhciCapParamsReg value.
253
; Copy of EhciCapParamsReg value.
254
DeferredActions         dd      ?
254
DeferredActions         dd      ?
255
; Bitmask of events from EhciStatusReg which were observed by the IRQ handler
255
; Bitmask of events from EhciStatusReg which were observed by the IRQ handler
256
; and needs to be processed in the IRQ thread.
256
; and needs to be processed in the IRQ thread.
257
PortRoutes              rb      16
257
PortRoutes              rb      16
258
; Companion port route description.
258
; Companion port route description.
259
; Each byte describes routing of one port, value = PCI function.
259
; Each byte describes routing of one port, value = PCI function.
260
; This field must be the last one:
260
; This field must be the last one:
261
; UHCI/OHCI code uses this field without knowing the entire structure.
261
; UHCI/OHCI code uses this field without knowing the entire structure.
262
ends
262
ends
263
 
263
 
264
if ehci_controller.IntEDs mod 32
264
if ehci_controller.IntEDs mod 32
265
.err Static endpoint descriptors must be 32-bytes aligned inside ehci_controller
265
.err Static endpoint descriptors must be 32-bytes aligned inside ehci_controller
266
end if
266
end if
267
 
267
 
268
; Description of #HCI-specific data and functions for
268
; Description of #HCI-specific data and functions for
269
; controller-independent code.
269
; controller-independent code.
270
; Implements the structure usb_hardware_func from hccommon.inc for EHCI.
270
; Implements the structure usb_hardware_func from hccommon.inc for EHCI.
271
iglobal
271
iglobal
272
align 4
272
align 4
273
ehci_hardware_func:
273
ehci_hardware_func:
274
        dd      USBHC_VERSION
274
        dd      USBHC_VERSION
275
        dd      'EHCI'
275
        dd      'EHCI'
276
        dd      sizeof.ehci_controller
276
        dd      sizeof.ehci_controller
277
        dd      ehci_kickoff_bios
277
        dd      ehci_kickoff_bios
278
        dd      ehci_init
278
        dd      ehci_init
279
        dd      ehci_process_deferred
279
        dd      ehci_process_deferred
280
        dd      ehci_set_device_address
280
        dd      ehci_set_device_address
281
        dd      ehci_get_device_address
281
        dd      ehci_get_device_address
282
        dd      ehci_port_disable
282
        dd      ehci_port_disable
283
        dd      ehci_new_port.reset
283
        dd      ehci_new_port.reset
284
        dd      ehci_set_endpoint_packet_size
284
        dd      ehci_set_endpoint_packet_size
285
        dd      ehci_alloc_pipe
285
        dd      ehci_alloc_pipe
286
        dd      ehci_free_pipe
286
        dd      ehci_free_pipe
287
        dd      ehci_init_pipe
287
        dd      ehci_init_pipe
288
        dd      ehci_unlink_pipe
288
        dd      ehci_unlink_pipe
289
        dd      ehci_alloc_td
289
        dd      ehci_alloc_td
290
        dd      ehci_free_td
290
        dd      ehci_free_td
291
        dd      ehci_alloc_transfer
291
        dd      ehci_alloc_transfer
292
        dd      ehci_insert_transfer
292
        dd      ehci_insert_transfer
293
        dd      ehci_new_device
293
        dd      ehci_new_device
294
        dd      ehci_disable_pipe
294
        dd      ehci_disable_pipe
295
        dd      ehci_enable_pipe
295
        dd      ehci_enable_pipe
296
ehci_name db    'EHCI',0
296
ehci_name db    'EHCI',0
297
endg
297
endg
298
 
298
 
299
; =============================================================================
299
; =============================================================================
300
; =================================== Code ====================================
300
; =================================== Code ====================================
301
; =============================================================================
301
; =============================================================================
302
 
302
 
303
; Called once when driver is loading and once at shutdown.
303
; Called once when driver is loading and once at shutdown.
304
; When loading, must initialize itself, register itself in the system
304
; When loading, must initialize itself, register itself in the system
305
; and return eax = value obtained when registering.
305
; and return eax = value obtained when registering.
306
proc start
306
proc start
307
virtual at esp
307
virtual at esp
308
                dd      ? ; return address
308
                dd      ? ; return address
309
.reason         dd      ? ; DRV_ENTRY or DRV_EXIT
309
.reason         dd      ? ; DRV_ENTRY or DRV_EXIT
310
.cmdline        dd      ? ; normally NULL
310
.cmdline        dd      ? ; normally NULL
311
end virtual
311
end virtual
312
        cmp     [.reason], DRV_ENTRY
312
        cmp     [.reason], DRV_ENTRY
313
        jnz     .nothing
313
        jnz     .nothing
314
        mov     ecx, ehci_ep_mutex
314
        mov     ecx, ehci_ep_mutex
315
        invoke  MutexInit
315
        invoke  MutexInit
316
        mov     ecx, ehci_gtd_mutex
316
        mov     ecx, ehci_gtd_mutex
317
        invoke  MutexInit
317
        invoke  MutexInit
318
        push    esi edi
318
        push    esi edi
319
        mov     esi, [USBHCFunc]
319
        mov     esi, [USBHCFunc]
320
        mov     edi, usbhc_api
320
        mov     edi, usbhc_api
321
        movi    ecx, sizeof.usbhc_func/4
321
        movi    ecx, sizeof.usbhc_func/4
322
        rep movsd
322
        rep movsd
323
        pop     edi esi
323
        pop     edi esi
324
        invoke  RegUSBDriver, ehci_name, 0, ehci_hardware_func
324
        invoke  RegUSBDriver, ehci_name, 0, ehci_hardware_func
325
.nothing:
325
.nothing:
326
        ret
326
        ret
327
endp
327
endp
328
 
328
 
329
; Controller-specific initialization function.
329
; Controller-specific initialization function.
330
; Called from usb_init_controller. Initializes the hardware and
330
; Called from usb_init_controller. Initializes the hardware and
331
; EHCI-specific parts of software structures.
331
; EHCI-specific parts of software structures.
332
; eax = pointer to ehci_controller to be initialized
332
; eax = pointer to ehci_controller to be initialized
333
; [ebp-4] = pcidevice
333
; [ebp-4] = pcidevice
334
proc ehci_init
334
proc ehci_init
335
; inherit some variables from the parent (usb_init_controller)
335
; inherit some variables from the parent (usb_init_controller)
336
.devfn   equ ebp - 4
336
.devfn   equ ebp - 4
337
.bus     equ ebp - 3
337
.bus     equ ebp - 3
338
; 1. Store pointer to ehci_controller for further use.
338
; 1. Store pointer to ehci_controller for further use.
339
        push    eax
339
        push    eax
340
        mov     edi, eax
340
        mov     edi, eax
341
        mov     esi, eax
341
        mov     esi, eax
342
; 2. Initialize ehci_controller.FrameList.
342
; 2. Initialize ehci_controller.FrameList.
343
; Note that FrameList is located in the beginning of ehci_controller,
343
; Note that FrameList is located in the beginning of ehci_controller,
344
; so esi and edi now point to ehci_controller.FrameList.
344
; so esi and edi now point to ehci_controller.FrameList.
345
; First 32 entries of FrameList contain physical addresses
345
; First 32 entries of FrameList contain physical addresses
346
; of first 32 Periodic static heads, further entries duplicate these.
346
; of first 32 Periodic static heads, further entries duplicate these.
347
; See the description of structures for full info.
347
; See the description of structures for full info.
348
; 2a. Get physical address of first static head.
348
; 2a. Get physical address of first static head.
349
; Note that 1) it is located in the beginning of a page
349
; Note that 1) it is located in the beginning of a page
350
; and 2) first 32 static heads fit in the same page,
350
; and 2) first 32 static heads fit in the same page,
351
; so one call to get_phys_addr without correction of lower 12 bits
351
; so one call to get_phys_addr without correction of lower 12 bits
352
; is sufficient.
352
; is sufficient.
353
if (ehci_controller.IntEDs / 0x1000) <> ((ehci_controller.IntEDs + 32 * sizeof.ehci_static_ep) / 0x1000)
353
if (ehci_controller.IntEDs / 0x1000) <> ((ehci_controller.IntEDs + 32 * sizeof.ehci_static_ep) / 0x1000)
354
.err assertion failed
354
.err assertion failed
355
end if
355
end if
356
if (ehci_controller.IntEDs mod 0x1000) <> 0
356
if (ehci_controller.IntEDs mod 0x1000) <> 0
357
.err assertion failed
357
.err assertion failed
358
end if
358
end if
359
        add     eax, ehci_controller.IntEDs
359
        add     eax, ehci_controller.IntEDs
360
        call    [GetPhysAddr]
360
        call    [GetPhysAddr]
361
; 2b. Fill first 32 entries.
361
; 2b. Fill first 32 entries.
362
        inc     eax
362
        inc     eax
363
        inc     eax     ; set Type to EHCI_TYPE_QH
363
        inc     eax     ; set Type to EHCI_TYPE_QH
364
        movi    ecx, 32
364
        movi    ecx, 32
365
        mov     edx, ecx
365
        mov     edx, ecx
366
@@:
366
@@:
367
        stosd
367
        stosd
368
        add     eax, sizeof.ehci_static_ep
368
        add     eax, sizeof.ehci_static_ep
369
        loop    @b
369
        loop    @b
370
; 2c. Fill the rest entries.
370
; 2c. Fill the rest entries.
371
        mov     ecx, 1024 - 32
371
        mov     ecx, 1024 - 32
372
        rep movsd
372
        rep movsd
373
; 3. Initialize static heads ehci_controller.*ED.
373
; 3. Initialize static heads ehci_controller.*ED.
374
; Use the loop over groups: first group consists of first 32 Periodic
374
; Use the loop over groups: first group consists of first 32 Periodic
375
; descriptors, next group consists of next 16 Periodic descriptors,
375
; descriptors, next group consists of next 16 Periodic descriptors,
376
; ..., last group consists of the last Periodic descriptor.
376
; ..., last group consists of the last Periodic descriptor.
377
; 3a. Prepare for the loop.
377
; 3a. Prepare for the loop.
378
; make esi point to the second group, other registers are already set.
378
; make esi point to the second group, other registers are already set.
379
        add     esi, 32*4 + 32*sizeof.ehci_static_ep
379
        add     esi, 32*4 + 32*sizeof.ehci_static_ep
380
; 3b. Loop over groups. On every iteration:
380
; 3b. Loop over groups. On every iteration:
381
; edx = size of group, edi = pointer to the current group,
381
; edx = size of group, edi = pointer to the current group,
382
; esi = pointer to the next group.
382
; esi = pointer to the next group.
383
.init_static_eds:
383
.init_static_eds:
384
; 3c. Get the size of next group.
384
; 3c. Get the size of next group.
385
        shr     edx, 1
385
        shr     edx, 1
386
; 3d. Exit the loop if there is no next group.
386
; 3d. Exit the loop if there is no next group.
387
        jz      .init_static_eds_done
387
        jz      .init_static_eds_done
388
; 3e. Initialize the first half of the current group.
388
; 3e. Initialize the first half of the current group.
389
; Advance edi to the second half.
389
; Advance edi to the second half.
390
        push    esi
390
        push    esi
391
        call    ehci_init_static_ep_group
391
        call    ehci_init_static_ep_group
392
        pop     esi
392
        pop     esi
393
; 3f. Initialize the second half of the current group
393
; 3f. Initialize the second half of the current group
394
; with the same values.
394
; with the same values.
395
; Advance edi to the next group, esi/eax to the next of the next group.
395
; Advance edi to the next group, esi/eax to the next of the next group.
396
        call    ehci_init_static_ep_group
396
        call    ehci_init_static_ep_group
397
        jmp     .init_static_eds
397
        jmp     .init_static_eds
398
.init_static_eds_done:
398
.init_static_eds_done:
399
; 3g. Initialize the last static head.
399
; 3g. Initialize the last static head.
400
        xor     esi, esi
400
        xor     esi, esi
401
        call    ehci_init_static_endpoint
401
        call    ehci_init_static_endpoint
402
; While we are here, initialize StopQueueTD.
402
; While we are here, initialize StopQueueTD.
403
if (ehci_controller.StopQueueTD <> ehci_controller.IntEDs + 63 * sizeof.ehci_static_ep)
403
if (ehci_controller.StopQueueTD <> ehci_controller.IntEDs + 63 * sizeof.ehci_static_ep)
404
.err assertion failed
404
.err assertion failed
405
end if
405
end if
406
        inc     [edi+ehci_hardware_td.NextTD]   ; 0 -> 1
406
        inc     [edi+ehci_hardware_td.NextTD]   ; 0 -> 1
407
        inc     [edi+ehci_hardware_td.AlternateNextTD]  ; 0 -> 1
407
        inc     [edi+ehci_hardware_td.AlternateNextTD]  ; 0 -> 1
408
; leave other fields as zero, including Active bit
408
; leave other fields as zero, including Active bit
409
; 3i. Initialize the head of Control list.
409
; 3i. Initialize the head of Control list.
410
        add     edi, ehci_controller.ControlDelta
410
        add     edi, ehci_controller.ControlDelta
411
        lea     esi, [edi+sizeof.ehci_static_ep]
411
        lea     esi, [edi+sizeof.ehci_static_ep]
412
        call    ehci_init_static_endpoint
412
        call    ehci_init_static_endpoint
413
        or      byte [edi-sizeof.ehci_static_ep+ehci_static_ep.Token+1], 80h
413
        or      byte [edi-sizeof.ehci_static_ep+ehci_static_ep.Token+1], 80h
414
; 3j. Initialize the head of Bulk list.
414
; 3j. Initialize the head of Bulk list.
415
        sub     esi, sizeof.ehci_static_ep
415
        sub     esi, sizeof.ehci_static_ep
416
        call    ehci_init_static_endpoint
416
        call    ehci_init_static_endpoint
417
; 4. Create a virtual memory area to talk with the controller.
417
; 4. Create a virtual memory area to talk with the controller.
418
; 4a. Enable memory & bus master access.
418
; 4a. Enable memory & bus master access.
419
        invoke  PciRead16, dword [.bus], dword [.devfn], 4
419
        invoke  PciRead16, dword [.bus], dword [.devfn], 4
420
        or      al, 6
420
        or      al, 6
421
        invoke  PciWrite16, dword [.bus], dword [.devfn], 4, eax
421
        invoke  PciWrite16, dword [.bus], dword [.devfn], 4, eax
422
; 4b. Read memory base address.
422
; 4b. Read memory base address.
423
        invoke  PciRead32, dword [.bus], dword [.devfn], 10h
423
        invoke  PciRead32, dword [.bus], dword [.devfn], 10h
424
;       DEBUGF 1,'K : phys MMIO %x\n',eax
424
;       DEBUGF 1,'K : phys MMIO %x\n',eax
425
        and     al, not 0Fh
425
        and     al, not 0Fh
426
; 4c. Create mapping for physical memory. 200h bytes are always sufficient.
426
; 4c. Create mapping for physical memory. 200h bytes are always sufficient.
427
        invoke  MapIoMem, eax, 200h, PG_SW+PG_NOCACHE
427
        invoke  MapIoMem, eax, 200h, PG_SW+PG_NOCACHE
428
        test    eax, eax
428
        test    eax, eax
429
        jz      .fail
429
        jz      .fail
430
;       DEBUGF 1,'K : MMIO %x\n',eax
430
;       DEBUGF 1,'K : MMIO %x\n',eax
431
if ehci_controller.MMIOBase1 <> ehci_controller.BulkED + sizeof.ehci_static_ep
431
if ehci_controller.MMIOBase1 <> ehci_controller.BulkED + sizeof.ehci_static_ep
432
.err assertion failed
432
.err assertion failed
433
end if
433
end if
434
        stosd   ; fill ehci_controller.MMIOBase1
434
        stosd   ; fill ehci_controller.MMIOBase1
435
; 5. Read basic parameters of the controller.
435
; 5. Read basic parameters of the controller.
436
; 5a. Structural parameters.
436
; 5a. Structural parameters.
437
        mov     ebx, [eax+EhciStructParamsReg]
437
        mov     ebx, [eax+EhciStructParamsReg]
438
; 5b. Port routing rules.
438
; 5b. Port routing rules.
439
; If bit 7 in HCSPARAMS is set, read and unpack EhciPortRouteReg.
439
; If bit 7 in HCSPARAMS is set, read and unpack EhciPortRouteReg.
440
; Otherwise, bits 11:8 are N_PCC = number of ports per companion,
440
; Otherwise, bits 11:8 are N_PCC = number of ports per companion,
441
; bits 15:12 are number of companions, maybe zero,
441
; bits 15:12 are number of companions, maybe zero,
442
; first N_PCC ports are routed to the first companion and so on.
442
; first N_PCC ports are routed to the first companion and so on.
443
        xor     esi, esi
443
        xor     esi, esi
444
        test    bl, bl
444
        test    bl, bl
445
        js      .read_routes
445
        js      .read_routes
446
        test    bh, 0x0F
446
        test    bh, 0x0F
447
        jz      .no_companions
447
        jz      .no_companions
448
        test    bh, 0xF0
448
        test    bh, 0xF0
449
        jz      .no_companions
449
        jz      .no_companions
450
        xor     edx, edx
450
        xor     edx, edx
451
.fill_routes:
451
.fill_routes:
452
        movzx   ecx, bh
452
        movzx   ecx, bh
453
        and     ecx, 15
453
        and     ecx, 15
454
@@:
454
@@:
455
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl
455
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl
456
        inc     esi
456
        inc     esi
457
        cmp     esi, 16
457
        cmp     esi, 16
458
        jz      .routes_filled
458
        jz      .routes_filled
459
        dec     ecx
459
        dec     ecx
460
        jnz     @b
460
        jnz     @b
461
        movzx   ecx, bh
461
        movzx   ecx, bh
462
        shr     ecx, 4
462
        shr     ecx, 4
463
        inc     edx
463
        inc     edx
464
        cmp     edx, ecx
464
        cmp     edx, ecx
465
        jb      .fill_routes
465
        jb      .fill_routes
466
.no_companions:
466
.no_companions:
467
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], 0xFF
467
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], 0xFF
468
        inc     esi
468
        inc     esi
469
        cmp     esi, 16
469
        cmp     esi, 16
470
        jnz     .no_companions
470
        jnz     .no_companions
471
        jmp     .routes_filled
471
        jmp     .routes_filled
472
.read_routes:
472
.read_routes:
473
rept 2 counter
473
rept 2 counter
474
{
474
{
475
        mov     ecx, [eax+EhciPortRouteReg+(counter-1)*4]
475
        mov     ecx, [eax+EhciPortRouteReg+(counter-1)*4]
476
@@:
476
@@:
477
        mov     edx, ecx
477
        mov     edx, ecx
478
        shr     ecx, 4
478
        shr     ecx, 4
479
        and     edx, 15
479
        and     edx, 15
480
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl
480
        mov     byte [edi+esi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)], dl
481
        inc     esi
481
        inc     esi
482
        cmp     esi, 8*counter
482
        cmp     esi, 8*counter
483
        jnz     @b
483
        jnz     @b
484
}
484
}
485
.routes_filled:
485
.routes_filled:
486
;        DEBUGF 1,'K : EhciPortRouteReg: %x %x\n',[eax+EhciPortRouteReg],[eax+EhciPortRouteReg+4]
486
;        DEBUGF 1,'K : EhciPortRouteReg: %x %x\n',[eax+EhciPortRouteReg],[eax+EhciPortRouteReg+4]
487
;        DEBUGF 1,'K : routes:\nK : '
487
;        DEBUGF 1,'K : routes:\nK : '
488
;rept 8 counter
488
;rept 8 counter
489
;{
489
;{
490
;        DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)+counter-1]:2
490
;        DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes-(ehci_controller.MMIOBase1+4)+counter-1]:2
491
;}
491
;}
492
;        DEBUGF 1,'\nK : '
492
;        DEBUGF 1,'\nK : '
493
;rept 8 counter
493
;rept 8 counter
494
;{
494
;{
495
;        DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes+8-(ehci_controller.MMIOBase1+4)+counter-1]:2
495
;        DEBUGF 1,' %x',[edi+ehci_controller.PortRoutes+8-(ehci_controller.MMIOBase1+4)+counter-1]:2
496
;}
496
;}
497
;        DEBUGF 1,'\n'
497
;        DEBUGF 1,'\n'
498
        movzx   ecx, byte [eax+EhciCapLengthReg]
498
        movzx   ecx, byte [eax+EhciCapLengthReg]
499
        mov     edx, [eax+EhciCapParamsReg]
499
        mov     edx, [eax+EhciCapParamsReg]
500
        add     eax, ecx
500
        add     eax, ecx
501
if ehci_controller.MMIOBase2 <> ehci_controller.MMIOBase1 + 4
501
if ehci_controller.MMIOBase2 <> ehci_controller.MMIOBase1 + 4
502
.err assertion failed
502
.err assertion failed
503
end if
503
end if
504
        stosd   ; fill ehci_controller.MMIOBase2
504
        stosd   ; fill ehci_controller.MMIOBase2
505
if ehci_controller.StructuralParams <> ehci_controller.MMIOBase2 + 4
505
if ehci_controller.StructuralParams <> ehci_controller.MMIOBase2 + 4
506
.err assertion failed
506
.err assertion failed
507
end if
507
end if
508
if ehci_controller.CapabilityParams <> ehci_controller.StructuralParams + 4
508
if ehci_controller.CapabilityParams <> ehci_controller.StructuralParams + 4
509
.err assertion failed
509
.err assertion failed
510
end if
510
end if
511
        mov     [edi], ebx      ; fill ehci_controller.StructuralParams
511
        mov     [edi], ebx      ; fill ehci_controller.StructuralParams
512
        mov     [edi+4], edx    ; fill ehci_controller.CapabilityParams
512
        mov     [edi+4], edx    ; fill ehci_controller.CapabilityParams
513
        DEBUGF 1,'K : HCSPARAMS=%x, HCCPARAMS=%x\n',ebx,edx
513
        DEBUGF 1,'K : HCSPARAMS=%x, HCCPARAMS=%x\n',ebx,edx
514
        and     ebx, 15
514
        and     ebx, 15
515
        mov     [edi+usb_controller.NumPorts+sizeof.ehci_controller-ehci_controller.StructuralParams], ebx
515
        mov     [edi+usb_controller.NumPorts+sizeof.ehci_controller-ehci_controller.StructuralParams], ebx
516
        mov     edi, eax
516
        mov     edi, eax
517
; now edi = MMIOBase2
517
; now edi = MMIOBase2
518
; 6. Transfer the controller to a known state.
518
; 6. Transfer the controller to a known state.
519
; 6b. Stop the controller if it is running.
519
; 6b. Stop the controller if it is running.
520
        movi    ecx, 10
520
        movi    ecx, 10
521
        test    dword [edi+EhciStatusReg], 1 shl 12
521
        test    dword [edi+EhciStatusReg], 1 shl 12
522
        jnz     .stopped
522
        jnz     .stopped
523
        and     dword [edi+EhciCommandReg], not 1
523
        and     dword [edi+EhciCommandReg], not 1
524
@@:
524
@@:
525
        movi    esi, 1
525
        movi    esi, 1
526
        invoke  Sleep
526
        invoke  Sleep
527
        test    dword [edi+EhciStatusReg], 1 shl 12
527
        test    dword [edi+EhciStatusReg], 1 shl 12
528
        jnz     .stopped
528
        jnz     .stopped
529
        loop    @b
529
        loop    @b
530
        dbgstr 'Failed to stop EHCI controller'
530
        dbgstr 'Failed to stop EHCI controller'
531
        jmp     .fail_unmap
531
        jmp     .fail_unmap
532
.stopped:
532
.stopped:
533
; 6c. Reset the controller. Wait up to 50 ms checking status every 1 ms.
533
; 6c. Reset the controller. Wait up to 50 ms checking status every 1 ms.
534
        or      dword [edi+EhciCommandReg], 2
534
        or      dword [edi+EhciCommandReg], 2
535
        movi    ecx, 50
535
        movi    ecx, 50
536
@@:
536
@@:
537
        movi    esi, 1
537
        movi    esi, 1
538
        invoke  Sleep
538
        invoke  Sleep
539
        test    dword [edi+EhciCommandReg], 2
539
        test    dword [edi+EhciCommandReg], 2
540
        jz      .reset_ok
540
        jz      .reset_ok
541
        loop    @b
541
        loop    @b
542
        dbgstr 'Failed to reset EHCI controller'
542
        dbgstr 'Failed to reset EHCI controller'
543
        jmp     .fail_unmap
543
        jmp     .fail_unmap
544
.reset_ok:
544
.reset_ok:
545
; 7. Configure the controller.
545
; 7. Configure the controller.
546
        pop     esi     ; restore the pointer saved at step 1
546
        pop     esi     ; restore the pointer saved at step 1
547
        add     esi, sizeof.ehci_controller
547
        add     esi, sizeof.ehci_controller
548
; 7a. If the controller is 64-bit, say to it that all structures are located
548
; 7a. If the controller is 64-bit, say to it that all structures are located
549
; in first 4G.
549
; in first 4G.
550
        test    byte [esi+ehci_controller.CapabilityParams-sizeof.ehci_controller], 1
550
        test    byte [esi+ehci_controller.CapabilityParams-sizeof.ehci_controller], 1
551
        jz      @f
551
        jz      @f
552
        mov     dword [edi+EhciCtrlDataSegReg], 0
552
        mov     dword [edi+EhciCtrlDataSegReg], 0
553
@@:
553
@@:
554
; 7b. Hook interrupt and enable appropriate interrupt sources.
554
; 7b. Hook interrupt and enable appropriate interrupt sources.
555
        invoke  PciRead8, dword [.bus], dword [.devfn], 3Ch
555
        invoke  PciRead8, dword [.bus], dword [.devfn], 3Ch
556
; al = IRQ
556
; al = IRQ
557
;        DEBUGF 1,'K : attaching to IRQ %x\n',al
557
;        DEBUGF 1,'K : attaching to IRQ %x\n',al
558
        movzx   eax, al
558
        movzx   eax, al
559
        invoke  AttachIntHandler, eax, ehci_irq, esi
559
        invoke  AttachIntHandler, eax, ehci_irq, esi
560
;       mov     dword [edi+EhciStatusReg], 111111b      ; clear status
560
;       mov     dword [edi+EhciStatusReg], 111111b      ; clear status
561
; disable Frame List Rollover interrupt, enable all other sources
561
; disable Frame List Rollover interrupt, enable all other sources
562
        mov     dword [edi+EhciInterruptReg], 110111b
562
        mov     dword [edi+EhciInterruptReg], 110111b
563
; 7c. Inform the controller of the address of periodic lists head.
563
; 7c. Inform the controller of the address of periodic lists head.
564
        lea     eax, [esi-sizeof.ehci_controller]
564
        lea     eax, [esi-sizeof.ehci_controller]
565
        invoke  GetPhysAddr
565
        invoke  GetPhysAddr
566
        mov     dword [edi+EhciPeriodicListReg], eax
566
        mov     dword [edi+EhciPeriodicListReg], eax
567
; 7d. Inform the controller of the address of asynchronous lists head.
567
; 7d. Inform the controller of the address of asynchronous lists head.
568
        lea     eax, [esi+ehci_controller.ControlED-sizeof.ehci_controller]
568
        lea     eax, [esi+ehci_controller.ControlED-sizeof.ehci_controller]
569
        invoke  GetPhysAddr
569
        invoke  GetPhysAddr
570
        mov     dword [edi+EhciAsyncListReg], eax
570
        mov     dword [edi+EhciAsyncListReg], eax
571
; 7e. Configure operational details and run the controller.
571
; 7e. Configure operational details and run the controller.
572
        mov     dword [edi+EhciCommandReg], \
572
        mov     dword [edi+EhciCommandReg], \
573
                (1 shl 16) + \ ; interrupt threshold = 1 microframe = 0.125ms
573
                (1 shl 16) + \ ; interrupt threshold = 1 microframe = 0.125ms
574
                (0 shl 11) + \ ; disable Async Park Mode
574
                (0 shl 11) + \ ; disable Async Park Mode
575
                (0 shl 8) +  \ ; zero Async Park Mode Count
575
                (0 shl 8) +  \ ; zero Async Park Mode Count
576
                (1 shl 5) +  \ ; Async Schedule Enable
576
                (1 shl 5) +  \ ; Async Schedule Enable
577
                (1 shl 4) +  \ ; Periodic Schedule Enable
577
                (1 shl 4) +  \ ; Periodic Schedule Enable
578
                (0 shl 2) +  \ ; 1024 elements in FrameList
578
                (0 shl 2) +  \ ; 1024 elements in FrameList
579
                1              ; Run
579
                1              ; Run
580
; 7f. Route all ports to this controller, not companion controllers.
580
; 7f. Route all ports to this controller, not companion controllers.
581
        mov     dword [edi+EhciConfigFlagReg], 1
581
        mov     dword [edi+EhciConfigFlagReg], 1
582
        DEBUGF 1,'K : EHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts]
582
        DEBUGF 1,'K : EHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts]
583
; 8. Apply port power, if needed, and disable all ports.
583
; 8. Apply port power, if needed, and disable all ports.
584
        xor     ecx, ecx
584
        xor     ecx, ecx
585
@@:
585
@@:
586
        mov     dword [edi+EhciPortsReg+ecx*4], 1000h   ; Port Power enabled, all other bits disabled
586
        mov     dword [edi+EhciPortsReg+ecx*4], 1000h   ; Port Power enabled, all other bits disabled
587
        inc     ecx
587
        inc     ecx
588
        cmp     ecx, [esi+usb_controller.NumPorts]
588
        cmp     ecx, [esi+usb_controller.NumPorts]
589
        jb      @b
589
        jb      @b
590
        test    byte [esi+ehci_controller.StructuralParams-sizeof.ehci_controller], 10h
590
        test    byte [esi+ehci_controller.StructuralParams-sizeof.ehci_controller], 10h
591
        jz      @f
591
        jz      @f
592
        push    esi
592
        push    esi
593
        movi    esi, 20
593
        movi    esi, 20
594
        invoke  Sleep
594
        invoke  Sleep
595
        pop     esi
595
        pop     esi
596
@@:
596
@@:
597
; 9. Return pointer to usb_controller.
597
; 9. Return pointer to usb_controller.
598
        xchg    eax, esi
598
        xchg    eax, esi
599
        ret
599
        ret
600
; On error, pop the pointer saved at step 1 and return zero.
600
; On error, pop the pointer saved at step 1 and return zero.
601
; Note that the main code branch restores the stack at step 7 and never fails
601
; Note that the main code branch restores the stack at step 7 and never fails
602
; after step 7.
602
; after step 7.
603
.fail_unmap:
603
.fail_unmap:
604
        pop     eax
604
        pop     eax
605
        push    eax
605
        push    eax
606
        invoke  FreeKernelSpace, [eax+ehci_controller.MMIOBase1]
606
        invoke  FreeKernelSpace, [eax+ehci_controller.MMIOBase1]
607
.fail:
607
.fail:
608
        pop     ecx
608
        pop     ecx
609
        xor     eax, eax
609
        xor     eax, eax
610
        ret
610
        ret
611
endp
611
endp
612
 
612
 
613
; Helper procedure for step 3 of ehci_init, see comments there.
613
; Helper procedure for step 3 of ehci_init, see comments there.
614
; Initializes the static head of one list.
614
; Initializes the static head of one list.
615
; esi = pointer to the "next" list, edi = pointer to head to initialize.
615
; esi = pointer to the "next" list, edi = pointer to head to initialize.
616
; Advances edi to the next head, keeps esi.
616
; Advances edi to the next head, keeps esi.
617
proc ehci_init_static_endpoint
617
proc ehci_init_static_endpoint
618
        xor     eax, eax
618
        xor     eax, eax
619
        inc     eax     ; set Terminate bit
619
        inc     eax     ; set Terminate bit
620
        mov     [edi+ehci_static_ep.NextTD], eax
620
        mov     [edi+ehci_static_ep.NextTD], eax
621
        mov     [edi+ehci_static_ep.AlternateNextTD], eax
621
        mov     [edi+ehci_static_ep.AlternateNextTD], eax
622
        test    esi, esi
622
        test    esi, esi
623
        jz      @f
623
        jz      @f
624
        mov     eax, esi
624
        mov     eax, esi
625
        invoke  GetPhysAddr
625
        invoke  GetPhysAddr
626
        inc     eax
626
        inc     eax
627
        inc     eax     ; set Type to EHCI_TYPE_QH
627
        inc     eax     ; set Type to EHCI_TYPE_QH
628
@@:
628
@@:
629
        mov     [edi+ehci_static_ep.NextQH], eax
629
        mov     [edi+ehci_static_ep.NextQH], eax
630
        mov     [edi+ehci_static_ep.NextList], esi
630
        mov     [edi+ehci_static_ep.NextList], esi
631
        mov     byte [edi+ehci_static_ep.OverlayToken], 1 shl 6 ; halted
631
        mov     byte [edi+ehci_static_ep.OverlayToken], 1 shl 6 ; halted
632
        add     edi, ehci_static_ep.SoftwarePart
632
        add     edi, ehci_static_ep.SoftwarePart
633
        mov     eax, [USBHCFunc]
633
        mov     eax, [USBHCFunc]
634
        call    [eax+usbhc_func.usb_init_static_endpoint]
634
        call    [eax+usbhc_func.usb_init_static_endpoint]
635
        add     edi, sizeof.ehci_static_ep - ehci_static_ep.SoftwarePart
635
        add     edi, sizeof.ehci_static_ep - ehci_static_ep.SoftwarePart
636
        ret
636
        ret
637
endp
637
endp
638
 
638
 
639
; Helper procedure for step 3 of ehci_init, see comments there.
639
; Helper procedure for step 3 of ehci_init, see comments there.
640
; Initializes one half of group of static heads.
640
; Initializes one half of group of static heads.
641
; edx = size of the next group = half of size of the group,
641
; edx = size of the next group = half of size of the group,
642
; edi = pointer to the group, esi = pointer to the next group.
642
; edi = pointer to the group, esi = pointer to the next group.
643
; Advances esi, edi to next group, keeps edx.
643
; Advances esi, edi to next group, keeps edx.
644
proc ehci_init_static_ep_group
644
proc ehci_init_static_ep_group
645
        push    edx
645
        push    edx
646
@@:
646
@@:
647
        call    ehci_init_static_endpoint
647
        call    ehci_init_static_endpoint
648
        add     esi, sizeof.ehci_static_ep
648
        add     esi, sizeof.ehci_static_ep
649
        dec     edx
649
        dec     edx
650
        jnz     @b
650
        jnz     @b
651
        pop     edx
651
        pop     edx
652
        ret
652
        ret
653
endp
653
endp
654
 
654
 
655
; Controller-specific pre-initialization function: take ownership from BIOS.
655
; Controller-specific pre-initialization function: take ownership from BIOS.
656
; Some BIOSes, although not all of them, use USB controllers themselves
656
; Some BIOSes, although not all of them, use USB controllers themselves
657
; to support USB flash drives. In this case,
657
; to support USB flash drives. In this case,
658
; we must notify the BIOS that we don't need that emulation and know how to
658
; we must notify the BIOS that we don't need that emulation and know how to
659
; deal with USB devices.
659
; deal with USB devices.
660
proc ehci_kickoff_bios
660
proc ehci_kickoff_bios
661
; 1. Get the physical address of MMIO registers.
661
; 1. Get the physical address of MMIO registers.
662
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], 10h
662
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], 10h
663
        and     al, not 0Fh
663
        and     al, not 0Fh
664
; 2. Create mapping for physical memory. 200h bytes are always sufficient.
664
; 2. Create mapping for physical memory. 200h bytes are always sufficient.
665
        invoke  MapIoMem, eax, 200h, PG_SW+PG_NOCACHE
665
        invoke  MapIoMem, eax, 200h, PG_SW+PG_NOCACHE
666
        test    eax, eax
666
        test    eax, eax
667
        jz      .nothing
667
        jz      .nothing
668
        push    eax     ; push argument for step 8
668
        push    eax     ; push argument for step 8
669
; 3. Some BIOSes enable controller interrupts as a result of giving
669
; 3. Some BIOSes enable controller interrupts as a result of giving
670
; controller away. At this point the system knows nothing about how to serve
670
; controller away. At this point the system knows nothing about how to serve
671
; EHCI interrupts, so such an interrupt will send the system into an infinite
671
; EHCI interrupts, so such an interrupt will send the system into an infinite
672
; loop handling the same IRQ again and again. Thus, we need to block EHCI
672
; loop handling the same IRQ again and again. Thus, we need to block EHCI
673
; interrupts. We can't do this at the controller level until step 5,
673
; interrupts. We can't do this at the controller level until step 5,
674
; because the controller is currently owned by BIOS, so we block all hardware
674
; because the controller is currently owned by BIOS, so we block all hardware
675
; interrupts on this processor until step 5.
675
; interrupts on this processor until step 5.
676
        pushf
676
        pushf
677
        cli
677
        cli
678
; 4. Take the ownership over the controller.
678
; 4. Take the ownership over the controller.
679
; 4a. Locate take-ownership capability in the PCI configuration space.
679
; 4a. Locate take-ownership capability in the PCI configuration space.
680
; Limit the loop with 100h iterations; since the entire configuration space is
680
; Limit the loop with 100h iterations; since the entire configuration space is
681
; 100h bytes long, hitting this number of iterations means that something is
681
; 100h bytes long, hitting this number of iterations means that something is
682
; corrupted.
682
; corrupted.
683
; Use a value from MMIO as a starting point.
683
; Use a value from MMIO as a starting point.
684
        mov     edx, [eax+EhciCapParamsReg]
684
        mov     edx, [eax+EhciCapParamsReg]
685
        movzx   edi, byte [eax+EhciCapLengthReg]
685
        movzx   edi, byte [eax+EhciCapLengthReg]
686
        add     edi, eax
686
        add     edi, eax
687
        push    0
687
        push    0
688
        mov     bl, dh          ; get Extended Capabilities Pointer
688
        mov     bl, dh          ; get Extended Capabilities Pointer
689
        test    bl, bl
689
        test    bl, bl
690
        jz      .has_ownership2
690
        jz      .has_ownership2
691
        cmp     bl, 40h
691
        cmp     bl, 40h
692
        jb      .no_capability
692
        jb      .no_capability
693
.look_bios_handoff:
693
.look_bios_handoff:
694
        test    bl, 3
694
        test    bl, 3
695
        jnz     .no_capability
695
        jnz     .no_capability
696
; In each iteration, read the current dword,
696
; In each iteration, read the current dword,
697
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
697
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
698
; check, whether the capability ID is take-ownership ID = 1,
698
; check, whether the capability ID is take-ownership ID = 1,
699
        cmp     al, 1
699
        cmp     al, 1
700
        jz      .found_bios_handoff
700
        jz      .found_bios_handoff
701
; if not, advance to next-capability link and continue loop.
701
; if not, advance to next-capability link and continue loop.
702
        dec     byte [esp]
702
        dec     byte [esp]
703
        jz      .no_capability
703
        jz      .no_capability
704
        mov     bl, ah
704
        mov     bl, ah
705
        cmp     bl, 40h
705
        cmp     bl, 40h
706
        jae     .look_bios_handoff
706
        jae     .look_bios_handoff
707
.no_capability:
707
.no_capability:
708
        dbgstr 'warning: cannot locate take-ownership capability'
708
        dbgstr 'warning: cannot locate take-ownership capability'
709
        jmp     .has_ownership2
709
        jmp     .has_ownership2
710
.found_bios_handoff:
710
.found_bios_handoff:
711
; 4b. Check whether BIOS has ownership.
711
; 4b. Check whether BIOS has ownership.
712
; Some BIOSes release ownership before loading OS, but forget to unwatch for
712
; Some BIOSes release ownership before loading OS, but forget to unwatch for
713
; change-ownership requests; they cannot handle ownership request, so
713
; change-ownership requests; they cannot handle ownership request, so
714
; such a request sends the system into infinite loop of handling the same SMI
714
; such a request sends the system into infinite loop of handling the same SMI
715
; over and over. Avoid this.
715
; over and over. Avoid this.
716
        inc     ebx
716
        inc     ebx
717
        inc     ebx
717
        inc     ebx
718
        test    eax, 0x10000
718
        test    eax, 0x10000
719
        jz      .has_ownership
719
        jz      .has_ownership
720
; 4c. Request ownership.
720
; 4c. Request ownership.
721
        inc     ebx
721
        inc     ebx
722
        invoke  PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 1
722
        invoke  PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 1
723
; 4d. Some BIOSes set ownership flag, but forget to watch for change-ownership
723
; 4d. Some BIOSes set ownership flag, but forget to watch for change-ownership
724
; requests; if so, there is no sense in waiting.
724
; requests; if so, there is no sense in waiting.
725
        inc     ebx
725
        inc     ebx
726
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
726
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
727
        dec     ebx
727
        dec     ebx
728
        dec     ebx
728
        dec     ebx
729
        test    ah, 20h
729
        test    ah, 20h
730
        jz      .force_ownership
730
        jz      .force_ownership
731
; 4e. Wait for result no more than 1 s, checking for status every 1 ms.
731
; 4e. Wait for result no more than 1 s, checking for status every 1 ms.
732
; If successful, go to 5.
732
; If successful, go to 5.
733
        mov     dword [esp], 1000
733
        mov     dword [esp], 1000
734
@@:
734
@@:
735
        invoke  PciRead8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
735
        invoke  PciRead8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
736
        test    al, 1
736
        test    al, 1
737
        jz      .has_ownership
737
        jz      .has_ownership
738
        push    esi
738
        push    esi
739
        movi    esi, 1
739
        movi    esi, 1
740
        invoke  Sleep
740
        invoke  Sleep
741
        pop     esi
741
        pop     esi
742
        dec     dword [esp]
742
        dec     dword [esp]
743
        jnz     @b
743
        jnz     @b
744
        dbgstr  'warning: taking EHCI ownership from BIOS timeout'
744
        dbgstr  'warning: taking EHCI ownership from BIOS timeout'
745
.force_ownership:
745
.force_ownership:
746
; 4f. BIOS has not responded within the timeout.
746
; 4f. BIOS has not responded within the timeout.
747
; Let's just clear BIOS ownership flag and hope that everything will be ok.
747
; Let's just clear BIOS ownership flag and hope that everything will be ok.
748
        invoke  PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 0
748
        invoke  PciWrite8, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, 0
749
.has_ownership:
749
.has_ownership:
750
; 5. Just in case clear all SMI event sources except change-ownership.
750
; 5. Just in case clear all SMI event sources except change-ownership.
751
        dbgstr 'has_ownership'
751
        dbgstr 'has_ownership'
752
        inc     ebx
752
        inc     ebx
753
        inc     ebx
753
        inc     ebx
754
        invoke  PciRead16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
754
        invoke  PciRead16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx
755
        and     ax, 2000h
755
        and     ax, 2000h
756
        invoke  PciWrite16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, eax
756
        invoke  PciWrite16, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], ebx, eax
757
.has_ownership2:
757
.has_ownership2:
758
        pop     ecx
758
        pop     ecx
759
; 6. Disable all controller interrupts until the system will be ready to
759
; 6. Disable all controller interrupts until the system will be ready to
760
; process them.
760
; process them.
761
        mov     dword [edi+EhciInterruptReg], 0
761
        mov     dword [edi+EhciInterruptReg], 0
762
; 7. Now we can unblock interrupts in the processor.
762
; 7. Now we can unblock interrupts in the processor.
763
        popf
763
        popf
764
; 8. Release memory mapping created in step 2 and return.
764
; 8. Release memory mapping created in step 2 and return.
765
        invoke  FreeKernelSpace
765
        invoke  FreeKernelSpace
766
.nothing:
766
.nothing:
767
        ret
767
        ret
768
endp
768
endp
769
 
769
 
770
; IRQ handler for EHCI controllers.
770
; IRQ handler for EHCI controllers.
771
ehci_irq.noint:
771
ehci_irq.noint:
772
        spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock]
772
        spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock]
773
; Not our interrupt: restore registers and return zero.
773
; Not our interrupt: restore registers and return zero.
774
        xor     eax, eax
774
        xor     eax, eax
775
        pop     edi esi ebx
775
        pop     edi esi ebx
776
        ret
776
        ret
777
 
777
 
778
proc ehci_irq
778
proc ehci_irq
779
        push    ebx esi edi     ; save registers to be cdecl
779
        push    ebx esi edi     ; save registers to be cdecl
780
virtual at esp
780
virtual at esp
781
        rd      3       ; saved registers
781
        rd      3       ; saved registers
782
        dd      ?       ; return address
782
        dd      ?       ; return address
783
.controller     dd      ?
783
.controller     dd      ?
784
end virtual
784
end virtual
785
; 1. ebx will hold whether some deferred processing is needed,
785
; 1. ebx will hold whether some deferred processing is needed,
786
; that cannot be done from the interrupt handler. Initialize to zero.
786
; that cannot be done from the interrupt handler. Initialize to zero.
787
        xor     ebx, ebx
787
        xor     ebx, ebx
788
; 2. Get the mask of events which should be processed.
788
; 2. Get the mask of events which should be processed.
789
        mov     esi, [.controller]
789
        mov     esi, [.controller]
790
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
790
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
791
        spin_lock_irqsave [esi+usb_controller.WaitSpinlock]
791
        spin_lock_irqsave [esi+usb_controller.WaitSpinlock]
792
        mov     eax, [edi+EhciStatusReg]
792
        mov     eax, [edi+EhciStatusReg]
793
; 3. Check whether that interrupt has been generated by our controller.
793
; 3. Check whether that interrupt has been generated by our controller.
794
; (One IRQ can be shared by several devices.)
794
; (One IRQ can be shared by several devices.)
795
        and     eax, [edi+EhciInterruptReg]
795
        and     eax, [edi+EhciInterruptReg]
796
        jz      .noint
796
        jz      .noint
797
; 4. Clear the events we know of.
797
; 4. Clear the events we know of.
798
; Note that this should be done before processing of events:
798
; Note that this should be done before processing of events:
799
; new events could arise while we are processing those, this way we won't lose
799
; new events could arise while we are processing those, this way we won't lose
800
; them (the controller would generate another interrupt after completion
800
; them (the controller would generate another interrupt after completion
801
; of this one).
801
; of this one).
802
;       DEBUGF 1,'K : EHCI interrupt: status = %x\n',eax
802
;       DEBUGF 1,'K : EHCI interrupt: status = %x\n',eax
803
        mov     [edi+EhciStatusReg], eax
803
        mov     [edi+EhciStatusReg], eax
804
; 5. Sanity check.
804
; 5. Sanity check.
805
        test    al, 10h
805
        test    al, 10h
806
        jz      @f
806
        jz      @f
807
        DEBUGF 1,'K : something terrible happened with EHCI %x (%x)\n',esi,al
807
        DEBUGF 1,'K : something terrible happened with EHCI %x (%x)\n',esi,al
808
@@:
808
@@:
809
; We can't do too much from an interrupt handler. Inform the processing thread
809
; We can't do too much from an interrupt handler. Inform the processing thread
810
; that it should perform appropriate actions.
810
; that it should perform appropriate actions.
811
        or      [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], eax
811
        or      [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], eax
812
        spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock]
812
        spin_unlock_irqrestore [esi+usb_controller.WaitSpinlock]
813
        inc     ebx
813
        inc     ebx
814
        invoke  usbhc_api.usb_wakeup_if_needed
814
        invoke  usbhc_api.usb_wakeup_if_needed
815
; 6. Interrupt processed; return non-zero.
815
; 6. Interrupt processed; return non-zero.
816
        mov     al, 1
816
        mov     al, 1
817
        pop     edi esi ebx     ; restore used registers to be cdecl
817
        pop     edi esi ebx     ; restore used registers to be cdecl
818
        ret
818
        ret
819
endp
819
endp
820
 
820
 
821
; This procedure is called from usb_set_address_callback
821
; This procedure is called from usb_set_address_callback
822
; and stores USB device address in the ehci_pipe structure.
822
; and stores USB device address in the ehci_pipe structure.
823
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
823
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
824
proc ehci_set_device_address
824
proc ehci_set_device_address
825
        mov     byte [ebx+ehci_pipe.Token-sizeof.ehci_pipe], cl
825
        mov     byte [ebx+ehci_pipe.Token-sizeof.ehci_pipe], cl
826
        jmp     [usbhc_api.usb_subscribe_control]
826
        jmp     [usbhc_api.usb_subscribe_control]
827
endp
827
endp
828
 
828
 
829
; This procedure returns USB device address from the ehci_pipe structure.
829
; This procedure returns USB device address from the ehci_pipe structure.
830
; in: esi -> usb_controller, ebx -> usb_pipe
830
; in: esi -> usb_controller, ebx -> usb_pipe
831
; out: eax = endpoint address
831
; out: eax = endpoint address
832
proc ehci_get_device_address
832
proc ehci_get_device_address
833
        mov     eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe]
833
        mov     eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe]
834
        and     eax, 7Fh
834
        and     eax, 7Fh
835
        ret
835
        ret
836
endp
836
endp
837
 
837
 
838
; This procedure is called from usb_set_address_callback
838
; This procedure is called from usb_set_address_callback
839
; if the device does not accept SET_ADDRESS command and needs
839
; if the device does not accept SET_ADDRESS command and needs
840
; to be disabled at the port level.
840
; to be disabled at the port level.
841
; in: esi -> usb_controller, ecx = port (zero-based)
841
; in: esi -> usb_controller, ecx = port (zero-based)
842
proc ehci_port_disable
842
proc ehci_port_disable
843
        mov     eax, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
843
        mov     eax, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
844
        and     dword [eax+EhciPortsReg+ecx*4], not (4 or 2Ah)
844
        and     dword [eax+EhciPortsReg+ecx*4], not (4 or 2Ah)
845
        ret
845
        ret
846
endp
846
endp
847
 
847
 
848
; This procedure is called from usb_get_descr8_callback when
848
; This procedure is called from usb_get_descr8_callback when
849
; the packet size for zero endpoint becomes known and
849
; the packet size for zero endpoint becomes known and
850
; stores the packet size in ehci_pipe structure.
850
; stores the packet size in ehci_pipe structure.
851
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
851
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
852
proc ehci_set_endpoint_packet_size
852
proc ehci_set_endpoint_packet_size
853
        mov     eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe]
853
        mov     eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe]
854
        and     eax, not (0x7FF shl 16)
854
        and     eax, not (0x7FF shl 16)
855
        shl     ecx, 16
855
        shl     ecx, 16
856
        or      eax, ecx
856
        or      eax, ecx
857
        mov     [ebx+ehci_pipe.Token-sizeof.ehci_pipe], eax
857
        mov     [ebx+ehci_pipe.Token-sizeof.ehci_pipe], eax
858
; Wait until hardware cache is evicted.
858
; Wait until hardware cache is evicted.
859
        jmp     [usbhc_api.usb_subscribe_control]
859
        jmp     [usbhc_api.usb_subscribe_control]
860
endp
860
endp
861
 
861
 
862
uglobal
862
uglobal
863
align 4
863
align 4
864
; Data for memory allocator, see memory.inc.
864
; Data for memory allocator, see memory.inc.
865
ehci_ep_first_page      dd      ?
865
ehci_ep_first_page      dd      ?
866
ehci_ep_mutex           MUTEX
866
ehci_ep_mutex           MUTEX
867
ehci_gtd_first_page     dd      ?
867
ehci_gtd_first_page     dd      ?
868
ehci_gtd_mutex          MUTEX
868
ehci_gtd_mutex          MUTEX
869
endg
869
endg
870
 
870
 
871
; This procedure allocates memory for pipe.
871
; This procedure allocates memory for pipe.
872
; Both hardware+software parts must be allocated, returns pointer to usb_pipe
872
; Both hardware+software parts must be allocated, returns pointer to usb_pipe
873
; (software part).
873
; (software part).
874
proc ehci_alloc_pipe
874
proc ehci_alloc_pipe
875
        push    ebx
875
        push    ebx
876
        mov     ebx, ehci_ep_mutex
876
        mov     ebx, ehci_ep_mutex
877
        invoke  usbhc_api.usb_allocate_common, (sizeof.ehci_pipe + sizeof.usb_pipe + 1Fh) and not 1Fh
877
        invoke  usbhc_api.usb_allocate_common, (sizeof.ehci_pipe + sizeof.usb_pipe + 1Fh) and not 1Fh
878
        test    eax, eax
878
        test    eax, eax
879
        jz      @f
879
        jz      @f
880
        add     eax, sizeof.ehci_pipe
880
        add     eax, sizeof.ehci_pipe
881
@@:
881
@@:
882
        pop     ebx
882
        pop     ebx
883
        ret
883
        ret
884
endp
884
endp
885
 
885
 
886
; This procedure frees memory for pipe allocated by ehci_alloc_pipe.
886
; This procedure frees memory for pipe allocated by ehci_alloc_pipe.
887
; void stdcall with one argument = pointer to usb_pipe.
887
; void stdcall with one argument = pointer to usb_pipe.
888
proc ehci_free_pipe
888
proc ehci_free_pipe
889
virtual at esp
889
virtual at esp
890
        dd      ?       ; return address
890
        dd      ?       ; return address
891
.ptr    dd      ?
891
.ptr    dd      ?
892
end virtual
892
end virtual
893
        sub     [.ptr], sizeof.ehci_pipe
893
        sub     [.ptr], sizeof.ehci_pipe
894
        jmp     [usbhc_api.usb_free_common]
894
        jmp     [usbhc_api.usb_free_common]
895
endp
895
endp
896
 
896
 
897
; This procedure is called from API usb_open_pipe and processes
897
; This procedure is called from API usb_open_pipe and processes
898
; the controller-specific part of this API. See docs.
898
; the controller-specific part of this API. See docs.
899
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
899
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
900
; esi -> usb_controller, eax -> usb_gtd for the first TD,
900
; esi -> usb_controller, eax -> usb_gtd for the first TD,
901
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
901
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
902
proc ehci_init_pipe
902
proc ehci_init_pipe
903
virtual at ebp+8
903
virtual at ebp+8
904
.config_pipe    dd      ?
904
.config_pipe    dd      ?
905
.endpoint       dd      ?
905
.endpoint       dd      ?
906
.maxpacket      dd      ?
906
.maxpacket      dd      ?
907
.type           dd      ?
907
.type           dd      ?
908
.interval       dd      ?
908
.interval       dd      ?
909
end virtual
909
end virtual
910
; 1. Zero all fields in the hardware part.
910
; 1. Zero all fields in the hardware part.
911
        push    eax ecx
911
        push    eax ecx
912
        sub     edi, sizeof.ehci_pipe
912
        sub     edi, sizeof.ehci_pipe
913
        xor     eax, eax
913
        xor     eax, eax
914
        movi    ecx, sizeof.ehci_pipe/4
914
        movi    ecx, sizeof.ehci_pipe/4
915
        rep stosd
915
        rep stosd
916
        pop     ecx eax
916
        pop     ecx eax
917
; 2. Setup PID in the first TD and make sure that the it is not active.
917
; 2. Setup PID in the first TD and make sure that the it is not active.
918
        xor     edx, edx
918
        xor     edx, edx
919
        test    byte [.endpoint], 80h
919
        test    byte [.endpoint], 80h
920
        setnz   dh
920
        setnz   dh
921
        mov     [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx
921
        mov     [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx
922
        mov     [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1
922
        mov     [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1
923
        mov     [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1
923
        mov     [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1
924
; 3. Store physical address of the first TD.
924
; 3. Store physical address of the first TD.
925
        sub     eax, sizeof.ehci_gtd
925
        sub     eax, sizeof.ehci_gtd
926
        call    [GetPhysAddr]
926
        call    [GetPhysAddr]
927
        mov     [edi+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
927
        mov     [edi+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
928
; 4. Fill ehci_pipe.Flags except for S- and C-masks.
928
; 4. Fill ehci_pipe.Flags except for S- and C-masks.
929
; Copy location from the config pipe.
929
; Copy location from the config pipe.
930
        mov     eax, [ecx+ehci_pipe.Flags-sizeof.ehci_pipe]
930
        mov     eax, [ecx+ehci_pipe.Flags-sizeof.ehci_pipe]
931
        and     eax, 3FFF0000h
931
        and     eax, 3FFF0000h
932
; Use 1 requests per microframe for control/bulk endpoints,
932
; Use 1 requests per microframe for control/bulk endpoints,
933
; use value from the endpoint descriptor for periodic endpoints
933
; use value from the endpoint descriptor for periodic endpoints
934
        movi    edx, 1
934
        movi    edx, 1
935
        test    [.type], 1
935
        test    [.type], 1
936
        jz      @f
936
        jz      @f
937
        mov     edx, [.maxpacket]
937
        mov     edx, [.maxpacket]
938
        shr     edx, 11
938
        shr     edx, 11
939
        inc     edx
939
        inc     edx
940
@@:
940
@@:
941
        shl     edx, 30
941
        shl     edx, 30
942
        or      eax, edx
942
        or      eax, edx
943
        mov     [edi+ehci_pipe.Flags-sizeof.ehci_pipe], eax
943
        mov     [edi+ehci_pipe.Flags-sizeof.ehci_pipe], eax
944
; 5. Fill ehci_pipe.Token.
944
; 5. Fill ehci_pipe.Token.
945
        mov     eax, [ecx+ehci_pipe.Token-sizeof.ehci_pipe]
945
        mov     eax, [ecx+ehci_pipe.Token-sizeof.ehci_pipe]
946
; copy following fields from the config pipe:
946
; copy following fields from the config pipe:
947
; DeviceAddress, EndpointSpeed, ControlEndpoint if new type is control
947
; DeviceAddress, EndpointSpeed, ControlEndpoint if new type is control
948
        mov     ecx, eax
948
        mov     ecx, eax
949
        and     eax, 307Fh
949
        and     eax, 307Fh
950
        and     ecx, 8000000h
950
        and     ecx, 8000000h
951
        or      ecx, 4000h
951
        or      ecx, 4000h
952
        mov     edx, [.endpoint]
952
        mov     edx, [.endpoint]
953
        and     edx, 15
953
        and     edx, 15
954
        shl     edx, 8
954
        shl     edx, 8
955
        or      eax, edx
955
        or      eax, edx
956
        mov     edx, [.maxpacket]
956
        mov     edx, [.maxpacket]
957
        shl     edx, 16
957
        shl     edx, 16
958
        or      eax, edx
958
        or      eax, edx
959
; for control endpoints, use DataToggle from TD, otherwise use DataToggle from QH
959
; for control endpoints, use DataToggle from TD, otherwise use DataToggle from QH
960
        cmp     [.type], CONTROL_PIPE
960
        cmp     [.type], CONTROL_PIPE
961
        jnz     @f
961
        jnz     @f
962
        or      eax, ecx
962
        or      eax, ecx
963
@@:
963
@@:
964
; for control/bulk USB2 endpoints, set NakCountReload to 4
964
; for control/bulk USB2 endpoints, set NakCountReload to 4
965
        test    eax, USB_SPEED_HS shl 12
965
        test    eax, USB_SPEED_HS shl 12
966
        jz      .nonak
966
        jz      .nonak
967
        cmp     [.type], CONTROL_PIPE
967
        cmp     [.type], CONTROL_PIPE
968
        jz      @f
968
        jz      @f
969
        cmp     [.type], BULK_PIPE
969
        cmp     [.type], BULK_PIPE
970
        jnz     .nonak
970
        jnz     .nonak
971
@@:
971
@@:
972
        or      eax, 40000000h
972
        or      eax, 40000000h
973
.nonak:
973
.nonak:
974
        mov     [edi+ehci_pipe.Token-sizeof.ehci_pipe], eax
974
        mov     [edi+ehci_pipe.Token-sizeof.ehci_pipe], eax
975
; 5. Select the corresponding list and insert to the list.
975
; 5. Select the corresponding list and insert to the list.
976
; 5a. Use Control list for control pipes, Bulk list for bulk pipes.
976
; 5a. Use Control list for control pipes, Bulk list for bulk pipes.
977
        lea     edx, [esi+ehci_controller.ControlED.SoftwarePart-sizeof.ehci_controller]
977
        lea     edx, [esi+ehci_controller.ControlED.SoftwarePart-sizeof.ehci_controller]
978
        cmp     [.type], BULK_PIPE
978
        cmp     [.type], BULK_PIPE
979
        jb      .insert ; control pipe
979
        jb      .insert ; control pipe
980
        lea     edx, [esi+ehci_controller.BulkED.SoftwarePart-sizeof.ehci_controller]
980
        lea     edx, [esi+ehci_controller.BulkED.SoftwarePart-sizeof.ehci_controller]
981
        jz      .insert ; bulk pipe
981
        jz      .insert ; bulk pipe
982
.interrupt_pipe:
982
.interrupt_pipe:
983
; 5b. For interrupt pipes, let the scheduler select the appropriate list
983
; 5b. For interrupt pipes, let the scheduler select the appropriate list
984
; and the appropriate microframe(s) (which goes to S-mask and C-mask)
984
; and the appropriate microframe(s) (which goes to S-mask and C-mask)
985
; based on the current bandwidth distribution and the requested bandwidth.
985
; based on the current bandwidth distribution and the requested bandwidth.
986
; There are two schedulers, one for high-speed devices,
986
; There are two schedulers, one for high-speed devices,
987
; another for split transactions.
987
; another for split transactions.
988
; This could fail if the requested bandwidth is not available;
988
; This could fail if the requested bandwidth is not available;
989
; if so, return an error.
989
; if so, return an error.
990
        test    word [edi+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh
990
        test    word [edi+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh
991
        jnz     .interrupt_tt
991
        jnz     .interrupt_tt
992
        call    ehci_select_hs_interrupt_list
992
        call    ehci_select_hs_interrupt_list
993
        jmp     .interrupt_common
993
        jmp     .interrupt_common
994
.interrupt_tt:
994
.interrupt_tt:
995
        call    ehci_select_tt_interrupt_list
995
        call    ehci_select_tt_interrupt_list
996
.interrupt_common:
996
.interrupt_common:
997
        test    edx, edx
997
        test    edx, edx
998
        jz      .return0
998
        jz      .return0
999
        mov     word [edi+ehci_pipe.Flags-sizeof.ehci_pipe], ax
999
        mov     word [edi+ehci_pipe.Flags-sizeof.ehci_pipe], ax
1000
.insert:
1000
.insert:
1001
        mov     [edi+usb_pipe.BaseList], edx
1001
        mov     [edi+usb_pipe.BaseList], edx
1002
; Insert to the head of the corresponding list.
1002
; Insert to the head of the corresponding list.
1003
; Note: inserting to the head guarantees that the list traverse in
1003
; Note: inserting to the head guarantees that the list traverse in
1004
; ehci_process_updated_schedule, once started, will not interact with new pipes.
1004
; ehci_process_updated_schedule, once started, will not interact with new pipes.
1005
; However, we still need to ensure that links in the new pipe (edi.NextVirt)
1005
; However, we still need to ensure that links in the new pipe (edi.NextVirt)
1006
; are initialized before links to the new pipe (edx.NextVirt).
1006
; are initialized before links to the new pipe (edx.NextVirt).
1007
; 5c. Insert in the list of virtual addresses.
1007
; 5c. Insert in the list of virtual addresses.
1008
        mov     ecx, [edx+usb_pipe.NextVirt]
1008
        mov     ecx, [edx+usb_pipe.NextVirt]
1009
        mov     [edi+usb_pipe.NextVirt], ecx
1009
        mov     [edi+usb_pipe.NextVirt], ecx
1010
        mov     [edi+usb_pipe.PrevVirt], edx
1010
        mov     [edi+usb_pipe.PrevVirt], edx
1011
        mov     [ecx+usb_pipe.PrevVirt], edi
1011
        mov     [ecx+usb_pipe.PrevVirt], edi
1012
        mov     [edx+usb_pipe.NextVirt], edi
1012
        mov     [edx+usb_pipe.NextVirt], edi
1013
; 5d. Insert in the hardware list: copy previous NextQH to the new pipe,
1013
; 5d. Insert in the hardware list: copy previous NextQH to the new pipe,
1014
; store the physical address of the new pipe to previous NextQH.
1014
; store the physical address of the new pipe to previous NextQH.
1015
        mov     ecx, [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart]
1015
        mov     ecx, [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart]
1016
        mov     [edi+ehci_pipe.NextQH-sizeof.ehci_pipe], ecx
1016
        mov     [edi+ehci_pipe.NextQH-sizeof.ehci_pipe], ecx
1017
        lea     eax, [edi-sizeof.ehci_pipe]
1017
        lea     eax, [edi-sizeof.ehci_pipe]
1018
        call    [GetPhysAddr]
1018
        call    [GetPhysAddr]
1019
        inc     eax
1019
        inc     eax
1020
        inc     eax
1020
        inc     eax
1021
        mov     [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1021
        mov     [edx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1022
; 6. Return with nonzero eax.
1022
; 6. Return with nonzero eax.
1023
        ret
1023
        ret
1024
.return0:
1024
.return0:
1025
        xor     eax, eax
1025
        xor     eax, eax
1026
        ret
1026
        ret
1027
endp
1027
endp
1028
 
1028
 
1029
; This function is called from ehci_process_deferred when
1029
; This function is called from ehci_process_deferred when
1030
; a new device was connected at least USB_CONNECT_DELAY ticks
1030
; a new device was connected at least USB_CONNECT_DELAY ticks
1031
; and therefore is ready to be configured.
1031
; and therefore is ready to be configured.
1032
; ecx = port, esi -> ehci_controller, edi -> EHCI MMIO
1032
; ecx = port, esi -> ehci_controller, edi -> EHCI MMIO
1033
proc ehci_new_port
1033
proc ehci_new_port
1034
; 1. If the device operates at low-speed, just release it to a companion.
1034
; 1. If the device operates at low-speed, just release it to a companion.
1035
        mov     eax, [edi+EhciPortsReg+ecx*4]
1035
        mov     eax, [edi+EhciPortsReg+ecx*4]
1036
        DEBUGF 1,'K : EHCI %x port %d state is %x\n',esi,ecx,eax
1036
        DEBUGF 1,'K : EHCI %x port %d state is %x\n',esi,ecx,eax
1037
        mov     edx, eax
1037
        mov     edx, eax
1038
        and     ah, 0Ch
1038
        and     ah, 0Ch
1039
        cmp     ah, 4
1039
        cmp     ah, 4
1040
        jz      .low_speed
1040
        jz      .low_speed
1041
; 2. Devices operating at full-speed and high-speed must now have ah == 8.
1041
; 2. Devices operating at full-speed and high-speed must now have ah == 8.
1042
; Some broken hardware asserts both D+ and D- even after initial decoupling;
1042
; Some broken hardware asserts both D+ and D- even after initial decoupling;
1043
; if so, stop initialization here, no sense in further actions.
1043
; if so, stop initialization here, no sense in further actions.
1044
        cmp     ah, 0Ch
1044
        cmp     ah, 0Ch
1045
        jz      .se1
1045
        jz      .se1
1046
; 3. If another port is resetting right now, mark this port as 'reset pending'
1046
; 3. If another port is resetting right now, mark this port as 'reset pending'
1047
; and return.
1047
; and return.
1048
        bts     [esi+usb_controller.PendingPorts], ecx
1048
        bts     [esi+usb_controller.PendingPorts], ecx
1049
        cmp     [esi+usb_controller.ResettingPort], -1
1049
        cmp     [esi+usb_controller.ResettingPort], -1
1050
        jnz     .nothing
1050
        jnz     .nothing
1051
        btr     [esi+usb_controller.PendingPorts], ecx
1051
        btr     [esi+usb_controller.PendingPorts], ecx
1052
; Otherwise, fall through to ohci_new_port.reset.
1052
; Otherwise, fall through to ohci_new_port.reset.
1053
 
1053
 
1054
; This function is called from ehci_new_port and usb_test_pending_port.
1054
; This function is called from ehci_new_port and usb_test_pending_port.
1055
; It starts reset signalling for the port. Note that in USB first stages
1055
; It starts reset signalling for the port. Note that in USB first stages
1056
; of configuration can not be done for several ports in parallel.
1056
; of configuration can not be done for several ports in parallel.
1057
.reset:
1057
.reset:
1058
        push    edi
1058
        push    edi
1059
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
1059
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
1060
        mov     eax, [edi+EhciPortsReg+ecx*4]
1060
        mov     eax, [edi+EhciPortsReg+ecx*4]
1061
; 1. Store information about resetting hub (roothub) and port.
1061
; 1. Store information about resetting hub (roothub) and port.
1062
        and     [esi+usb_controller.ResettingHub], 0
1062
        and     [esi+usb_controller.ResettingHub], 0
1063
        mov     [esi+usb_controller.ResettingPort], cl
1063
        mov     [esi+usb_controller.ResettingPort], cl
1064
; 2. Initiate reset signalling.
1064
; 2. Initiate reset signalling.
1065
        or      ah, 1
1065
        or      ah, 1
1066
        and     al, not (4 or 2Ah)
1066
        and     al, not (4 or 2Ah)
1067
        mov     [edi+EhciPortsReg+ecx*4], eax
1067
        mov     [edi+EhciPortsReg+ecx*4], eax
1068
; 3. Store the current time and set status to 1 = reset signalling active.
1068
; 3. Store the current time and set status to 1 = reset signalling active.
1069
        invoke  GetTimerTicks
1069
        invoke  GetTimerTicks
1070
        mov     [esi+usb_controller.ResetTime], eax
1070
        mov     [esi+usb_controller.ResetTime], eax
1071
        mov     [esi+usb_controller.ResettingStatus], 1
1071
        mov     [esi+usb_controller.ResettingStatus], 1
1072
;       dbgstr 'high-speed or full-speed device, resetting'
1072
;       dbgstr 'high-speed or full-speed device, resetting'
1073
        DEBUGF 1,'K : EHCI %x: port %d has HS or FS device, resetting\n',esi,ecx
1073
        DEBUGF 1,'K : EHCI %x: port %d has HS or FS device, resetting\n',esi,ecx
1074
        pop     edi
1074
        pop     edi
1075
.nothing:
1075
.nothing:
1076
        ret
1076
        ret
1077
.low_speed:
1077
.low_speed:
1078
;       dbgstr 'low-speed device, releasing'
1078
;       dbgstr 'low-speed device, releasing'
1079
        DEBUGF 1,'K : EHCI %x: port %d has LS device, releasing\n',esi,ecx
1079
        DEBUGF 1,'K : EHCI %x: port %d has LS device, releasing\n',esi,ecx
1080
        or      dh, 20h
1080
        or      dh, 20h
1081
        and     dl, not 2Ah
1081
        and     dl, not 2Ah
1082
        mov     [edi+EhciPortsReg+ecx*4], edx
1082
        mov     [edi+EhciPortsReg+ecx*4], edx
1083
        ret
1083
        ret
1084
.se1:
1084
.se1:
1085
        dbgstr 'SE1 after connect debounce. Broken hardware?'
1085
        dbgstr 'SE1 after connect debounce. Broken hardware?'
1086
        ret
1086
        ret
1087
endp
1087
endp
1088
 
1088
 
1089
; This procedure is called from several places in main USB code
1089
; This procedure is called from several places in main USB code
1090
; and allocates required packets for the given transfer.
1090
; and allocates required packets for the given transfer.
1091
; ebx = pipe, other parameters are passed through the stack:
1091
; ebx = pipe, other parameters are passed through the stack:
1092
; buffer,size = data to transfer
1092
; buffer,size = data to transfer
1093
; flags = same as in usb_open_pipe: bit 0 = allow short transfer, other bits reserved
1093
; flags = same as in usb_open_pipe: bit 0 = allow short transfer, other bits reserved
1094
; td = pointer to the current end-of-queue descriptor
1094
; td = pointer to the current end-of-queue descriptor
1095
; direction =
1095
; direction =
1096
;   0000b for normal transfers,
1096
;   0000b for normal transfers,
1097
;   1000b for control SETUP transfer,
1097
;   1000b for control SETUP transfer,
1098
;   1101b for control OUT transfer,
1098
;   1101b for control OUT transfer,
1099
;   1110b for control IN transfer
1099
;   1110b for control IN transfer
1100
; returns eax = pointer to the new end-of-queue descriptor
1100
; returns eax = pointer to the new end-of-queue descriptor
1101
; (not included in the queue itself) or 0 on error
1101
; (not included in the queue itself) or 0 on error
1102
proc ehci_alloc_transfer stdcall uses edi, \
1102
proc ehci_alloc_transfer stdcall uses edi, \
1103
        buffer:dword, size:dword, flags:dword, td:dword, direction:dword
1103
        buffer:dword, size:dword, flags:dword, td:dword, direction:dword
1104
locals
1104
locals
1105
origTD          dd      ?
1105
origTD          dd      ?
1106
packetSize      dd      ?       ; must be last variable, see usb_init_transfer
1106
packetSize      dd      ?       ; must be last variable, see usb_init_transfer
1107
endl
1107
endl
1108
; 1. Save original value of td:
1108
; 1. Save original value of td:
1109
; it will be useful for rollback if something would fail.
1109
; it will be useful for rollback if something would fail.
1110
        mov     eax, [td]
1110
        mov     eax, [td]
1111
        mov     [origTD], eax
1111
        mov     [origTD], eax
1112
; One transfer descriptor can describe up to 5 pages.
1112
; One transfer descriptor can describe up to 5 pages.
1113
; In the worst case (when the buffer is something*1000h+0FFFh)
1113
; In the worst case (when the buffer is something*1000h+0FFFh)
1114
; this corresponds to 4001h bytes. If the requested size is
1114
; this corresponds to 4001h bytes. If the requested size is
1115
; greater, we should split the transfer into several descriptors.
1115
; greater, we should split the transfer into several descriptors.
1116
; Boundaries to split must be multiples of endpoint transfer size
1116
; Boundaries to split must be multiples of endpoint transfer size
1117
; to avoid short packets except in the end of the transfer.
1117
; to avoid short packets except in the end of the transfer.
1118
        cmp     [size], 4001h
1118
        cmp     [size], 4001h
1119
        jbe     .lastpacket
1119
        jbe     .lastpacket
1120
; 2. While the remaining data cannot fit in one descriptor,
1120
; 2. While the remaining data cannot fit in one descriptor,
1121
; allocate full descriptors (of maximal possible size).
1121
; allocate full descriptors (of maximal possible size).
1122
; 2a. Calculate size of one descriptor: must be a multiple of transfer size
1122
; 2a. Calculate size of one descriptor: must be a multiple of transfer size
1123
; and must be not greater than 4001h.
1123
; and must be not greater than 4001h.
1124
        movzx   ecx, word [ebx+ehci_pipe.Token+2-sizeof.ehci_pipe]
1124
        movzx   ecx, word [ebx+ehci_pipe.Token+2-sizeof.ehci_pipe]
1125
        and     ecx, (1 shl 11) - 1
1125
        and     ecx, (1 shl 11) - 1
1126
        mov     eax, 4001h
1126
        mov     eax, 4001h
1127
        xor     edx, edx
1127
        xor     edx, edx
1128
        mov     edi, eax
1128
        mov     edi, eax
1129
        div     ecx
1129
        div     ecx
1130
        sub     edi, edx
1130
        sub     edi, edx
1131
        mov     [packetSize], edi
1131
        mov     [packetSize], edi
1132
.fullpackets:
1132
.fullpackets:
1133
        call    ehci_alloc_packet
1133
        call    ehci_alloc_packet
1134
        test    eax, eax
1134
        test    eax, eax
1135
        jz      .fail
1135
        jz      .fail
1136
        mov     [td], eax
1136
        mov     [td], eax
1137
        add     [buffer], edi
1137
        add     [buffer], edi
1138
        sub     [size], edi
1138
        sub     [size], edi
1139
        cmp     [size], 4001h
1139
        cmp     [size], 4001h
1140
        ja      .fullpackets
1140
        ja      .fullpackets
1141
; 3. The remaining data can fit in one packet;
1141
; 3. The remaining data can fit in one packet;
1142
; allocate the last descriptor with size = size of remaining data.
1142
; allocate the last descriptor with size = size of remaining data.
1143
.lastpacket:
1143
.lastpacket:
1144
        mov     eax, [size]
1144
        mov     eax, [size]
1145
        mov     [packetSize], eax
1145
        mov     [packetSize], eax
1146
        call    ehci_alloc_packet
1146
        call    ehci_alloc_packet
1147
        test    eax, eax
1147
        test    eax, eax
1148
        jz      .fail
1148
        jz      .fail
1149
; 9. Update flags in the last packet.
1149
; 9. Update flags in the last packet.
1150
        mov     edx, [flags]
1150
        mov     edx, [flags]
1151
        mov     [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], edx
1151
        mov     [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], edx
1152
; 10. Fill AlternateNextTD field in all allocated TDs.
1152
; 10. Fill AlternateNextTD field in all allocated TDs.
1153
; If the caller says that short transfer is ok, the queue must advance to
1153
; If the caller says that short transfer is ok, the queue must advance to
1154
; the next descriptor, which is in eax.
1154
; the next descriptor, which is in eax.
1155
; Otherwise, the queue should stop, so make AlternateNextTD point to
1155
; Otherwise, the queue should stop, so make AlternateNextTD point to
1156
; always-inactive descriptor StopQueueTD.
1156
; always-inactive descriptor StopQueueTD.
1157
        push    eax
1157
        push    eax
1158
        test    dl, 1
1158
        test    dl, 1
1159
        jz      .disable_short
1159
        jz      .disable_short
1160
        sub     eax, sizeof.ehci_gtd
1160
        sub     eax, sizeof.ehci_gtd
1161
        jmp     @f
1161
        jmp     @f
1162
.disable_short:
1162
.disable_short:
1163
        mov     eax, [ebx+usb_pipe.Controller]
1163
        mov     eax, [ebx+usb_pipe.Controller]
1164
        add     eax, ehci_controller.StopQueueTD - sizeof.ehci_controller
1164
        add     eax, ehci_controller.StopQueueTD - sizeof.ehci_controller
1165
@@:
1165
@@:
1166
        call    [GetPhysAddr]
1166
        call    [GetPhysAddr]
1167
        mov     edx, [origTD]
1167
        mov     edx, [origTD]
1168
@@:
1168
@@:
1169
        cmp     edx, [esp]
1169
        cmp     edx, [esp]
1170
        jz      @f
1170
        jz      @f
1171
        mov     [edx+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], eax
1171
        mov     [edx+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], eax
1172
        mov     edx, [edx+usb_gtd.NextVirt]
1172
        mov     edx, [edx+usb_gtd.NextVirt]
1173
        jmp     @b
1173
        jmp     @b
1174
@@:
1174
@@:
1175
        pop     eax
1175
        pop     eax
1176
        ret
1176
        ret
1177
.fail:
1177
.fail:
1178
        mov     edi, ehci_hardware_func
1178
        mov     edi, ehci_hardware_func
1179
        mov     eax, [td]
1179
        mov     eax, [td]
1180
        invoke  usbhc_api.usb_undo_tds, [origTD]
1180
        invoke  usbhc_api.usb_undo_tds, [origTD]
1181
        xor     eax, eax
1181
        xor     eax, eax
1182
        ret
1182
        ret
1183
endp
1183
endp
1184
 
1184
 
1185
; Helper procedure for ehci_alloc_transfer.
1185
; Helper procedure for ehci_alloc_transfer.
1186
; Allocates and initializes one transfer descriptor.
1186
; Allocates and initializes one transfer descriptor.
1187
; ebx = pipe, other parameters are passed through the stack;
1187
; ebx = pipe, other parameters are passed through the stack;
1188
; fills the current last descriptor and
1188
; fills the current last descriptor and
1189
; returns eax = next descriptor (not filled).
1189
; returns eax = next descriptor (not filled).
1190
proc ehci_alloc_packet
1190
proc ehci_alloc_packet
1191
; inherit some variables from the parent ehci_alloc_transfer
1191
; inherit some variables from the parent ehci_alloc_transfer
1192
virtual at ebp-8
1192
virtual at ebp-8
1193
.origTD         dd      ?
1193
.origTD         dd      ?
1194
.packetSize     dd      ?
1194
.packetSize     dd      ?
1195
                rd      2
1195
                rd      2
1196
.buffer         dd      ?
1196
.buffer         dd      ?
1197
.transferSize   dd      ?
1197
.transferSize   dd      ?
1198
.Flags          dd      ?
1198
.Flags          dd      ?
1199
.td             dd      ?
1199
.td             dd      ?
1200
.direction      dd      ?
1200
.direction      dd      ?
1201
end virtual
1201
end virtual
1202
; 1. Allocate the next TD.
1202
; 1. Allocate the next TD.
1203
        call    ehci_alloc_td
1203
        call    ehci_alloc_td
1204
        test    eax, eax
1204
        test    eax, eax
1205
        jz      .nothing
1205
        jz      .nothing
1206
; 2. Initialize controller-independent parts of both TDs.
1206
; 2. Initialize controller-independent parts of both TDs.
1207
        push    eax
1207
        push    eax
1208
        invoke  usbhc_api.usb_init_transfer
1208
        invoke  usbhc_api.usb_init_transfer
1209
        pop     eax
1209
        pop     eax
1210
; 3. Copy PID to the new descriptor.
1210
; 3. Copy PID to the new descriptor.
1211
        mov     edx, [ecx+ehci_gtd.Token-sizeof.ehci_gtd]
1211
        mov     edx, [ecx+ehci_gtd.Token-sizeof.ehci_gtd]
1212
        mov     [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx
1212
        mov     [eax+ehci_gtd.Token-sizeof.ehci_gtd], edx
1213
        mov     [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1
1213
        mov     [eax+ehci_gtd.NextTD-sizeof.ehci_gtd], 1
1214
        mov     [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1
1214
        mov     [eax+ehci_gtd.AlternateNextTD-sizeof.ehci_gtd], 1
1215
; 4. Save the returned value (next descriptor).
1215
; 4. Save the returned value (next descriptor).
1216
        push    eax
1216
        push    eax
1217
; 5. Store the physical address of the next descriptor.
1217
; 5. Store the physical address of the next descriptor.
1218
        sub     eax, sizeof.ehci_gtd
1218
        sub     eax, sizeof.ehci_gtd
1219
        call    [GetPhysAddr]
1219
        call    [GetPhysAddr]
1220
        mov     [ecx+ehci_gtd.NextTD-sizeof.ehci_gtd], eax
1220
        mov     [ecx+ehci_gtd.NextTD-sizeof.ehci_gtd], eax
1221
; 6. For zero-length transfers, store zero in all fields for buffer addresses.
1221
; 6. For zero-length transfers, store zero in all fields for buffer addresses.
1222
; Otherwise, fill them with real values.
1222
; Otherwise, fill them with real values.
1223
        xor     eax, eax
1223
        xor     eax, eax
1224
        mov     [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], eax
1224
        mov     [ecx+ehci_gtd.Flags-sizeof.ehci_gtd], eax
1225
repeat 10
1225
repeat 10
1226
        mov     [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd+(%-1)*4], eax
1226
        mov     [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd+(%-1)*4], eax
1227
end repeat
1227
end repeat
1228
        cmp     [.packetSize], eax
1228
        cmp     [.packetSize], eax
1229
        jz      @f
1229
        jz      @f
1230
        mov     eax, [.buffer]
1230
        mov     eax, [.buffer]
1231
        call    [GetPhysAddr]
1231
        call    [GetPhysAddr]
1232
        mov     [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd], eax
1232
        mov     [ecx+ehci_gtd.BufferPointers-sizeof.ehci_gtd], eax
1233
        and     eax, 0xFFF
1233
        and     eax, 0xFFF
1234
        mov     edx, [.packetSize]
1234
        mov     edx, [.packetSize]
1235
        add     edx, eax
1235
        add     edx, eax
1236
        sub     edx, 0x1000
1236
        sub     edx, 0x1000
1237
        jbe     @f
1237
        jbe     @f
1238
        mov     eax, [.buffer]
1238
        mov     eax, [.buffer]
1239
        add     eax, 0x1000
1239
        add     eax, 0x1000
1240
        call    [GetPgAddr]
1240
        call    [GetPgAddr]
1241
        mov     [ecx+ehci_gtd.BufferPointers+4-sizeof.ehci_gtd], eax
1241
        mov     [ecx+ehci_gtd.BufferPointers+4-sizeof.ehci_gtd], eax
1242
        sub     edx, 0x1000
1242
        sub     edx, 0x1000
1243
        jbe     @f
1243
        jbe     @f
1244
        mov     eax, [.buffer]
1244
        mov     eax, [.buffer]
1245
        add     eax, 0x2000
1245
        add     eax, 0x2000
1246
        call    [GetPgAddr]
1246
        call    [GetPgAddr]
1247
        mov     [ecx+ehci_gtd.BufferPointers+8-sizeof.ehci_gtd], eax
1247
        mov     [ecx+ehci_gtd.BufferPointers+8-sizeof.ehci_gtd], eax
1248
        sub     edx, 0x1000
1248
        sub     edx, 0x1000
1249
        jbe     @f
1249
        jbe     @f
1250
        mov     eax, [.buffer]
1250
        mov     eax, [.buffer]
1251
        add     eax, 0x3000
1251
        add     eax, 0x3000
1252
        call    [GetPgAddr]
1252
        call    [GetPgAddr]
1253
        mov     [ecx+ehci_gtd.BufferPointers+12-sizeof.ehci_gtd], eax
1253
        mov     [ecx+ehci_gtd.BufferPointers+12-sizeof.ehci_gtd], eax
1254
        sub     edx, 0x1000
1254
        sub     edx, 0x1000
1255
        jbe     @f
1255
        jbe     @f
1256
        mov     eax, [.buffer]
1256
        mov     eax, [.buffer]
1257
        add     eax, 0x4000
1257
        add     eax, 0x4000
1258
        call    [GetPgAddr]
1258
        call    [GetPgAddr]
1259
        mov     [ecx+ehci_gtd.BufferPointers+16-sizeof.ehci_gtd], eax
1259
        mov     [ecx+ehci_gtd.BufferPointers+16-sizeof.ehci_gtd], eax
1260
@@:
1260
@@:
1261
; 7. Fill Token field:
1261
; 7. Fill Token field:
1262
; set Status = 0 (inactive, ehci_insert_transfer would mark everything active);
1262
; set Status = 0 (inactive, ehci_insert_transfer would mark everything active);
1263
; keep current PID if [.direction] is zero, use two lower bits of [.direction]
1263
; keep current PID if [.direction] is zero, use two lower bits of [.direction]
1264
; otherwise shifted as (0|1|2) -> (2|0|1);
1264
; otherwise shifted as (0|1|2) -> (2|0|1);
1265
; set error counter to 3;
1265
; set error counter to 3;
1266
; set current page to 0;
1266
; set current page to 0;
1267
; do not interrupt on complete (ehci_insert_transfer sets this bit where needed);
1267
; do not interrupt on complete (ehci_insert_transfer sets this bit where needed);
1268
; set DataToggle to bit 2 of [.direction].
1268
; set DataToggle to bit 2 of [.direction].
1269
        mov     eax, [ecx+ehci_gtd.Token-sizeof.ehci_gtd]
1269
        mov     eax, [ecx+ehci_gtd.Token-sizeof.ehci_gtd]
1270
        and     eax, 300h       ; keep PID code
1270
        and     eax, 300h       ; keep PID code
1271
        mov     edx, [.direction]
1271
        mov     edx, [.direction]
1272
        test    edx, edx
1272
        test    edx, edx
1273
        jz      .haspid
1273
        jz      .haspid
1274
        and     edx, 3
1274
        and     edx, 3
1275
        dec     edx
1275
        dec     edx
1276
        jns     @f
1276
        jns     @f
1277
        add     edx, 3
1277
        add     edx, 3
1278
@@:
1278
@@:
1279
        mov     ah, dl
1279
        mov     ah, dl
1280
        mov     edx, [.direction]
1280
        mov     edx, [.direction]
1281
        and     edx, not 3
1281
        and     edx, not 3
1282
        shl     edx, 29
1282
        shl     edx, 29
1283
        or      eax, edx
1283
        or      eax, edx
1284
.haspid:
1284
.haspid:
1285
        or      eax, 0C00h
1285
        or      eax, 0C00h
1286
        mov     edx, [.packetSize]
1286
        mov     edx, [.packetSize]
1287
        shl     edx, 16
1287
        shl     edx, 16
1288
        or      eax, edx
1288
        or      eax, edx
1289
        mov     [ecx+ehci_gtd.Token-sizeof.ehci_gtd], eax
1289
        mov     [ecx+ehci_gtd.Token-sizeof.ehci_gtd], eax
1290
; 4. Restore the returned value saved in step 2.
1290
; 4. Restore the returned value saved in step 2.
1291
        pop     eax
1291
        pop     eax
1292
.nothing:
1292
.nothing:
1293
        ret
1293
        ret
1294
endp
1294
endp
1295
 
1295
 
1296
; This procedure is called from several places in main USB code
1296
; This procedure is called from several places in main USB code
1297
; and activates the transfer which was previously allocated by
1297
; and activates the transfer which was previously allocated by
1298
; ehci_alloc_transfer.
1298
; ehci_alloc_transfer.
1299
; ecx -> last descriptor for the transfer, ebx -> usb_pipe
1299
; ecx -> last descriptor for the transfer, ebx -> usb_pipe
1300
proc ehci_insert_transfer
1300
proc ehci_insert_transfer
1301
        or      byte [ecx+ehci_gtd.Token+1-sizeof.ehci_gtd], 80h  ; set IOC bit
1301
        or      byte [ecx+ehci_gtd.Token+1-sizeof.ehci_gtd], 80h  ; set IOC bit
1302
        mov     eax, [esp+4]
1302
        mov     eax, [esp+4]
1303
.activate:
1303
.activate:
1304
        or      byte [eax+ehci_gtd.Token-sizeof.ehci_gtd], 80h    ; set Active bit
1304
        or      byte [eax+ehci_gtd.Token-sizeof.ehci_gtd], 80h    ; set Active bit
1305
        cmp     eax, ecx
1305
        cmp     eax, ecx
1306
        mov     eax, [eax+usb_gtd.NextVirt]
1306
        mov     eax, [eax+usb_gtd.NextVirt]
1307
        jnz     .activate
1307
        jnz     .activate
1308
        ret
1308
        ret
1309
endp
1309
endp
1310
 
1310
 
1311
; This function is called from ehci_process_deferred when
1311
; This function is called from ehci_process_deferred when
1312
; reset signalling for a new device needs to be finished.
1312
; reset signalling for a new device needs to be finished.
1313
proc ehci_port_reset_done
1313
proc ehci_port_reset_done
1314
        movzx   ecx, [esi+usb_controller.ResettingPort]
1314
        movzx   ecx, [esi+usb_controller.ResettingPort]
1315
        and     dword [edi+EhciPortsReg+ecx*4], not 12Ah
1315
        and     dword [edi+EhciPortsReg+ecx*4], not 12Ah
1316
        invoke  GetTimerTicks
1316
        invoke  GetTimerTicks
1317
        mov     [esi+usb_controller.ResetTime], eax
1317
        mov     [esi+usb_controller.ResetTime], eax
1318
        mov     [esi+usb_controller.ResettingStatus], 2
1318
        mov     [esi+usb_controller.ResettingStatus], 2
1319
;        DEBUGF 1,'K : EHCI %x: reset port %d done\n',esi,ecx
1319
;        DEBUGF 1,'K : EHCI %x: reset port %d done\n',esi,ecx
1320
        ret
1320
        ret
1321
endp
1321
endp
1322
 
1322
 
1323
; This function is called from ehci_process_deferred when
1323
; This function is called from ehci_process_deferred when
1324
; a new device has been reset, recovered after reset and needs to be configured.
1324
; a new device has been reset, recovered after reset and needs to be configured.
1325
proc ehci_port_init
1325
proc ehci_port_init
1326
; 1. Get the status and set it to zero.
1326
; 1. Get the status and set it to zero.
1327
; If reset has been failed (device disconnected during reset),
1327
; If reset has been failed (device disconnected during reset),
1328
; continue to next device (if there is one).
1328
; continue to next device (if there is one).
1329
        xor     eax, eax
1329
        xor     eax, eax
1330
        xchg    al, [esi+usb_controller.ResettingStatus]
1330
        xchg    al, [esi+usb_controller.ResettingStatus]
1331
        test    al, al
1331
        test    al, al
1332
        jns     @f
1332
        jns     @f
1333
        jmp     [usbhc_api.usb_test_pending_port]
1333
        jmp     [usbhc_api.usb_test_pending_port]
1334
@@:
1334
@@:
1335
; 2. Get the port status. High-speed devices should be now enabled,
1335
; 2. Get the port status. High-speed devices should be now enabled,
1336
; full-speed devices are left disabled;
1336
; full-speed devices are left disabled;
1337
; if the port is disabled, release it to a companion and continue to
1337
; if the port is disabled, release it to a companion and continue to
1338
; next device (if there is one).
1338
; next device (if there is one).
1339
        movzx   ecx, [esi+usb_controller.ResettingPort]
1339
        movzx   ecx, [esi+usb_controller.ResettingPort]
1340
        mov     eax, [edi+EhciPortsReg+ecx*4]
1340
        mov     eax, [edi+EhciPortsReg+ecx*4]
1341
        DEBUGF 1,'K : EHCI %x status of port %d is %x\n',esi,ecx,eax
1341
        DEBUGF 1,'K : EHCI %x status of port %d is %x\n',esi,ecx,eax
1342
        test    al, 4
1342
        test    al, 4
1343
        jnz     @f
1343
        jnz     @f
1344
;       DEBUGF 1,'K : USB port disabled after reset, status = %x\n',eax
1344
;       DEBUGF 1,'K : USB port disabled after reset, status = %x\n',eax
1345
        dbgstr 'releasing to companion'
1345
        dbgstr 'releasing to companion'
1346
        or      ah, 20h
1346
        or      ah, 20h
1347
        mov     [edi+EhciPortsReg+ecx*4], eax
1347
        mov     [edi+EhciPortsReg+ecx*4], eax
1348
        jmp     [usbhc_api.usb_test_pending_port]
1348
        jmp     [usbhc_api.usb_test_pending_port]
1349
@@:
1349
@@:
1350
; 3. Call the worker procedure to notify the protocol layer
1350
; 3. Call the worker procedure to notify the protocol layer
1351
; about new EHCI device. It is high-speed.
1351
; about new EHCI device. It is high-speed.
1352
        movi    eax, USB_SPEED_HS
1352
        movi    eax, USB_SPEED_HS
1353
        call    ehci_new_device
1353
        call    ehci_new_device
1354
        test    eax, eax
1354
        test    eax, eax
1355
        jnz     .nothing
1355
        jnz     .nothing
1356
; 4. If something at the protocol layer has failed
1356
; 4. If something at the protocol layer has failed
1357
; (no memory, no bus address), disable the port and stop the initialization.
1357
; (no memory, no bus address), disable the port and stop the initialization.
1358
.disable_exit:
1358
.disable_exit:
1359
        and     dword [edi+EhciPortsReg+ecx*4], not (4 or 2Ah)
1359
        and     dword [edi+EhciPortsReg+ecx*4], not (4 or 2Ah)
1360
        jmp     [usbhc_api.usb_test_pending_port]
1360
        jmp     [usbhc_api.usb_test_pending_port]
1361
.nothing:
1361
.nothing:
1362
        ret
1362
        ret
1363
endp
1363
endp
1364
 
1364
 
1365
; This procedure is called from ehci_port_init and from hub support code
1365
; This procedure is called from ehci_port_init and from hub support code
1366
; when a new device is connected and has been reset.
1366
; when a new device is connected and has been reset.
1367
; It calls usb_new_device at the protocol layer with correct parameters.
1367
; It calls usb_new_device at the protocol layer with correct parameters.
1368
; in: esi -> usb_controller, eax = speed.
1368
; in: esi -> usb_controller, eax = speed.
1369
proc ehci_new_device
1369
proc ehci_new_device
1370
        push    ebx ecx ; save used registers (ecx is important for ehci_port_init)
1370
        push    ebx ecx ; save used registers (ecx is important for ehci_port_init)
1371
; 1. Store the speed for the protocol layer.
1371
; 1. Store the speed for the protocol layer.
1372
        mov     [esi+usb_controller.ResettingSpeed], al
1372
        mov     [esi+usb_controller.ResettingSpeed], al
1373
; 2. Shift speed bits to the proper place in ehci_pipe.Token.
1373
; 2. Shift speed bits to the proper place in ehci_pipe.Token.
1374
        shl     eax, 12
1374
        shl     eax, 12
1375
; 3. For high-speed devices, go to step 5 with edx = 0.
1375
; 3. For high-speed devices, go to step 5 with edx = 0.
1376
        xor     edx, edx
1376
        xor     edx, edx
1377
        cmp     ah, USB_SPEED_HS shl (12-8)
1377
        cmp     ah, USB_SPEED_HS shl (12-8)
1378
        jz      .common
1378
        jz      .common
1379
; 4. For low-speed and full-speed devices, fill address:port
1379
; 4. For low-speed and full-speed devices, fill address:port
1380
; of the last high-speed hub (the closest to the device hub)
1380
; of the last high-speed hub (the closest to the device hub)
1381
; for split transactions, and set ControlEndpoint bit in eax;
1381
; for split transactions, and set ControlEndpoint bit in eax;
1382
; ehci_init_pipe assumes that the parent pipe is a control pipe.
1382
; ehci_init_pipe assumes that the parent pipe is a control pipe.
1383
        push    eax
1383
        push    eax
1384
        movzx   ecx, [esi+usb_controller.ResettingPort]
1384
        movzx   ecx, [esi+usb_controller.ResettingPort]
1385
        mov     edx, [esi+usb_controller.ResettingHub]
1385
        mov     edx, [esi+usb_controller.ResettingHub]
1386
        invoke  usbhc_api.usb_get_tt
1386
        invoke  usbhc_api.usb_get_tt
1387
        inc     ecx
1387
        inc     ecx
1388
        mov     edx, [edx+ehci_pipe.Token-sizeof.ehci_pipe]
1388
        mov     edx, [edx+ehci_pipe.Token-sizeof.ehci_pipe]
1389
        shl     ecx, 23
1389
        shl     ecx, 23
1390
        and     edx, 7Fh
1390
        and     edx, 7Fh
1391
        shl     edx, 16
1391
        shl     edx, 16
1392
        or      edx, ecx        ; ehci_pipe.Flags
1392
        or      edx, ecx        ; ehci_pipe.Flags
1393
        pop     eax
1393
        pop     eax
1394
        or      eax, 1 shl 27   ; ehci_pipe.Token
1394
        or      eax, 1 shl 27   ; ehci_pipe.Token
1395
.common:
1395
.common:
1396
; 5. Create pseudo-pipe in the stack.
1396
; 5. Create pseudo-pipe in the stack.
1397
; See ehci_init_pipe: only .Controller, .Token, .Flags fields are used.
1397
; See ehci_init_pipe: only .Controller, .Token, .Flags fields are used.
1398
        push    esi     ; usb_pipe.Controller
1398
        push    esi     ; usb_pipe.Controller
1399
        mov     ecx, esp
1399
        mov     ecx, esp
1400
        sub     esp, sizeof.ehci_pipe - ehci_pipe.Flags - 4
1400
        sub     esp, sizeof.ehci_pipe - ehci_pipe.Flags - 4
1401
        push    edx     ; ehci_pipe.Flags
1401
        push    edx     ; ehci_pipe.Flags
1402
        push    eax     ; ehci_pipe.Token
1402
        push    eax     ; ehci_pipe.Token
1403
; 6. Notify the protocol layer.
1403
; 6. Notify the protocol layer.
1404
        invoke  usbhc_api.usb_new_device
1404
        invoke  usbhc_api.usb_new_device
1405
; 7. Cleanup the stack after step 5 and return.
1405
; 7. Cleanup the stack after step 5 and return.
1406
        add     esp, sizeof.ehci_pipe - ehci_pipe.Flags + 8
1406
        add     esp, sizeof.ehci_pipe - ehci_pipe.Flags + 8
1407
        pop     ecx ebx ; restore used registers
1407
        pop     ecx ebx ; restore used registers
1408
        ret
1408
        ret
1409
endp
1409
endp
1410
 
1410
 
1411
; This procedure is called in the USB thread from usb_thread_proc,
1411
; This procedure is called in the USB thread from usb_thread_proc,
1412
; processes regular actions and those actions which can't be safely done
1412
; processes regular actions and those actions which can't be safely done
1413
; from interrupt handler.
1413
; from interrupt handler.
1414
; Returns maximal time delta before the next call.
1414
; Returns maximal time delta before the next call.
1415
proc ehci_process_deferred
1415
proc ehci_process_deferred
1416
        push    ebx edi         ; save used registers to be stdcall
1416
        push    ebx edi         ; save used registers to be stdcall
1417
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
1417
        mov     edi, [esi+ehci_controller.MMIOBase2-sizeof.ehci_controller]
1418
; 1. Get the mask of events to process.
1418
; 1. Get the mask of events to process.
1419
        xor     eax, eax
1419
        xor     eax, eax
1420
        xchg    eax, [esi+ehci_controller.DeferredActions-sizeof.ehci_controller]
1420
        xchg    eax, [esi+ehci_controller.DeferredActions-sizeof.ehci_controller]
1421
        push    eax
1421
        push    eax
1422
; 2. Initialize the return value.
1422
; 2. Initialize the return value.
1423
        push    -1
1423
        push    -1
1424
; Handle roothub events.
1424
; Handle roothub events.
1425
; 3a. Test whether there are such events.
1425
; 3a. Test whether there are such events.
1426
        test    al, 4
1426
        test    al, 4
1427
        jz      .skip_roothub
1427
        jz      .skip_roothub
1428
; Status of some port has changed. Loop over all ports.
1428
; Status of some port has changed. Loop over all ports.
1429
; 3b. Prepare for the loop: start from port 0.
1429
; 3b. Prepare for the loop: start from port 0.
1430
        xor     ecx, ecx
1430
        xor     ecx, ecx
1431
.portloop:
1431
.portloop:
1432
; 3c. Get the port status and changes of it.
1432
; 3c. Get the port status and changes of it.
1433
; If there are no changes, just continue to the next port.
1433
; If there are no changes, just continue to the next port.
1434
        mov     eax, [edi+EhciPortsReg+ecx*4]
1434
        mov     eax, [edi+EhciPortsReg+ecx*4]
1435
        test    al, 2Ah
1435
        test    al, 2Ah
1436
        jz      .nextport
1436
        jz      .nextport
1437
; 3d. Clear change bits and read the status again.
1437
; 3d. Clear change bits and read the status again.
1438
; (It is possible, although quite unlikely, that some event occurs between
1438
; (It is possible, although quite unlikely, that some event occurs between
1439
; the first read and the clearing, invalidating the old status. If an event
1439
; the first read and the clearing, invalidating the old status. If an event
1440
; occurs after the clearing, we will not miss it, looking in the next scan.
1440
; occurs after the clearing, we will not miss it, looking in the next scan.
1441
        mov     [edi+EhciPortsReg+ecx*4], eax
1441
        mov     [edi+EhciPortsReg+ecx*4], eax
1442
        mov     ebx, eax
1442
        mov     ebx, eax
1443
        mov     eax, [edi+EhciPortsReg+ecx*4]
1443
        mov     eax, [edi+EhciPortsReg+ecx*4]
1444
        DEBUGF 1,'K : EHCI %x: status of port %d changed to %x\n',esi,ecx,ebx
1444
        DEBUGF 1,'K : EHCI %x: status of port %d changed to %x\n',esi,ecx,ebx
1445
; 3e. Handle overcurrent.
1445
; 3e. Handle overcurrent.
1446
; Note: that needs work.
1446
; Note: that needs work.
1447
        test    bl, 20h ; overcurrent change
1447
        test    bl, 20h ; overcurrent change
1448
        jz      .noovercurrent
1448
        jz      .noovercurrent
1449
        test    al, 10h ; overcurrent active
1449
        test    al, 10h ; overcurrent active
1450
        jz      .noovercurrent
1450
        jz      .noovercurrent
1451
        DEBUGF 1,'K : overcurrent at port %d\n',ecx
1451
        DEBUGF 1,'K : overcurrent at port %d\n',ecx
1452
.noovercurrent:
1452
.noovercurrent:
1453
; 3f. Handle changing of connection status.
1453
; 3f. Handle changing of connection status.
1454
        test    bl, 2
1454
        test    bl, 2
1455
        jz      .nocsc
1455
        jz      .nocsc
1456
; There was a connect or disconnect event at this port.
1456
; There was a connect or disconnect event at this port.
1457
; 3g. Disconnect the old device on this port, if any.
1457
; 3g. Disconnect the old device on this port, if any.
1458
; If the port was resetting, indicate fail; later stages will process it.
1458
; If the port was resetting, indicate fail; later stages will process it.
1459
; Ignore connect event immediately after resetting.
1459
; Ignore connect event immediately after resetting.
1460
        cmp     [esi+usb_controller.ResettingHub], 0
1460
        cmp     [esi+usb_controller.ResettingHub], 0
1461
        jnz     .csc.noreset
1461
        jnz     .csc.noreset
1462
        cmp     cl, [esi+usb_controller.ResettingPort]
1462
        cmp     cl, [esi+usb_controller.ResettingPort]
1463
        jnz     .csc.noreset
1463
        jnz     .csc.noreset
1464
        cmp     [esi+usb_controller.ResettingStatus], 2
1464
        cmp     [esi+usb_controller.ResettingStatus], 2
1465
        jnz     @f
1465
        jnz     @f
1466
        test    al, 1
1466
        test    al, 1
1467
        jnz     .nextport
1467
        jnz     .nextport
1468
@@:
1468
@@:
1469
        mov     [esi+usb_controller.ResettingStatus], -1
1469
        mov     [esi+usb_controller.ResettingStatus], -1
1470
.csc.noreset:
1470
.csc.noreset:
1471
        bts     [esi+usb_controller.NewDisconnected], ecx
1471
        bts     [esi+usb_controller.NewDisconnected], ecx
1472
; 3h. Change connected status. For the connection event, also store
1472
; 3h. Change connected status. For the connection event, also store
1473
; the connection time; any further processing is permitted only after
1473
; the connection time; any further processing is permitted only after
1474
; USB_CONNECT_DELAY ticks.
1474
; USB_CONNECT_DELAY ticks.
1475
        test    al, 1
1475
        test    al, 1
1476
        jz      .disconnect
1476
        jz      .disconnect
1477
        invoke  GetTimerTicks
1477
        invoke  GetTimerTicks
1478
        mov     [esi+usb_controller.ConnectedTime+ecx*4], eax
1478
        mov     [esi+usb_controller.ConnectedTime+ecx*4], eax
1479
        bts     [esi+usb_controller.NewConnected], ecx
1479
        bts     [esi+usb_controller.NewConnected], ecx
1480
        jmp     .nextport
1480
        jmp     .nextport
1481
.disconnect:
1481
.disconnect:
1482
        btr     [esi+usb_controller.NewConnected], ecx
1482
        btr     [esi+usb_controller.NewConnected], ecx
1483
        jmp     .nextport
1483
        jmp     .nextport
1484
.nocsc:
1484
.nocsc:
1485
; 3i. Handle port disabling.
1485
; 3i. Handle port disabling.
1486
; Note: that needs work.
1486
; Note: that needs work.
1487
        test    al, 8
1487
        test    al, 8
1488
        jz      @f
1488
        jz      @f
1489
        test    al, 4
1489
        test    al, 4
1490
        jz      @f
1490
        jz      @f
1491
        DEBUGF 1,'K : port %d disabled\n',ecx
1491
        DEBUGF 1,'K : port %d disabled\n',ecx
1492
@@:
1492
@@:
1493
; 3j. Continue the loop for the next port.
1493
; 3j. Continue the loop for the next port.
1494
.nextport:
1494
.nextport:
1495
        inc     ecx
1495
        inc     ecx
1496
        cmp     ecx, [esi+usb_controller.NumPorts]
1496
        cmp     ecx, [esi+usb_controller.NumPorts]
1497
        jb      .portloop
1497
        jb      .portloop
1498
.skip_roothub:
1498
.skip_roothub:
1499
; 4. Process disconnect events. This should be done after step 3
1499
; 4. Process disconnect events. This should be done after step 3
1500
; (which includes the first stage of disconnect processing).
1500
; (which includes the first stage of disconnect processing).
1501
        invoke  usbhc_api.usb_disconnect_stage2
1501
        invoke  usbhc_api.usb_disconnect_stage2
1502
; 5. Check for previously connected devices.
1502
; 5. Check for previously connected devices.
1503
; If there is a connected device which was connected less than
1503
; If there is a connected device which was connected less than
1504
; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over.
1504
; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over.
1505
; Otherwise, call ehci_new_port.
1505
; Otherwise, call ehci_new_port.
1506
; This should be done after step 3.
1506
; This should be done after step 3.
1507
        xor     ecx, ecx
1507
        xor     ecx, ecx
1508
        cmp     [esi+usb_controller.NewConnected], ecx
1508
        cmp     [esi+usb_controller.NewConnected], ecx
1509
        jz      .skip_newconnected
1509
        jz      .skip_newconnected
1510
.portloop2:
1510
.portloop2:
1511
        bt      [esi+usb_controller.NewConnected], ecx
1511
        bt      [esi+usb_controller.NewConnected], ecx
1512
        jnc     .noconnect
1512
        jnc     .noconnect
1513
        invoke  GetTimerTicks
1513
        invoke  GetTimerTicks
1514
        sub     eax, [esi+usb_controller.ConnectedTime+ecx*4]
1514
        sub     eax, [esi+usb_controller.ConnectedTime+ecx*4]
1515
        sub     eax, USB_CONNECT_DELAY
1515
        sub     eax, USB_CONNECT_DELAY
1516
        jge     .connected
1516
        jge     .connected
1517
        neg     eax
1517
        neg     eax
1518
        cmp     [esp], eax
1518
        cmp     [esp], eax
1519
        jb      .nextport2
1519
        jb      .nextport2
1520
        mov     [esp], eax
1520
        mov     [esp], eax
1521
        jmp     .nextport2
1521
        jmp     .nextport2
1522
.connected:
1522
.connected:
1523
        btr     [esi+usb_controller.NewConnected], ecx
1523
        btr     [esi+usb_controller.NewConnected], ecx
1524
        call    ehci_new_port
1524
        call    ehci_new_port
1525
        jmp     .portloop2
1525
        jmp     .portloop2
1526
.noconnect:
1526
.noconnect:
1527
.nextport2:
1527
.nextport2:
1528
        inc     ecx
1528
        inc     ecx
1529
        cmp     ecx, [esi+usb_controller.NumPorts]
1529
        cmp     ecx, [esi+usb_controller.NumPorts]
1530
        jb      .portloop2
1530
        jb      .portloop2
1531
.skip_newconnected:
1531
.skip_newconnected:
1532
; 6. Process wait lists.
1532
; 6. Process wait lists.
1533
; 6a. Periodic endpoints.
1533
; 6a. Periodic endpoints.
1534
; If a request is pending >8 microframes, satisfy it.
1534
; If a request is pending >8 microframes, satisfy it.
1535
; If a request is pending <=8 microframes, schedule next wakeup in 0.01s.
1535
; If a request is pending <=8 microframes, schedule next wakeup in 0.01s.
1536
        mov     eax, [esi+usb_controller.WaitPipeRequestPeriodic]
1536
        mov     eax, [esi+usb_controller.WaitPipeRequestPeriodic]
1537
        cmp     eax, [esi+usb_controller.ReadyPipeHeadPeriodic]
1537
        cmp     eax, [esi+usb_controller.ReadyPipeHeadPeriodic]
1538
        jz      .noperiodic
1538
        jz      .noperiodic
1539
        mov     edx, [edi+EhciFrameIndexReg]
1539
        mov     edx, [edi+EhciFrameIndexReg]
1540
        sub     edx, [esi+usb_controller.StartWaitFrame]
1540
        sub     edx, [esi+usb_controller.StartWaitFrame]
1541
        and     edx, 0x3FFF
1541
        and     edx, 0x3FFF
1542
        cmp     edx, 8
1542
        cmp     edx, 8
1543
        jbe     @f
1543
        jbe     @f
1544
        mov     [esi+usb_controller.ReadyPipeHeadPeriodic], eax
1544
        mov     [esi+usb_controller.ReadyPipeHeadPeriodic], eax
1545
        jmp     .noperiodic
1545
        jmp     .noperiodic
1546
@@:
1546
@@:
1547
        pop     eax
1547
        pop     eax
1548
        push    1               ; wakeup in 0.01 sec for next test
1548
        push    1               ; wakeup in 0.01 sec for next test
1549
.noperiodic:
1549
.noperiodic:
1550
; 6b. Asynchronous endpoints.
1550
; 6b. Asynchronous endpoints.
1551
; Satisfy a request when InterruptOnAsyncAdvance fired.
1551
; Satisfy a request when InterruptOnAsyncAdvance fired.
1552
        test    byte [esp+4], 20h
1552
        test    byte [esp+4], 20h
1553
        jz      @f
1553
        jz      @f
1554
;        dbgstr 'async advance int'
1554
;        dbgstr 'async advance int'
1555
        mov     eax, [esi+usb_controller.WaitPipeRequestAsync]
1555
        mov     eax, [esi+usb_controller.WaitPipeRequestAsync]
1556
        mov     [esi+usb_controller.ReadyPipeHeadAsync], eax
1556
        mov     [esi+usb_controller.ReadyPipeHeadAsync], eax
1557
@@:
1557
@@:
1558
; Some hardware in some (rarely) conditions set the status bit,
1558
; Some hardware in some (rarely) conditions set the status bit,
1559
; but just does not generate the corresponding interrupt.
1559
; but just does not generate the corresponding interrupt.
1560
; Force checking the status here.
1560
; Force checking the status here.
1561
        mov     eax, [esi+usb_controller.WaitPipeRequestAsync]
1561
        mov     eax, [esi+usb_controller.WaitPipeRequestAsync]
1562
        cmp     [esi+usb_controller.ReadyPipeHeadAsync], eax
1562
        cmp     [esi+usb_controller.ReadyPipeHeadAsync], eax
1563
        jz      .noasync
1563
        jz      .noasync
1564
        spin_lock_irq [esi+usb_controller.WaitSpinlock]
1564
        spin_lock_irq [esi+usb_controller.WaitSpinlock]
1565
        mov     edx, [edi+EhciStatusReg]
1565
        mov     edx, [edi+EhciStatusReg]
1566
        test    dl, 20h
1566
        test    dl, 20h
1567
        jz      @f
1567
        jz      @f
1568
        mov     dword [edi+EhciStatusReg], 20h
1568
        mov     dword [edi+EhciStatusReg], 20h
1569
        and     dword [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], not 20h
1569
        and     dword [esi+ehci_controller.DeferredActions-sizeof.ehci_controller], not 20h
1570
        dbgstr 'warning: async advance int missed'
1570
        dbgstr 'warning: async advance int missed'
1571
        mov     [esi+usb_controller.ReadyPipeHeadAsync], eax
1571
        mov     [esi+usb_controller.ReadyPipeHeadAsync], eax
-
 
1572
        spin_unlock_irq [esi+usb_controller.WaitSpinlock]
1572
        jmp     .async_unlock
1573
        jmp     .noasync
1573
@@:
1574
@@:
-
 
1575
        spin_unlock_irq [esi+usb_controller.WaitSpinlock]
1574
        cmp     dword [esp], 100
1576
        cmp     dword [esp], 100
1575
        jb      .async_unlock
1577
        jb      .noasync
1576
        mov     dword [esp], 100
1578
        mov     dword [esp], 100
1577
.async_unlock:
-
 
1578
        spin_unlock_irq [esi+usb_controller.WaitSpinlock]
-
 
1579
.noasync:
1579
.noasync:
1580
; 7. Finalize transfers processed by hardware.
1580
; 7. Finalize transfers processed by hardware.
1581
; It is better to perform this step after step 4 (disconnect events),
1581
; It is better to perform this step after step 4 (disconnect events),
1582
; although not strictly obligatory. This way, an active transfer aborted
1582
; although not strictly obligatory. This way, an active transfer aborted
1583
; due to disconnect would be handled with more specific USB_STATUS_CLOSED,
1583
; due to disconnect would be handled with more specific USB_STATUS_CLOSED,
1584
; not USB_STATUS_NORESPONSE.
1584
; not USB_STATUS_NORESPONSE.
1585
        test    byte [esp+4], 3
1585
        test    byte [esp+4], 3
1586
        jz      @f
1586
        jz      @f
1587
        call    ehci_process_updated_schedule
1587
        call    ehci_process_updated_schedule
1588
@@:
1588
@@:
1589
; 8. Test whether reset signalling has been started and should be stopped now.
1589
; 8. Test whether reset signalling has been started and should be stopped now.
1590
; This must be done after step 7, because completion of some transfer could
1590
; This must be done after step 7, because completion of some transfer could
1591
; result in resetting a new port.
1591
; result in resetting a new port.
1592
.test_reset:
1592
.test_reset:
1593
; 8a. Test whether reset signalling is active.
1593
; 8a. Test whether reset signalling is active.
1594
        cmp     [esi+usb_controller.ResettingStatus], 1
1594
        cmp     [esi+usb_controller.ResettingStatus], 1
1595
        jnz     .no_reset_in_progress
1595
        jnz     .no_reset_in_progress
1596
; 8b. Yep. Test whether it should be stopped.
1596
; 8b. Yep. Test whether it should be stopped.
1597
        invoke  GetTimerTicks
1597
        invoke  GetTimerTicks
1598
        sub     eax, [esi+usb_controller.ResetTime]
1598
        sub     eax, [esi+usb_controller.ResetTime]
1599
        sub     eax, USB_RESET_TIME
1599
        sub     eax, USB_RESET_TIME
1600
        jge     .reset_done
1600
        jge     .reset_done
1601
; 8c. Not yet, but initiate wakeup in -eax ticks and exit this step.
1601
; 8c. Not yet, but initiate wakeup in -eax ticks and exit this step.
1602
        neg     eax
1602
        neg     eax
1603
        cmp     [esp], eax
1603
        cmp     [esp], eax
1604
        jb      .skip_reset
1604
        jb      .skip_reset
1605
        mov     [esp], eax
1605
        mov     [esp], eax
1606
        jmp     .skip_reset
1606
        jmp     .skip_reset
1607
.reset_done:
1607
.reset_done:
1608
; 8d. Yep, call the worker function and proceed to 8e.
1608
; 8d. Yep, call the worker function and proceed to 8e.
1609
        call    ehci_port_reset_done
1609
        call    ehci_port_reset_done
1610
.no_reset_in_progress:
1610
.no_reset_in_progress:
1611
; 8e. Test whether reset process is done, either successful or failed.
1611
; 8e. Test whether reset process is done, either successful or failed.
1612
        cmp     [esi+usb_controller.ResettingStatus], 0
1612
        cmp     [esi+usb_controller.ResettingStatus], 0
1613
        jz      .skip_reset
1613
        jz      .skip_reset
1614
; 8f. Yep. Test whether it should be stopped.
1614
; 8f. Yep. Test whether it should be stopped.
1615
        invoke  GetTimerTicks
1615
        invoke  GetTimerTicks
1616
        sub     eax, [esi+usb_controller.ResetTime]
1616
        sub     eax, [esi+usb_controller.ResetTime]
1617
        sub     eax, USB_RESET_RECOVERY_TIME
1617
        sub     eax, USB_RESET_RECOVERY_TIME
1618
        jge     .reset_recovery_done
1618
        jge     .reset_recovery_done
1619
; 8g. Not yet, but initiate wakeup in -eax ticks and exit this step.
1619
; 8g. Not yet, but initiate wakeup in -eax ticks and exit this step.
1620
        neg     eax
1620
        neg     eax
1621
        cmp     [esp], eax
1621
        cmp     [esp], eax
1622
        jb      .skip_reset
1622
        jb      .skip_reset
1623
        mov     [esp], eax
1623
        mov     [esp], eax
1624
        jmp     .skip_reset
1624
        jmp     .skip_reset
1625
.reset_recovery_done:
1625
.reset_recovery_done:
1626
; 8h. Yep, call the worker function. This could initiate another reset,
1626
; 8h. Yep, call the worker function. This could initiate another reset,
1627
; so return to the beginning of this step.
1627
; so return to the beginning of this step.
1628
        call    ehci_port_init
1628
        call    ehci_port_init
1629
        jmp     .test_reset
1629
        jmp     .test_reset
1630
.skip_reset:
1630
.skip_reset:
1631
; 9. Process wait-done notifications, test for new wait requests.
1631
; 9. Process wait-done notifications, test for new wait requests.
1632
; Note: that must be done after steps 4 and 7 which could create new requests.
1632
; Note: that must be done after steps 4 and 7 which could create new requests.
1633
; 9a. Call the worker function.
1633
; 9a. Call the worker function.
1634
        invoke  usbhc_api.usb_process_wait_lists
1634
        invoke  usbhc_api.usb_process_wait_lists
1635
; 9b. If it reports that an asynchronous endpoint should be removed,
1635
; 9b. If it reports that an asynchronous endpoint should be removed,
1636
; doorbell InterruptOnAsyncAdvance and schedule wakeup in 1s
1636
; doorbell InterruptOnAsyncAdvance and schedule wakeup in 1s
1637
; (sometimes it just does not fire).
1637
; (sometimes it just does not fire).
1638
        test    al, 1 shl CONTROL_PIPE
1638
        test    al, 1 shl CONTROL_PIPE
1639
        jz      @f
1639
        jz      @f
1640
        mov     edx, [esi+usb_controller.WaitPipeListAsync]
1640
        mov     edx, [esi+usb_controller.WaitPipeListAsync]
1641
        mov     [esi+usb_controller.WaitPipeRequestAsync], edx
1641
        mov     [esi+usb_controller.WaitPipeRequestAsync], edx
1642
        or      dword [edi+EhciCommandReg], 1 shl 6
1642
        or      dword [edi+EhciCommandReg], 1 shl 6
1643
;        dbgstr 'async advance doorbell'
1643
;        dbgstr 'async advance doorbell'
1644
        cmp     dword [esp], 100
1644
        cmp     dword [esp], 100
1645
        jb      @f
1645
        jb      @f
1646
        mov     dword [esp], 100
1646
        mov     dword [esp], 100
1647
@@:
1647
@@:
1648
; 9c. If it reports that a periodic endpoint should be removed,
1648
; 9c. If it reports that a periodic endpoint should be removed,
1649
; save the current frame and schedule wakeup in 0.01 sec.
1649
; save the current frame and schedule wakeup in 0.01 sec.
1650
        test    al, 1 shl INTERRUPT_PIPE
1650
        test    al, 1 shl INTERRUPT_PIPE
1651
        jz      @f
1651
        jz      @f
1652
        mov     eax, [esi+usb_controller.WaitPipeListPeriodic]
1652
        mov     eax, [esi+usb_controller.WaitPipeListPeriodic]
1653
        mov     [esi+usb_controller.WaitPipeRequestPeriodic], eax
1653
        mov     [esi+usb_controller.WaitPipeRequestPeriodic], eax
1654
        mov     edx, [edi+EhciFrameIndexReg]
1654
        mov     edx, [edi+EhciFrameIndexReg]
1655
        mov     [esi+usb_controller.StartWaitFrame], edx
1655
        mov     [esi+usb_controller.StartWaitFrame], edx
1656
        mov     dword [esp], 1  ; wakeup in 0.01 sec for next test
1656
        mov     dword [esp], 1  ; wakeup in 0.01 sec for next test
1657
@@:
1657
@@:
1658
; 10. Pop the return value, restore the stack after step 1 and return.
1658
; 10. Pop the return value, restore the stack after step 1 and return.
1659
        pop     eax
1659
        pop     eax
1660
        pop     ecx
1660
        pop     ecx
1661
        pop     edi ebx ; restore used registers to be stdcall
1661
        pop     edi ebx ; restore used registers to be stdcall
1662
        ret
1662
        ret
1663
endp
1663
endp
1664
 
1664
 
1665
; This procedure is called in the USB thread from ehci_process_deferred
1665
; This procedure is called in the USB thread from ehci_process_deferred
1666
; when EHCI IRQ handler has signalled that new IOC-packet was processed.
1666
; when EHCI IRQ handler has signalled that new IOC-packet was processed.
1667
; It scans all lists for completed packets and calls ehci_process_finalized_td
1667
; It scans all lists for completed packets and calls ehci_process_finalized_td
1668
; for those packets.
1668
; for those packets.
1669
proc ehci_process_updated_schedule
1669
proc ehci_process_updated_schedule
1670
; Important note: we cannot hold the list lock during callbacks,
1670
; Important note: we cannot hold the list lock during callbacks,
1671
; because callbacks sometimes open and/or close pipes and thus acquire/release
1671
; because callbacks sometimes open and/or close pipes and thus acquire/release
1672
; the corresponding lock itself.
1672
; the corresponding lock itself.
1673
; Fortunately, pipes can be finally freed only by another step of
1673
; Fortunately, pipes can be finally freed only by another step of
1674
; ehci_process_deferred, so all pipes existing at the start of this function
1674
; ehci_process_deferred, so all pipes existing at the start of this function
1675
; will be valid while this function is running. Some pipes can be removed
1675
; will be valid while this function is running. Some pipes can be removed
1676
; from the corresponding list, some pipes can be inserted; insert/remove
1676
; from the corresponding list, some pipes can be inserted; insert/remove
1677
; functions guarantee that traversing one list yields all pipes that were in
1677
; functions guarantee that traversing one list yields all pipes that were in
1678
; that list at the beginning of the traversing (possibly with some new pipes,
1678
; that list at the beginning of the traversing (possibly with some new pipes,
1679
; possibly without some new pipes, that doesn't matter).
1679
; possibly without some new pipes, that doesn't matter).
1680
        push    edi
1680
        push    edi
1681
; 1. Process all Periodic lists.
1681
; 1. Process all Periodic lists.
1682
        lea     edi, [esi+ehci_controller.IntEDs-sizeof.ehci_controller+ehci_static_ep.SoftwarePart]
1682
        lea     edi, [esi+ehci_controller.IntEDs-sizeof.ehci_controller+ehci_static_ep.SoftwarePart]
1683
        lea     ebx, [esi+ehci_controller.IntEDs+63*sizeof.ehci_static_ep-sizeof.ehci_controller+ehci_static_ep.SoftwarePart]
1683
        lea     ebx, [esi+ehci_controller.IntEDs+63*sizeof.ehci_static_ep-sizeof.ehci_controller+ehci_static_ep.SoftwarePart]
1684
@@:
1684
@@:
1685
        call    ehci_process_updated_list
1685
        call    ehci_process_updated_list
1686
        cmp     edi, ebx
1686
        cmp     edi, ebx
1687
        jnz     @b
1687
        jnz     @b
1688
; 2. Process the Control list.
1688
; 2. Process the Control list.
1689
        add     edi, ehci_controller.ControlDelta
1689
        add     edi, ehci_controller.ControlDelta
1690
        call    ehci_process_updated_list
1690
        call    ehci_process_updated_list
1691
; 3. Process the Bulk list.
1691
; 3. Process the Bulk list.
1692
        call    ehci_process_updated_list
1692
        call    ehci_process_updated_list
1693
; 4. Return.
1693
; 4. Return.
1694
        pop     edi
1694
        pop     edi
1695
        ret
1695
        ret
1696
endp
1696
endp
1697
 
1697
 
1698
; This procedure is called from ehci_process_updated_schedule, see comments there.
1698
; This procedure is called from ehci_process_updated_schedule, see comments there.
1699
; It processes one list, esi -> usb_controller, edi -> usb_static_ep,
1699
; It processes one list, esi -> usb_controller, edi -> usb_static_ep,
1700
; and advances edi to next head.
1700
; and advances edi to next head.
1701
proc ehci_process_updated_list
1701
proc ehci_process_updated_list
1702
        push    ebx
1702
        push    ebx
1703
; 1. Perform the external loop over all pipes.
1703
; 1. Perform the external loop over all pipes.
1704
        mov     ebx, [edi+usb_static_ep.NextVirt]
1704
        mov     ebx, [edi+usb_static_ep.NextVirt]
1705
.loop:
1705
.loop:
1706
        cmp     ebx, edi
1706
        cmp     ebx, edi
1707
        jz      .done
1707
        jz      .done
1708
; store pointer to the next pipe in the stack
1708
; store pointer to the next pipe in the stack
1709
        push    [ebx+usb_static_ep.NextVirt]
1709
        push    [ebx+usb_static_ep.NextVirt]
1710
; 2. For every pipe, perform the internal loop over all descriptors.
1710
; 2. For every pipe, perform the internal loop over all descriptors.
1711
; All descriptors are organized in the queue; we process items from the start
1711
; All descriptors are organized in the queue; we process items from the start
1712
; of the queue until a) the last descriptor (not the part of the queue itself)
1712
; of the queue until a) the last descriptor (not the part of the queue itself)
1713
; or b) an active (not yet processed by the hardware) descriptor is reached.
1713
; or b) an active (not yet processed by the hardware) descriptor is reached.
1714
        lea     ecx, [ebx+usb_pipe.Lock]
1714
        lea     ecx, [ebx+usb_pipe.Lock]
1715
        invoke  MutexLock
1715
        invoke  MutexLock
1716
        mov     ebx, [ebx+usb_pipe.LastTD]
1716
        mov     ebx, [ebx+usb_pipe.LastTD]
1717
        push    ebx
1717
        push    ebx
1718
        mov     ebx, [ebx+usb_gtd.NextVirt]
1718
        mov     ebx, [ebx+usb_gtd.NextVirt]
1719
.tdloop:
1719
.tdloop:
1720
; 3. For every descriptor, test active flag and check for end-of-queue;
1720
; 3. For every descriptor, test active flag and check for end-of-queue;
1721
; if either of conditions holds, exit from the internal loop.
1721
; if either of conditions holds, exit from the internal loop.
1722
        cmp     ebx, [esp]
1722
        cmp     ebx, [esp]
1723
        jz      .tddone
1723
        jz      .tddone
1724
        cmp     byte [ebx+ehci_gtd.Token-sizeof.ehci_gtd], 0
1724
        cmp     byte [ebx+ehci_gtd.Token-sizeof.ehci_gtd], 0
1725
        js      .tddone
1725
        js      .tddone
1726
; Release the queue lock while processing one descriptor:
1726
; Release the queue lock while processing one descriptor:
1727
; callback function could (and often would) schedule another transfer.
1727
; callback function could (and often would) schedule another transfer.
1728
        push    ecx
1728
        push    ecx
1729
        invoke  MutexUnlock
1729
        invoke  MutexUnlock
1730
        call    ehci_process_updated_td
1730
        call    ehci_process_updated_td
1731
        pop     ecx
1731
        pop     ecx
1732
        invoke  MutexLock
1732
        invoke  MutexLock
1733
        jmp     .tdloop
1733
        jmp     .tdloop
1734
.tddone:
1734
.tddone:
1735
        invoke  MutexUnlock
1735
        invoke  MutexUnlock
1736
        pop     ebx
1736
        pop     ebx
1737
; End of internal loop, restore pointer to the next pipe
1737
; End of internal loop, restore pointer to the next pipe
1738
; and continue the external loop.
1738
; and continue the external loop.
1739
        pop     ebx
1739
        pop     ebx
1740
        jmp     .loop
1740
        jmp     .loop
1741
.done:
1741
.done:
1742
        pop     ebx
1742
        pop     ebx
1743
        add     edi, sizeof.ehci_static_ep
1743
        add     edi, sizeof.ehci_static_ep
1744
        ret
1744
        ret
1745
endp
1745
endp
1746
 
1746
 
1747
; This procedure is called from ehci_process_updated_list, which is itself
1747
; This procedure is called from ehci_process_updated_list, which is itself
1748
; called from ehci_process_updated_schedule, see comments there.
1748
; called from ehci_process_updated_schedule, see comments there.
1749
; It processes one completed descriptor.
1749
; It processes one completed descriptor.
1750
; in: ebx -> usb_gtd, out: ebx -> next usb_gtd.
1750
; in: ebx -> usb_gtd, out: ebx -> next usb_gtd.
1751
proc ehci_process_updated_td
1751
proc ehci_process_updated_td
1752
;       mov     eax, [ebx+usb_gtd.Pipe]
1752
;       mov     eax, [ebx+usb_gtd.Pipe]
1753
;       cmp     [eax+usb_pipe.Type], INTERRUPT_PIPE
1753
;       cmp     [eax+usb_pipe.Type], INTERRUPT_PIPE
1754
;       jnz     @f
1754
;       jnz     @f
1755
;       DEBUGF 1,'K : finalized TD for pipe %x:\n',eax
1755
;       DEBUGF 1,'K : finalized TD for pipe %x:\n',eax
1756
;       lea     eax, [ebx-sizeof.ehci_gtd]
1756
;       lea     eax, [ebx-sizeof.ehci_gtd]
1757
;       DEBUGF 1,'K : %x %x %x %x\n',[eax],[eax+4],[eax+8],[eax+12]
1757
;       DEBUGF 1,'K : %x %x %x %x\n',[eax],[eax+4],[eax+8],[eax+12]
1758
;       DEBUGF 1,'K : %x %x %x %x\n',[eax+16],[eax+20],[eax+24],[eax+28]
1758
;       DEBUGF 1,'K : %x %x %x %x\n',[eax+16],[eax+20],[eax+24],[eax+28]
1759
;@@:
1759
;@@:
1760
; 1. Remove this descriptor from the list of descriptors for this pipe.
1760
; 1. Remove this descriptor from the list of descriptors for this pipe.
1761
        invoke  usbhc_api.usb_unlink_td
1761
        invoke  usbhc_api.usb_unlink_td
1762
; 2. Calculate actual number of bytes transferred.
1762
; 2. Calculate actual number of bytes transferred.
1763
        mov     eax, [ebx+ehci_gtd.Token-sizeof.ehci_gtd]
1763
        mov     eax, [ebx+ehci_gtd.Token-sizeof.ehci_gtd]
1764
        lea     edx, [eax+eax]
1764
        lea     edx, [eax+eax]
1765
        shr     edx, 17
1765
        shr     edx, 17
1766
        sub     edx, [ebx+usb_gtd.Length]
1766
        sub     edx, [ebx+usb_gtd.Length]
1767
        neg     edx
1767
        neg     edx
1768
; 3. Check whether we need some special processing beyond notifying the driver.
1768
; 3. Check whether we need some special processing beyond notifying the driver.
1769
; Transfer errors require special processing.
1769
; Transfer errors require special processing.
1770
; Short packets require special processing if
1770
; Short packets require special processing if
1771
; a) this is not the last descriptor for transfer stage
1771
; a) this is not the last descriptor for transfer stage
1772
; (in this case we need to process subsequent descriptors for the stage too)
1772
; (in this case we need to process subsequent descriptors for the stage too)
1773
; or b) the caller considers short transfers to be an error.
1773
; or b) the caller considers short transfers to be an error.
1774
; ehci_alloc_transfer sets bit 0 of ehci_gtd.Flags to 0 if short packet
1774
; ehci_alloc_transfer sets bit 0 of ehci_gtd.Flags to 0 if short packet
1775
; in this descriptor requires special processing and to 1 otherwise.
1775
; in this descriptor requires special processing and to 1 otherwise.
1776
; If special processing is not needed, advance to 4 with ecx = 0.
1776
; If special processing is not needed, advance to 4 with ecx = 0.
1777
; Otherwise, go to 6.
1777
; Otherwise, go to 6.
1778
        xor     ecx, ecx
1778
        xor     ecx, ecx
1779
        test    al, 40h
1779
        test    al, 40h
1780
        jnz     .error
1780
        jnz     .error
1781
        test    byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1
1781
        test    byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1
1782
        jnz     .notify
1782
        jnz     .notify
1783
        cmp     edx, [ebx+usb_gtd.Length]
1783
        cmp     edx, [ebx+usb_gtd.Length]
1784
        jnz     .special
1784
        jnz     .special
1785
.notify:
1785
.notify:
1786
; 4. Either the descriptor in ebx was processed without errors,
1786
; 4. Either the descriptor in ebx was processed without errors,
1787
; or all necessary error actions were taken and ebx points to the last
1787
; or all necessary error actions were taken and ebx points to the last
1788
; related descriptor.
1788
; related descriptor.
1789
        invoke  usbhc_api.usb_process_gtd
1789
        invoke  usbhc_api.usb_process_gtd
1790
; 5. Free the current descriptor and return the next one.
1790
; 5. Free the current descriptor and return the next one.
1791
        push    [ebx+usb_gtd.NextVirt]
1791
        push    [ebx+usb_gtd.NextVirt]
1792
        stdcall ehci_free_td, ebx
1792
        stdcall ehci_free_td, ebx
1793
        pop     ebx
1793
        pop     ebx
1794
        ret
1794
        ret
1795
.error:
1795
.error:
1796
        push    ebx
1796
        push    ebx
1797
        sub     ebx, sizeof.ehci_gtd
1797
        sub     ebx, sizeof.ehci_gtd
1798
        DEBUGF 1,'K : TD failed:\n'
1798
        DEBUGF 1,'K : TD failed:\n'
1799
        DEBUGF 1,'K : %x %x %x %x\n',[ebx],[ebx+4],[ebx+8],[ebx+12]
1799
        DEBUGF 1,'K : %x %x %x %x\n',[ebx],[ebx+4],[ebx+8],[ebx+12]
1800
        DEBUGF 1,'K : %x %x %x %x\n',[ebx+16],[ebx+20],[ebx+24],[ebx+28]
1800
        DEBUGF 1,'K : %x %x %x %x\n',[ebx+16],[ebx+20],[ebx+24],[ebx+28]
1801
        pop     ebx
1801
        pop     ebx
1802
        DEBUGF 1,'K : pipe now:\n'
1802
        DEBUGF 1,'K : pipe now:\n'
1803
        mov     ecx, [ebx+usb_gtd.Pipe]
1803
        mov     ecx, [ebx+usb_gtd.Pipe]
1804
        sub     ecx, sizeof.ehci_pipe
1804
        sub     ecx, sizeof.ehci_pipe
1805
        DEBUGF 1,'K : %x %x %x %x\n',[ecx],[ecx+4],[ecx+8],[ecx+12]
1805
        DEBUGF 1,'K : %x %x %x %x\n',[ecx],[ecx+4],[ecx+8],[ecx+12]
1806
        DEBUGF 1,'K : %x %x %x %x\n',[ecx+16],[ecx+20],[ecx+24],[ecx+28]
1806
        DEBUGF 1,'K : %x %x %x %x\n',[ecx+16],[ecx+20],[ecx+24],[ecx+28]
1807
        DEBUGF 1,'K : %x %x %x %x\n',[ecx+32],[ecx+36],[ecx+40],[ecx+44]
1807
        DEBUGF 1,'K : %x %x %x %x\n',[ecx+32],[ecx+36],[ecx+40],[ecx+44]
1808
.special:
1808
.special:
1809
; 6. Special processing is needed.
1809
; 6. Special processing is needed.
1810
; 6a. Save the status and length.
1810
; 6a. Save the status and length.
1811
        push    edx
1811
        push    edx
1812
        push    eax
1812
        push    eax
1813
; 6b. Traverse the list of descriptors looking for the final descriptor
1813
; 6b. Traverse the list of descriptors looking for the final descriptor
1814
; for this transfer. Free and unlink non-final descriptors.
1814
; for this transfer. Free and unlink non-final descriptors.
1815
; Final descriptor will be freed in step 5.
1815
; Final descriptor will be freed in step 5.
1816
.look_final:
1816
.look_final:
1817
        invoke  usbhc_api.usb_is_final_packet
1817
        invoke  usbhc_api.usb_is_final_packet
1818
        jnc     .found_final
1818
        jnc     .found_final
1819
        push    [ebx+usb_gtd.NextVirt]
1819
        push    [ebx+usb_gtd.NextVirt]
1820
        stdcall ehci_free_td, ebx
1820
        stdcall ehci_free_td, ebx
1821
        pop     ebx
1821
        pop     ebx
1822
        invoke  usbhc_api.usb_unlink_td
1822
        invoke  usbhc_api.usb_unlink_td
1823
        jmp     .look_final
1823
        jmp     .look_final
1824
.found_final:
1824
.found_final:
1825
; 6c. Restore the status saved in 6a and transform it to the error code.
1825
; 6c. Restore the status saved in 6a and transform it to the error code.
1826
; Notes:
1826
; Notes:
1827
; * any USB transaction error results in Halted bit; if it is not set,
1827
; * any USB transaction error results in Halted bit; if it is not set,
1828
;   but we are here, it must be due to short packet;
1828
;   but we are here, it must be due to short packet;
1829
; * babble is considered a fatal USB transaction error,
1829
; * babble is considered a fatal USB transaction error,
1830
;   other errors just lead to retrying the transaction;
1830
;   other errors just lead to retrying the transaction;
1831
;   if babble is detected, return the corresponding error;
1831
;   if babble is detected, return the corresponding error;
1832
; * if several non-fatal errors have occured during transaction retries,
1832
; * if several non-fatal errors have occured during transaction retries,
1833
;   all corresponding bits are set. In this case, return some error code,
1833
;   all corresponding bits are set. In this case, return some error code,
1834
;   the order is quite arbitrary.
1834
;   the order is quite arbitrary.
1835
        pop     eax     ; status
1835
        pop     eax     ; status
1836
        movi    ecx, USB_STATUS_UNDERRUN
1836
        movi    ecx, USB_STATUS_UNDERRUN
1837
        test    al, 40h         ; not Halted?
1837
        test    al, 40h         ; not Halted?
1838
        jz      .know_error
1838
        jz      .know_error
1839
        mov     cl, USB_STATUS_OVERRUN
1839
        mov     cl, USB_STATUS_OVERRUN
1840
        test    al, 10h         ; Babble detected?
1840
        test    al, 10h         ; Babble detected?
1841
        jnz     .know_error
1841
        jnz     .know_error
1842
        mov     cl, USB_STATUS_BUFOVERRUN
1842
        mov     cl, USB_STATUS_BUFOVERRUN
1843
        test    al, 20h         ; Data Buffer error?
1843
        test    al, 20h         ; Data Buffer error?
1844
        jnz     .know_error
1844
        jnz     .know_error
1845
        mov     cl, USB_STATUS_NORESPONSE
1845
        mov     cl, USB_STATUS_NORESPONSE
1846
        test    al, 8           ; Transaction Error?
1846
        test    al, 8           ; Transaction Error?
1847
        jnz     .know_error
1847
        jnz     .know_error
1848
        mov     cl, USB_STATUS_STALL
1848
        mov     cl, USB_STATUS_STALL
1849
.know_error:
1849
.know_error:
1850
; 6d. If error code is USB_STATUS_UNDERRUN and the last TD allows short packets,
1850
; 6d. If error code is USB_STATUS_UNDERRUN and the last TD allows short packets,
1851
; it is not an error; in this case, go to 4 with ecx = 0.
1851
; it is not an error; in this case, go to 4 with ecx = 0.
1852
        cmp     ecx, USB_STATUS_UNDERRUN
1852
        cmp     ecx, USB_STATUS_UNDERRUN
1853
        jnz     @f
1853
        jnz     @f
1854
        test    byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1
1854
        test    byte [ebx+ehci_gtd.Flags-sizeof.ehci_gtd], 1
1855
        jz      @f
1855
        jz      @f
1856
        xor     ecx, ecx
1856
        xor     ecx, ecx
1857
        pop     edx     ; length
1857
        pop     edx     ; length
1858
        jmp     .notify
1858
        jmp     .notify
1859
@@:
1859
@@:
1860
; 6e. Abort the entire transfer.
1860
; 6e. Abort the entire transfer.
1861
; There are two cases: either there is only one transfer stage
1861
; There are two cases: either there is only one transfer stage
1862
; (everything except control transfers), then ebx points to the last TD and
1862
; (everything except control transfers), then ebx points to the last TD and
1863
; all previous TD were unlinked and dismissed (if possible),
1863
; all previous TD were unlinked and dismissed (if possible),
1864
; or there are several stages (a control transfer) and ebx points to the last
1864
; or there are several stages (a control transfer) and ebx points to the last
1865
; TD of Data or Status stage (usb_is_final_packet does not stop in Setup stage,
1865
; TD of Data or Status stage (usb_is_final_packet does not stop in Setup stage,
1866
; because Setup stage can not produce short packets); for Data stage, we need
1866
; because Setup stage can not produce short packets); for Data stage, we need
1867
; to unlink and free (if possible) one more TD and advance ebx to the next one.
1867
; to unlink and free (if possible) one more TD and advance ebx to the next one.
1868
        cmp     [ebx+usb_gtd.Callback], 0
1868
        cmp     [ebx+usb_gtd.Callback], 0
1869
        jnz     .normal
1869
        jnz     .normal
1870
        push    ecx
1870
        push    ecx
1871
        push    [ebx+usb_gtd.NextVirt]
1871
        push    [ebx+usb_gtd.NextVirt]
1872
        stdcall ehci_free_td, ebx
1872
        stdcall ehci_free_td, ebx
1873
        pop     ebx
1873
        pop     ebx
1874
        invoke  usbhc_api.usb_unlink_td
1874
        invoke  usbhc_api.usb_unlink_td
1875
        pop     ecx
1875
        pop     ecx
1876
.normal:
1876
.normal:
1877
; 6f. For bulk/interrupt transfers we have no choice but halt the queue,
1877
; 6f. For bulk/interrupt transfers we have no choice but halt the queue,
1878
; the driver should intercede (through some API which is not written yet).
1878
; the driver should intercede (through some API which is not written yet).
1879
; Control pipes normally recover at the next SETUP transaction (first stage
1879
; Control pipes normally recover at the next SETUP transaction (first stage
1880
; of any control transfer), so we hope on the best and just advance the queue
1880
; of any control transfer), so we hope on the best and just advance the queue
1881
; to the next transfer. (According to the standard, "A control pipe may also
1881
; to the next transfer. (According to the standard, "A control pipe may also
1882
; support functional stall as well, but this is not recommended.").
1882
; support functional stall as well, but this is not recommended.").
1883
        mov     edx, [ebx+usb_gtd.Pipe]
1883
        mov     edx, [ebx+usb_gtd.Pipe]
1884
        mov     eax, [ebx+ehci_gtd.NextTD-sizeof.ehci_gtd]
1884
        mov     eax, [ebx+ehci_gtd.NextTD-sizeof.ehci_gtd]
1885
        or      al, 1
1885
        or      al, 1
1886
        mov     [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
1886
        mov     [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
1887
        mov     [edx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax
1887
        mov     [edx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax
1888
        cmp     [edx+usb_pipe.Type], CONTROL_PIPE
1888
        cmp     [edx+usb_pipe.Type], CONTROL_PIPE
1889
        jz      .control
1889
        jz      .control
1890
; Bulk/interrupt transfer; halt the queue.
1890
; Bulk/interrupt transfer; halt the queue.
1891
        mov     [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 40h
1891
        mov     [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 40h
1892
        pop     edx
1892
        pop     edx
1893
        jmp     .notify
1893
        jmp     .notify
1894
; Control transfer.
1894
; Control transfer.
1895
.control:
1895
.control:
1896
        and     [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 0
1896
        and     [edx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 0
1897
        dec     [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe]
1897
        dec     [edx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe]
1898
        pop     edx
1898
        pop     edx
1899
        jmp     .notify
1899
        jmp     .notify
1900
endp
1900
endp
1901
 
1901
 
1902
; This procedure unlinks the pipe from the corresponding pipe list.
1902
; This procedure unlinks the pipe from the corresponding pipe list.
1903
; esi -> usb_controller, ebx -> usb_pipe
1903
; esi -> usb_controller, ebx -> usb_pipe
1904
proc ehci_unlink_pipe
1904
proc ehci_unlink_pipe
1905
        cmp     [ebx+usb_pipe.Type], INTERRUPT_PIPE
1905
        cmp     [ebx+usb_pipe.Type], INTERRUPT_PIPE
1906
        jnz     @f
1906
        jnz     @f
1907
        test    word [ebx+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh
1907
        test    word [ebx+ehci_pipe.Flags-sizeof.ehci_pipe+2], 3FFFh
1908
        jnz     .interrupt_fs
1908
        jnz     .interrupt_fs
1909
        call    ehci_hs_interrupt_list_unlink
1909
        call    ehci_hs_interrupt_list_unlink
1910
        jmp     .interrupt_common
1910
        jmp     .interrupt_common
1911
.interrupt_fs:
1911
.interrupt_fs:
1912
        call    ehci_fs_interrupt_list_unlink
1912
        call    ehci_fs_interrupt_list_unlink
1913
.interrupt_common:
1913
.interrupt_common:
1914
@@:
1914
@@:
1915
        ret
1915
        ret
1916
endp
1916
endp
1917
 
1917
 
1918
; This procedure temporarily removes the given pipe from hardware queue.
1918
; This procedure temporarily removes the given pipe from hardware queue.
1919
; esi -> usb_controller, ebx -> usb_pipe
1919
; esi -> usb_controller, ebx -> usb_pipe
1920
proc ehci_disable_pipe
1920
proc ehci_disable_pipe
1921
        mov     eax, [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe]
1921
        mov     eax, [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe]
1922
        mov     ecx, [ebx+usb_pipe.PrevVirt]
1922
        mov     ecx, [ebx+usb_pipe.PrevVirt]
1923
        mov     edx, esi
1923
        mov     edx, esi
1924
        sub     edx, ecx
1924
        sub     edx, ecx
1925
        cmp     edx, sizeof.ehci_controller
1925
        cmp     edx, sizeof.ehci_controller
1926
        jb      .prev_is_static
1926
        jb      .prev_is_static
1927
        mov     [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax
1927
        mov     [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax
1928
        ret
1928
        ret
1929
.prev_is_static:
1929
.prev_is_static:
1930
        mov     [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1930
        mov     [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1931
        ret
1931
        ret
1932
endp
1932
endp
1933
 
1933
 
1934
; This procedure reinserts the given pipe to hardware queue
1934
; This procedure reinserts the given pipe to hardware queue
1935
; after ehci_disable_pipe, with clearing transfer queue.
1935
; after ehci_disable_pipe, with clearing transfer queue.
1936
; esi -> usb_controller, ebx -> usb_pipe
1936
; esi -> usb_controller, ebx -> usb_pipe
1937
; edx -> current descriptor, eax -> new last descriptor
1937
; edx -> current descriptor, eax -> new last descriptor
1938
proc ehci_enable_pipe
1938
proc ehci_enable_pipe
1939
; 1. Clear transfer queue.
1939
; 1. Clear transfer queue.
1940
; 1a. Clear status bits so that the controller will try to advance the queue
1940
; 1a. Clear status bits so that the controller will try to advance the queue
1941
; without doing anything, keep DataToggle and PID bits.
1941
; without doing anything, keep DataToggle and PID bits.
1942
        and     [ebx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 80000000h
1942
        and     [ebx+ehci_pipe.Overlay.Token-sizeof.ehci_pipe], 80000000h
1943
; 1b. Set [Alternate]NextTD to physical address of the new last descriptor.
1943
; 1b. Set [Alternate]NextTD to physical address of the new last descriptor.
1944
        sub     eax, sizeof.ehci_gtd
1944
        sub     eax, sizeof.ehci_gtd
1945
        invoke  GetPhysAddr
1945
        invoke  GetPhysAddr
1946
        mov     [ebx+ehci_pipe.HeadTD-sizeof.ehci_pipe], eax
1946
        mov     [ebx+ehci_pipe.HeadTD-sizeof.ehci_pipe], eax
1947
        mov     [ebx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
1947
        mov     [ebx+ehci_pipe.Overlay.NextTD-sizeof.ehci_pipe], eax
1948
        mov     [ebx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax
1948
        mov     [ebx+ehci_pipe.Overlay.AlternateNextTD-sizeof.ehci_pipe], eax
1949
; 2. Reinsert the pipe to hardware queue.
1949
; 2. Reinsert the pipe to hardware queue.
1950
        lea     eax, [ebx-sizeof.ehci_pipe]
1950
        lea     eax, [ebx-sizeof.ehci_pipe]
1951
        invoke  GetPhysAddr
1951
        invoke  GetPhysAddr
1952
        inc     eax
1952
        inc     eax
1953
        inc     eax
1953
        inc     eax
1954
        mov     ecx, [ebx+usb_pipe.PrevVirt]
1954
        mov     ecx, [ebx+usb_pipe.PrevVirt]
1955
        mov     edx, esi
1955
        mov     edx, esi
1956
        sub     edx, ecx
1956
        sub     edx, ecx
1957
        cmp     edx, sizeof.ehci_controller
1957
        cmp     edx, sizeof.ehci_controller
1958
        jb      .prev_is_static
1958
        jb      .prev_is_static
1959
        mov     edx, [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe]
1959
        mov     edx, [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe]
1960
        mov     [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx
1960
        mov     [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx
1961
        mov     [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax
1961
        mov     [ecx+ehci_pipe.NextQH-sizeof.ehci_pipe], eax
1962
        ret
1962
        ret
1963
.prev_is_static:
1963
.prev_is_static:
1964
        mov     edx, [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart]
1964
        mov     edx, [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart]
1965
        mov     [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx
1965
        mov     [ebx+ehci_pipe.NextQH-sizeof.ehci_pipe], edx
1966
        mov     [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1966
        mov     [ecx+ehci_static_ep.NextQH-ehci_static_ep.SoftwarePart], eax
1967
        ret
1967
        ret
1968
endp
1968
endp
1969
 
1969
 
1970
proc ehci_alloc_td
1970
proc ehci_alloc_td
1971
        push    ebx
1971
        push    ebx
1972
        mov     ebx, ehci_gtd_mutex
1972
        mov     ebx, ehci_gtd_mutex
1973
        invoke  usbhc_api.usb_allocate_common, (sizeof.ehci_gtd + sizeof.usb_gtd + 1Fh) and not 1Fh
1973
        invoke  usbhc_api.usb_allocate_common, (sizeof.ehci_gtd + sizeof.usb_gtd + 1Fh) and not 1Fh
1974
        test    eax, eax
1974
        test    eax, eax
1975
        jz      @f
1975
        jz      @f
1976
        add     eax, sizeof.ehci_gtd
1976
        add     eax, sizeof.ehci_gtd
1977
@@:
1977
@@:
1978
        pop     ebx
1978
        pop     ebx
1979
        ret
1979
        ret
1980
endp
1980
endp
1981
 
1981
 
1982
; This procedure is called from several places from main USB code and
1982
; This procedure is called from several places from main USB code and
1983
; frees all additional data associated with the transfer descriptor.
1983
; frees all additional data associated with the transfer descriptor.
1984
; EHCI has no additional data, so just free ehci_gtd structure.
1984
; EHCI has no additional data, so just free ehci_gtd structure.
1985
proc ehci_free_td
1985
proc ehci_free_td
1986
        sub     dword [esp+4], sizeof.ehci_gtd
1986
        sub     dword [esp+4], sizeof.ehci_gtd
1987
        jmp     [usbhc_api.usb_free_common]
1987
        jmp     [usbhc_api.usb_free_common]
1988
endp
1988
endp
1989
 
1989
 
1990
include 'ehci_scheduler.inc'
1990
include 'ehci_scheduler.inc'
1991
 
1991
 
1992
section '.data' readable writable
1992
section '.data' readable writable
1993
include '../peimport.inc'
1993
include '../peimport.inc'
1994
include_debug_strings
1994
include_debug_strings
1995
IncludeIGlobals
1995
IncludeIGlobals
1996
IncludeUGlobals
1996
IncludeUGlobals
1997
align 4
1997
align 4
1998
usbhc_api usbhc_func
1998
usbhc_api usbhc_func