Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3520 clevermous 1
; Code for OHCI 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
; OHCI register declarations
20
; All of the registers should be read and written as Dwords.
21
; Partition 1. Control and Status registers.
22
OhciRevisionReg         = 0
23
OhciControlReg          = 4
24
OhciCommandStatusReg    = 8
25
OhciInterruptStatusReg  = 0Ch
26
OhciInterruptEnableReg  = 10h
27
OhciInterruptDisableReg = 14h
28
; Partition 2. Memory Pointer registers.
29
OhciHCCAReg             = 18h
30
OhciPeriodCurrentEDReg  = 1Ch
31
OhciControlHeadEDReg    = 20h
32
OhciControlCurrentEDReg = 24h
33
OhciBulkHeadEDReg       = 28h
34
OhciBulkCurrentEDReg    = 2Ch
35
OhciDoneHeadReg         = 30h
36
; Partition 3. Frame Counter registers.
37
OhciFmIntervalReg       = 34h
38
OhciFmRemainingReg      = 38h
39
OhciFmNumberReg         = 3Ch
40
OhciPeriodicStartReg    = 40h
41
OhciLSThresholdReg      = 44h
42
; Partition 4. Root Hub registers.
43
OhciRhDescriptorAReg    = 48h
44
OhciRhDescriptorBReg    = 4Ch
45
OhciRhStatusReg         = 50h
46
OhciRhPortStatusReg     = 54h
47
 
48
; =============================================================================
49
; ================================ Structures =================================
50
; =============================================================================
51
 
52
; OHCI-specific part of a pipe descriptor.
53
; * This structure corresponds to the Endpoint Descriptor aka ED from the OHCI
54
;   specification.
55
; * The hardware requires 16-bytes alignment of the hardware part.
56
;   Since the allocator (usb_allocate_common) allocates memory sequentially
3653 clevermous 57
;   from page start (aligned on 0x1000 bytes), block size for the allocator
58
;   must be divisible by 16; usb1_allocate_endpoint ensures this.
3520 clevermous 59
struct ohci_pipe
60
; All addresses are physical.
61
Flags           dd      ?
62
; 1. Lower 7 bits (bits 0-6) are FunctionAddress. This is the USB address of
63
;    the function containing the endpoint that this ED controls.
64
; 2. Next 4 bits (bits 7-10) are EndpointNumber. This is the USB address of
65
;    the endpoint within the function.
66
; 3. Next 2 bits (bits 11-12) are Direction. This 2-bit field indicates the
4547 clevermous 67
;    direction of data flow: 1 = OUT, 2 = IN. If neither IN nor OUT is
3520 clevermous 68
;    specified, then the direction is determined from the PID field of the TD.
69
;    For CONTROL endpoints, the transfer direction is different
70
;    for different transfers, so the value of this field is 0
71
;    (3 would have the same effect) and the actual direction
72
;    of one transfer is encoded in the Transfer Descriptor.
73
; 4. Next bit (bit 13) is Speed bit. It indicates the speed of the endpoint:
74
;    full-speed (S = 0) or low-speed (S = 1).
75
; 5. Next bit (bit 14) is sKip bit. When this bit is set, the hardware
76
;    continues on to the next ED on the list without attempting access
77
;    to the TD queue or issuing any USB token for the endpoint.
78
;    Always cleared.
79
; 6. Next bit (bit 15) is Format bit. It must be 0 for Control, Bulk and
80
;    Interrupt endpoints and 1 for Isochronous endpoints.
81
; 7. Next 11 bits (bits 16-26) are MaximumPacketSize. This field indicates
82
;    the maximum number of bytes that can be sent to or received from the
83
;    endpoint in a single data packet.
84
TailP           dd      ?
85
; Physical address of the tail descriptor in the TD queue.
86
; The descriptor itself is not in the queue. See also HeadP.
87
HeadP           dd      ?
88
; 1. First bit (bit 0) is Halted bit. This bit is set by the hardware to
89
;    indicate that processing of the TD queue on the endpoint is halted.
90
; 2. Second bit (bit 1) is toggleCarry bit. Whenever a TD is retired, this
91
;    bit is written to contain the last data toggle value from the retired TD.
92
; 3. Next two bits (bits 2-3) are reserved and always zero.
93
; 4. With masked 4 lower bits, this is HeadP itself: physical address of the
94
;    head descriptor in the TD queue, that is, next TD to be processed for this
95
;    endpoint. Note that a TD must be 16-bytes aligned.
96
;    Empty queue is characterized by the condition HeadP == TailP.
97
NextED          dd      ?
98
; If nonzero, then this entry is a physical address of the next ED to be
99
; processed. See also the description before NextVirt field of the usb_pipe
100
; structure. Additionally to that description, the following is specific for
101
; the OHCI controller:
102
; * n=5, N=32, there are 32 "leaf" periodic lists.
103
; * The 1ms periodic list also serves Isochronous endpoints, which should be
104
;   in the end of the list.
105
; * There is no "next" list for Bulk and Control lists, they are processed
106
;   separately from others.
107
; * There is no "next" list for Periodic list for 1ms interval.
108
ends
109
 
110
; This structure describes the static head of every list of pipes.
111
; The hardware requires 16-bytes alignment of this structure.
112
; All instances of this structure are located sequentially in uhci_controller,
113
; uhci_controller is page-aligned, so it is sufficient to make this structure
114
; 16-bytes aligned and verify that the first instance is 16-bytes aligned
115
; inside uhci_controller.
116
struct ohci_static_ep
117
Flags           dd      ?
118
; Same as ohci_pipe.Flags.
119
; sKip bit is set, so the hardware ignores other fields except NextED.
120
                dd      ?
121
; Corresponds to ohci_pipe.TailP. Not used.
122
NextList        dd      ?
123
; Virtual address of the next list.
124
NextED          dd      ?
125
; Same as ohci_pipe.NextED.
126
SoftwarePart    rd      sizeof.usb_static_ep/4
127
; Software part, common for all controllers.
128
                dd      ?
129
; Padding for 16-bytes alignment.
130
ends
131
 
132
if sizeof.ohci_static_ep mod 16
133
.err ohci_static_ep must be 16-bytes aligned
134
end if
135
 
136
; OHCI-specific part of controller data.
137
; * The structure describes the memory area used for controller data,
138
;   additionally to the registers of the controller.
139
; * The structure includes two parts, the hardware part and the software part.
140
; * The hardware part consists of first 256 bytes and corresponds to
141
;   the HCCA from OHCI specification.
142
; * The hardware requires 256-bytes alignment of the hardware part, so
143
;   the entire descriptor must be 256-bytes aligned.
144
;   This structure is allocated with kernel_alloc (see usb_init_controller),
145
;   this gives page-aligned data.
146
; * The controller is described by both ohci_controller and usb_controller
147
;   structures, for each controller there is one ohci_controller and one
148
;   usb_controller structure. These structures are located sequentially
149
;   in the memory: beginning from some page start, there is ohci_controller
150
;   structure - this enforces hardware alignment requirements - and then
151
;   usb_controller structure.
152
; * The code keeps pointer to usb_controller structure. The ohci_controller
153
;   structure is addressed as [ptr + ohci_controller.field - sizeof.ohci_controller].
154
struct ohci_controller
155
; ------------------------------ hardware fields ------------------------------
156
InterruptTable  rd      32
157
; Pointers to interrupt EDs. The hardware starts processing of periodic lists
158
; within the frame N from the ED pointed to by [InterruptTable+(N and 31)*4].
159
; See also the description of periodic lists inside ohci_pipe structure.
160
FrameNumber     dw      ?
161
; The current frame number. This field is written by hardware only.
162
; This field is read by ohci_process_deferred and ohci_irq to
163
; communicate when control/bulk processing needs to be temporarily
164
; stopped/restarted.
165
                dw      ?
166
; Padding. Written as zero at every update of FrameNumber.
167
DoneHead        dd      ?
168
; Physical pointer to the start of Done Queue.
169
; When the hardware updates this field, it sets bit 0 to one if there is
170
; unmasked interrupt pending.
171
                rb      120
172
; Reserved for the hardware.
173
; ------------------------------ software fields ------------------------------
174
IntEDs          ohci_static_ep
175
                rb      62 * sizeof.ohci_static_ep
176
; Heads of 63 Periodic lists, see the description in usb_pipe.
177
ControlED       ohci_static_ep
178
; Head of Control list, see the description in usb_pipe.
179
BulkED          ohci_static_ep
180
; Head of Bulk list, see the description in usb_pipe.
181
MMIOBase        dd      ?
182
; Virtual address of memory-mapped area with OHCI registers OhciXxxReg.
183
PoweredUp       db      ?
184
; 1 in normal work, 0 during early phases of the initialization.
185
; This field is initialized to zero during memory allocation
186
; (see usb_init_controller), set to one by ohci_init when ports of the root hub
187
; are powered up, so connect/disconnect events can be handled.
188
                rb      3 ; alignment
189
DoneList        dd      ?
190
; List of descriptors which were processed by the controller and now need
191
; to be finalized.
192
DoneListEndPtr  dd      ?
193
; Pointer to dword which should receive a pointer to the next item in DoneList.
194
; If DoneList is empty, this is a pointer to DoneList itself;
195
; otherwise, this is a pointer to NextTD field of the last item in DoneList.
4418 clevermous 196
EhciCompanion   dd      ?
197
; Pointer to usb_controller for EHCI companion, if any, or NULL.
3520 clevermous 198
ends
199
 
200
if ohci_controller.IntEDs mod 16
201
.err Static endpoint descriptors must be 16-bytes aligned inside ohci_controller
202
end if
203
 
