Subversion Repositories Kolibri OS

Rev

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