Subversion Repositories Kolibri OS

Rev

Rev 4418 | Details | Compare with Previous | Last modification | View Log | RSS feed

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