204
; OHCI general transfer descriptor.
205
; * The structure describes transfers to be performed on Control, Bulk or
206
;   Interrupt endpoints.
207
; * The structure includes two parts, the hardware part and the software part.
208
; * The hardware part consists of first 16 bytes and corresponds to
209
;   the General Transfer Descriptor aka general TD from OHCI specification.
210
; * The hardware requires 16-bytes alignment of the hardware part, so
211
;   the entire descriptor must be 16-bytes aligned. Since the allocator
212
;   (usb_allocate_common) allocates memory sequentially from page start
3653 clevermous 213
;   (aligned on 0x1000 bytes), block size for the allocator must be
214
;   divisible by 16; usb1_allocate_generic_td ensures this.
3520 clevermous 215
struct ohci_gtd
216
; ------------------------------ hardware fields ------------------------------
217
; All addresses in this part are physical.
218
Flags           dd      ?
219
; 1. Lower 18 bits (bits 0-17) are ignored and not modified by the hardware.
220
; 2. Next bit (bit 18) is bufferRounding bit. If this bit is 0, then the last
221
;    data packet must exactly fill the defined data buffer. If this bit is 1,
222
;    then the last data packet may be smaller than the defined buffer without
223
;    causing an error condition on the TD.
224
; 3. Next 2 bits (bits 19-20) are Direction field. This field indicates the
225
;    direction of data flow. If the Direction field in the ED is OUT or IN,
226
;    this field is ignored and the direction from the ED is used instead.
227
;    Otherwise, 0 = SETUP, 1 = OUT, 2 = IN, 3 is reserved.
228
; 4. Next 3 bits (bits 21-23) are DelayInterrupt field. This field contains
229
;    the interrupt delay count for this TD. When a TD is complete, the hardware
230
;    may wait up to DelayInterrupt frames before generating an interrupt.
231
;    If DelayInterrupt is 7 (maximum possible), then there is no interrupt
232
;    associated with completion of this TD.
233
; 5. Next 2 bits (bits 24-25) are DataToggle field. This field is used to
234
;    generate/compare the data PID value (DATA0 or DATA1). It is updated after
235
;    each successful transmission/reception of a data packet. The bit 25
236
;    is 0 when the data toggle value is acquired from the toggleCarry field in
237
;    the ED and 1 when the data toggle value is taken from the bit 24.
238
; 6. Next 2 bits (bits 26-27) are ErrorCount field. For each transmission
239
;    error, this value is incremented. If ErrorCount is 2 and another error
240
;    occurs, the TD is retired with error. When a transaction completes without
241
;    error, ErrorCount is reset to 0.
242
; 7. Upper 4 bits (bits 28-31) are ConditionCode field. This field contains
243
;    the status of the last attempted transaction, one of USB_STATUS_* values.
244
CurBufPtr       dd      ?
245
; Physical address of the next memory location that will be accessed for
246
; transfer to/from the endpoint. 0 means zero-length data packet or that all
247
; bytes have been transferred.
248
NextTD          dd      ?
249
; This field has different meanings depending on the status of the descriptor.
250
; When the descriptor is queued for processing, but not yet processed:
251
;   Physical address of the next TD for the endpoint.
252
; When the descriptor is processed by hardware, but not yet by software:
253
;   Physical address of the previous processed TD.
254
; When the descriptor is processed by the IRQ handler, but not yet completed:
255
;   Virtual pointer to the next processed TD.
256
BufEnd          dd      ?
257
; Physical address of the last byte in the buffer for this TD.
3711 clevermous 258
                dd      ?       ; padding to align with uhci_gtd
3520 clevermous 259
ends
260
 
261
; OHCI isochronous transfer descriptor.
262
; * The structure describes transfers to be performed on Isochronous endpoints.
263
; * The structure includes two parts, the hardware part and the software part.
264
; * The hardware part consists of first 32 bytes and corresponds to
265
;   the Isochronous Transfer Descriptor aka isochronous TD from OHCI
266
;   specification.
267
; * The hardware requires 32-bytes alignment of the hardware part, so
268
;   the entire descriptor must be 32-bytes aligned.
269
; * The isochronous endpoints are not supported yet, so only hardware part is
270
;   defined at the moment.
271
struct ohci_itd
272
StartingFrame   dw      ?
273
; This field contains the low order 16 bits of the frame number in which the
274
; first data packet of the Isochronous TD is to be sent.
275
Flags           dw      ?
276
; 1. Lower 5 bits (bits 0-4) are ignored and not modified by the hardware.
277
; 2. Next 3 bits (bits 5-7) are DelayInterrupt field.
278
; 3. Next 3 bits (bits 8-10) are FrameCount field. The TD describes
279
;    FrameCount+1 data packets.
280
; 4. Next bit (bit 11) is ignored and not modified by the hardware.
281
; 5. Upper 4 bits (bits 12-15) are ConditionCode field. This field contains
282
;    the completion code, one of USB_STATUS_* values, when the TD is moved to
283
;    the Done Queue.
284
BufPage0        dd      ?
285
; Lower 12 bits are ignored and not modified by the hardware.
286
; With masked 12 bits this field is the physical page containing all buffers.
287
NextTD          dd      ?
288
; Physical address of the next TD in the transfer queue.
289
BufEnd          dd      ?
290
; Physical address of the last byte in the buffer.
291
OffsetArray     rw      8
292
; Initialized by software, read by hardware: Offset for packet 0..7.
293
; Used to determine size and starting address of an isochronous data packet.
294
; Written by hardware, read by software: PacketStatusWord for packet 0..7.
295
; Contains completion code and, if applicable, size received for an isochronous
296
; data packet.
297
ends
298
 
299
; Description of OHCI-specific data and functions for
300
; controller-independent code.
301
; Implements the structure usb_hardware_func from hccommon.inc for OHCI.
302
iglobal
303
align 4
304
ohci_hardware_func:
4418 clevermous 305
        dd      USBHC_VERSION
3520 clevermous 306
        dd      'OHCI'
307
        dd      sizeof.ohci_controller
4418 clevermous 308
        dd      ohci_kickoff_bios
3520 clevermous 309
        dd      ohci_init
310
        dd      ohci_process_deferred
311
        dd      ohci_set_device_address
312
        dd      ohci_get_device_address
313
        dd      ohci_port_disable
314
        dd      ohci_new_port.reset
315
        dd      ohci_set_endpoint_packet_size
4418 clevermous 316
        dd      ohci_alloc_pipe
317
        dd      ohci_free_pipe
3520 clevermous 318
        dd      ohci_init_pipe
319
        dd      ohci_unlink_pipe
4418 clevermous 320
        dd      ohci_alloc_gtd
321
        dd      ohci_free_gtd
3520 clevermous 322
        dd      ohci_alloc_transfer
323
        dd      ohci_insert_transfer
324
        dd      ohci_new_device
4547 clevermous 325
        dd      ohci_disable_pipe
326
        dd      ohci_enable_pipe
4418 clevermous 327
ohci_name db    'OHCI',0
3520 clevermous 328
endg
329
 
330
; =============================================================================
331
; =================================== Code ====================================
332
; =============================================================================
333
 
4418 clevermous 334
; Called once when driver is loading and once at shutdown.
335
; When loading, must initialize itself, register itself in the system
336
; and return eax = value obtained when registering.
337
proc start
338
virtual at esp
339
                dd      ? ; return address
340
.reason         dd      ? ; DRV_ENTRY or DRV_EXIT
341
.cmdline        dd      ? ; normally NULL
342
end virtual
343
        cmp     [.reason], DRV_ENTRY
344
        jnz     .nothing
345
        mov     ecx, ohci_ep_mutex
346
        and     dword [ecx-4], 0
347
        invoke  MutexInit
348
        mov     ecx, ohci_gtd_mutex
349
        and     dword [ecx-4], 0
350
        invoke  MutexInit
351
        push    esi edi
352
        mov     esi, [USBHCFunc]
353
        mov     edi, usbhc_api
354
        movi    ecx, sizeof.usbhc_func/4
355
        rep movsd
356
        pop     edi esi
357
        invoke  RegUSBDriver, ohci_name, 0, ohci_hardware_func
358
.nothing:
359
        ret
360
endp
361
 
3520 clevermous 362
; Controller-specific initialization function.
363
; Called from usb_init_controller. Initializes the hardware and
364
; OHCI-specific parts of software structures.
365
; eax = pointer to ohci_controller to be initialized
366
; [ebp-4] = pcidevice
367
proc ohci_init
368
; inherit some variables from the parent (usb_init_controller)
369
.devfn   equ ebp - 4
370
.bus     equ ebp - 3
371
; 1. Store pointer to ohci_controller for further use.
372
        push    eax
373
        mov     edi, eax
374
; 2. Initialize hardware fields of ohci_controller.
375
; Namely, InterruptTable needs to be initialized with
376
; physical addresses of heads of first 32 Periodic lists.
377
; Note that all static heads fit in one page, so one call
378
; to get_pg_addr is sufficient.
379
if (ohci_controller.IntEDs / 0x1000) <> (ohci_controller.BulkED / 0x1000)
380
.err assertion failed
381
end if
382
if ohci_controller.IntEDs >= 0x1000
383
.err assertion failed
384
end if
385
        lea     esi, [eax+ohci_controller.IntEDs+32*sizeof.ohci_static_ep]
4418 clevermous 386
        invoke  GetPgAddr
3520 clevermous 387
        add     eax, ohci_controller.IntEDs
3598 clevermous 388
        movi    ecx, 32
3520 clevermous 389
        mov     edx, ecx
390
@@:
391
        stosd
392
        add     eax, sizeof.ohci_static_ep
393
        loop    @b
394
; 3. Initialize static heads ohci_controller.IntEDs, .ControlED, .BulkED.
395
; Use the loop over groups: first group consists of first 32 Periodic
396
; descriptors, next group consists of next 16 Periodic descriptors,
397
; ..., last group consists of the last Periodic descriptor.
398
; 3a. Prepare for the loop.
399
; make edi point to start of ohci_controller.IntEDs,
400
; other registers are already set.
401
; -128 fits in one byte, +128 does not fit.
402
        sub     edi, -128
403
; 3b. Loop over groups. On every iteration:
404
; edx = size of group, edi = pointer to the current group,
405
; esi = pointer to the next group, eax = physical address of the next group.
406
.init_static_eds:
407
; 3c. Get the size of the next group.
408
        shr     edx, 1
409
; 3d. Exit the loop if there is no next group.
410
        jz      .init_static_eds_done
411
; 3e. Initialize the first half of the current group.
412
; Advance edi to the second half.
413
        push    eax esi
414
        call    ohci_init_static_ep_group
415
        pop     esi eax
416
; 3f. Initialize the second half of the current group
417
; with the same values.
418
; Advance edi to the next group, esi/eax to the next of the next group.
419
        call    ohci_init_static_ep_group
420
        jmp     .init_static_eds
421
.init_static_eds_done:
422
; 3g. Initialize the head of the last Periodic list.
423
        xor     eax, eax
424
        xor     esi, esi
425
        call    ohci_init_static_endpoint
426
; 3i. Initialize the heads of Control and Bulk lists.
427
        call    ohci_init_static_endpoint
428
        call    ohci_init_static_endpoint
429
; 4. Create a virtual memory area to talk with the controller.
430
; 4a. Enable memory & bus master access.
4418 clevermous 431
        invoke  PciRead16, dword [.bus], dword [.devfn], 4
3520 clevermous 432
        or      al, 6
4418 clevermous 433
        invoke  PciWrite16, dword [.bus], dword [.devfn], 4, eax
3520 clevermous 434
; 4b. Read memory base address.
4418 clevermous 435
        invoke  PciRead32, dword [.bus], dword [.devfn], 10h
3520 clevermous 436
        and     al, not 0Fh
437
; 4c. Create mapping for physical memory. 256 bytes are sufficient.
4418 clevermous 438
        invoke  MapIoMem, eax, 100h, PG_SW+PG_NOCACHE
3520 clevermous 439
        test    eax, eax
440
        jz      .fail
