Rev 3555 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3555 | Serge | 1 | ; Code for UHCI controllers. |
2 | ; Note: it should be moved to an external driver, |
||
3 | ; it was convenient to have this code compiled into the kernel during initial |
||
4 | ; development, but there are no reasons to keep it here. |
||
5 | |||
6 | ; ============================================================================= |
||
7 | ; ================================= Constants ================================= |
||
8 | ; ============================================================================= |
||
9 | ; UHCI register declarations |
||
10 | UhciCommandReg = 0 |
||
11 | UhciStatusReg = 2 |
||
12 | UhciInterruptReg = 4 |
||
13 | UhciFrameNumberReg = 6 |
||
14 | UhciBaseAddressReg = 8 |
||
15 | UhciSOFModifyReg = 0Ch |
||
16 | UhciPort1StatusReg = 10h |
||
17 | ; possible PIDs for USB data transfers |
||
18 | USB_PID_SETUP = 2Dh |
||
19 | USB_PID_IN = 69h |
||
20 | USB_PID_OUT = 0E1h |
||
21 | ; UHCI does not support an interrupt on root hub status change. We must poll |
||
22 | ; the controller periodically. This is the period in timer ticks (10ms). |
||
23 | ; We use the value 100 ms: it is valid value for USB hub poll rate (1-255 ms), |
||
24 | ; small enough to be responsible to connect events and large enough to not |
||
25 | ; load CPU too often. |
||
26 | UHCI_POLL_INTERVAL = 100 |
||
27 | ; the following constant is an invalid encoding for length fields in |
||
28 | ; uhci_gtd; it is used to check whether an inactive TD has been |
||
29 | ; completed (actual length of the transfer is valid) or not processed at all |
||
30 | ; (actual length of the transfer is UHCI_INVALID_LENGTH). |
||
31 | ; Valid values are 0-4FFh and 7FFh. We use 700h as an invalid value. |
||
32 | UHCI_INVALID_LENGTH = 700h |
||
33 | |||
34 | ; ============================================================================= |
||
35 | ; ================================ Structures ================================= |
||
36 | ; ============================================================================= |
||
37 | |||
38 | ; UHCI-specific part of a pipe descriptor. |
||
39 | ; * The structure corresponds to the Queue Head aka QH from the UHCI |
||
40 | ; specification with some additional fields. |
||
41 | ; * The hardware uses first two fields (8 bytes). Next two fields are used for |
||
42 | ; software book-keeping. |
||
43 | ; * The hardware requires 16-bytes alignment of the hardware part. |
||
44 | ; Since the allocator (usb_allocate_common) allocates memory sequentially |
||
45 | ; from page start (aligned on 0x1000 bytes), size of the structure must be |
||
46 | ; divisible by 16. |
||
47 | struct uhci_pipe |
||
48 | NextQH dd ? |
||
49 | ; 1. First bit (bit 0) is Terminate bit. 1 = there is no next QH. |
||
50 | ; 2. Next bit (bit 1) is QH/TD select bit. 1 = NextQH points to QH. |
||
51 | ; 3. Next two bits (bits 2-3) are reserved. |
||
52 | ; 4. With masked 4 lower bits, this is the physical address of the next QH in |
||
53 | ; the QH list. |
||
54 | ; See also the description before NextVirt field of the usb_pipe |
||
55 | ; structure. Additionally to that description, the following is specific for |
||
56 | ; the UHCI controller: |
||
57 | ; * n=10, N=1024. However, this number is quite large. |
||
58 | ; * 1024 lists are used only for individual transfer descriptors for |
||
59 | ; Isochronous endpoints. This means that the software can sleep up to 1024 ms |
||
60 | ; before initiating the next portion of a large isochronous transfer, which |
||
61 | ; is a sufficiently large value. |
||
62 | ; * We use the 32ms upper limit for interrupt endpoint polling interval. |
||
63 | ; This seems to be a reasonable value. |
||
64 | ; * The "next" list for last Periodic list is the Control list. |
||
65 | ; * The "next" list for Control list is Bulk list and the "next" |
||
66 | ; list for Bulk list is Control list. This loop is used for bandwidth |
||
67 | ; reclamation: the hardware traverses lists until end-of-frame. |
||
68 | HeadTD dd ? |
||
69 | ; 1. First bit (bit 0) is Terminate bit. 1 = there is no TDs in this QH. |
||
70 | ; 2. Next bit (bit 1) is QH/TD select bit. 1 = HeadTD points to QH. |
||
71 | ; 3. Next two bits (bits 2-3) are reserved. |
||
72 | ; 4. With masked 4 lower bits, this is the physical address of the first TD in |
||
73 | ; the TD queue for this QH. |
||
74 | Token dd ? |
||
75 | ; This field is a template for uhci_gtd.Token field in transfer |
||
76 | ; descriptors. The meaning of individual bits is the same as for |
||
77 | ; uhci_gtd.Token, except that PID bitfield is always |
||
78 | ; USB_PID_SETUP/IN/OUT for control/in/out pipes, |
||
79 | ; the MaximumLength bitfield encodes maximum packet size, |
||
80 | ; the Reserved bit 20 is LowSpeedDevice bit. |
||
81 | ErrorTD dd ? |
||
82 | ; Usually NULL. If nonzero, it is a pointer to descriptor which was error'd |
||
83 | ; and should be freed sometime in the future (the hardware could still use it). |
||
84 | SoftwarePart rd sizeof.usb_pipe/4 |
||
85 | ; Common part for all controllers, described by usb_pipe structure. |
||
86 | ends |
||
87 | |||
88 | if sizeof.uhci_pipe mod 16 |
||
89 | .err uhci_pipe must be 16-bytes aligned |
||
90 | end if |
||
91 | |||
92 | ; This structure describes the static head of every list of pipes. |
||
93 | ; The hardware requires 16-bytes alignment of this structure. |
||
94 | ; All instances of this structure are located sequentially in uhci_controller, |
||
95 | ; uhci_controller is page-aligned, so it is sufficient to make this structure |
||
96 | ; 16-bytes aligned and verify that the first instance is 16-bytes aligned |
||
97 | ; inside uhci_controller. |
||
98 | struct uhci_static_ep |
||
99 | NextQH dd ? |
||
100 | ; Same as uhci_pipe.NextQH. |
||
101 | HeadTD dd ? |
||
102 | ; Same as uhci_pipe.HeadTD. |
||
103 | NextList dd ? |
||
104 | ; Virtual address of the next list. |
||
105 | dd ? |
||
106 | ; Not used. |
||
107 | SoftwarePart rd sizeof.usb_static_ep/4 |
||
108 | ; Common part for all controllers, described by usb_static_ep structure. |
||
109 | dd ? |
||
110 | ; Padding for 16-byte alignment. |
||
111 | ends |
||
112 | |||
113 | if sizeof.uhci_static_ep mod 16 |
||
114 | .err uhci_static_ep must be 16-bytes aligned |
||
115 | end if |
||
116 | |||
117 | ; UHCI-specific part of controller data. |
||
118 | ; * The structure includes two parts, the hardware part and the software part. |
||
119 | ; * The hardware part consists of first 4096 bytes and corresponds to |
||
120 | ; the Frame List from UHCI specification. |
||
121 | ; * The hardware requires page-alignment of the hardware part, so |
||
122 | ; the entire descriptor must be page-aligned. |
||
123 | ; This structure is allocated with kernel_alloc (see usb_init_controller), |
||
124 | ; this gives page-aligned data. |
||
125 | struct uhci_controller |
||
126 | ; ------------------------------ hardware fields ------------------------------ |
||
127 | FrameList rd 1024 |
||
128 | ; Entry n corresponds to the head of the frame list to be executed in |
||
3589 | Serge | 129 | ; the frames n,n+1024,n+2048,n+3072,... |
3555 | Serge | 130 | ; The first bit of each entry is Terminate bit, 1 = the frame is empty. |
131 | ; The second bit of each entry is QH/TD select bit, 1 = the entry points to |
||
132 | ; QH, 0 = to TD. |
||
133 | ; With masked 2 lower bits, the entry is a physical address of the first QH/TD |
||
134 | ; to be executed. |
||
135 | ; ------------------------------ software fields ------------------------------ |
||
136 | ; Every list has the static head, which is an always empty QH. |
||
137 | ; The following fields are static heads, one per list: |
||
138 | ; 32+16+8+4+2+1 = 63 for Periodic lists, 1 for Control list and 1 for Bulk list. |
||
139 | IntEDs uhci_static_ep |
||
140 | rb 62 * sizeof.uhci_static_ep |
||
141 | ControlED uhci_static_ep |
||
142 | BulkED uhci_static_ep |
||
143 | IOBase dd ? |
||
144 | ; Base port in I/O space for UHCI controller. |
||
145 | ; UHCI register UhciXxx is addressed as in/out to IOBase + UhciXxx, |
||
146 | ; see declarations in the beginning of this source. |
||
147 | DeferredActions dd ? |
||
148 | ; Bitmask of bits from UhciStatusReg which need to be processed |
||
149 | ; by uhci_process_deferred. Bit 0 = a transaction with IOC bit |
||
150 | ; has completed. Bit 1 = a transaction has failed. Set by uhci_irq, |
||
151 | ; cleared by uhci_process_deferred. |
||
152 | LastPollTime dd ? |
||
153 | ; See the comment before UHCI_POLL_INTERVAL. This variable keeps the |
||
154 | ; last time, in timer ticks, when the polling was done. |
||
155 | ends |
||
156 | |||
157 | if uhci_controller.IntEDs mod 16 |
||
158 | .err Static endpoint descriptors must be 16-bytes aligned inside uhci_controller |
||
159 | end if |
||
160 | |||
161 | ; UHCI general transfer descriptor. |
||
162 | ; * The structure describes non-Isochronous data transfers |
||
163 | ; for the UHCI controller. |
||
164 | ; * The structure includes two parts, the hardware part and the software part. |
||
165 | ; * The hardware part consists of first 16 bytes and corresponds to the |
||
166 | ; Transfer Descriptor aka TD from UHCI specification. |
||
167 | ; * The hardware requires 16-bytes alignment of the hardware part, so |
||
168 | ; the entire descriptor must be 16-bytes aligned. Since the allocator |
||
169 | ; (uhci_allocate_common) allocates memory sequentially from page start |
||
170 | ; (aligned on 0x1000 bytes), size of the structure must be divisible by 16. |
||
171 | struct uhci_gtd |
||
172 | NextTD dd ? |
||
173 | ; 1. First bit (bit 0) is Terminate bit. 1 = there is no next TD. |
||
174 | ; 2. Next bit (bit 1) is QH/TD select bit. 1 = NextTD points to QH. |
||
175 | ; This bit is always set to 0 in the implementation. |
||
176 | ; 3. Next bit (bit 2) is Depth/Breadth select bit. 1 = the controller should |
||
177 | ; proceed to the NextTD after this TD is complete. 0 = the controller |
||
178 | ; should proceed to the next endpoint after this TD is complete. |
||
179 | ; The implementation sets this bit to 0 for final stages of all transactions |
||
180 | ; and to 1 for other stages. |
||
181 | ; 4. Next bit (bit 3) is reserved and must be zero. |
||
182 | ; 5. With masked 4 lower bits, this is the physical address of the next TD |
||
183 | ; in the TD list. |
||
184 | ControlStatus dd ? |
||
185 | ; 1. Lower 11 bits (bits 0-10) are ActLen. This is written by the controller |
||
186 | ; at the conclusion of a USB transaction to indicate the actual number of |
||
187 | ; bytes that were transferred minus 1. |
||
188 | ; 2. Next 6 bits (bits 11-16) are reserved. |
||
189 | ; 3. Next bit (bit 17) signals Bitstuff error. |
||
190 | ; 4. Next bit (bit 18) signals CRC/Timeout error. |
||
191 | ; 5. Next bit (bit 19) signals NAK receive. |
||
192 | ; 6. Next bit (bit 20) signals Babble error. |
||
193 | ; 7. Next bit (bit 21) signals Data Buffer error. |
||
194 | ; 8. Next bit (bit 22) signals Stall error. |
||
195 | ; 9. Next bit (bit 23) is Active field. 1 = this TD should be processed. |
||
196 | ; 10. Next bit (bit 24) is InterruptOnComplete bit. 1 = the controller should |
||
197 | ; issue an interrupt on completion of the frame in which this TD is |
||
198 | ; executed. |
||
199 | ; 11. Next bit (bit 25) is IsochronousSelect bit. 1 = this TD is isochronous. |
||
200 | ; 12. Next bit (bit 26) is LowSpeedDevice bit. 1 = this TD is for low-speed. |
||
201 | ; 13. Next two bits (bits 27-28) are ErrorCounter field. This field is |
||
202 | ; decremented by the controller on every non-fatal error with this TD. |
||
203 | ; Babble and Stall are considered fatal errors and immediately deactivate |
||
204 | ; the TD without decrementing this field. 0 = no error limit, |
||
205 | ; n = deactivate the TD after n errors. |
||
206 | ; 14. Next bit (bit 29) is ShortPacketDetect bit. 1 = short packet is an error. |
||
207 | ; Note: the specification defines this bit as input for the controller, |
||
208 | ; but does not specify the value written by controller. |
||
209 | ; Some controllers (e.g. Intel) keep the value, some controllers (e.g. VIA) |
||
210 | ; set the value to whether a short packet was actually detected |
||
211 | ; (or something like that). |
||
212 | ; Thus, we duplicate this bit as bit 0 of OrigBufferInfo. |
||
213 | ; 15. Upper two bits (bits 30-31) are reserved. |
||
214 | Token dd ? |
||
215 | ; 1. Lower 8 bits (bits 0-7) are PID, one of USB_PID_*. |
||
216 | ; 2. Next 7 bits (bits 8-14) are DeviceAddress field. This is the address of |
||
217 | ; the target device on the USB bus. |
||
218 | ; 3. Next 4 bits (bits 15-18) are Endpoint field. This is the target endpoint |
||
219 | ; number. |
||
220 | ; 4. Next bit (bit 19) is DataToggle bit. n = issue/expect DATAn token. |
||
221 | ; 5. Next bit (bit 20) is reserved. |
||
222 | ; 6. Upper 11 bits (bits 21-31) are MaximumLength field. This field specifies |
||
223 | ; the maximum number of data bytes for the transfer minus 1 byte. Null data |
||
224 | ; packet is encoded as 0x7FF, maximum possible non-null data packet is 1280 |
||
225 | ; bytes, encoded as 0x4FF. |
||
226 | Buffer dd ? |
||
227 | ; Physical address of the data buffer for this TD. |
||
228 | OrigBufferInfo dd ? |
||
229 | ; Usually NULL. If the original buffer crosses a page boundary, this is a |
||
230 | ; pointer to the structure uhci_original_buffer for this request. |
||
231 | ; bit 0: 1 = short packet is NOT allowed |
||
232 | ; (before the TD is processed, it is the copy of bit 29 of ControlStatus; |
||
233 | ; some controllers modify that bit, so we need a copy in a safe place) |
||
234 | SoftwarePart rd sizeof.usb_gtd/4 |
||
235 | ; Software part, common for all controllers. |
||
236 | ends |
||
237 | |||
238 | if sizeof.uhci_gtd mod 16 |
||
239 | .err uhci_gtd must be 16-bytes aligned |
||
240 | end if |
||
241 | |||
242 | ; UHCI requires that the entire transfer buffer should be on one page. |
||
243 | ; If the actual buffer crosses page boundary, uhci_alloc_packet |
||
244 | ; allocates additional memory for buffer for hardware. |
||
245 | ; This structure describes correspondence between two buffers. |
||
246 | struct uhci_original_buffer |
||
247 | OrigBuffer dd ? |
||
248 | UsedBuffer dd ? |
||
249 | ends |
||
250 | |||
251 | ; Description of UHCI-specific data and functions for |
||
252 | ; controller-independent code. |
||
253 | ; Implements the structure usb_hardware_func from hccommon.inc for UHCI. |
||
254 | iglobal |
||
255 | align 4 |
||
256 | uhci_hardware_func: |
||
257 | dd 'UHCI' |
||
258 | dd sizeof.uhci_controller |
||
259 | dd uhci_init |
||
260 | dd uhci_process_deferred |
||
261 | dd uhci_set_device_address |
||
262 | dd uhci_get_device_address |
||
263 | dd uhci_port_disable |
||
264 | dd uhci_new_port.reset |
||
265 | dd uhci_set_endpoint_packet_size |
||
266 | dd usb1_allocate_endpoint |
||
267 | dd uhci_free_pipe |
||
268 | dd uhci_init_pipe |
||
269 | dd uhci_unlink_pipe |
||
270 | dd usb1_allocate_general_td |
||
271 | dd uhci_free_td |
||
272 | dd uhci_alloc_transfer |
||
273 | dd uhci_insert_transfer |
||
274 | dd uhci_new_device |
||
275 | endg |
||
276 | |||
277 | ; ============================================================================= |
||
278 | ; =================================== Code ==================================== |
||
279 | ; ============================================================================= |
||
280 | |||
281 | ; Controller-specific initialization function. |
||
282 | ; Called from usb_init_controller. Initializes the hardware and |
||
283 | ; UHCI-specific parts of software structures. |
||
284 | ; eax = pointer to uhci_controller to be initialized |
||
285 | ; [ebp-4] = pcidevice |
||
286 | proc uhci_init |
||
287 | ; inherit some variables from the parent (usb_init_controller) |
||
288 | .devfn equ ebp - 4 |
||
289 | .bus equ ebp - 3 |
||
290 | ; 1. Store pointer to uhci_controller for further use. |
||
291 | push eax |
||
292 | mov edi, eax |
||
293 | mov esi, eax |
||
294 | ; 2. Initialize uhci_controller.FrameList. |
||
295 | ; Note that FrameList is located in the beginning of uhci_controller, |
||
296 | ; so esi and edi now point to uhci_controller.FrameList. |
||
297 | ; First 32 entries of FrameList contain physical addresses |
||
298 | ; of first 32 Periodic static heads, further entries duplicate these. |
||
299 | ; See the description of structures for full info. |
||
300 | ; Note that all static heads fit in one page, so one call to |
||
301 | ; get_phys_addr is sufficient. |
||
302 | if (uhci_controller.IntEDs / 0x1000) <> (uhci_controller.BulkED / 0x1000) |
||
303 | .err assertion failed |
||
304 | end if |
||
305 | ; 2a. Get physical address of first static head. |
||
306 | ; Note that 1) it is located in the beginning of a page |
||
307 | ; and 2) all other static heads fit in the same page, |
||
308 | ; so one call to get_phys_addr without correction of lower 12 bits |
||
309 | ; is sufficient. |
||
310 | if (uhci_controller.IntEDs mod 0x1000) <> 0 |
||
311 | .err assertion failed |
||
312 | end if |
||
313 | add eax, uhci_controller.IntEDs |
||
314 | call get_phys_addr |
||
315 | ; 2b. Fill first 32 entries. |
||
316 | inc eax |
||
317 | inc eax ; set QH bit for uhci_pipe.NextQH |
||
318 | push 32 |
||
319 | pop ecx |
||
320 | mov edx, ecx |
||
321 | @@: |
||
322 | stosd |
||
323 | add eax, sizeof.uhci_static_ep |
||
324 | loop @b |
||
325 | ; 2c. Fill the rest entries. |
||
326 | mov ecx, 1024 - 32 |
||
327 | rep movsd |
||
328 | ; 3. Initialize static heads uhci_controller.*ED. |
||
329 | ; Use the loop over groups: first group consists of first 32 Periodic |
||
330 | ; descriptors, next group consists of next 16 Periodic descriptors, |
||
331 | ; ..., last group consists of the last Periodic descriptor. |
||
332 | ; 3a. Prepare for the loop. |
||
333 | ; make esi point to the second group, other registers are already set. |
||
334 | add esi, 32*4 + 32*sizeof.uhci_static_ep |
||
335 | ; 3b. Loop over groups. On every iteration: |
||
336 | ; edx = size of group, edi = pointer to the current group, |
||
337 | ; esi = pointer to the next group, eax = physical address of the next group. |
||
338 | .init_static_eds: |
||
339 | ; 3c. Get the size of next group. |
||
340 | shr edx, 1 |
||
341 | ; 3d. Exit the loop if there is no next group. |
||
342 | jz .init_static_eds_done |
||
343 | ; 3e. Initialize the first half of the current group. |
||
344 | ; Advance edi to the second half. |
||
345 | push eax esi |
||
346 | call uhci_init_static_ep_group |
||
347 | pop esi eax |
||
348 | ; 3f. Initialize the second half of the current group |
||
349 | ; with the same values. |
||
350 | ; Advance edi to the next group, esi/eax to the next of the next group. |
||
351 | call uhci_init_static_ep_group |
||
352 | jmp .init_static_eds |
||
353 | .init_static_eds_done: |
||
354 | ; 3g. Initialize the last static head. |
||
355 | xor esi, esi |
||
356 | call uhci_init_static_endpoint |
||
357 | ; 3i. Initialize the head of Control list. |
||
358 | add eax, sizeof.uhci_static_ep |
||
359 | call uhci_init_static_endpoint |
||
360 | ; 3j. Initialize the head of Bulk list. |
||
361 | sub eax, sizeof.uhci_static_ep |
||
362 | call uhci_init_static_endpoint |
||
363 | ; 4. Get I/O base address and size from PCI bus. |
||
364 | ; 4a. Read&save PCI command state. |
||
365 | mov bh, [.devfn] |
||
366 | mov ch, [.bus] |
||
367 | mov cl, 1 |
||
368 | mov eax, ecx |
||
369 | mov bl, 4 |
||
370 | call pci_read_reg |
||
371 | push eax |
||
372 | ; 4b. Disable IO access. |
||
373 | and al, not 1 |
||
374 | push ecx |
||
375 | xchg eax, ecx |
||
376 | call pci_write_reg |
||
377 | pop ecx |
||
378 | ; 4c. Read&save IO base address. |
||
379 | mov eax, ecx |
||
380 | mov bl, 20h |
||
381 | call pci_read_reg |
||
382 | and al, not 3 |
||
383 | xchg eax, edi |
||
384 | ; now edi = IO base |
||
385 | ; 4d. Write 0xffff to IO base address. |
||
386 | push ecx |
||
387 | xchg eax, ecx |
||
388 | or ecx, -1 |
||
389 | call pci_write_reg |
||
390 | pop ecx |
||
391 | ; 4e. Read IO base address. |
||
392 | mov eax, ecx |
||
393 | call pci_read_reg |
||
394 | and al, not 3 |
||
395 | cwde |
||
396 | not eax |
||
397 | inc eax |
||
398 | xchg eax, esi |
||
399 | ; now esi = IO size |
||
400 | ; 4f. Restore IO base address. |
||
401 | xchg eax, ecx |
||
402 | mov ecx, edi |
||
403 | push eax |
||
404 | call pci_write_reg |
||
405 | pop eax |
||
406 | ; 4g. Restore PCI command state and enable io & bus master access. |
||
407 | pop ecx |
||
408 | or ecx, 5 |
||
409 | mov bl, 4 |
||
410 | push eax |
||
411 | call pci_write_reg |
||
412 | pop eax |
||
413 | ; 5. Reset the controller. |
||
414 | ; 5e. Host reset. |
||
415 | mov edx, edi |
||
416 | mov ax, 2 |
||
417 | out dx, ax |
||
418 | ; 5f. Wait up to 10ms. |
||
419 | push 10 |
||
420 | pop ecx |
||
421 | @@: |
||
422 | push esi |
||
423 | push 1 |
||
424 | pop esi |
||
425 | call delay_ms |
||
426 | pop esi |
||
427 | in ax, dx |
||
428 | test al, 2 |
||
429 | loopnz @b |
||
430 | jz @f |
||
431 | dbgstr 'UHCI controller reset timeout' |
||
432 | jmp .fail |
||
433 | @@: |
||
434 | if 0 |
||
435 | ; emergency variant for tests - always wait 10 ms |
||
436 | ; wait 10 ms |
||
437 | push esi |
||
438 | push 10 |
||
439 | pop esi |
||
440 | call delay_ms |
||
441 | pop esi |
||
442 | ; clear reset signal |
||
443 | xor eax, eax |
||
444 | out dx, ax |
||
445 | end if |
||
446 | .resetok: |
||
447 | ; 6. Get number of ports & disable all ports. |
||
448 | add esi, edi |
||
449 | lea edx, [edi+UhciPort1StatusReg] |
||
450 | .scanports: |
||
451 | cmp edx, esi |
||
452 | jae .doneports |
||
453 | in ax, dx |
||
454 | cmp ax, 0xFFFF |
||
455 | jz .doneports |
||
456 | test al, al |
||
457 | jns .doneports |
||
458 | xor eax, eax |
||
459 | out dx, ax |
||
460 | inc edx |
||
461 | inc edx |
||
462 | jmp .scanports |
||
463 | .doneports: |
||
464 | lea esi, [edx-UhciPort1StatusReg] |
||
465 | sub esi, edi |
||
466 | shr esi, 1 ; esi = number of ports |
||
467 | jnz @f |
||
468 | dbgstr 'error: no ports on UHCI controller' |
||
469 | jmp .fail |
||
470 | @@: |
||
471 | ; 7. Setup the rest of uhci_controller. |
||
472 | xchg esi, [esp] ; restore the pointer to uhci_controller from the step 1 |
||
473 | add esi, sizeof.uhci_controller |
||
474 | pop [esi+usb_controller.NumPorts] |
||
475 | DEBUGF 1,'K : UHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts] |
||
476 | mov [esi+uhci_controller.IOBase-sizeof.uhci_controller], edi |
||
477 | mov eax, [timer_ticks] |
||
478 | mov [esi+uhci_controller.LastPollTime-sizeof.uhci_controller], eax |
||
479 | ; 8. Hook interrupt. |
||
480 | mov ah, [.bus] |
||
481 | mov al, 0 |
||
482 | mov bh, [.devfn] |
||
483 | mov bl, 3Ch |
||
484 | call pci_read_reg |
||
485 | ; al = IRQ |
||
486 | ; DEBUGF 1,'K : UHCI %x: io=%x, irq=%x\n',esi,edi,al |
||
487 | movzx eax, al |
||
488 | stdcall attach_int_handler, eax, uhci_irq, esi |
||
489 | ; 9. Setup controller registers. |
||
490 | xor eax, eax |
||
491 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
492 | ; 9a. UhciStatusReg := 3Fh: clear all status bits |
||
493 | ; (for this register 1 clears the corresponding bit, 0 does not change it). |
||
494 | inc edx |
||
495 | inc edx ; UhciStatusReg == 2 |
||
496 | mov al, 3Fh |
||
497 | out dx, ax |
||
498 | ; 9b. UhciInterruptReg := 0Dh. |
||
499 | inc edx |
||
500 | inc edx ; UhciInterruptReg == 4 |
||
501 | mov al, 0Dh |
||
502 | out dx, ax |
||
503 | ; 9c. UhciFrameNumberReg := 0. |
||
504 | inc edx |
||
505 | inc edx ; UhciFrameNumberReg == 6 |
||
506 | mov al, 0 |
||
507 | out dx, ax |
||
508 | ; 9d. UhciBaseAddressReg := physical address of uhci_controller. |
||
509 | inc edx |
||
510 | inc edx ; UhciBaseAddressReg == 8 |
||
511 | lea eax, [esi-sizeof.uhci_controller] |
||
512 | call get_phys_addr |
||
513 | out dx, eax |
||
514 | ; 9e. UhciCommandReg := Run + Configured + (MaxPacket is 64 bytes) |
||
515 | sub edx, UhciBaseAddressReg ; UhciCommandReg == 0 |
||
516 | mov ax, 0C1h ; Run, Configured, MaxPacket = 64b |
||
517 | out dx, ax |
||
518 | ; 10. Do initial scan of existing devices. |
||
519 | call uhci_poll_roothub |
||
520 | ; 11. Return pointer to usb_controller. |
||
521 | xchg eax, esi |
||
522 | ret |
||
523 | .fail: |
||
524 | ; On error, pop the pointer saved at step 1 and return zero. |
||
525 | ; Note that the main code branch restores the stack at step 7 and never fails |
||
526 | ; after step 7. |
||
527 | pop ecx |
||
528 | xor eax, eax |
||
529 | ret |
||
530 | endp |
||
531 | |||
532 | ; Controller-specific pre-initialization function: take ownership from BIOS. |
||
533 | ; UHCI has no mechanism to ask the owner politely to release ownership, |
||
534 | ; so do it in inpolite way, preventing controller from any SMI activity. |
||
535 | proc uhci_kickoff_bios |
||
536 | ; 1. Get the I/O address. |
||
537 | mov ah, [esi+PCIDEV.bus] |
||
538 | mov al, 1 |
||
539 | mov bh, [esi+PCIDEV.devfn] |
||
540 | mov bl, 20h |
||
541 | call pci_read_reg |
||
542 | and eax, 0xFFFC |
||
543 | xchg eax, edx |
||
544 | ; 2. Stop the controller and disable all interrupts. |
||
545 | in ax, dx |
||
546 | and al, not 1 |
||
547 | out dx, ax |
||
548 | add edx, UhciInterruptReg |
||
549 | xor eax, eax |
||
550 | out dx, ax |
||
551 | ; 3. Disable all bits for SMI routing, clear SMI routing status, |
||
552 | ; enable master interrupt bit. |
||
553 | mov ah, [esi+PCIDEV.bus] |
||
554 | mov al, 1 |
||
555 | mov bl, 0xC0 |
||
556 | mov ecx, 0AF00h |
||
557 | call pci_write_reg |
||
558 | ret |
||
559 | endp |
||
560 | |||
561 | ; Helper procedure for step 3 of uhci_init. |
||
562 | ; Initializes the static head of one list. |
||
563 | ; eax = physical address of the "next" list, esi = pointer to the "next" list, |
||
564 | ; edi = pointer to head to initialize. |
||
565 | ; Advances edi to the next head, keeps eax/esi. |
||
566 | proc uhci_init_static_endpoint |
||
567 | mov [edi+uhci_static_ep.NextQH], eax |
||
568 | mov byte [edi+uhci_static_ep.HeadTD], 1 |
||
569 | mov [edi+uhci_static_ep.NextList], esi |
||
570 | add edi, uhci_static_ep.SoftwarePart |
||
571 | call usb_init_static_endpoint |
||
572 | add edi, sizeof.uhci_static_ep - uhci_static_ep.SoftwarePart |
||
573 | ret |
||
574 | endp |
||
575 | |||
576 | ; Helper procedure for step 3 of uhci_init, see comments there. |
||
577 | ; Initializes one half of group of static heads. |
||
578 | ; edx = size of the next group = half of size of the group, |
||
579 | ; edi = pointer to the group, eax = physical address of the next group, |
||
580 | ; esi = pointer to the next group. |
||
581 | ; Advances eax, esi, edi to next group, keeps edx. |
||
582 | proc uhci_init_static_ep_group |
||
583 | push edx |
||
584 | @@: |
||
585 | call uhci_init_static_endpoint |
||
586 | add eax, sizeof.uhci_static_ep |
||
587 | add esi, sizeof.uhci_static_ep |
||
588 | dec edx |
||
589 | jnz @b |
||
590 | pop edx |
||
591 | ret |
||
592 | endp |
||
593 | |||
594 | ; IRQ handler for UHCI controllers. |
||
595 | uhci_irq.noint: |
||
596 | ; Not our interrupt: restore esi and return zero. |
||
597 | pop esi |
||
598 | xor eax, eax |
||
599 | ret |
||
600 | proc uhci_irq |
||
601 | push esi ; save used register to be cdecl |
||
602 | virtual at esp |
||
603 | dd ? ; saved esi |
||
604 | dd ? ; return address |
||
605 | .controller dd ? |
||
606 | end virtual |
||
607 | mov esi, [.controller] |
||
608 | ; 1. Read UhciStatusReg. |
||
609 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
610 | inc edx |
||
611 | inc edx ; UhciStatusReg == 2 |
||
612 | in ax, dx |
||
613 | ; 2. Test whether it is our interrupt; if so, at least one status bit is set. |
||
614 | test al, 0x1F |
||
615 | jz .noint |
||
616 | ; 3. Clear all status bits. |
||
617 | out dx, ax |
||
618 | ; 4. Sanity check. |
||
619 | test al, 0x3C |
||
620 | jz @f |
||
621 | DEBUGF 1,'K : something terrible happened with UHCI (%x)\n',al |
||
622 | @@: |
||
623 | ; 5. We can't do too much from an interrupt handler, e.g. we can't take |
||
624 | ; any mutex locks since our code could be called when another code holds the |
||
625 | ; lock and has no chance to release it. Thus, only inform the processing thread |
||
626 | ; that it should scan the queue and wake it if needed. |
||
627 | lock or byte [esi+uhci_controller.DeferredActions-sizeof.uhci_controller], al |
||
628 | push ebx |
||
629 | xor ebx, ebx |
||
630 | inc ebx |
||
631 | call usb_wakeup_if_needed |
||
632 | pop ebx |
||
633 | ; 6. This is our interrupt; return 1. |
||
634 | mov al, 1 |
||
635 | pop esi ; restore used register to be stdcall |
||
636 | ret |
||
637 | endp |
||
638 | |||
639 | ; This procedure is called in the USB thread from usb_thread_proc, |
||
640 | ; processes regular actions and those actions which can't be safely done |
||
641 | ; from interrupt handler. |
||
642 | ; Returns maximal time delta before the next call. |
||
643 | proc uhci_process_deferred |
||
644 | push ebx edi ; save used registers to be stdcall |
||
645 | ; 1. Initialize the return value. |
||
646 | push -1 |
||
647 | ; 2. Poll the root hub every UHCI_POLL_INTERVAL ticks. |
||
648 | ; Also force polling if some transaction has completed with errors; |
||
649 | ; the error can be caused by disconnect, try to detect it. |
||
650 | test byte [esi+uhci_controller.DeferredActions-sizeof.uhci_controller], 2 |
||
651 | jnz .force_poll |
||
652 | mov eax, [timer_ticks] |
||
653 | sub eax, [esi+uhci_controller.LastPollTime-sizeof.uhci_controller] |
||
654 | sub eax, UHCI_POLL_INTERVAL |
||
655 | jl .nopoll |
||
656 | .force_poll: |
||
657 | mov eax, [timer_ticks] |
||
658 | mov [esi+uhci_controller.LastPollTime-sizeof.uhci_controller], eax |
||
659 | call uhci_poll_roothub |
||
660 | mov eax, -UHCI_POLL_INTERVAL |
||
661 | .nopoll: |
||
662 | neg eax |
||
663 | cmp [esp], eax |
||
664 | jb @f |
||
665 | mov [esp], eax |
||
666 | @@: |
||
667 | ; 3. Process wait lists. |
||
668 | ; 3a. Test whether there is a wait request. |
||
669 | mov eax, [esi+usb_controller.WaitPipeRequestAsync] |
||
670 | cmp eax, [esi+usb_controller.ReadyPipeHeadAsync] |
||
671 | jnz .check_removed |
||
672 | mov eax, [esi+usb_controller.WaitPipeRequestPeriodic] |
||
673 | cmp eax, [esi+usb_controller.ReadyPipeHeadPeriodic] |
||
674 | jz @f |
||
675 | .check_removed: |
||
676 | ; 3b. Yep. Find frame and compare it with the saved one. |
||
677 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
678 | add edx, UhciFrameNumberReg |
||
679 | in ax, dx |
||
680 | cmp word [esi+usb_controller.StartWaitFrame], ax |
||
681 | jnz .removed |
||
682 | ; 3c. The same frame; wake up in 0.01 sec. |
||
683 | mov dword [esp], 1 |
||
684 | jmp @f |
||
685 | .removed: |
||
686 | ; 3d. The frame is changed, old contents is guaranteed to be forgotten. |
||
687 | mov eax, [esi+usb_controller.WaitPipeRequestAsync] |
||
688 | mov [esi+usb_controller.ReadyPipeHeadAsync], eax |
||
689 | mov eax, [esi+usb_controller.WaitPipeRequestPeriodic] |
||
690 | mov [esi+usb_controller.ReadyPipeHeadPeriodic], eax |
||
691 | @@: |
||
692 | ; 4. Process disconnect events. This should be done after step 2 |
||
693 | ; (which includes the first stage of disconnect processing). |
||
694 | call usb_disconnect_stage2 |
||
695 | ; 5. Test whether USB_CONNECT_DELAY for a connected device is over. |
||
696 | ; Call uhci_new_port for all such devices. |
||
697 | xor ecx, ecx |
||
698 | cmp [esi+usb_controller.NewConnected], ecx |
||
699 | jz .skip_newconnected |
||
700 | .portloop: |
||
701 | bt [esi+usb_controller.NewConnected], ecx |
||
702 | jnc .noconnect |
||
703 | mov eax, [timer_ticks] |
||
704 | sub eax, [esi+usb_controller.ConnectedTime+ecx*4] |
||
705 | sub eax, USB_CONNECT_DELAY |
||
706 | jge .connected |
||
707 | neg eax |
||
708 | cmp [esp], eax |
||
709 | jb .nextport |
||
710 | mov [esp], eax |
||
711 | jmp .nextport |
||
712 | .connected: |
||
713 | btr [esi+usb_controller.NewConnected], ecx |
||
714 | call uhci_new_port |
||
715 | .noconnect: |
||
716 | .nextport: |
||
717 | inc ecx |
||
718 | cmp ecx, [esi+usb_controller.NumPorts] |
||
719 | jb .portloop |
||
720 | .skip_newconnected: |
||
721 | ; 6. Test for processed packets. |
||
722 | ; This should be done after step 4, so transfers which were failed due |
||
723 | ; to disconnect are marked with the exact reason, not just |
||
724 | ; 'device not responding'. |
||
725 | xor eax, eax |
||
726 | xchg byte [esi+uhci_controller.DeferredActions-sizeof.uhci_controller], al |
||
727 | test al, 3 |
||
728 | jz .noioc |
||
729 | call uhci_process_updated_schedule |
||
730 | .noioc: |
||
731 | ; 7. Test whether reset signalling has been started. If so, |
||
732 | ; either should be stopped now (if time is over) or schedule wakeup (otherwise). |
||
733 | ; This should be done after step 6, because a completed SET_ADDRESS command |
||
734 | ; could result in reset of a new port. |
||
735 | .test_reset: |
||
736 | ; 7a. Test whether reset signalling is active. |
||
737 | cmp [esi+usb_controller.ResettingStatus], 1 |
||
738 | jnz .no_reset_in_progress |
||
739 | ; 7b. Yep. Test whether it should be stopped. |
||
740 | mov eax, [timer_ticks] |
||
741 | sub eax, [esi+usb_controller.ResetTime] |
||
742 | sub eax, USB_RESET_TIME |
||
743 | jge .reset_done |
||
744 | ; 7c. Not yet, but initiate wakeup in -eax ticks and exit this step. |
||
745 | neg eax |
||
746 | cmp [esp], eax |
||
747 | jb .skip_reset |
||
748 | mov [esp], eax |
||
749 | jmp .skip_reset |
||
750 | .reset_done: |
||
751 | ; 7d. Yep, call the worker function and proceed to 7e. |
||
752 | call uhci_port_reset_done |
||
753 | .no_reset_in_progress: |
||
754 | ; 7e. Test whether reset process is done, either successful or failed. |
||
755 | cmp [esi+usb_controller.ResettingStatus], 0 |
||
756 | jz .skip_reset |
||
757 | ; 7f. Yep. Test whether it should be stopped. |
||
758 | mov eax, [timer_ticks] |
||
759 | sub eax, [esi+usb_controller.ResetTime] |
||
760 | sub eax, USB_RESET_RECOVERY_TIME |
||
761 | jge .reset_recovery_done |
||
762 | ; 7g. Not yet, but initiate wakeup in -eax ticks and exit this step. |
||
763 | neg eax |
||
764 | cmp [esp], eax |
||
765 | jb .skip_reset |
||
766 | mov [esp], eax |
||
767 | jmp .skip_reset |
||
768 | .reset_recovery_done: |
||
769 | ; 7h. Yep, call the worker function. This could initiate another reset, |
||
770 | ; so return to the beginning of this step. |
||
771 | call uhci_port_init |
||
772 | jmp .test_reset |
||
773 | .skip_reset: |
||
774 | ; 8. Process wait-done notifications, test for new wait requests. |
||
775 | ; Note: that must be done after steps 4 and 6 which could create new requests. |
||
776 | ; 8a. Call the worker function. |
||
777 | call usb_process_wait_lists |
||
778 | ; 8b. If no new requests, skip the rest of this step. |
||
779 | test eax, eax |
||
780 | jz @f |
||
781 | ; 8c. UHCI is not allowed to cache anything; we don't know what is |
||
782 | ; processed right now, but we can be sure that the controller will not |
||
783 | ; use any removed structure starting from the next frame. |
||
784 | ; Request removal of everything disconnected until now, |
||
785 | ; schedule wakeup in 0.01 sec. |
||
786 | mov eax, [esi+usb_controller.WaitPipeListAsync] |
||
787 | mov [esi+usb_controller.WaitPipeRequestAsync], eax |
||
788 | mov eax, [esi+usb_controller.WaitPipeListPeriodic] |
||
789 | mov [esi+usb_controller.WaitPipeRequestPeriodic], eax |
||
790 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
791 | add edx, UhciFrameNumberReg |
||
792 | in ax, dx |
||
793 | mov word [esi+usb_controller.StartWaitFrame], ax |
||
794 | mov dword [esp], 1 |
||
795 | @@: |
||
796 | ; 9. Return the value from the top of stack. |
||
797 | pop eax |
||
798 | pop edi ebx ; restore used registers to be stdcall. |
||
799 | ret |
||
800 | endp |
||
801 | |||
802 | ; This procedure is called in the USB thread from uhci_process_deferred |
||
803 | ; when UHCI IRQ handler has signalled that new IOC-packet was processed. |
||
804 | ; It scans all lists for completed packets and calls uhci_process_finalized_td |
||
805 | ; for those packets. |
||
806 | ; in: esi -> usb_controller |
||
807 | proc uhci_process_updated_schedule |
||
808 | ; Important note: we cannot hold the list lock during callbacks, |
||
809 | ; because callbacks sometimes open and/or close pipes and thus acquire/release |
||
810 | ; the corresponding lock itself. |
||
811 | ; Fortunately, pipes can be finally freed only by another step of |
||
812 | ; uhci_process_deferred, so all pipes existing at the start of this function |
||
813 | ; will be valid while this function is running. Some pipes can be removed |
||
814 | ; from the corresponding list, some pipes can be inserted; insert/remove |
||
815 | ; functions guarantee that traversing one list yields all pipes that were in |
||
816 | ; that list at the beginning of the traversing (possibly with some new pipes, |
||
817 | ; possibly without some new pipes, that doesn't matter). |
||
818 | ; 1. Process all Periodic lists. |
||
819 | lea edi, [esi+uhci_controller.IntEDs.SoftwarePart-sizeof.uhci_controller] |
||
820 | lea ebx, [esi+uhci_controller.IntEDs.SoftwarePart+63*sizeof.uhci_static_ep-sizeof.uhci_controller] |
||
821 | @@: |
||
822 | call uhci_process_updated_list |
||
823 | cmp edi, ebx |
||
824 | jnz @b |
||
825 | ; 2. Process the Control list. |
||
826 | call uhci_process_updated_list |
||
827 | ; 3. Process the Bulk list. |
||
828 | call uhci_process_updated_list |
||
829 | ; 4. Return. |
||
830 | ret |
||
831 | endp |
||
832 | |||
833 | ; This procedure is called from uhci_process_updated_schedule, |
||
834 | ; see comments there. |
||
835 | ; It processes one list, esi -> usb_controller, edi -> usb_static_ep, |
||
836 | ; and advances edi to the next head. |
||
837 | proc uhci_process_updated_list |
||
838 | push ebx ; save used register to be stdcall |
||
839 | ; 1. Perform the external loop over all pipes. |
||
840 | mov ebx, [edi+usb_static_ep.NextVirt] |
||
841 | .loop: |
||
842 | cmp ebx, edi |
||
843 | jz .done |
||
844 | ; store pointer to the next pipe in the stack |
||
845 | push [ebx+usb_static_ep.NextVirt] |
||
846 | ; 2. For every pipe, perform the internal loop over all descriptors. |
||
847 | ; All descriptors are organized in the queue; we process items from the start |
||
848 | ; of the queue until a) the last descriptor (not the part of the queue itself) |
||
849 | ; or b) an active (not yet processed by the hardware) descriptor is reached. |
||
850 | lea ecx, [ebx+usb_pipe.Lock] |
||
851 | call mutex_lock |
||
852 | mov ebx, [ebx+usb_pipe.LastTD] |
||
853 | push ebx |
||
854 | mov ebx, [ebx+usb_gtd.NextVirt] |
||
855 | .tdloop: |
||
856 | ; 3. For every descriptor, test active flag and check for end-of-queue; |
||
857 | ; if either of conditions holds, exit from the internal loop. |
||
858 | cmp ebx, [esp] |
||
859 | jz .tddone |
||
860 | mov eax, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
||
861 | test eax, 1 shl 23 ; active? |
||
862 | jnz .tddone |
||
863 | ; Release the queue lock while processing one descriptor: |
||
864 | ; callback function could (and often would) schedule another transfer. |
||
865 | push ecx |
||
866 | call mutex_unlock |
||
867 | call uhci_process_finalized_td |
||
868 | pop ecx |
||
869 | call mutex_lock |
||
870 | jmp .tdloop |
||
871 | .tddone: |
||
872 | call mutex_unlock |
||
873 | pop ebx |
||
874 | ; End of internal loop, restore pointer to the next pipe |
||
875 | ; and continue the external loop. |
||
876 | pop ebx |
||
877 | jmp .loop |
||
878 | .done: |
||
879 | pop ebx ; restore used register to be stdcall |
||
880 | add edi, sizeof.uhci_static_ep |
||
881 | ret |
||
882 | endp |
||
883 | |||
884 | ; This procedure is called from uhci_process_updated_list, which is itself |
||
885 | ; called from uhci_process_updated_schedule, see comments there. |
||
886 | ; It processes one completed descriptor. |
||
887 | ; in: esi -> usb_controller, ebx -> usb_gtd, out: ebx -> next usb_gtd. |
||
888 | proc uhci_process_finalized_td |
||
889 | ; 1. Remove this descriptor from the list of descriptors for this pipe. |
||
890 | call usb_unlink_td |
||
891 | ; DEBUGF 1,'K : finalized TD:\n' |
||
892 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-20],[ebx-16],[ebx-12],[ebx-8] |
||
893 | ; DEBUGF 1,'K : %x %x %x %x\n',[ebx-4],[ebx],[ebx+4],[ebx+8] |
||
894 | ; 2. If this is IN transfer into special buffer, copy the data |
||
895 | ; to target location. |
||
896 | mov edx, [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
||
897 | and edx, not 1 ; clear lsb (used for another goal) |
||
898 | jz .nocopy |
||
899 | cmp byte [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart], USB_PID_IN |
||
900 | jnz .nocopy |
||
901 | ; Note: we assume that pointer to buffer is valid in the memory space of |
||
902 | ; the USB thread. This means that buffer must reside in kernel memory |
||
903 | ; (shared by all processes). |
||
904 | push esi edi |
||
905 | mov esi, [edx+uhci_original_buffer.UsedBuffer] |
||
906 | mov edi, [edx+uhci_original_buffer.OrigBuffer] |
||
907 | mov ecx, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
||
908 | inc ecx |
||
909 | and ecx, 7FFh |
||
910 | mov edx, ecx |
||
911 | shr ecx, 2 |
||
912 | and edx, 3 |
||
913 | rep movsd |
||
914 | mov ecx, edx |
||
915 | rep movsb |
||
916 | pop edi esi |
||
917 | .nocopy: |
||
918 | ; 3. Calculate actual number of bytes transferred. |
||
919 | ; 3a. Read the state. |
||
920 | mov eax, [ebx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart] |
||
921 | mov ecx, [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
||
922 | ; 3b. Get number of bytes processed. |
||
923 | lea edx, [eax+1] |
||
924 | and edx, 7FFh |
||
925 | ; 3c. Subtract number of bytes in this packet. |
||
926 | add ecx, 1 shl 21 |
||
927 | shr ecx, 21 |
||
928 | sub edx, ecx |
||
929 | ; 3d. Add total length transferred so far. |
||
930 | add edx, [ebx+usb_gtd.Length] |
||
931 | ; Actions on error and on success are slightly different. |
||
932 | ; 4. Test for error. On error, proceed to step 5, otherwise go to step 6 |
||
933 | ; with ecx = 0 (no error). |
||
934 | ; USB transaction error is always considered as such. |
||
935 | ; If short packets are not allowed, UHCI controllers do not set an error bit, |
||
936 | ; but stop (clear Active bit and do not advance) the queue. |
||
937 | ; Short packet is considered as an error if the packet is actually short |
||
938 | ; (actual length is less than maximal one) and the code creating the packet |
||
939 | ; requested that behaviour (so bit 0 of OrigBufferInfo is set; this could be |
||
940 | ; because the caller disallowed short packets or because the packet is not |
||
941 | ; the last one in the corresponding transfer). |
||
942 | xor ecx, ecx |
||
943 | test eax, 1 shl 22 |
||
944 | jnz .error |
||
945 | test byte [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
||
946 | jz .notify |
||
947 | cmp edx, [ebx+usb_gtd.Length] |
||
948 | jz .notify |
||
949 | .error: |
||
950 | ; 5. There was an error while processing this packet. |
||
951 | ; The hardware has stopped processing the queue. |
||
952 | DEBUGF 1,'K : TD failed:\n' |
||
953 | if uhci_gtd.SoftwarePart <> 20 |
||
954 | .err modify offsets for debug output |
||
955 | end if |
||
956 | DEBUGF 1,'K : %x %x %x %x\n',[ebx-20],[ebx-16],[ebx-12],[ebx-8] |
||
957 | DEBUGF 1,'K : %x %x %x %x\n',[ebx-4],[ebx],[ebx+4],[ebx+8] |
||
958 | ; 5a. Save the status and length. |
||
959 | push edx |
||
960 | push eax |
||
961 | mov eax, [ebx+usb_gtd.Pipe] |
||
962 | DEBUGF 1,'K : pipe: %x %x\n',[eax+0-uhci_pipe.SoftwarePart],[eax+4-uhci_pipe.SoftwarePart] |
||
963 | ; 5b. Store the current TD as an error packet. |
||
964 | ; If an error packet is already stored for this pipe, |
||
965 | ; it is definitely not used already, so free the old packet. |
||
966 | mov eax, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
||
967 | test eax, eax |
||
968 | jz @f |
||
969 | stdcall uhci_free_td, eax |
||
970 | @@: |
||
971 | mov eax, [ebx+usb_gtd.Pipe] |
||
972 | mov [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], ebx |
||
973 | ; 5c. Traverse the list of descriptors looking for the final packet |
||
974 | ; for this transfer. |
||
975 | ; Free and unlink non-final descriptors, except the current one. |
||
976 | ; Final descriptor will be freed in step 7. |
||
977 | call usb_is_final_packet |
||
978 | jnc .found_final |
||
979 | mov ebx, [ebx+usb_gtd.NextVirt] |
||
980 | .look_final: |
||
981 | call usb_unlink_td |
||
982 | call usb_is_final_packet |
||
983 | jnc .found_final |
||
984 | push [ebx+usb_gtd.NextVirt] |
||
985 | stdcall uhci_free_td, ebx |
||
986 | pop ebx |
||
987 | jmp .look_final |
||
988 | .found_final: |
||
989 | ; 5d. Restore the status saved in 5a and transform it to the error code. |
||
990 | pop eax ; error code |
||
991 | shr eax, 16 |
||
992 | ; Notes: |
||
993 | ; * any USB transaction error results in Stalled bit; if it is not set, |
||
994 | ; but we are here, it must be due to short packet; |
||
995 | ; * babble is considered a fatal USB transaction error, |
||
996 | ; other errors just lead to retrying the transaction; |
||
997 | ; if babble is detected, return the corresponding error; |
||
998 | ; * if several non-fatal errors have occured during transaction retries, |
||
999 | ; all corresponding bits are set. In this case, return some error code, |
||
1000 | ; the order is quite arbitrary. |
||
1001 | push USB_STATUS_UNDERRUN |
||
1002 | pop ecx |
||
1003 | test al, 1 shl (22-16) ; not Stalled? |
||
1004 | jz .know_error |
||
1005 | mov cl, USB_STATUS_OVERRUN |
||
1006 | test al, 1 shl (20-16) ; Babble detected? |
||
1007 | jnz .know_error |
||
1008 | mov cl, USB_STATUS_BITSTUFF |
||
1009 | test al, 1 shl (17-16) ; Bitstuff error? |
||
1010 | jnz .know_error |
||
1011 | mov cl, USB_STATUS_NORESPONSE |
||
1012 | test al, 1 shl (18-16) ; CRC/TimeOut error? |
||
1013 | jnz .know_error |
||
1014 | mov cl, USB_STATUS_BUFOVERRUN |
||
1015 | test al, 1 shl (21-16) ; Data Buffer error? |
||
1016 | jnz .know_error |
||
1017 | mov cl, USB_STATUS_STALL |
||
1018 | .know_error: |
||
1019 | ; 5e. If error code is USB_STATUS_UNDERRUN |
||
1020 | ; and the last TD allows short packets, it is not an error. |
||
1021 | ; Note: all TDs except the last one in any transfer stage are marked |
||
1022 | ; as short-packet-is-error to stop controller from further processing |
||
1023 | ; of that stage; we need to restart processing from a TD following the last. |
||
1024 | ; After that, go to step 6 with ecx = 0 (no error). |
||
1025 | cmp ecx, USB_STATUS_UNDERRUN |
||
1026 | jnz @f |
||
1027 | test byte [ebx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
||
1028 | jnz @f |
||
1029 | ; The controller has stopped this queue on the error packet. |
||
1030 | ; Update uhci_pipe.HeadTD to point to the next packet in the queue. |
||
1031 | call uhci_fix_toggle |
||
1032 | xor ecx, ecx |
||
1033 | .control: |
||
1034 | mov eax, [ebx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart] |
||
1035 | and al, not 0xF |
||
1036 | mov edx, [ebx+usb_gtd.Pipe] |
||
1037 | mov [edx+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
||
1038 | pop edx ; length |
||
1039 | jmp .notify |
||
1040 | @@: |
||
1041 | ; 5f. Abort the entire transfer. |
||
1042 | ; There are two cases: either there is only one transfer stage |
||
1043 | ; (everything except control transfers), then ebx points to the last TD and |
||
1044 | ; all previous TD were unlinked and dismissed (if possible), |
||
1045 | ; or there are several stages (a control transfer) and ebx points to the last |
||
1046 | ; TD of Data or Status stage (usb_is_final_packet does not stop in Setup stage, |
||
1047 | ; because Setup stage can not produce short packets); for Data stage, we need |
||
1048 | ; to unlink and free (if possible) one more TD and advance ebx to the next one. |
||
1049 | cmp [ebx+usb_gtd.Callback], 0 |
||
1050 | jnz .normal |
||
1051 | ; We cannot free ErrorTD yet, it could still be used by the hardware. |
||
1052 | push ecx |
||
1053 | mov eax, [ebx+usb_gtd.Pipe] |
||
1054 | push [ebx+usb_gtd.NextVirt] |
||
1055 | cmp ebx, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
||
1056 | jz @f |
||
1057 | stdcall uhci_free_td, ebx |
||
1058 | @@: |
||
1059 | pop ebx |
||
1060 | call usb_unlink_td |
||
1061 | pop ecx |
||
1062 | .normal: |
||
1063 | ; 5g. For bulk/interrupt transfers we have no choice but halt the queue, |
||
1064 | ; the driver should intercede (through some API which is not written yet). |
||
1065 | ; Control pipes normally recover at the next SETUP transaction (first stage |
||
1066 | ; of any control transfer), so we hope on the best and just advance the queue |
||
1067 | ; to the next transfer. (According to the standard, "A control pipe may also |
||
1068 | ; support functional stall as well, but this is not recommended."). |
||
1069 | mov edx, [ebx+usb_gtd.Pipe] |
||
1070 | cmp [edx+usb_pipe.Type], CONTROL_PIPE |
||
1071 | jz .control |
||
1072 | ; Bulk/interrupt transfer; halt the queue. |
||
1073 | mov eax, [ebx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart] |
||
1074 | and al, not 0xF |
||
1075 | inc eax ; set Halted bit |
||
1076 | mov [edx+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
||
1077 | pop edx ; restore length saved in step 5a |
||
1078 | .notify: |
||
1079 | ; 6. Either the descriptor in ebx was processed without errors, |
||
1080 | ; or all necessary error actions were taken and ebx points to the last |
||
1081 | ; related descriptor. |
||
1082 | ; 6a. Test whether it is the last packet in the transfer |
||
1083 | ; <=> it has an associated callback. |
||
1084 | mov eax, [ebx+usb_gtd.Callback] |
||
1085 | test eax, eax |
||
1086 | jz .nocallback |
||
1087 | ; 6b. It has an associated callback; call it with corresponding parameters. |
||
1088 | stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \ |
||
1089 | [ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData] |
||
1090 | jmp .callback |
||
1091 | .nocallback: |
||
1092 | ; 6c. It is an intermediate packet. Add its length to the length |
||
1093 | ; in the following packet. |
||
1094 | mov eax, [ebx+usb_gtd.NextVirt] |
||
1095 | add [eax+usb_gtd.Length], edx |
||
1096 | .callback: |
||
1097 | ; 7. Free the current descriptor (if allowed) and return the next one. |
||
1098 | ; 7a. Save pointer to the next descriptor. |
||
1099 | push [ebx+usb_gtd.NextVirt] |
||
1100 | ; 7b. Free the descriptor, unless it is saved as ErrorTD. |
||
1101 | mov eax, [ebx+usb_gtd.Pipe] |
||
1102 | cmp [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], ebx |
||
1103 | jz @f |
||
1104 | stdcall uhci_free_td, ebx |
||
1105 | @@: |
||
1106 | ; 7c. Restore pointer to the next descriptor and return. |
||
1107 | pop ebx |
||
1108 | ret |
||
1109 | endp |
||
1110 | |||
1111 | ; Helper procedure for restarting transfer queue. |
||
1112 | ; When transfers are queued, their toggle bit is filled assuming that |
||
1113 | ; everything will go without errors. On error, some packets needs to be |
||
1114 | ; skipped, so toggle bits may become incorrect. |
||
1115 | ; This procedure fixes toggle bits. |
||
1116 | ; in: ebx -> last packet to be skipped, ErrorTD -> last processed packet |
||
1117 | proc uhci_fix_toggle |
||
1118 | ; 1. Nothing to do for control pipes: in that case, |
||
1119 | ; toggle bits for different transfer stages are independent. |
||
1120 | mov ecx, [ebx+usb_gtd.Pipe] |
||
1121 | cmp [ecx+usb_pipe.Type], CONTROL_PIPE |
||
1122 | jz .nothing |
||
1123 | ; 2. The hardware expects next packet with toggle = (ErrorTD.toggle xor 1), |
||
1124 | ; the current value in next packet is (ebx.toggle xor 1). |
||
1125 | ; Nothing to do if ErrorTD.toggle == ebx.toggle. |
||
1126 | mov eax, [ecx+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
||
1127 | mov eax, [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
||
1128 | xor eax, [ebx+uhci_gtd.Token-uhci_gtd.SoftwarePart] |
||
1129 | test eax, 1 shl 19 |
||
1130 | jz .nothing |
||
1131 | ; 3. Lock the transfer queue. |
||
1132 | add ecx, usb_pipe.Lock |
||
1133 | call mutex_lock |
||
1134 | ; 4. Flip the toggle bit in all packets from ebx.NextVirt to ecx.LastTD |
||
1135 | ; (inclusive). |
||
1136 | mov eax, [ebx+usb_gtd.NextVirt] |
||
1137 | .loop: |
||
1138 | xor byte [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart+2], 1 shl (19-16) |
||
1139 | cmp eax, [ecx+usb_pipe.LastTD-usb_pipe.Lock] |
||
1140 | mov eax, [eax+usb_gtd.NextVirt] |
||
1141 | jnz .loop |
||
1142 | ; 5. Flip the toggle bit in uhci_pipe structure. |
||
1143 | xor byte [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart-usb_pipe.Lock+2], 1 shl (19-16) |
||
1144 | or dword [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart-usb_pipe.Lock], eax |
||
1145 | ; 6. Unlock the transfer queue. |
||
1146 | call mutex_unlock |
||
1147 | .nothing: |
||
1148 | ret |
||
1149 | endp |
||
1150 | |||
1151 | ; This procedure is called in the USB thread from uhci_process_deferred |
||
1152 | ; every UHCI_POLL_INTERVAL ticks. It polls the controller for |
||
1153 | ; connect/disconnect events. |
||
1154 | ; in: esi -> usb_controller |
||
1155 | proc uhci_poll_roothub |
||
1156 | push ebx ; save used register to be stdcall |
||
1157 | ; 1. Prepare for the loop for every port. |
||
1158 | xor ecx, ecx |
||
1159 | .portloop: |
||
1160 | ; 2. Some implementations of UHCI set ConnectStatusChange bit in a response to |
||
1161 | ; PortReset. Thus, we must ignore this change for port which is resetting. |
||
1162 | cmp cl, [esi+usb_controller.ResettingPort] |
||
1163 | jz .nextport |
||
1164 | ; 3. Read port status. |
||
1165 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
1166 | lea edx, [edx+ecx*2+UhciPort1StatusReg] |
||
1167 | in ax, dx |
||
1168 | ; 4. If no change bits are set, continue to the next port. |
||
1169 | test al, 0Ah |
||
1170 | jz .nextport |
||
1171 | ; 5. Clear change bits and read the status again. |
||
1172 | ; (It is possible, although quite unlikely, that some event occurs between |
||
1173 | ; the first read and the clearing, invalidating the old status. If an event |
||
1174 | ; occurs after the clearing, we will not miss it, looking in the next scan. |
||
1175 | out dx, ax |
||
1176 | mov ebx, eax |
||
1177 | in ax, dx |
||
1178 | ; 6. Process connect change notifications. |
||
1179 | ; Note: if connect status has changed, ignore enable status change; |
||
1180 | ; it is normal to disable a port at disconnect event. |
||
1181 | ; Some controllers set enable status change bit, some don't. |
||
1182 | test bl, 2 |
||
1183 | jz .noconnectchange |
||
1184 | DEBUGF 1,'K : [%d] UHCI %x connect status changed, %x/%x\n',[timer_ticks],esi,bx,ax |
||
1185 | ; yep. Regardless of the current status, note disconnect event; |
||
1186 | ; if there is something connected, store the connect time and note connect event. |
||
1187 | ; In any way, do not process |
||
1188 | bts [esi+usb_controller.NewDisconnected], ecx |
||
1189 | test al, 1 |
||
1190 | jz .disconnect |
||
1191 | mov eax, [timer_ticks] |
||
1192 | mov [esi+usb_controller.ConnectedTime+ecx*4], eax |
||
1193 | bts [esi+usb_controller.NewConnected], ecx |
||
1194 | jmp .nextport |
||
1195 | .disconnect: |
||
1196 | btr [esi+usb_controller.NewConnected], ecx |
||
1197 | jmp .nextport |
||
1198 | .noconnectchange: |
||
1199 | ; 7. Process enable change notifications. |
||
1200 | ; Note: that needs work. |
||
1201 | test bl, 8 |
||
1202 | jz .nextport |
||
1203 | test al, 4 |
||
1204 | jnz .nextport |
||
1205 | dbgstr 'Port disabled' |
||
1206 | .nextport: |
||
1207 | ; 8. Continue the loop for every port. |
||
1208 | inc ecx |
||
1209 | cmp ecx, [esi+usb_controller.NumPorts] |
||
1210 | jb .portloop |
||
1211 | pop ebx ; restore used register to be stdcall |
||
1212 | ret |
||
1213 | endp |
||
1214 | |||
1215 | ; This procedure is called from uhci_process_deferred when |
||
1216 | ; a new device was connected at least USB_CONNECT_DELAY ticks |
||
1217 | ; and therefore is ready to be configured. |
||
1218 | ; in: esi -> usb_controller, ecx = port (zero-based) |
||
1219 | proc uhci_new_port |
||
1220 | ; test whether we are configuring another port |
||
1221 | ; if so, postpone configuring and return |
||
1222 | bts [esi+usb_controller.PendingPorts], ecx |
||
1223 | cmp [esi+usb_controller.ResettingPort], -1 |
||
1224 | jnz .nothing |
||
1225 | btr [esi+usb_controller.PendingPorts], ecx |
||
1226 | ; fall through to uhci_new_port.reset |
||
1227 | |||
1228 | ; This function is called from uhci_new_port and uhci_test_pending_port. |
||
1229 | ; It starts reset signalling for the port. Note that in USB first stages |
||
1230 | ; of configuration can not be done for several ports in parallel. |
||
1231 | .reset: |
||
1232 | ; 1. Store information about resetting hub (roothub) and port. |
||
1233 | and [esi+usb_controller.ResettingHub], 0 |
||
1234 | mov [esi+usb_controller.ResettingPort], cl |
||
1235 | ; 2. Initiate reset signalling. |
||
1236 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
1237 | lea edx, [edx+ecx*2+UhciPort1StatusReg] |
||
1238 | in ax, dx |
||
1239 | or ah, 2 |
||
1240 | out dx, ax |
||
1241 | ; 3. Store the current time and set status to 1 = reset signalling active. |
||
1242 | mov eax, [timer_ticks] |
||
1243 | mov [esi+usb_controller.ResetTime], eax |
||
1244 | mov [esi+usb_controller.ResettingStatus], 1 |
||
1245 | .nothing: |
||
1246 | ret |
||
1247 | endp |
||
1248 | |||
1249 | ; This procedure is called from uhci_process_deferred when |
||
1250 | ; reset signalling for a port needs to be finished. |
||
1251 | proc uhci_port_reset_done |
||
1252 | ; 1. Stop reset signalling. |
||
1253 | movzx ecx, [esi+usb_controller.ResettingPort] |
||
1254 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
1255 | lea edx, [edx+ecx*2+UhciPort1StatusReg] |
||
1256 | in ax, dx |
||
1257 | DEBUGF 1,'K : [%d] UHCI %x status %x/',[timer_ticks],esi,ax |
||
1258 | and ah, not 2 |
||
1259 | out dx, ax |
||
1260 | ; 2. Status bits in UHCI are invalid during reset signalling. |
||
1261 | ; Wait a millisecond while status bits become valid again. |
||
1262 | push esi |
||
1263 | push 1 |
||
1264 | pop esi |
||
1265 | call delay_ms |
||
1266 | pop esi |
||
1267 | ; 3. ConnectStatus bit is zero during reset and becomes 1 during step 2; |
||
1268 | ; some controllers interpret this as a (fake) connect event. |
||
1269 | ; Enable port and clear status change notification. |
||
1270 | in ax, dx |
||
1271 | DEBUGF 1,'%x\n',ax |
||
1272 | or al, 6 ; enable port, clear status change |
||
1273 | out dx, ax |
||
1274 | ; 4. Store the current time and set status to 2 = reset recovery active. |
||
1275 | mov eax, [timer_ticks] |
||
1276 | DEBUGF 1,'K : reset done at %d\n',[timer_ticks] |
||
1277 | mov [esi+usb_controller.ResetTime], eax |
||
1278 | mov [esi+usb_controller.ResettingStatus], 2 |
||
1279 | ret |
||
1280 | endp |
||
1281 | |||
1282 | ; This procedure is called from uhci_process_deferred when |
||
1283 | ; a new device has been reset, recovered after reset and |
||
1284 | ; needs to be configured. |
||
1285 | ; in: esi -> usb_controller |
||
1286 | proc uhci_port_init |
||
1287 | ; 1. Read port status. |
||
1288 | mov [esi+usb_controller.ResettingStatus], 0 |
||
1289 | movzx ecx, [esi+usb_controller.ResettingPort] |
||
1290 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
1291 | lea edx, [edx+ecx*2+UhciPort1StatusReg] |
||
1292 | in ax, dx |
||
1293 | DEBUGF 1,'K : [%d] UHCI %x status %x\n',[timer_ticks],esi,ax |
||
1294 | ; 2. If the device has been disconnected, stop the initialization. |
||
1295 | test al, 1 |
||
1296 | jnz @f |
||
1297 | dbgstr 'USB port disabled after reset' |
||
1298 | jmp usb_test_pending_port |
||
1299 | @@: |
||
1300 | ; 3. Copy LowSpeed bit to bit 0 of eax and call the worker procedure |
||
1301 | ; to notify the protocol layer about new UHCI device. |
||
1302 | push edx |
||
1303 | mov al, ah |
||
1304 | call uhci_new_device |
||
1305 | pop edx |
||
1306 | test eax, eax |
||
1307 | jnz .nothing |
||
1308 | ; 4. If something at the protocol layer has failed |
||
1309 | ; (no memory, no bus address), disable the port and stop the initialization. |
||
1310 | .disable_exit: |
||
1311 | in ax, dx |
||
1312 | and al, not 4 |
||
1313 | out dx, ax ; disable the port |
||
1314 | jmp usb_test_pending_port |
||
1315 | .nothing: |
||
1316 | ret |
||
1317 | endp |
||
1318 | |||
1319 | ; This procedure is called from uhci_port_init and from hub support code |
||
1320 | ; when a new device is connected and has been reset. |
||
1321 | ; It calls usb_new_device at the protocol layer with correct parameters. |
||
1322 | ; in: esi -> usb_controller, eax = speed; |
||
1323 | ; UHCI is USB1 device, so only low bit of eax (LowSpeed) is used. |
||
1324 | proc uhci_new_device |
||
1325 | ; 1. Clear all bits of speed except bit 0. |
||
1326 | and eax, 1 |
||
1327 | ; 2. Store the speed for the protocol layer. |
||
1328 | mov [esi+usb_controller.ResettingSpeed], al |
||
1329 | ; 3. Create pseudo-pipe in the stack. |
||
1330 | ; See uhci_init_pipe: only .Controller and .Token fields are used. |
||
1331 | push esi ; fill .Controller field |
||
1332 | mov ecx, esp |
||
1333 | shl eax, 20 ; bit 20 = LowSpeedDevice |
||
1334 | push eax ; ignored (ErrorTD) |
||
1335 | push eax ; .Token field: DeviceAddress is zero, bit 20 = LowSpeedDevice |
||
1336 | ; 4. Notify the protocol layer. |
||
1337 | call usb_new_device |
||
1338 | ; 5. Cleanup the stack after step 3 and return. |
||
1339 | add esp, 12 |
||
1340 | ret |
||
1341 | endp |
||
1342 | |||
1343 | ; This procedure is called from usb_set_address_callback |
||
1344 | ; and stores USB device address in the uhci_pipe structure. |
||
1345 | ; in: esi -> usb_controller, ebx -> usb_pipe, cl = address |
||
1346 | proc uhci_set_device_address |
||
1347 | mov byte [ebx+uhci_pipe.Token+1-uhci_pipe.SoftwarePart], cl |
||
1348 | call usb_subscription_done |
||
1349 | ret |
||
1350 | endp |
||
1351 | |||
1352 | ; This procedure returns USB device address from the uhci_pipe structure. |
||
1353 | ; in: esi -> usb_controller, ebx -> usb_pipe |
||
1354 | ; out: eax = endpoint address |
||
1355 | proc uhci_get_device_address |
||
1356 | mov al, byte [ebx+uhci_pipe.Token+1-uhci_pipe.SoftwarePart] |
||
1357 | and eax, 7Fh |
||
1358 | ret |
||
1359 | endp |
||
1360 | |||
1361 | ; This procedure is called from usb_set_address_callback |
||
1362 | ; if the device does not accept SET_ADDRESS command and needs |
||
1363 | ; to be disabled at the port level. |
||
1364 | ; in: esi -> usb_controller, ecx = port (zero-based) |
||
1365 | proc uhci_port_disable |
||
1366 | mov edx, [esi+uhci_controller.IOBase-sizeof.uhci_controller] |
||
1367 | lea edx, [edx+UhciPort1StatusReg+ecx*2] |
||
1368 | in ax, dx |
||
1369 | and al, not 4 |
||
1370 | out dx, ax |
||
1371 | ret |
||
1372 | endp |
||
1373 | |||
1374 | ; This procedure is called from usb_get_descr8_callback when |
||
1375 | ; the packet size for zero endpoint becomes known and |
||
1376 | ; stores the packet size in uhci_pipe structure. |
||
1377 | ; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size |
||
1378 | proc uhci_set_endpoint_packet_size |
||
1379 | dec ecx |
||
1380 | shl ecx, 21 |
||
1381 | and [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], (1 shl 21) - 1 |
||
1382 | or [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], ecx |
||
1383 | ; uhci_pipe.Token field is purely for software bookkeeping and does not affect |
||
1384 | ; the hardware; thus, we can continue initialization immediately. |
||
1385 | call usb_subscription_done |
||
1386 | ret |
||
1387 | endp |
||
1388 | |||
1389 | ; This procedure is called from API usb_open_pipe and processes |
||
1390 | ; the controller-specific part of this API. See docs. |
||
1391 | ; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe, |
||
1392 | ; esi -> usb_controller, eax -> usb_gtd for the first TD, |
||
1393 | ; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type |
||
1394 | proc uhci_init_pipe |
||
1395 | ; inherit some variables from the parent usb_open_pipe |
||
1396 | virtual at ebp+8 |
||
1397 | .config_pipe dd ? |
||
1398 | .endpoint dd ? |
||
1399 | .maxpacket dd ? |
||
1400 | .type dd ? |
||
1401 | .interval dd ? |
||
1402 | end virtual |
||
1403 | ; 1. Initialize ErrorTD to zero. |
||
1404 | and [edi+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart], 0 |
||
1405 | ; 2. Initialize HeadTD to the physical address of the first TD. |
||
1406 | push eax ; store pointer to the first TD for step ? |
||
1407 | sub eax, uhci_gtd.SoftwarePart |
||
1408 | call get_phys_addr |
||
1409 | mov [edi+uhci_pipe.HeadTD-uhci_pipe.SoftwarePart], eax |
||
1410 | ; 3. Initialize Token field: |
||
1411 | ; take DeviceAddress and LowSpeedDevice from the parent pipe, |
||
1412 | ; take Endpoint and MaximumLength fields from API arguments, |
||
1413 | ; set PID depending on pipe type and provided pipe direction, |
||
1414 | ; set DataToggle to zero. |
||
1415 | mov eax, [ecx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
||
1416 | and eax, 0x107F00 ; keep DeviceAddress and LowSpeedDevice |
||
1417 | mov edx, [.endpoint] |
||
1418 | and edx, 15 |
||
1419 | shl edx, 15 |
||
1420 | or eax, edx |
||
1421 | mov edx, [.maxpacket] |
||
1422 | dec edx |
||
1423 | shl edx, 21 |
||
1424 | or eax, edx |
||
1425 | mov al, USB_PID_SETUP |
||
1426 | cmp [.type], CONTROL_PIPE |
||
1427 | jz @f |
||
1428 | mov al, USB_PID_OUT |
||
1429 | test byte [.endpoint], 80h |
||
1430 | jz @f |
||
1431 | mov al, USB_PID_IN |
||
1432 | @@: |
||
1433 | mov [edi+uhci_pipe.Token-uhci_pipe.SoftwarePart], eax |
||
1434 | ; 4. Initialize the first TD: |
||
1435 | ; copy Token from uhci_pipe.Token zeroing reserved bit 20, |
||
1436 | ; set ControlStatus for future transfers, bit make it inactive, |
||
1437 | ; set bit 0 in NextTD = "no next TD". |
||
1438 | pop edx ; restore pointer saved in step 2 |
||
1439 | mov [edx+uhci_gtd.Token-uhci_gtd.SoftwarePart], eax |
||
1440 | and byte [edx+uhci_gtd.Token+2-uhci_gtd.SoftwarePart], not (1 shl (20-16)) |
||
1441 | and eax, 1 shl 20 |
||
1442 | shl eax, 6 |
||
1443 | or eax, UHCI_INVALID_LENGTH + (3 shl 27) |
||
1444 | ; not processed, inactive, allow 3 errors |
||
1445 | mov [edx+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart], eax |
||
1446 | mov [edx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 1 |
||
1447 | ; 5. Select the corresponding list and insert to the list. |
||
1448 | ; 5a. Use Control list for control pipes, Bulk list for bulk pipes. |
||
1449 | lea edx, [esi+uhci_controller.ControlED.SoftwarePart-sizeof.uhci_controller] |
||
1450 | cmp [.type], BULK_PIPE |
||
1451 | jb .insert ; control pipe |
||
1452 | lea edx, [esi+uhci_controller.BulkED.SoftwarePart-sizeof.uhci_controller] |
||
1453 | jz .insert ; bulk pipe |
||
1454 | .interrupt_pipe: |
||
1455 | ; 5b. For interrupt pipes, let the scheduler select the appropriate list |
||
1456 | ; based on the current bandwidth distribution and the requested bandwidth. |
||
1457 | ; This could fail if the requested bandwidth is not available; |
||
1458 | ; if so, return an error. |
||
1459 | lea edx, [esi + uhci_controller.IntEDs - sizeof.uhci_controller] |
||
1460 | lea eax, [esi + uhci_controller.IntEDs + 32*sizeof.uhci_static_ep - sizeof.uhci_controller] |
||
1461 | push 64 |
||
1462 | pop ecx |
||
1463 | call usb1_select_interrupt_list |
||
1464 | test edx, edx |
||
1465 | jz .return0 |
||
1466 | .insert: |
||
1467 | ; Insert to the head of the corresponding list. |
||
1468 | ; Note: inserting to the head guarantees that the list traverse in |
||
1469 | ; uhci_process_updated_schedule, once started, will not interact with new pipes. |
||
1470 | ; However, we still need to ensure that links in the new pipe (edi.NextVirt) |
||
1471 | ; are initialized before links to the new pipe (edx.NextVirt). |
||
1472 | ; 5c. Insert in the list of virtual addresses. |
||
1473 | mov ecx, [edx+usb_pipe.NextVirt] |
||
1474 | mov [edi+usb_pipe.NextVirt], ecx |
||
1475 | mov [edi+usb_pipe.PrevVirt], edx |
||
1476 | mov [ecx+usb_pipe.PrevVirt], edi |
||
1477 | mov [edx+usb_pipe.NextVirt], edi |
||
1478 | ; 5d. Insert in the hardware list: copy previous NextQH to the new pipe, |
||
1479 | ; store the physical address of the new pipe to previous NextQH. |
||
1480 | mov ecx, [edx+uhci_static_ep.NextQH-uhci_static_ep.SoftwarePart] |
||
1481 | mov [edi+uhci_pipe.NextQH-uhci_pipe.SoftwarePart], ecx |
||
1482 | lea eax, [edi-uhci_pipe.SoftwarePart] |
||
1483 | call get_phys_addr |
||
1484 | inc eax |
||
1485 | inc eax |
||
1486 | mov [edx+uhci_static_ep.NextQH-uhci_static_ep.SoftwarePart], eax |
||
1487 | ; 6. Return with nonzero eax. |
||
1488 | ret |
||
1489 | .return0: |
||
1490 | xor eax, eax |
||
1491 | ret |
||
1492 | endp |
||
1493 | |||
1494 | ; This procedure is called when a pipe is closing (either due to API call |
||
1495 | ; or due to disconnect); it unlinks a pipe from the corresponding list. |
||
1496 | if uhci_static_ep.SoftwarePart <> uhci_pipe.SoftwarePart |
||
1497 | .err uhci_unlink_pipe assumes that uhci_static_ep.SoftwarePart == uhci_pipe.SoftwarePart |
||
1498 | end if |
||
1499 | proc uhci_unlink_pipe |
||
1500 | cmp [ebx+usb_pipe.Type], INTERRUPT_PIPE |
||
1501 | jnz @f |
||
1502 | mov eax, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
||
1503 | cmp al, USB_PID_IN |
||
1504 | setz ch |
||
1505 | bt eax, 20 |
||
1506 | setc cl |
||
1507 | add eax, 1 shl 21 |
||
1508 | shr eax, 21 |
||
1509 | stdcall usb1_interrupt_list_unlink, eax, ecx |
||
1510 | @@: |
||
1511 | ; Note: we need to ensure that NextVirt field of the pipe is not modified; |
||
1512 | ; this procedure can be called while uhci_process_updated_schedule processes |
||
1513 | ; the same pipe, and it needs a correct NextVirt field to continue. |
||
1514 | mov edx, [ebx+usb_pipe.NextVirt] |
||
1515 | mov eax, [ebx+usb_pipe.PrevVirt] |
||
1516 | mov [edx+usb_pipe.PrevVirt], eax |
||
1517 | mov [eax+usb_pipe.NextVirt], edx |
||
1518 | ; Note: eax could be either usb_pipe or usb_static_ep; |
||
1519 | ; fortunately, NextQH and SoftwarePart have same offsets in both. |
||
1520 | mov edx, [ebx+uhci_pipe.NextQH-uhci_pipe.SoftwarePart] |
||
1521 | mov [eax+uhci_pipe.NextQH-uhci_pipe.SoftwarePart], edx |
||
1522 | ret |
||
1523 | endp |
||
1524 | |||
1525 | ; Free memory associated with pipe. |
||
1526 | ; For UHCI, this includes usb_pipe structure and ErrorTD, if present. |
||
1527 | proc uhci_free_pipe |
||
1528 | mov eax, [esp+4] |
||
1529 | mov eax, [eax+uhci_pipe.ErrorTD-uhci_pipe.SoftwarePart] |
||
1530 | test eax, eax |
||
1531 | jz @f |
||
1532 | stdcall uhci_free_td, eax |
||
1533 | @@: |
||
1534 | jmp usb1_free_endpoint |
||
1535 | endp |
||
1536 | |||
1537 | ; This procedure is called from the several places in main USB code |
||
1538 | ; and allocates required packets for the given transfer stage. |
||
1539 | ; ebx = pipe, other parameters are passed through the stack |
||
1540 | proc uhci_alloc_transfer stdcall uses edi, buffer:dword, size:dword, flags:dword, td:dword, direction:dword |
||
1541 | locals |
||
1542 | token dd ? |
||
1543 | origTD dd ? |
||
1544 | packetSize dd ? ; must be the last variable, see usb_init_transfer |
||
1545 | endl |
||
1546 | ; 1. [td] will be the first packet in the transfer. |
||
1547 | ; Save it to allow unrolling if something will fail. |
||
1548 | mov eax, [td] |
||
1549 | mov [origTD], eax |
||
1550 | ; In UHCI one TD describes one packet, transfers should be split into parts |
||
1551 | ; with size <= endpoint max packet size. |
||
1552 | ; 2. Get the maximum packet size for endpoint from uhci_pipe.Token |
||
1553 | ; and generate Token field for TDs. |
||
1554 | mov edi, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
||
1555 | mov eax, edi |
||
1556 | shr edi, 21 |
||
1557 | inc edi |
||
1558 | ; zero packet size (it will be set for every packet individually), |
||
1559 | ; zero reserved bit 20, |
||
1560 | and eax, (1 shl 20) - 1 |
||
1561 | mov [packetSize], edi |
||
1562 | ; set the correct PID if it is different from the pipe-wide PID |
||
1563 | ; (Data and Status stages of control transfers), |
||
1564 | mov ecx, [direction] |
||
1565 | and ecx, 3 |
||
1566 | jz @f |
||
1567 | mov al, USB_PID_OUT |
||
1568 | dec ecx |
||
1569 | jz @f |
||
1570 | mov al, USB_PID_IN |
||
1571 | @@: |
||
1572 | ; set the toggle bit for control transfers, |
||
1573 | mov ecx, [direction] |
||
1574 | test cl, 1 shl 3 |
||
1575 | jz @f |
||
1576 | and ecx, 1 shl 2 |
||
1577 | and eax, not (1 shl 19) |
||
1578 | shl ecx, 19-2 |
||
1579 | or eax, ecx |
||
1580 | @@: |
||
1581 | ; store the resulting Token in the stack variable. |
||
1582 | mov [token], eax |
||
1583 | ; 3. While the remaining data cannot fit in one packet, |
||
1584 | ; allocate full packets (of maximal possible size). |
||
1585 | .fullpackets: |
||
1586 | cmp [size], edi |
||
1587 | jbe .lastpacket |
||
1588 | call uhci_alloc_packet |
||
1589 | test eax, eax |
||
1590 | jz .fail |
||
1591 | mov [td], eax |
||
1592 | add [buffer], edi |
||
1593 | sub [size], edi |
||
1594 | jmp .fullpackets |
||
1595 | .lastpacket: |
||
1596 | ; 4. The remaining data can fit in one packet; |
||
1597 | ; allocate the last packet with size = size of remaining data. |
||
1598 | mov eax, [size] |
||
1599 | mov [packetSize], eax |
||
1600 | call uhci_alloc_packet |
||
1601 | test eax, eax |
||
1602 | jz .fail |
||
1603 | ; 5. Clear 'short packets are not allowed' bit for the last packet, |
||
1604 | ; if the caller requested this. |
||
1605 | ; Note: even if the caller says that short transfers are ok, |
||
1606 | ; all packets except the last one are marked as 'must be complete': |
||
1607 | ; if one of them will be short, the software intervention is needed |
||
1608 | ; to skip remaining packets; uhci_process_finalized_td will handle this |
||
1609 | ; transparently to the caller. |
||
1610 | test [flags], 1 |
||
1611 | jz @f |
||
1612 | and byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], not (1 shl (29-24)) |
||
1613 | and byte [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], not 1 |
||
1614 | @@: |
||
1615 | ; 6. Update toggle bit in uhci_pipe structure from current value of [token]. |
||
1616 | mov edx, [token] |
||
1617 | xor edx, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
||
1618 | and edx, 1 shl 19 |
||
1619 | xor [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart], edx |
||
1620 | .nothing: |
||
1621 | ret |
||
1622 | .fail: |
||
1623 | mov edi, uhci_hardware_func |
||
1624 | mov eax, [td] |
||
1625 | stdcall usb_undo_tds, [origTD] |
||
1626 | xor eax, eax |
||
1627 | jmp .nothing |
||
1628 | endp |
||
1629 | |||
1630 | ; Helper procedure for uhci_alloc_transfer. Allocates one packet. |
||
1631 | proc uhci_alloc_packet |
||
1632 | ; inherit some variables from the parent uhci_alloc_transfer |
||
1633 | virtual at ebp-12 |
||
1634 | .token dd ? |
||
1635 | .origTD dd ? |
||
1636 | .packetSize dd ? |
||
1637 | rd 2 |
||
1638 | .buffer dd ? |
||
1639 | .transferSize dd ? |
||
1640 | .Flags dd ? |
||
1641 | .td dd ? |
||
1642 | .direction dd ? |
||
1643 | end virtual |
||
1644 | ; 1. In UHCI all data for one packet must be on the same page. |
||
1645 | ; Thus, if the given buffer splits page boundary, we need a temporary buffer |
||
1646 | ; and code that transfers data between the given buffer and the temporary one. |
||
1647 | ; 1a. There is no buffer for zero-length packets. |
||
1648 | xor eax, eax |
||
1649 | cmp [.packetSize], eax |
||
1650 | jz .notempbuf |
||
1651 | ; 1b. A temporary buffer is not required if the first and the last bytes |
||
1652 | ; of the given buffer are the same except lower 12 bits. |
||
1653 | mov edx, [.buffer] |
||
1654 | add edx, [.packetSize] |
||
1655 | dec edx |
||
1656 | xor edx, [.buffer] |
||
1657 | test edx, -0x1000 |
||
1658 | jz .notempbuf |
||
1659 | ; 1c. We need a temporary buffer. Allocate [packetSize]*2 bytes, so that |
||
1660 | ; there must be [packetSize] bytes on one page, |
||
1661 | ; plus space for a header uhci_original_buffer. |
||
1662 | push ebx |
||
1663 | mov eax, [.packetSize] |
||
1664 | add eax, eax |
||
1665 | add eax, sizeof.uhci_original_buffer |
||
1666 | call malloc |
||
1667 | pop ebx |
||
1668 | ; 1d. If failed, return zero. |
||
1669 | test eax, eax |
||
1670 | jz .nothing |
||
1671 | ; 1e. Test whether [.packetSize] bytes starting from |
||
1672 | ; eax + sizeof.uhci_original_buffer are in the same page. |
||
1673 | ; If so, use eax + sizeof.uhci_original_buffer as a temporary buffer. |
||
1674 | ; Otherwise, use the beginning of the next page as a temporary buffer |
||
1675 | ; (since we have overallocated, sufficient space must remain). |
||
1676 | lea ecx, [eax+sizeof.uhci_original_buffer] |
||
1677 | mov edx, ecx |
||
1678 | add edx, [.packetSize] |
||
1679 | dec edx |
||
1680 | xor edx, ecx |
||
1681 | test edx, -0x1000 |
||
1682 | jz @f |
||
1683 | mov ecx, eax |
||
1684 | or ecx, 0xFFF |
||
1685 | inc ecx |
||
1686 | @@: |
||
1687 | mov [eax+uhci_original_buffer.UsedBuffer], ecx |
||
1688 | mov ecx, [.buffer] |
||
1689 | mov [eax+uhci_original_buffer.OrigBuffer], ecx |
||
1690 | ; 1f. For SETUP and OUT packets, copy data from the given buffer |
||
1691 | ; to the temporary buffer now. For IN packets, data go in other direction |
||
1692 | ; when the transaction completes. |
||
1693 | cmp byte [.token], USB_PID_IN |
||
1694 | jz .nocopy |
||
1695 | push esi edi |
||
1696 | mov esi, ecx |
||
1697 | mov edi, [eax+uhci_original_buffer.UsedBuffer] |
||
1698 | mov ecx, [.packetSize] |
||
1699 | mov edx, ecx |
||
1700 | shr ecx, 2 |
||
1701 | and edx, 3 |
||
1702 | rep movsd |
||
1703 | mov ecx, edx |
||
1704 | rep movsb |
||
1705 | pop edi esi |
||
1706 | .nocopy: |
||
1707 | .notempbuf: |
||
1708 | ; 2. Allocate the next TD. |
||
1709 | push eax |
||
1710 | call usb1_allocate_general_td |
||
1711 | pop edx |
||
1712 | ; If failed, free the temporary buffer (if it was allocated) and return zero. |
||
1713 | test eax, eax |
||
1714 | jz .fail |
||
1715 | ; 3. Initialize controller-independent parts of both TDs. |
||
1716 | push edx |
||
1717 | call usb_init_transfer |
||
1718 | ; 4. Initialize the next TD: |
||
1719 | ; mark it as last one (this will be changed when further packets will be |
||
1720 | ; allocated), copy Token field from uhci_pipe.Token zeroing bit 20, |
||
1721 | ; generate ControlStatus field, mark as Active |
||
1722 | ; (for last descriptor, this will be changed by uhci_insert_transfer). |
||
1723 | mov [eax+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 1 ; no next TD |
||
1724 | mov edx, [ebx+uhci_pipe.Token-uhci_pipe.SoftwarePart] |
||
1725 | mov [eax+uhci_gtd.Token-uhci_gtd.SoftwarePart], edx |
||
1726 | and byte [eax+uhci_gtd.Token+2-uhci_gtd.SoftwarePart], not (1 shl (20-16)) |
||
1727 | and edx, 1 shl 20 |
||
1728 | shl edx, 6 |
||
1729 | or edx, UHCI_INVALID_LENGTH + (1 shl 23) + (3 shl 27) |
||
1730 | ; not processed, active, allow 3 errors |
||
1731 | mov [eax+uhci_gtd.ControlStatus-uhci_gtd.SoftwarePart], edx |
||
1732 | ; 5. Initialize remaining fields of the current TD. |
||
1733 | ; 5a. Store pointer to the buffer allocated in step 1 (or zero). |
||
1734 | pop [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
||
1735 | ; 5b. Store physical address of the next TD. |
||
1736 | push eax |
||
1737 | sub eax, uhci_gtd.SoftwarePart |
||
1738 | call get_phys_addr |
||
1739 | ; use Depth traversal unless this is the first TD in the transfer stage; |
||
1740 | ; uhci_insert_transfer will set Depth traversal for the first TD and clear |
||
1741 | ; it in the last TD |
||
1742 | cmp ecx, [ebx+usb_pipe.LastTD] |
||
1743 | jz @f |
||
1744 | or eax, 4 |
||
1745 | @@: |
||
1746 | mov [ecx+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], eax |
||
1747 | ; 5c. Store physical address of the buffer: zero if no data present, |
||
1748 | ; the temporary buffer if it was allocated, the given buffer otherwise. |
||
1749 | xor eax, eax |
||
1750 | cmp [.packetSize], eax |
||
1751 | jz .hasphysbuf |
||
1752 | mov eax, [.buffer] |
||
1753 | mov edx, [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
||
1754 | test edx, edx |
||
1755 | jz @f |
||
1756 | mov eax, [edx+uhci_original_buffer.UsedBuffer] |
||
1757 | @@: |
||
1758 | call get_phys_addr |
||
1759 | .hasphysbuf: |
||
1760 | mov [ecx+uhci_gtd.Buffer-uhci_gtd.SoftwarePart], eax |
||
1761 | ; 5d. For IN transfers, disallow short packets. |
||
1762 | ; This will be overridden, if needed, by uhci_alloc_transfer. |
||
1763 | mov eax, [.token] |
||
1764 | mov edx, [.packetSize] |
||
1765 | dec edx |
||
1766 | cmp al, USB_PID_IN |
||
1767 | jnz @f |
||
1768 | or byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], 1 shl (29-24) ; disallow short packets |
||
1769 | or byte [ecx+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart], 1 |
||
1770 | @@: |
||
1771 | ; 5e. Get Token field: combine [.token] with [.packetSize]. |
||
1772 | shl edx, 21 |
||
1773 | or edx, eax |
||
1774 | mov [ecx+uhci_gtd.Token-uhci_gtd.SoftwarePart], edx |
||
1775 | ; 6. Flip toggle bit in [.token]. |
||
1776 | xor eax, 1 shl 19 |
||
1777 | mov [.token], eax |
||
1778 | ; 7. Return pointer to the next TD. |
||
1779 | pop eax |
||
1780 | .nothing: |
||
1781 | ret |
||
1782 | .fail: |
||
1783 | xchg eax, edx |
||
1784 | call free |
||
1785 | xor eax, eax |
||
1786 | ret |
||
1787 | endp |
||
1788 | |||
1789 | ; This procedure is called from the several places in main USB code |
||
1790 | ; and activates the transfer which was previously allocated by |
||
1791 | ; uhci_alloc_transfer. |
||
1792 | ; ecx -> last descriptor for the transfer, ebx -> usb_pipe |
||
1793 | proc uhci_insert_transfer |
||
1794 | ; DEBUGF 1,'K : uhci_insert_transfer: eax=%x, ecx=%x, [esp+4]=%x\n',eax,ecx,[esp+4] |
||
1795 | and byte [eax+uhci_gtd.ControlStatus+2-uhci_gtd.SoftwarePart], not (1 shl (23-16)) ; clear Active bit |
||
1796 | or byte [ecx+uhci_gtd.ControlStatus+3-uhci_gtd.SoftwarePart], 1 shl (24-24) ; set InterruptOnComplete bit |
||
1797 | mov eax, [esp+4] |
||
1798 | or byte [eax+uhci_gtd.ControlStatus+2-uhci_gtd.SoftwarePart], 1 shl (23-16) ; set Active bit |
||
1799 | or byte [eax+uhci_gtd.NextTD-uhci_gtd.SoftwarePart], 4 ; set Depth bit |
||
1800 | ret |
||
1801 | endp |
||
1802 | |||
1803 | ; Free all memory associated with one TD. |
||
1804 | ; For UHCI, this includes memory for uhci_gtd itself |
||
1805 | ; and the temporary buffer, if present. |
||
1806 | proc uhci_free_td |
||
1807 | mov eax, [esp+4] |
||
1808 | mov eax, [eax+uhci_gtd.OrigBufferInfo-uhci_gtd.SoftwarePart] |
||
1809 | and eax, not 1 |
||
1810 | jz .nobuf |
||
1811 | push ebx |
||
1812 | call free |
||
1813 | pop ebx |
||
1814 | .nobuf: |
||
1815 | sub dword [esp+4], uhci_gtd.SoftwarePart |
||
1816 | jmp usb_free_common |
||
1817 | endp=>>=>>>> |