441
        stosd   ; fill ohci_controller.MMIOBase
442
        xchg    eax, edi
443
; now edi = MMIOBase
444
; 5. Reset the controller if needed.
445
; 5a. Check operational state.
446
; 0 = reset, 1 = resume, 2 = operational, 3 = suspended
447
        mov     eax, [edi+OhciControlReg]
448
        and     al, 3 shl 6
449
        cmp     al, 2 shl 6
450
        jz      .operational
451
; 5b. State is not operational, reset is needed.
452
.reset:
453
; 5c. Save FmInterval register.
454
        pushd   [edi+OhciFmIntervalReg]
455
; 5d. Issue software reset and wait up to 10ms, checking status every 1 ms.
3598 clevermous 456
        movi    ecx, 1
457
        movi    edx, 10
3520 clevermous 458
        mov     [edi+OhciCommandStatusReg], ecx
459
@@:
460
        mov     esi, ecx
4418 clevermous 461
        invoke  Sleep
3520 clevermous 462
        test    [edi+OhciCommandStatusReg], ecx
463
        jz      .resetdone
464
        dec     edx
465
        jnz     @b
466
        pop     eax
467
        dbgstr 'controller reset timeout'
468
        jmp     .fail_unmap
469
.resetdone:
470
; 5e. Restore FmInterval register.
471
        pop     eax
472
        mov     edx, eax
473
        and     edx, 3FFFh
474
        jz      .setfminterval
475
        cmp     dx, 2EDFh       ; default value?
476
        jnz     @f              ; assume that BIOS has configured the value
477
.setfminterval:
478
        mov     eax, 27792EDFh  ; default value
479
@@:
480
        mov     [edi+OhciFmIntervalReg], eax
481
; 5f. Set PeriodicStart to 90% of FmInterval.
482
        movzx   eax, ax
483
; Two following lines are equivalent to eax = floor(eax * 0.9)
484
; for any 0 <= eax < 1C71C71Dh, which of course is far from maximum 0FFFFh.
485
        mov     edx, 0E6666667h
486
        mul     edx
487
        mov     [edi+OhciPeriodicStartReg], edx
488
.operational:
489
; 6. Setup controller registers.
490
        pop     esi     ; restore pointer to ohci_controller saved in step 1
491
; 6a. Physical address of HCCA.
492
        mov     eax, esi
4418 clevermous 493
        invoke  GetPgAddr
3520 clevermous 494
        mov     [edi+OhciHCCAReg], eax
495
; 6b. Transition to operational state and clear all Enable bits.
496
        mov     cl, 2 shl 6
497
        mov     [edi+OhciControlReg], ecx
498
; 6c. Physical addresses of head of Control and Bulk lists.
499
if ohci_controller.BulkED >= 0x1000
500
.err assertion failed
501
end if
502
        add     eax, ohci_controller.ControlED
503
        mov     [edi+OhciControlHeadEDReg], eax
504
        add     eax, ohci_controller.BulkED - ohci_controller.ControlED
505
        mov     [edi+OhciBulkHeadEDReg], eax
506
; 6d. Zero Head registers: there are no active Control and Bulk descriptors yet.
507
        xor     eax, eax
508
;       mov     [edi+OhciPeriodCurrentEDReg], eax
509
        mov     [edi+OhciControlCurrentEDReg], eax
510
        mov     [edi+OhciBulkCurrentEDReg], eax
511
;       mov     [edi+OhciDoneHeadReg], eax
512
; 6e. Enable processing of all lists with control:bulk ratio = 1:1.
513
        mov     dword [edi+OhciControlReg], 10111100b
4418 clevermous 514
; 7. Find the EHCI companion.
515
; Note: this assumes that EHCI is initialized before USB1 companions.
3520 clevermous 516
        add     esi, sizeof.ohci_controller
4418 clevermous 517
        mov     ebx, dword [.devfn]
518
        invoke  usbhc_api.usb_find_ehci_companion
519
        mov     [esi+ohci_controller.EhciCompanion-sizeof.ohci_controller], eax
520
; 8. Get number of ports.
3520 clevermous 521
        mov     eax, [edi+OhciRhDescriptorAReg]
522
        and     eax, 0xF
523
        mov     [esi+usb_controller.NumPorts], eax
4418 clevermous 524
; 9. Initialize DoneListEndPtr to point to DoneList.
3520 clevermous 525
        lea     eax, [esi+ohci_controller.DoneList-sizeof.ohci_controller]
526
        mov     [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller], eax
4418 clevermous 527
; 10. Hook interrupt.
528
        invoke  PciRead8, dword [.bus], dword [.devfn], 3Ch
3520 clevermous 529
; al = IRQ
530
        movzx   eax, al
4418 clevermous 531
        invoke  AttachIntHandler, eax, ohci_irq, esi
532
; 11. Enable controller interrupt on HcDoneHead writeback and RootHubStatusChange.
3520 clevermous 533
        mov     dword [edi+OhciInterruptEnableReg], 80000042h
534
        DEBUGF 1,'K : OHCI controller at %x:%x with %d ports initialized\n',[.bus]:2,[.devfn]:2,[esi+usb_controller.NumPorts]
4418 clevermous 535
; 12. Initialize ports of the controller.
536
; 12a. Initiate power up, disable all ports, clear all "changed" bits.
3520 clevermous 537
        mov     dword [edi+OhciRhStatusReg], 10000h     ; SetGlobalPower
538
        xor     ecx, ecx
539
@@:
540
        mov     dword [edi+OhciRhPortStatusReg+ecx*4], 1F0101h  ; SetPortPower+ClearPortEnable+clear "changed" bits
541
        inc     ecx
542
        cmp     ecx, [esi+usb_controller.NumPorts]
543
        jb      @b
4418 clevermous 544
; 12b. Wait for power up.
3520 clevermous 545
; VirtualBox has AReg == 0, delay_ms doesn't like zero value; ignore zero delay
546
        push    esi
547
        mov     esi, [edi+OhciRhDescriptorAReg]
548
        shr     esi, 24
549
        add     esi, esi
550
        jz      @f
4418 clevermous 551
        invoke  Sleep
3520 clevermous 552
@@:
553
        pop     esi
4418 clevermous 554
; 12c. Ports are powered up; now it is ok to process connect/disconnect events.
3520 clevermous 555
        mov     [esi+ohci_controller.PoweredUp-sizeof.ohci_controller], 1
556
                ; IRQ handler doesn't accept connect/disconnect events before this point
4418 clevermous 557
; 12d. We could miss some events while waiting for powering up;
3520 clevermous 558
; scan all ports manually and check for connected devices.
559
        xor     ecx, ecx
560
.port_loop:
561
        test    dword [edi+OhciRhPortStatusReg+ecx*4], 1
562
        jz      .next_port
563
; There is a connected device; mark the port as 'connected'
564
; and save the connected time.
565
; Note that ConnectedTime must be set before 'connected' mark,
566
; otherwise the code in ohci_process_deferred could use incorrect time.
4418 clevermous 567
        invoke  GetTimerTicks
3520 clevermous 568
        mov     [esi+usb_controller.ConnectedTime+ecx*4], eax
569
        lock bts [esi+usb_controller.NewConnected], ecx
570
.next_port:
571
        inc     ecx
572
        cmp     ecx, [esi+usb_controller.NumPorts]
573
        jb      .port_loop
4418 clevermous 574
; 13. Return pointer to usb_controller.
3520 clevermous 575
        xchg    eax, esi
576
        ret
577
.fail_unmap:
4418 clevermous 578
; On error after step 5, release the virtual memory area.
579
        invoke  FreeKernelSpace, edi
3520 clevermous 580
.fail:
581
; On error, free the ohci_controller structure and return zero.
582
; Note that the pointer was placed in the stack at step 1.
4418 clevermous 583
; Note also that there can be no errors after step 6,
3520 clevermous 584
; where that pointer is popped from the stack.
585
        pop     ecx
586
.nothing:
587
        xor     eax, eax
588
        ret
589
endp
590
 
591
; Helper procedure for step 3 of ohci_init.
592
; Initializes the static head of one list.
593
; eax = physical address of the "next" list, esi = pointer to the "next" list,
594
; edi = pointer to head to initialize.
595
; Advances edi to the next head, keeps eax/esi.
596
proc ohci_init_static_endpoint
597
        mov     byte [edi+ohci_static_ep.Flags+1], 1 shl (14 - 8)       ; sKip this endpoint
598
        mov     [edi+ohci_static_ep.NextED], eax
599
        mov     [edi+ohci_static_ep.NextList], esi
600
        add     edi, ohci_static_ep.SoftwarePart
4418 clevermous 601
        invoke  usbhc_api.usb_init_static_endpoint
3520 clevermous 602
        add     edi, sizeof.ohci_static_ep - ohci_static_ep.SoftwarePart
603
        ret
604
endp
605
 
606
; Helper procedure for step 3 of ohci_init.
607
; Initializes one half of group of static heads.
608
; edx = size of the next group = half of size of the group,
609
; edi = pointer to the group, eax = physical address of the next group,
610
; esi = pointer to the next group.
611
; Advances eax, esi, edi to next group, keeps edx.
612
proc ohci_init_static_ep_group
613
        push    edx
614
@@:
615
        call    ohci_init_static_endpoint
616
        add     eax, sizeof.ohci_static_ep
617
        add     esi, sizeof.ohci_static_ep
618
        dec     edx
619
        jnz     @b
620
        pop     edx
621
        ret
622
endp
623
 
624
; Controller-specific pre-initialization function: take ownership from BIOS.
625
; Some BIOSes, although not all of them, provide legacy emulation
626
; for USB keyboard and/or mice as PS/2-devices. In this case,
627
; we must notify the BIOS that we don't need that emulation and know how to
628
; deal with USB devices.
629
proc ohci_kickoff_bios
630
; 1. Get the physical address of MMIO registers.
4418 clevermous 631
        invoke  PciRead32, dword [esi+PCIDEV.bus], dword [esi+PCIDEV.devfn], 10h
3520 clevermous 632
        and     al, not 0Fh
633
; 2. Create mapping for physical memory. 256 bytes are sufficient.
4418 clevermous 634
        invoke  MapIoMem, eax, 100h, PG_SW+PG_NOCACHE
3520 clevermous 635
        test    eax, eax
636
        jz      .nothing
637
; 3. Some BIOSes enable controller interrupts as a result of giving
638
; controller away. At this point the system knows nothing about how to serve
639
; OHCI interrupts, so such an interrupt will send the system into an infinite
640
; loop handling the same IRQ again and again. Thus, we need to block OHCI
641
; interrupts. We can't do this at the controller level until step 5,
642
; because the controller is currently owned by BIOS, so we block all hardware
643
; interrupts on this processor until step 5.
644
        pushf
645
        cli
646
; 4. Take the ownership over the controller.
647
; 4a. Check whether BIOS handles this controller at all.
648
        mov     edx, 100h
649
        test    dword [eax+OhciControlReg], edx
650
        jz      .has_ownership
651
; 4b. Send "take ownership" command to the BIOS.
652
; (This should generate SMI, BIOS should release its ownership in SMI handler.)
653
        mov     dword [eax+OhciCommandStatusReg], 8
654
; 4c. Wait for result no more than 50 ms, checking for status every 1 ms.
3598 clevermous 655
        movi    ecx, 50
3520 clevermous 656
@@:
657
        test    dword [eax+OhciControlReg], edx
658
        jz      .has_ownership
659
        push    esi
3598 clevermous 660
        movi    esi, 1
4418 clevermous 661
        invoke  Sleep
3520 clevermous 662
        pop     esi
663
        loop    @b
664
        dbgstr 'warning: taking OHCI ownership from BIOS timeout'
665
.has_ownership:
666
; 5. Disable all controller interrupts until the system will be ready to
667
; process them.
668
        mov     dword [eax+OhciInterruptDisableReg], 0C000007Fh
669
; 6. Now we can unblock interrupts in the processor.
670
        popf
671
; 7. Release memory mapping created in step 2 and return.
4418 clevermous 672
        invoke  FreeKernelSpace, eax
3520 clevermous 673
.nothing:
674
        ret
675
endp
676
 
677
; IRQ handler for OHCI controllers.
678
ohci_irq.noint:
679
; Not our interrupt: restore registers and return zero.
680
        xor     eax, eax
681
        pop     edi esi ebx
682
        ret
683
 
684
proc ohci_irq
685
        push    ebx esi edi     ; save used registers to be cdecl
686
virtual at esp
687
                rd      3       ; saved registers
688
                dd      ?       ; return address
689
.controller     dd      ?
690
end virtual
691
; 1. ebx will hold whether some deferred processing is needed,
692
; that cannot be done from the interrupt handler. Initialize to zero.
693
        xor     ebx, ebx
694
; 2. Get the mask of events which should be processed.
695
        mov     esi, [.controller]
696
        mov     edi, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller]
697
        mov     eax, [edi+OhciInterruptStatusReg]
698
; 3. Check whether that interrupt has been generated by our controller.
699
; (One IRQ can be shared by several devices.)
700
        and     eax, [edi+OhciInterruptEnableReg]
701
        jz      .noint
702
; 4. Get the physical pointer to the last processed descriptor.
703
; All processed descriptors form single-linked list from last to first
704
; with the help of NextTD field. The list is restarted every time when
705
; the controller writes to DoneHead, so grab the pointer now (before the next
706
; step) or it could be lost (the controller could write new value to DoneHead
707
; any time after WorkDone bit is cleared in OhciInterruptStatusReg).
708
        mov     ecx, [esi+ohci_controller.DoneHead-sizeof.ohci_controller]
709
        and     ecx, not 1
710
; 5. Clear the events we know of.
711
; Note that this should be done before processing of events:
712
; new events could arise while we are processing those, this way we won't lose
713
; them (the controller would generate another interrupt
714
; after completion of this one).
715
        mov     [edi+OhciInterruptStatusReg], eax
716
; 6. Save the mask of events for further reference.
717
        push    eax
718
; 7. Handle 'transfer is done' events.
719
; 7a. Test whether there are such events.
720
        test    al, 2
721
        jz      .skip_donehead
722
; There are some 'transfer is done' events, processed descriptors are linked
723
; through physical addresses in the reverse order.
724
; We can't do much in an interrupt handler, since callbacks could require
725
; waiting for locks and that can't be done in an interrupt handler.
726
; However, we can't also just defer all work to the USB thread, since
727
; it is possible that previous lists are not yet processed and it is hard
728
; to store unlimited number of list heads. Thus, we reverse the current list,
729
; append it to end of the previous list (if there is one) and defer other
730
; processing to the USB thread; this way there always is no more than one list
731
; (possibly joined from several controller-reported lists).
732
; The list traversal requires converting physical addresses to virtual pointers,
733
; so we may as well store pointers instead of physical addresses.
734
; 7b. Prepare for the reversing loop.
735
        push    ebx
736
        xor     ebx, ebx
737
        test    ecx, ecx
738
        jz      .tddone
4418 clevermous 739
        mov     eax, [ohci_gtd_first_page]
740
        invoke  usbhc_api.usb_td_to_virt
3520 clevermous 741
        test    eax, eax
742
        jz      .tddone
743
        lea     edx, [eax+ohci_gtd.NextTD]
744
; 7c. Reverse the list, converting physical to virtual. On every iteration:
745
; ecx = physical address of the current item
746
; eax = virtual pointer to the current item
747
; edx = virtual pointer to the last item.NextTD (first in the reverse list)
748
; ebx = virtual pointer to the next item (previous in the reverse list)
749
.tdloop:
750
        mov     ecx, [eax+ohci_gtd.NextTD]
751
        mov     [eax+ohci_gtd.NextTD], ebx
3653 clevermous 752
        lea     ebx, [eax+sizeof.ohci_gtd]
3520 clevermous 753
        test    ecx, ecx
754
        jz      .tddone
4418 clevermous 755
        mov     eax, [ohci_gtd_first_page]
756
        invoke  usbhc_api.usb_td_to_virt
3520 clevermous 757
        test    eax, eax
758
        jnz     .tdloop
759
.tddone:
760
        mov     ecx, ebx
761
        pop     ebx
762
; 7d. The list is reversed,
763
; ecx = pointer to the first item, edx = pointer to the last item.NextTD.
764
; If the list is empty (unusual case), step 7 is done.
765
        test    ecx, ecx
766
        jz      .skip_donehead
767
; 7e. Otherwise, append this list to the end of previous one.
768
; Note that in theory the interrupt handler and the USB thread
769
; could execute in parallel.
770
.append_restart:
771
; Atomically get DoneListEndPtr in eax and set it to edx.
772
        mov     eax, [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller]
773
        lock cmpxchg [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller], edx
774
        jnz     .append_restart
775
; Store pointer to the new list.
776
; Note: we cannot perform any operations with [DoneListEndPtr]
777
; until we switch DoneListEndPtr to a new descriptor:
778
; it is possible that after first line of .append_restart loop
779
; ohci_process_deferred obtains the control, finishes processing
780
; of the old list, sets DoneListEndPtr to address of DoneList,
781
; frees all old descriptors, so eax would point to invalid location.
782
; This way, .append_restart loop would detect that DoneListEndPtr
783
; has changed, so eax needs to be re-read.
784
        mov     [eax], ecx
785
; 7f. Notify the USB thread that there is new work.
786
        inc     ebx
787
.skip_donehead:
788
; 8. Handle start-of-frame events.
789
; 8a. Test whether there are such events.
790
        test    byte [esp], 4
791
        jz      .skip_sof
792
; We enable SOF interrupt only when some pipes are waiting after changes.
793
        spin_lock_irqsave [esi+usb_controller.WaitSpinlock]
794
; 8b. Make sure that there was at least one frame update
795
; since the request. If not, wait for the next SOF.
796
        movzx   eax, [esi+ohci_controller.FrameNumber-sizeof.ohci_controller]
797
        cmp     eax, [esi+usb_controller.StartWaitFrame]
798
        jz      .sof_unlock
799
; 8c. Copy WaitPipeRequest* to ReadyPipeHead*.
800
        mov     eax, [esi+usb_controller.WaitPipeRequestAsync]
801
        mov     [esi+usb_controller.ReadyPipeHeadAsync], eax
802
        mov     eax, [esi+usb_controller.WaitPipeRequestPeriodic]
803
        mov     [esi+usb_controller.ReadyPipeHeadPeriodic], eax
804
; 8d. It is possible that pipe change is due to removal and
805
; Control/BulkCurrentED registers still point to one of pipes to be removed.
806
; The code responsible for disconnect events has temporarily stopped
807
; Control/Bulk processing, so it is safe to clear Control/BulkCurrentED.
808
; After that, restart processing.
809
        xor     edx, edx
810
        mov     [edi+OhciControlCurrentEDReg], edx
811
        mov     [edi+OhciBulkCurrentEDReg], edx
812
        mov     dword [edi+OhciCommandStatusReg], 6
813
        or      dword [edi+OhciControlReg], 30h
814
; 8e. Disable further interrupts on SOF.
815
; Note: OhciInterruptEnableReg/OhciInterruptDisableReg have unusual semantics.
816
        mov     dword [edi+OhciInterruptDisableReg], 4
817
; Notify the USB thread that there is new work (with pipes from ReadyPipeHead*).
818
        inc     ebx
819
.sof_unlock:
820
        spin_unlock_irqrestore [esi+usb_controller.RemoveSpinlock]
821
.skip_sof:
822
; Handle roothub events.
823
; 9. Test whether there are such events.
824
        test    byte [esp], 40h
825
        jz      .skip_roothub
826
; 10. Check the status of the roothub itself.
827
; 10a. Global overcurrent?
828
        test    dword [edi+OhciRhStatusReg], 2
829
        jz      @f
830
; Note: this needs work.
831
        dbgstr 'global overcurrent'
832
@@:
833
; 10b. Clear roothub events.
834
        mov     dword [edi+OhciRhStatusReg], 80020000h
835
; 11. Check the status of individual ports.
836
; Look for connect/disconnect and reset events.
837
; 11a. Prepare for the loop: start from port 0.
838
        xor     ecx, ecx
839
.portloop:
840
; 11b. Get the port status and changes of it.
841
; Accumulate change information.
842
; Look to "11.12.3 Port Change Information Processing" of the USB2 spec.
843
        xor     eax, eax
844
.accloop:
845
        mov     edx, [edi+OhciRhPortStatusReg+ecx*4]
846
        xor     ax, ax
847
        or      eax, edx
848
        test    edx, 1F0000h
849
        jz      .accdone
850
        mov     dword [edi+OhciRhPortStatusReg+ecx*4], 1F0000h
851
        jmp     .accloop
852
.accdone:
853
; debugging output, not needed for work
854
;       test    eax, 1F0000h
855
;       jz      @f
5246 clevermous 856
;       DEBUGF 1,'K : ohci %x status of port %d is %x\n',esi,ecx,eax
3520 clevermous 857
;@@:
858
; 11c. Ignore any events until all ports are powered up.
859
; They will be processed by ohci_init.
860
        cmp     [esi+ohci_controller.PoweredUp-sizeof.ohci_controller], 0
861
        jz      .nextport
862
; Handle changing of connection status.
863
        test    eax, 10000h
864
        jz      .nocsc
865
; There was a connect or disconnect event at this port.
866
; 11d. Disconnect the old device on this port, if any.
867
; if the port was resetting, indicate fail and signal
868
        cmp     cl, [esi+usb_controller.ResettingPort]
869
        jnz     @f
870
        mov     [esi+usb_controller.ResettingStatus], -1
871
        inc     ebx
872
@@:
873
        lock bts [esi+usb_controller.NewDisconnected], ecx
874
; notify the USB thread that new work is waiting
875
        inc     ebx
876
; 11e. Change connected status. For the connection event, also
877
; store the connection time; any further processing is permitted only
878
; after USB_CONNECT_DELAY ticks.
879
        test    al, 1
880
        jz      .disconnect
881
; Note: ConnectedTime must be stored before setting the 'connected' bit,
882
; otherwise ohci_process_deferred could use an old time.
4418 clevermous 883
        invoke  GetTimerTicks
3520 clevermous 884
        mov     [esi+usb_controller.ConnectedTime+ecx*4], eax
885
        lock bts [esi+usb_controller.NewConnected], ecx
886
        jmp     .nextport
887
.disconnect:
888
        lock btr [esi+usb_controller.NewConnected], ecx
889
        jmp     .nextport
890
.nocsc:
891
; 11f. Process 'reset done' events.
892
        test    eax, 100000h
893
        jz      .nextport
894
        test    al, 10h
895
        jnz     .nextport
4418 clevermous 896
        invoke  GetTimerTicks
897
        mov     [esi+usb_controller.ResetTime], eax
3520 clevermous 898
        mov     [esi+usb_controller.ResettingStatus], 2
899
        inc     ebx
900
.nextport:
901
; 11g. Continue the loop for the next port.
902
        inc     ecx
903
        cmp     ecx, [esi+usb_controller.NumPorts]
904
        jb      .portloop
905
.skip_roothub:
906
; 12. Restore the stack after step 6.
907
        pop     eax
908
; 13. Notify the USB thread if some deferred processing is required.
4418 clevermous 909
        invoke  usbhc_api.usb_wakeup_if_needed
3520 clevermous 910
; 14. Interrupt processed; return something non-zero.
911
        mov     al, 1
912
        pop     edi esi ebx     ; restore used registers to be stdcall
913
        ret
914
endp
915
 
916
; This procedure is called from usb_set_address_callback
917
; and stores USB device address in the ohci_pipe structure.
918
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
919
proc ohci_set_device_address
3653 clevermous 920
        mov     byte [ebx+ohci_pipe.Flags-sizeof.ohci_pipe], cl
3520 clevermous 921
; Wait until the hardware will forget the old value.
4418 clevermous 922
        jmp     [usbhc_api.usb_subscribe_control]
3520 clevermous 923
endp
924
 
925
; This procedure returns USB device address from the usb_pipe structure.
926
; in: esi -> usb_controller, ebx -> usb_pipe
927
; out: eax = endpoint address
928
proc ohci_get_device_address
3653 clevermous 929
        mov     eax, [ebx+ohci_pipe.Flags-sizeof.ohci_pipe]
3520 clevermous 930
        and     eax, 7Fh
931
        ret
932
endp
933
 
934
; This procedure is called from usb_set_address_callback
935
; if the device does not accept SET_ADDRESS command and needs
936
; to be disabled at the port level.
937
; in: esi -> usb_controller, ecx = port
938
proc ohci_port_disable
939
        mov     edx, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller]
940
        mov     dword [edx+OhciRhPortStatusReg+ecx*4], 1
941
        ret
942
endp
943
 
944
; This procedure is called from usb_get_descr8_callback when
945
; the packet size for zero endpoint becomes known and
946
; stores the packet size in ohci_pipe structure.
947
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
948
proc ohci_set_endpoint_packet_size
3653 clevermous 949
        mov     byte [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe], cl
3520 clevermous 950
; Wait until the hardware will forget the old value.
4418 clevermous 951
        jmp     [usbhc_api.usb_subscribe_control]
3520 clevermous 952
endp
953
 
954
; This procedure is called from API usb_open_pipe and processes
955
; the controller-specific part of this API. See docs.
956
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
957
; esi -> usb_controller, eax -> usb_gtd for the first TD,
958
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
959
proc ohci_init_pipe
3816 clevermous 960
virtual at ebp-12
961
.speed          db      ?
962
                rb      3
963
.bandwidth      dd      ?
964
.target         dd      ?
965
                rd      2
3520 clevermous 966
.config_pipe    dd      ?
967
.endpoint       dd      ?
968
.maxpacket      dd      ?
969
.type           dd      ?
970
.interval       dd      ?
971
end virtual
972
; 1. Initialize the queue of transfer descriptors: empty.
3653 clevermous 973
        sub     eax, sizeof.ohci_gtd
4418 clevermous 974
        invoke  GetPhysAddr
3653 clevermous 975
        mov     [edi+ohci_pipe.TailP-sizeof.ohci_pipe], eax
976
        mov     [edi+ohci_pipe.HeadP-sizeof.ohci_pipe], eax
3520 clevermous 977
; 2. Generate ohci_pipe.Flags, see the description in ohci_pipe.
3653 clevermous 978
        mov     eax, [ecx+ohci_pipe.Flags-sizeof.ohci_pipe]
3520 clevermous 979
        and     eax, 0x207F     ; keep Speed bit and FunctionAddress
980
        mov     edx, [.endpoint]
981
        and     edx, 15
982
        shl     edx, 7
983
        or      eax, edx
3653 clevermous 984
        mov     [edi+ohci_pipe.Flags-sizeof.ohci_pipe], eax
3816 clevermous 985
        bt      eax, 13
986
        setc    [.speed]
3520 clevermous 987
        mov     eax, [.maxpacket]
3653 clevermous 988
        mov     word [edi+ohci_pipe.Flags+2-sizeof.ohci_pipe], ax
3520 clevermous 989
        cmp     [.type], CONTROL_PIPE
990
        jz      @f
991
        test    byte [.endpoint], 80h
992
        setnz   al
993
        inc     eax
994
        shl     al, 3
3653 clevermous 995
        or      byte [edi+ohci_pipe.Flags+1-sizeof.ohci_pipe], al
3520 clevermous 996
@@:
997
; 3. Insert the new pipe to the corresponding list of endpoints.
998
; 3a. Use Control list for control pipes, Bulk list for bulk pipes.
999
        lea     edx, [esi+ohci_controller.ControlED.SoftwarePart-sizeof.ohci_controller]
1000
        cmp     [.type], BULK_PIPE
1001
        jb      .insert ; control pipe
1002
        lea     edx, [esi+ohci_controller.BulkED.SoftwarePart-sizeof.ohci_controller]
1003
        jz      .insert ; bulk pipe
1004
.interrupt_pipe:
1005
; 3b. For interrupt pipes, let the scheduler select the appropriate list
1006
; based on the current bandwidth distribution and the requested bandwidth.
1007
; This could fail if the requested bandwidth is not available;
1008
; if so, return an error.
1009
        lea     edx, [esi + ohci_controller.IntEDs - sizeof.ohci_controller]
1010
        lea     eax, [esi + ohci_controller.IntEDs + 32*sizeof.ohci_static_ep - sizeof.ohci_controller]
3598 clevermous 1011
        movi    ecx, 64
3520 clevermous 1012
        call    usb1_select_interrupt_list
1013
        test    edx, edx
1014
        jz      .return0
1015
; 3c. Insert endpoint at edi to the head of list in edx.
1016
; Inserting to tail would work as well,
1017
; but let's be consistent with other controllers.
1018
.insert:
4547 clevermous 1019
        mov     [edi+usb_pipe.BaseList], edx
3520 clevermous 1020
        mov     ecx, [edx+usb_pipe.NextVirt]
1021
        mov     [edi+usb_pipe.NextVirt], ecx
1022
        mov     [edi+usb_pipe.PrevVirt], edx
1023
        mov     [ecx+usb_pipe.PrevVirt], edi
1024
        mov     [edx+usb_pipe.NextVirt], edi
3653 clevermous 1025
        mov     ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe]
1026
        mov     [edi+ohci_pipe.NextED-sizeof.ohci_pipe], ecx
1027
        lea     eax, [edi-sizeof.ohci_pipe]
4418 clevermous 1028
        invoke  GetPhysAddr
3653 clevermous 1029
        mov     [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax
3520 clevermous 1030
; 4. Return something non-zero.
1031
        ret
1032
.return0:
1033
        xor     eax, eax
1034
        ret
1035
endp
1036
 
1037
; This function is called from ohci_process_deferred when
1038
; a new device was connected at least USB_CONNECT_DELAY ticks
1039
; and therefore is ready to be configured.
1040
; ecx = port, esi -> usb_controller
1041
proc ohci_new_port
1042
; test whether we are configuring another port
1043
; if so, postpone configuring and return
1044
        bts     [esi+usb_controller.PendingPorts], ecx
1045
        cmp     [esi+usb_controller.ResettingPort], -1
1046
        jnz     .nothing
1047
        btr     [esi+usb_controller.PendingPorts], ecx
1048
; fall through to ohci_new_port.reset
1049
 
1050
; This function is called from usb_test_pending_port.
1051
; It starts reset signalling for the port. Note that in USB first stages
1052
; of configuration can not be done for several ports in parallel.
1053
.reset:
1054
; reset port
1055
        and     [esi+usb_controller.ResettingHub], 0
1056
        mov     [esi+usb_controller.ResettingPort], cl
1057
; Note: setting status must be the last action:
1058
; it is possible that the device has been disconnected
1059
; after timeout of USB_CONNECT_DELAY but before call to ohci_new_port.
1060
; In this case, ohci_irq would not set reset status to 'failed',
1061
; because ohci_irq would not know that this port is to be reset.
1062
; However, the hardware would generate another interrupt
1063
; in a response to reset a disconnected port, and this time
1064
; ohci_irq knows that it needs to generate 'reset failed' event
1065
; (because ResettingPort is now filled).
1066
        push    edi
1067
        mov     edi, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller]
1068
        mov     dword [edi+OhciRhPortStatusReg+ecx*4], 10h
1069
        pop     edi
1070
.nothing:
1071
        ret
1072
endp
1073
 
1074
; This procedure is called from the several places in main USB code
1075
; and allocates required packets for the given transfer.
1076
; ebx = pipe, other parameters are passed through the stack:
1077
; buffer,size = data to transfer
1078
; flags = same as in usb_open_pipe: bit 0 = allow short transfer, other bits reserved
1079
; td = pointer to the current end-of-queue descriptor
1080
; direction =
1081
;   0000b for normal transfers,
1082
;   1000b for control SETUP transfer,
1083
;   1101b for control OUT transfer,
1084
;   1110b for control IN transfer
1085
; returns eax = pointer to the new end-of-queue descriptor
1086
; (not included in the queue itself) or 0 on error
1087
proc ohci_alloc_transfer stdcall uses edi, \
1088
        buffer:dword, size:dword, flags:dword, td:dword, direction:dword
1089
locals
1090
origTD          dd      ?
1091
packetSize      dd      ?       ; must be the last variable, see usb_init_transfer
1092
endl
1093
; 1. Save original value of td:
1094
; it will be useful for rollback if something would fail.
1095
        mov     eax, [td]
1096
        mov     [origTD], eax
1097
; One transfer descriptor can describe up to two pages.
1098
; In the worst case (when the buffer is something*1000h+0FFFh)
1099
; this corresponds to 1001h bytes. If the requested size is
1100
; greater, we should split the transfer into several descriptors.
1101
; Boundaries to split must be multiples of endpoint transfer size
3656 clevermous 1102
; to avoid short packets except in the end of the transfer.
1103
        cmp     [size], 1001h
1104
        jbe     .lastpacket
3520 clevermous 1105
; 2. While the remaining data cannot fit in one packet,
3656 clevermous 1106
; allocate full-sized descriptors.
1107
; 2a. Calculate size of one descriptor: must be a multiple of transfer size
1108
; and must be not greater than 1001h.
1109
        movzx   ecx, word [ebx+ohci_pipe.Flags+2-sizeof.ohci_pipe]
1110
        mov     eax, 1001h
1111
        xor     edx, edx
1112
        mov     edi, eax
1113
        div     ecx
1114
        sub     edi, edx
1115
; 2b. Allocate in loop.
3520 clevermous 1116
        mov     [packetSize], edi
1117
.fullpackets:
1118
        call    ohci_alloc_packet
1119
        test    eax, eax
1120
        jz      .fail
1121
        mov     [td], eax
1122
        add     [buffer], edi
1123
        sub     [size], edi
3656 clevermous 1124
        cmp     [size], 1001h
1125
        ja      .fullpackets
3520 clevermous 1126
; 3. The remaining data can fit in one descriptor;
1127
; allocate the last descriptor with size = size of remaining data.
1128
.lastpacket:
1129
        mov     eax, [size]
1130
        mov     [packetSize], eax
1131
        call    ohci_alloc_packet
1132
        test    eax, eax
1133
        jz      .fail
1134
; 4. Enable an immediate interrupt on completion of the last packet.
3653 clevermous 1135
        and     byte [ecx+ohci_gtd.Flags+2-sizeof.ohci_gtd], not (7 shl (21-16))
3520 clevermous 1136
; 5. If a short transfer is ok for a caller, set the corresponding bit in
1137
; the last descriptor, but not in others.
1138
; Note: even if the caller says that short transfers are ok,
1139
; all packets except the last one are marked as 'must be complete':
1140
; if one of them will be short, the software intervention is needed
1141
; to skip remaining packets; ohci_process_finalized_td will handle this
1142
; transparently to the caller.
1143
        test    [flags], 1
1144
        jz      @f
3653 clevermous 1145
        or      byte [ecx+ohci_gtd.Flags+2-sizeof.ohci_gtd], 1 shl (18-16)
3520 clevermous 1146
@@:
1147
        ret
1148
.fail:
1149
        mov     edi, ohci_hardware_func
1150
        mov     eax, [td]
4418 clevermous 1151
        invoke  usbhc_api.usb_undo_tds, [origTD]
3520 clevermous 1152
        xor     eax, eax
1153
        ret
1154
endp
1155
 
1156
; Helper procedure for ohci_alloc_transfer.
1157
; Allocates and initializes one transfer descriptor.
1158
; ebx = pipe, other parameters are passed through the stack;
1159
; fills the current last descriptor and
1160
; returns eax = next descriptor (not filled).
1161
proc ohci_alloc_packet
1162
; inherit some variables from the parent ohci_alloc_transfer
1163
virtual at ebp-8
1164
.origTD         dd      ?
1165
.packetSize     dd      ?
1166
                rd      2
1167
.buffer         dd      ?
1168
.transferSize   dd      ?
1169
.Flags          dd      ?
1170
.td             dd      ?
1171
.direction      dd      ?
1172
end virtual
1173
; 1. Allocate the next TD.
4418 clevermous 1174
        call    ohci_alloc_gtd
3520 clevermous 1175
        test    eax, eax
1176
        jz      .nothing
1177
; 2. Initialize controller-independent parts of both TDs.
1178
        push    eax
4418 clevermous 1179
        invoke  usbhc_api.usb_init_transfer
3520 clevermous 1180
        pop     eax
1181
; 3. Save the returned value (next descriptor).
1182
        push    eax
1183
; 4. Store the physical address of the next descriptor.
3653 clevermous 1184
        sub     eax, sizeof.ohci_gtd
4418 clevermous 1185
        invoke  GetPhysAddr
3653 clevermous 1186
        mov     [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd], eax
3520 clevermous 1187
; 5. For zero-length transfers, store zero in both fields for buffer addresses.
1188
; Otherwise, fill them with real values.
1189
        xor     eax, eax
3653 clevermous 1190
        mov     [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax
1191
        mov     [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax
3520 clevermous 1192
        cmp     [.packetSize], eax
1193
        jz      @f
1194
        mov     eax, [.buffer]
4418 clevermous 1195
        invoke  GetPhysAddr
3653 clevermous 1196
        mov     [ecx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], eax
3520 clevermous 1197
        mov     eax, [.buffer]
1198
        add     eax, [.packetSize]
1199
        dec     eax
4418 clevermous 1200
        invoke  GetPhysAddr
3653 clevermous 1201
        mov     [ecx+ohci_gtd.BufEnd-sizeof.ohci_gtd], eax
3520 clevermous 1202
@@:
1203
; 6. Generate Flags field:
1204
; - set bufferRounding (bit 18) to zero = disallow short transfers;
1205
;   for the last transfer in a row, ohci_alloc_transfer would set the real value;
1206
; - set Direction (bits 19-20) to lower 2 bits of [.direction];
1207
; - set DelayInterrupt (bits 21-23) to 7 = do not generate interrupt;
1208
;   for the last transfer in a row, ohci_alloc_transfer would set the real value;
1209
; - set DataToggle (bits 24-25) to next 2 bits of [.direction];
1210
; - set ConditionCode (bits 28-31) to 1111b as a indicator that there was no
1211
;   attempts to perform this transfer yet;
1212
; - zero all other bits.
1213
        mov     eax, [.direction]
1214
        mov     edx, eax
1215
        and     eax, 3
1216
        shl     eax, 19
1217
        and     edx, (3 shl 2)
1218
        shl     edx, 24 - 2
1219
        lea     eax, [eax + edx + (7 shl 21) + (15 shl 28)]
3653 clevermous 1220
        mov     [ecx+ohci_gtd.Flags-sizeof.ohci_gtd], eax
3520 clevermous 1221
; 7. Restore the returned value saved in step 3.
1222
        pop     eax
1223
.nothing:
1224
        ret
1225
endp
1226
 
1227
; This procedure is called from the several places in main USB code
1228
; and activates the transfer which was previously allocated by
1229
; ohci_alloc_transfer.
1230
; ecx -> last descriptor for the transfer, ebx -> usb_pipe
1231
proc ohci_insert_transfer
1232
; 1. Advance the queue of transfer descriptors.
3653 clevermous 1233
        mov     eax, [ecx+ohci_gtd.NextTD-sizeof.ohci_gtd]
1234
        mov     [ebx+ohci_pipe.TailP-sizeof.ohci_pipe], eax
3520 clevermous 1235
; 2. For control and bulk pipes, notify the controller that
1236
; there is new work in control/bulk queue respectively.
1237
ohci_notify_new_work:
1238
        mov     edx, [ebx+usb_pipe.Controller]
1239
        mov     edx, [edx+ohci_controller.MMIOBase-sizeof.ohci_controller]
1240
        cmp     [ebx+usb_pipe.Type], CONTROL_PIPE
1241
        jz      .control
1242
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
1243
        jnz     .nothing
1244
.bulk:
1245
        mov     dword [edx+OhciCommandStatusReg], 4
1246
        jmp     .nothing
1247
.control:
1248
        mov     dword [edx+OhciCommandStatusReg], 2
1249
.nothing:
1250
        ret
1251
endp
1252
 
1253
; This function is called from ohci_process_deferred when
1254
; a new device has been reset and needs to be configured.
1255
proc ohci_port_after_reset
1256
; 1. Get the status.
1257
; If reset has been failed (device disconnected during reset),
1258
; continue to next device (if there is one).
1259
        xor     eax, eax
1260
        xchg    al, [esi+usb_controller.ResettingStatus]
1261
        test    al, al
4418 clevermous 1262
        jns     @f
1263
        jmp     [usbhc_api.usb_test_pending_port]
1264
@@:
3520 clevermous 1265
; If the controller has disabled the port (e.g. overcurrent),
1266
; continue to next device (if there is one).
1267
        movzx   ecx, [esi+usb_controller.ResettingPort]
1268
        mov     eax, [edi+OhciRhPortStatusReg+ecx*4]
1269
        test    al, 2
1270
        jnz     @f
1271
        DEBUGF 1,'K : USB port disabled after reset, status=%x\n',eax
4418 clevermous 1272
        jmp     [usbhc_api.usb_test_pending_port]
3520 clevermous 1273
@@:
1274
        push    ecx
1275
; 2. Get LowSpeed bit to bit 0 of eax and call the worker procedure
1276
; to notify the protocol layer about new OHCI device.
1277
        mov     eax, [edi+OhciRhPortStatusReg+ecx*4]
4418 clevermous 1278
        DEBUGF 1,'K : port_after_reset, status of port %d is %x\n',ecx,eax
3520 clevermous 1279
        shr     eax, 9
1280
        call    ohci_new_device
1281
        pop     ecx
1282
; 3. If something at the protocol layer has failed
1283
; (no memory, no bus address), disable the port and stop the initialization.
1284
        test    eax, eax
1285
        jnz     .nothing
1286
.disable_exit:
1287
        mov     dword [edi+OhciRhPortStatusReg+ecx*4], 1
4418 clevermous 1288
        jmp     [usbhc_api.usb_test_pending_port]
3520 clevermous 1289
.nothing:
1290
        ret
1291
endp
1292
 
1293
; This procedure is called from uhci_port_init and from hub support code
1294
; when a new device is connected and has been reset.
1295
; It calls usb_new_device at the protocol layer with correct parameters.
1296
; in: esi -> usb_controller, eax = speed;
1297
; OHCI is USB1 device, so only low bit of eax (LowSpeed) is used.
1298
proc ohci_new_device
1299
; 1. Clear all bits of speed except bit 0.
1300
        and     eax, 1
1301
; 2. Store the speed for the protocol layer.
1302
        mov     [esi+usb_controller.ResettingSpeed], al
1303
; 3. Create pseudo-pipe in the stack.
1304
; See ohci_init_pipe: only .Controller and .Flags fields are used.
1305
        shl     eax, 13
1306
        push    esi     ; .Controller
1307
        mov     ecx, esp
1308
        sub     esp, 12 ; ignored fields
1309
        push    eax     ; .Flags
1310
; 4. Notify the protocol layer.
4418 clevermous 1311
        invoke  usbhc_api.usb_new_device
3520 clevermous 1312
; 5. Cleanup the stack after step 3 and return.
1313
        add     esp, 20
1314
        ret
1315
endp
1316
 
1317
; This procedure is called in the USB thread from usb_thread_proc,
1318
; processes regular actions and those actions which can't be safely done
1319
; from interrupt handler.
1320
; Returns maximal time delta before the next call.
1321
proc ohci_process_deferred
1322
        push    ebx edi         ; save used registers to be stdcall
1323
; 1. Initialize the return value.
1324
        push    -1
1325
; 2. Process disconnect events.
5246 clevermous 1326
; Capture NewConnected mask in the state before disconnect processing;
1327
; IRQ handler could asynchronously signal disconnect+connect event,
1328
; connect events should be handled after disconnect events.
1329
        push    [esi+usb_controller.NewConnected]
4418 clevermous 1330
        invoke  usbhc_api.usb_disconnect_stage2
3520 clevermous 1331
; 3. Check for connected devices.
1332
; If there is a connected device which was connected less than
1333
; USB_CONNECT_DELAY ticks ago, plan to wake up when the delay will be over.
1334
; Otherwise, call ohci_new_port.
1335
        mov     edi, [esi+ohci_controller.MMIOBase-sizeof.ohci_controller]
1336
        xor     ecx, ecx
5246 clevermous 1337
        cmp     [esp], ecx
3520 clevermous 1338
        jz      .skip_newconnected
1339
.portloop:
5246 clevermous 1340
        bt      [esp], ecx
3520 clevermous 1341
        jnc     .noconnect
4418 clevermous 1342
; If this port is shared with the EHCI companion and we see the connect event,
1343
; then the device is USB1 dropped by EHCI,
1344
; so EHCI has already waited for debounce delay, we can proceed immediately.
1345
        cmp     [esi+ohci_controller.EhciCompanion-sizeof.ohci_controller], 0
1346
        jz      .portloop.test_time
1347
        dbgstr 'port is shared with EHCI, skipping initial debounce'
1348
        jmp     .connected
1349
.portloop.test_time:
1350
        invoke  GetTimerTicks
3520 clevermous 1351
        sub     eax, [esi+usb_controller.ConnectedTime+ecx*4]
1352
        sub     eax, USB_CONNECT_DELAY
1353
        jge     .connected
1354
        neg     eax
5246 clevermous 1355
        cmp     [esp+4], eax
3520 clevermous 1356
        jb      .nextport
5246 clevermous 1357
        mov     [esp+4], eax
3520 clevermous 1358
        jmp     .nextport
1359
.connected:
1360
        lock btr [esi+usb_controller.NewConnected], ecx
1361
        jnc     .nextport
1362
        call    ohci_new_port
1363
.noconnect:
1364
.nextport:
1365
        inc     ecx
1366
        cmp     ecx, [esi+usb_controller.NumPorts]
1367
        jb      .portloop
1368
.skip_newconnected:
5246 clevermous 1369
        pop     eax
3520 clevermous 1370
; 4. Check for end of reset signalling. If so, call ohci_port_after_reset.
1371
        cmp     [esi+usb_controller.ResettingStatus], 2
1372
        jnz     .no_reset_recovery
4418 clevermous 1373
        invoke  GetTimerTicks
3520 clevermous 1374
        sub     eax, [esi+usb_controller.ResetTime]
1375
        sub     eax, USB_RESET_RECOVERY_TIME
1376
        jge     .reset_done
1377
        neg     eax
1378
        cmp     [esp], eax
1379
        jb      .skip_roothub
1380
        mov     [esp], eax
1381
        jmp     .skip_roothub
1382
.no_reset_recovery:
1383
        cmp     [esi+usb_controller.ResettingStatus], 0
1384
        jz      .skip_roothub
1385
.reset_done:
1386
        call    ohci_port_after_reset
1387
.skip_roothub:
1388
; 5. Finalize transfers processed by hardware.
1389
; It is better to perform this step after processing disconnect events,
1390
; although not strictly obligatory. This way, an active transfer aborted
1391
; due to disconnect would be handled with more specific USB_STATUS_CLOSED,
1392
; not USB_STATUS_NORESPONSE.
1393
; Loop over all items in DoneList, call ohci_process_finalized_td for each.
1394
        xor     ebx, ebx
1395
        xchg    ebx, [esi+ohci_controller.DoneList-sizeof.ohci_controller]
1396
.tdloop:
1397
        test    ebx, ebx
1398
        jz      .tddone
1399
        call    ohci_process_finalized_td
1400
        jmp     .tdloop
1401
.tddone:
1402
; 6. Process wait-done notifications, test for new wait requests.
1403
; Note: that must be done after steps 2 and 5 which could create new requests.
1404
; 6a. Call the worker function from main USB code.
4418 clevermous 1405
        invoke  usbhc_api.usb_process_wait_lists
3520 clevermous 1406
; 6b. If no new requests, skip the rest of this step.
1407
        test    eax, eax
1408
        jz      @f
1409
; 6c. OHCI is not allowed to cache anything; we don't know what is
1410
; processed right now, but we can be sure that the controller will not
1411
; use any removed structure starting from the next frame.
1412
; Schedule SOF event.
1413
        spin_lock_irq [esi+usb_controller.RemoveSpinlock]
1414
        mov     eax, [esi+usb_controller.WaitPipeListAsync]
1415
        mov     [esi+usb_controller.WaitPipeRequestAsync], eax
1416
        mov     eax, [esi+usb_controller.WaitPipeListPeriodic]
1417
        mov     [esi+usb_controller.WaitPipeRequestPeriodic], eax
1418
; temporarily stop bulk and interrupt processing;
1419
; this is required for handler of SOF event
1420
        and     dword [edi+OhciControlReg], not 30h
1421
; remember the frame number when processing has been stopped
1422
; (needs to be done after stopping)
1423
        movzx   eax, [esi+ohci_controller.FrameNumber-sizeof.ohci_controller]
1424
        mov     [esi+usb_controller.StartWaitFrame], eax
1425
; make sure that the next SOF will happen after the request
1426
        mov     dword [edi+OhciInterruptStatusReg], 4
1427
; enable interrupt on SOF
1428
; Note: OhciInterruptEnableReg/OhciInterruptDisableReg have unusual semantics,
1429
; so there should be 'mov' here, not 'or'
1430
        mov     dword [edi+OhciInterruptEnableReg], 4
1431
        spin_unlock_irq [esi+usb_controller.RemoveSpinlock]
1432
@@:
1433
; 7. Restore the return value and return.
1434
        pop     eax
1435
        pop     edi ebx         ; restore used registers to be stdcall
1436
        ret
1437
endp
1438
 
1439
; Helper procedure for ohci_process_deferred. Processes one completed TD.
1440
; in: esi -> usb_controller, ebx -> usb_gtd, out: ebx -> next usb_gtd.
1441
proc ohci_process_finalized_td
1442
;       DEBUGF 1,'K : processing %x\n',ebx
1443
; 1. Check whether the pipe has been closed, either due to API call or due to
1444
; disconnect; if so, the callback will be called by usb_pipe_closed with
1445
; correct status, so go to step 6 with ebx = 0 (do not free the TD).
1446
        mov     edx, [ebx+usb_gtd.Pipe]
1447
        test    [edx+usb_pipe.Flags], USB_FLAG_CLOSED
1448
        jz      @f
3653 clevermous 1449
        lea     eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd]
3520 clevermous 1450
        xor     ebx, ebx
1451
        jmp     .next_td2
1452
@@:
1453
; 2. Remove the descriptor from the descriptors queue.
4418 clevermous 1454
        invoke  usbhc_api.usb_unlink_td
3520 clevermous 1455
; 3. Get number of bytes that remain to be transferred.
1456
; If CurBufPtr is zero, everything was transferred.
1457
        xor     edx, edx
3653 clevermous 1458
        cmp     [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd], edx
3520 clevermous 1459
        jz      .gotlen
1460
; Otherwise, the remaining length is
1461
; (BufEnd and 0xFFF) - (CurBufPtr and 0xFFF) + 1,
1462
; plus 0x1000 if BufEnd and CurBufPtr are in different pages.
3653 clevermous 1463
        mov     edx, [ebx+ohci_gtd.BufEnd-sizeof.ohci_gtd]
1464
        mov     eax, [ebx+ohci_gtd.CurBufPtr-sizeof.ohci_gtd]
3520 clevermous 1465
        mov     ecx, edx
1466
        and     edx, 0xFFF
1467
        inc     edx
1468
        xor     ecx, eax
1469
        and     ecx, -0x1000
1470
        jz      @f
1471
        add     edx, 0x1000
1472
@@:
1473
        and     eax, 0xFFF
1474
        sub     edx, eax
1475
.gotlen:
1476
; The actual length is Length - (remaining length).
1477
        sub     edx, [ebx+usb_gtd.Length]
1478
        neg     edx
1479
; 4. Check for error. If so, go to 7.
1480
        push    ebx
4418 clevermous 1481
        mov     ecx, [ebx+ohci_gtd.Flags-sizeof.ohci_gtd]
1482
        shr     ecx, 28
3520 clevermous 1483
        jnz     .error
1484
.notify:
1485
; 5. Successful completion.
4418 clevermous 1486
        invoke  usbhc_api.usb_process_gtd
3520 clevermous 1487
.next_td:
1488
; 6. Free the current descriptor and advance to the next item.
1489
; If the current item is the last in the list,
1490
; set DoneListEndPtr to pointer to DoneList.
1491
        cmp     ebx, [esp]
1492
        jz      @f
4418 clevermous 1493
        stdcall ohci_free_gtd, ebx
3520 clevermous 1494
@@:
1495
        pop     ebx
3653 clevermous 1496
        lea     eax, [ebx+ohci_gtd.NextTD-sizeof.ohci_gtd]
3520 clevermous 1497
.next_td2:
1498
        push    ebx
1499
        mov     ebx, eax
1500
        lea     edx, [esi+ohci_controller.DoneList-sizeof.ohci_controller]
1501
        xor     ecx, ecx        ; no next item
1502
        lock cmpxchg [esi+ohci_controller.DoneListEndPtr-sizeof.ohci_controller], edx
1503
        jz      .last
1504
; The current item is not the last.
1505
; It is possible, although very rare, that ohci_irq has already advanced
1506
; DoneListEndPtr, but not yet written NextTD. Wait until NextTD is nonzero.
1507
@@:
1508
        mov     ecx, [ebx]
1509
        test    ecx, ecx
1510
        jz      @b
1511
.last:
1512
        pop     ebx
1513
; ecx = the next item
1514
        push    ecx
1515
; Free the current item, set ebx to the next item, continue to 5a.
1516
        test    ebx, ebx
1517
        jz      @f
4418 clevermous 1518
        stdcall ohci_free_gtd, ebx
3520 clevermous 1519
@@:
1520
        pop     ebx
1521
        ret
1522
.error:
1523
; 7. There was an error while processing this descriptor.
1524
; The hardware has stopped processing the queue.
1525
; 7a. Save status and length.
4418 clevermous 1526
        push    ecx
3520 clevermous 1527
        push    edx
1528
;       DEBUGF 1,'K : TD failed:\n'
3653 clevermous 1529
;       DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd],[ebx-sizeof.ohci_gtd+4],[ebx-sizeof.ohci_gtd+8],[ebx-sizeof.ohci_gtd+12]
1530
;       DEBUGF 1,'K : %x %x %x %x\n',[ebx-sizeof.ohci_gtd+16],[ebx-sizeof.ohci_gtd+20],[ebx-sizeof.ohci_gtd+24],[ebx-sizeof.ohci_gtd+28]
3520 clevermous 1531
;       mov     eax, [ebx+usb_gtd.Pipe]
3653 clevermous 1532
;       DEBUGF 1,'K : pipe: %x %x %x %x\n',[eax-sizeof.ohci_pipe],[eax-sizeof.ohci_pipe+4],[eax-sizeof.ohci_pipe+8],[eax-sizeof.ohci_pipe+12]
3520 clevermous 1533
; 7b. Traverse the list of descriptors looking for the final packet
1534
; for this transfer.
1535
; Free and unlink non-final descriptors, except the current one.
1536
; Final descriptor will be freed in step 6.
4418 clevermous 1537
        invoke  usbhc_api.usb_is_final_packet
3520 clevermous 1538
        jnc     .found_final
1539
        mov     ebx, [ebx+usb_gtd.NextVirt]
1540
virtual at esp
1541
.length         dd      ?
1542
.error_code     dd      ?
1543
.current_item   dd      ?
1544
end virtual
1545
.look_final:
4418 clevermous 1546
        invoke  usbhc_api.usb_unlink_td
1547
        invoke  usbhc_api.usb_is_final_packet
3520 clevermous 1548
        jnc     .found_final
1549
        push    [ebx+usb_gtd.NextVirt]
4418 clevermous 1550
        stdcall ohci_free_gtd, ebx
3520 clevermous 1551
        pop     ebx
1552
        jmp     .look_final
1553
.found_final:
1554
; 7c. If error code is USB_STATUS_UNDERRUN and the last TD allows short packets,
1555
; it is not an error.
1556
; Note: all TDs except the last one in any transfer stage are marked
1557
; as short-packet-is-error to stop controller from further processing
1558
; of that stage; we need to restart processing from a TD following the last.
1559
; After that, go to step 5 with eax = 0 (no error).
1560
        cmp     dword [.error_code], USB_STATUS_UNDERRUN
1561
        jnz     .no_underrun
3653 clevermous 1562
        test    byte [ebx+ohci_gtd.Flags+2-sizeof.ohci_gtd], 1 shl (18-16)
3520 clevermous 1563
        jz      .no_underrun
1564
        and     dword [.error_code], 0
1565
        mov     ecx, [ebx+usb_gtd.Pipe]
3653 clevermous 1566
        mov     edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe]
3520 clevermous 1567
        and     edx, 2
1568
.advance_queue:
1569
        mov     eax, [ebx+usb_gtd.NextVirt]
3653 clevermous 1570
        sub     eax, sizeof.ohci_gtd
4418 clevermous 1571
        invoke  GetPhysAddr
3520 clevermous 1572
        or      eax, edx
3653 clevermous 1573
        mov     [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax
3520 clevermous 1574
        push    ebx
1575
        mov     ebx, ecx
1576
        call    ohci_notify_new_work
1577
        pop     ebx
4418 clevermous 1578
        pop     edx ecx
3520 clevermous 1579
        jmp     .notify
1580
; 7d. Abort the entire transfer.
1581
; There are two cases: either there is only one transfer stage
1582
; (everything except control transfers), then ebx points to the last TD and
1583
; all previous TD were unlinked and dismissed (if possible),
1584
; or there are several stages (a control transfer) and ebx points to the last
1585
; TD of Data or Status stage (usb_is_final_packet does not stop in Setup stage,
1586
; because Setup stage can not produce short packets); for Data stage, we need
1587
; to unlink and free (if possible) one more TD and advance ebx to the next one.
1588
.no_underrun:
1589
        cmp     [ebx+usb_gtd.Callback], 0
1590
        jnz     .halted
1591
        cmp     ebx, [.current_item]
1592
        push    [ebx+usb_gtd.NextVirt]
1593
        jz      @f
4418 clevermous 1594
        stdcall ohci_free_gtd, ebx
3520 clevermous 1595
@@:
1596
        pop     ebx
4418 clevermous 1597
        invoke  usbhc_api.usb_unlink_td
3520 clevermous 1598
.halted:
1599
; 7e. For bulk/interrupt transfers we have no choice but halt the queue,
1600
; the driver should intercede (through some API which is not written yet).
1601
; Control pipes normally recover at the next SETUP transaction (first stage
1602
; of any control transfer), so we hope on the best and just advance the queue
1603
; to the next transfer. (According to the standard, "A control pipe may also
1604
; support functional stall as well, but this is not recommended.").
1605
; Advance the transfer queue to the next descriptor.
1606
        mov     ecx, [ebx+usb_gtd.Pipe]
3653 clevermous 1607
        mov     edx, [ecx+ohci_pipe.HeadP-sizeof.ohci_pipe]
3520 clevermous 1608
        and     edx, 2  ; keep toggleCarry bit
1609
        cmp     [ecx+usb_pipe.Type], CONTROL_PIPE
3707 clevermous 1610
        jz      @f
3520 clevermous 1611
        inc     edx     ; set Halted bit
1612
@@:
1613
        jmp     .advance_queue
1614
endp
1615
 
1616
; This procedure is called when a pipe is closing (either due to API call
1617
; or due to disconnect); it unlinks the pipe from the corresponding list.
1618
; esi -> usb_controller, ebx -> usb_pipe
1619
proc ohci_unlink_pipe
1620
        cmp     [ebx+usb_pipe.Type], INTERRUPT_PIPE
1621
        jnz     @f
3653 clevermous 1622
        mov     eax, [ebx+ohci_pipe.Flags-sizeof.ohci_pipe]
3520 clevermous 1623
        bt      eax, 13
1624
        setc    cl
4547 clevermous 1625
        bt      eax, 12
3520 clevermous 1626
        setc    ch
1627
        shr     eax, 16
1628
        stdcall usb1_interrupt_list_unlink, eax, ecx
1629
@@:
1630
        ret
1631
endp
4418 clevermous 1632
 
4547 clevermous 1633
; This procedure temporarily removes the given pipe from hardware queue,
1634
; keeping it in software lists.
1635
; esi -> usb_controller, ebx -> usb_pipe
1636
proc ohci_disable_pipe
1637
        mov     eax, [ebx+ohci_pipe.NextED-sizeof.ohci_pipe]
1638
        mov     edx, [ebx+usb_pipe.PrevVirt]
1639
        mov     [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax
1640
        ret
1641
endp
1642
 
1643
; This procedure reinserts the given pipe from hardware queue
1644
; after ehci_disable_pipe, with clearing transfer queue.
1645
; esi -> usb_controller, ebx -> usb_pipe
1646
; edx -> current descriptor, eax -> new last descriptor
1647
proc ohci_enable_pipe
1648
        sub     eax, sizeof.ohci_gtd
1649
        invoke  GetPhysAddr
1650
        mov     edx, [ebx+ohci_pipe.HeadP-sizeof.ohci_pipe]
1651
        and     edx, 2
1652
        or      eax, edx
1653
        mov     [ebx+ohci_pipe.HeadP-sizeof.ohci_pipe], eax
1654
        lea     eax, [ebx-sizeof.ohci_pipe]
1655
        invoke  GetPhysAddr
1656
        mov     edx, [ebx+usb_pipe.PrevVirt]
1657
        mov     ecx, [edx+ohci_pipe.NextED-sizeof.ohci_pipe]
1658
        mov     [ebx+ohci_pipe.NextED-sizeof.ohci_pipe], ecx
1659
        mov     [edx+ohci_pipe.NextED-sizeof.ohci_pipe], eax
1660
        ret
1661
endp
1662
 
4418 clevermous 1663
; Allocates one endpoint structure for OHCI.
1664
; Returns pointer to software part (usb_pipe) in eax.
1665
proc ohci_alloc_pipe
1666
        push    ebx
1667
        mov     ebx, ohci_ep_mutex
1668
        invoke  usbhc_api.usb_allocate_common, (sizeof.ohci_pipe + sizeof.usb_pipe + 0Fh) and not 0Fh
1669
        test    eax, eax
1670
        jz      @f
1671
        add     eax, sizeof.ohci_pipe
1672
@@:
1673
        pop     ebx
1674
        ret
1675
endp
1676
 
1677
; Free one endpoint structure for OHCI.
1678
; Stdcall with one argument, pointer to software part (usb_pipe).
1679
proc ohci_free_pipe
1680
        sub     dword [esp+4], sizeof.ohci_pipe
1681
        jmp     [usbhc_api.usb_free_common]
1682
endp
1683
 
1684
; Allocates one general transfer descriptor structure for OHCI.
1685
; Returns pointer to software part (usb_gtd) in eax.
1686
proc ohci_alloc_gtd
1687
        push    ebx
1688
        mov     ebx, ohci_gtd_mutex
1689
        invoke  usbhc_api.usb_allocate_common, (sizeof.ohci_gtd + sizeof.usb_gtd + 0Fh) and not 0Fh
1690
        test    eax, eax
1691
        jz      @f
1692
        add     eax, sizeof.ohci_gtd
1693
@@:
1694
        pop     ebx
1695
        ret
1696
endp
1697
 
1698
; Free one general transfer descriptor structure for OHCI.
1699
; Stdcall with one argument, pointer to software part (usb_gtd).
1700
proc ohci_free_gtd
1701
        sub     dword [esp+4], sizeof.ohci_gtd
1702
        jmp     [usbhc_api.usb_free_common]
1703
endp
1704
 
1705
include 'usb1_scheduler.inc'
1706
define_controller_name ohci
1707
 
1708
section '.data' readable writable
1709
include '../peimport.inc'
1710
include_debug_strings
1711
IncludeIGlobals
1712
IncludeUGlobals
1713
align 4
1714
usbhc_api usbhc_func
1715
ohci_ep_first_page      dd      ?
1716
ohci_ep_mutex           MUTEX
1717
ohci_gtd_first_page     dd      ?
1718
ohci_gtd_mutex          MUTEX