Subversion Repositories Kolibri OS

Rev

Rev 3520 | Rev 3826 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3520 clevermous 1
; Functions for USB pipe manipulation: opening/closing, sending data etc.
2
;
3
; =============================================================================
4
; ================================= Constants =================================
5
; =============================================================================
6
; USB pipe types
7
CONTROL_PIPE = 0
8
ISOCHRONOUS_PIPE = 1
9
BULK_PIPE = 2
10
INTERRUPT_PIPE = 3
11
 
12
; Status codes for transfer callbacks.
13
; Taken from OHCI as most verbose controller in this sense.
14
USB_STATUS_OK           = 0     ; no error
15
USB_STATUS_CRC          = 1     ; CRC error
16
USB_STATUS_BITSTUFF     = 2     ; bit stuffing violation
17
USB_STATUS_TOGGLE       = 3     ; data toggle mismatch
18
USB_STATUS_STALL        = 4     ; device returned STALL
19
USB_STATUS_NORESPONSE   = 5     ; device not responding
20
USB_STATUS_PIDCHECK     = 6     ; invalid PID check bits
21
USB_STATUS_WRONGPID     = 7     ; unexpected PID value
22
USB_STATUS_OVERRUN      = 8     ; too many data from endpoint
23
USB_STATUS_UNDERRUN     = 9     ; too few data from endpoint
24
USB_STATUS_BUFOVERRUN   = 12    ; overflow of internal controller buffer
25
USB_STATUS_BUFUNDERRUN  = 13    ; underflow of internal controller buffer
26
USB_STATUS_CLOSED       = 16    ; pipe closed
27
                                ; either explicitly with USBClosePipe
28
                                ; or implicitly due to device disconnect
29
 
30
; flags for usb_pipe.Flags
31
USB_FLAG_CLOSED     = 1         ; pipe is closed, no new transfers
32
; pipe is closed, return error instead of submitting any new transfer
33
USB_FLAG_CAN_FREE   = 2
34
; pipe is closed via explicit call to USBClosePipe, so it can be freed without
35
; any driver notification; if this flag is not set, then the pipe is closed due
36
; to device disconnect, so it must remain valid until return from disconnect
37
; callback provided by the driver
38
USB_FLAG_EXTRA_WAIT = 4
39
; The pipe was in wait list, while another event occured;
40
; when the first wait will be done, reinsert the pipe to wait list
41
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
42
 
43
; =============================================================================
44
; ================================ Structures =================================
45
; =============================================================================
46
 
47
; Pipe descriptor.
48
; * An USB pipe is described by two structures, for hardware and for software.
49
; * This is the software part. The hardware part is defined in a driver
50
;   of the corresponding controller.
51
; * The hardware part is located immediately before usb_pipe,
52
;   both are allocated at once by controller-specific code
53
;   (it knows the total length, which depends on the hardware part).
54
struct usb_pipe
55
Controller      dd      ?
56
; Pointer to usb_controller structure corresponding to this pipe.
57
; Must be the first dword after hardware part, see *hci_new_device.
58
;
59
; Every endpoint is included into one of processing lists:
60
; * Bulk list contains all Bulk endpoints.
61
; * Control list contains all Control endpoints.
62
; * Several Periodic lists serve Interrupt endpoints with different interval.
63
;   - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
64
;     in the frames 0,N,2N,..., another is processed in the frames
65
;     1,1+N,1+2N,... and so on. The hardware starts processing of periodic
66
;     endpoints in every frame from the list identified by lower n bits of the
67
;     frame number; the addresses of these N lists are written to the
68
;     controller data area during the initialization.
69
;   - We assume that n=5, N=32 to simplify the code and compact the data.
70
;     OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
71
;     but this is an overkill for interrupt endpoints; the large value of N is
72
;     useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
73
;     initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
74
;     giving essentially N=32.
75
;     This restriction means that the actual maximum interval of polling any
76
;     interrupt endpoint is 32ms, which seems to be a reasonable value.
77
;   - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
78
;     interval and so on. Finally, there is one list for 1ms interval. Their
79
;     addresses are not directly known to the controller.
80
;   - The hardware serves endpoints following a physical link from the hardware
81
;     part.
82
;   - The hardware links are organized as follows. If the list item is not the
83
;     last, it's hardware link points to the next item. The hardware link of
84
;     the last item points to the first item of the "next" list.
85
;   - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
86
;     is the k-th periodic list for interval M ms, M >= 1. In this scheme,
87
;     if two "previous" lists are served in the frames k,k+2M,k+4M,...
88
;     and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
89
;     the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
90
;   - The links between Periodic, Control, Bulk lists and the processing of
91
;     Isochronous endpoints are controller-specific.
92
; * The head of every processing list is a static entry which does not
93
;   correspond to any real pipe. It is described by usb_static_ep
94
;   structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
95
;   sizeof hardware part is 20h, the total number of lists is
96
;   32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
97
;   leaving space for other data. This is another reason for 32ms limit.
98
; * Static endpoint descriptors are kept in *hci_controller structure.
99
; * All items in every processing list, including the static head, are
100
;   organized in a double-linked list using .NextVirt and .PrevVirt fields.
101
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
102
NextVirt        dd      ?
103
; Next endpoint in the processing list.
104
; See also PrevVirt field and the description before NextVirt field.
105
PrevVirt        dd      ?
106
; Previous endpoint in the processing list.
107
; See also NextVirt field and the description before NextVirt field.
108
;
109
; Every pipe has the associated transfer queue, that is, the double-linked
110
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
111
; endpoints this list consists of usb_gtd structures
112
; (GTD = General Transfer Descriptors), for Isochronous endpoints
113
; this list consists of usb_itd structures, which are not developed yet.
114
; The pipe needs to know only the last TD; the first TD can be
115
; obtained as [[pipe.LastTD].NextVirt].
116
LastTD          dd      ?
117
; Last TD in the transfer queue.
118
;
119
; All opened pipes corresponding to the same physical device are organized in
120
; the double-linked list using .NextSibling and .PrevSibling fields.
121
; The head of this list is kept in usb_device_data structure (OpenedPipeList).
122
; This list is used when the device is disconnected and all pipes for the
123
; device should be closed.
124
; Also, all pipes closed due to disconnect must remain valid at least until
125
; driver-provided disconnect function returns; all should-be-freed-but-not-now
126
; pipes for one device are organized in another double-linked list with
127
; the head in usb_device_data.ClosedPipeList; this list uses the same link
128
; fields, one pipe can never be in both lists.
129
NextSibling     dd      ?
130
; Next pipe for the physical device.
131
PrevSibling     dd      ?
132
; Previous pipe for the physical device.
133
;
134
; When hardware part of pipe is changed, some time is needed before further
135
; actions so that hardware reacts on this change. During that time,
136
; all changed pipes are organized in single-linked list with the head
137
; usb_controller.WaitPipeList* and link field NextWait.
138
; Currently there are two possible reasons to change:
139
; change of address/packet size in initial configuration,
140
; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
141
NextWait        dd      ?
142
Lock            MUTEX
143
; Mutex that guards operations with transfer queue for this pipe.
144
Type            db      ?
145
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
146
Flags           db      ?
147
; Combination of flags, USB_FLAG_*.
148
                rb      2       ; dword alignment
149
DeviceData      dd      ?
150
; Pointer to usb_device_data, common for all pipes for one device.
151
ends
152
 
153
; This structure describes the static head of every list of pipes.
154
struct usb_static_ep
155
; software fields
156
Bandwidth       dd      ?
157
; valid only for interrupt/isochronous USB1 lists
158
; The offsets of the following two fields must be the same in this structure
159
; and in usb_pipe.
160
NextVirt        dd      ?
161
PrevVirt        dd      ?
162
ends
163
 
164
; This structure represents one transfer descriptor
165
; ('g' stands for "general" as opposed to isochronous usb_itd).
166
; Note that one transfer can have several descriptors:
167
; a control transfer has three stages.
168
; Additionally, every controller has a limit on transfer length with
169
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
170
; large transfers must be split into individual packets according to that limit.
171
struct usb_gtd
172
Callback        dd      ?
173
; Zero for intermediate descriptors, pointer to callback function
174
; for final descriptor. See the docs for description of the callback.
175
UserData        dd      ?
176
; Dword which is passed to Callback as is, not used by USB code itself.
177
; Two following fields organize all descriptors for one pipe in
178
; the linked list.
179
NextVirt        dd      ?
180
PrevVirt        dd      ?
181
Pipe            dd      ?
182
; Pointer to the parent usb_pipe.
183
Buffer          dd      ?
184
; Pointer to data for this descriptor.
185
Length          dd      ?
186
; Length of data for this descriptor.
187
ends
188
 
189
; =============================================================================
190
; =================================== Code ====================================
191
; =============================================================================
192
 
193
USB_STDCALL_VERIFY = 1
194
macro stdcall_verify [arg]
195
{
196
common
197
if USB_STDCALL_VERIFY
198
        pushad
199
        stdcall arg
200
        call    verify_regs
201
        popad
202
else
203
        stdcall arg
204
end if
205
}
206
 
207
; Initialization of usb_static_ep structure,
208
; called from controller-specific initialization; edi -> usb_static_ep
209
proc usb_init_static_endpoint
210
        mov     [edi+usb_static_ep.NextVirt], edi
211
        mov     [edi+usb_static_ep.PrevVirt], edi
212
        ret
213
endp
214
 
215
; Part of API for drivers, see documentation for USBOpenPipe.
216
proc usb_open_pipe stdcall uses ebx esi edi,\
217
 config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
218
locals
219
targetsmask     dd      ?       ; S-Mask for USB2
220
bandwidth       dd      ?
221
target          dd      ?
222
endl
223
; 1. Verify type of pipe: it must be one of *_PIPE constants.
224
; Isochronous pipes are not supported yet.
225
        mov     eax, [type]
226
        cmp     eax, INTERRUPT_PIPE
227
        ja      .badtype
228
        cmp     al, ISOCHRONOUS_PIPE
229
        jnz     .goodtype
230
.badtype:
231
        dbgstr 'unsupported type of USB pipe'
232
        jmp     .return0
233
.goodtype:
234
; 2. Allocate memory for pipe and transfer queue.
235
; Empty transfer queue consists of one inactive TD.
236
        mov     ebx, [config_pipe]
237
        mov     esi, [ebx+usb_pipe.Controller]
238
        mov     edx, [esi+usb_controller.HardwareFunc]
239
        call    [edx+usb_hardware_func.AllocPipe]
240
        test    eax, eax
241
        jz      .nothing
242
        mov     edi, eax
243
        mov     edx, [esi+usb_controller.HardwareFunc]
244
        call    [edx+usb_hardware_func.AllocTD]
245
        test    eax, eax
246
        jz      .free_and_return0
247
; 3. Initialize transfer queue: pointer to transfer descriptor,
248
; pointers in transfer descriptor, queue lock.
249
        mov     [edi+usb_pipe.LastTD], eax
250
        mov     [eax+usb_gtd.NextVirt], eax
251
        mov     [eax+usb_gtd.PrevVirt], eax
252
        mov     [eax+usb_gtd.Pipe], edi
253
        lea     ecx, [edi+usb_pipe.Lock]
254
        call    mutex_init
255
; 4. Initialize software part of pipe structure, except device-related fields.
256
        mov     al, byte [type]
257
        mov     [edi+usb_pipe.Type], al
258
        xor     eax, eax
259
        mov     [edi+usb_pipe.Flags], al
260
        mov     [edi+usb_pipe.DeviceData], eax
261
        mov     [edi+usb_pipe.Controller], esi
262
        or      [edi+usb_pipe.NextWait], -1
263
; 5. Initialize device-related fields:
264
; for zero endpoint, set .NextSibling = .PrevSibling = this;
265
; for other endpoins, copy device data, take the lock guarding pipe list
266
; for the device and verify that disconnect processing has not yet started
267
; for the device. (Since disconnect processing also takes that lock,
268
; either it has completed or it will not start until we release the lock.)
269
; Note: usb_device_disconnected should not see the new pipe until
270
; initialization is complete, so that lock will be held during next steps
271
; (disconnect processing should either not see it at all, or see fully
272
; initialized pipe).
273
        cmp     [endpoint], eax
274
        jz      .zero_endpoint
275
        mov     ecx, [ebx+usb_pipe.DeviceData]
276
        mov     [edi+usb_pipe.DeviceData], ecx
277
        call    mutex_lock
278
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
279
        jz      .common
280
.fail:
281
; If disconnect processing has completed, unlock the mutex, free memory
282
; allocated in step 2 and return zero.
283
        call    mutex_unlock
284
        mov     edx, [esi+usb_controller.HardwareFunc]
285
        stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
286
.free_and_return0:
287
        mov     edx, [esi+usb_controller.HardwareFunc]
288
        stdcall [edx+usb_hardware_func.FreePipe], edi
289
.return0:
290
        xor     eax, eax
291
        jmp     .nothing
292
.zero_endpoint:
293
        mov     [edi+usb_pipe.NextSibling], edi
294
        mov     [edi+usb_pipe.PrevSibling], edi
295
.common:
296
; 6. Initialize hardware part of pipe structure.
297
; 6a. Acquire the corresponding mutex.
298
        lea     ecx, [esi+usb_controller.ControlLock]
299
        cmp     [type], BULK_PIPE
300
        jb      @f      ; control pipe
301
        lea     ecx, [esi+usb_controller.BulkLock]
302
        jz      @f      ; bulk pipe
303
        lea     ecx, [esi+usb_controller.PeriodicLock]
304
@@:
305
        call    mutex_lock
306
; 6b. Let the controller-specific code do its job.
307
        push    ecx
308
        mov     edx, [esi+usb_controller.HardwareFunc]
309
        mov     eax, [edi+usb_pipe.LastTD]
310
        mov     ecx, [config_pipe]
311
        call    [edx+usb_hardware_func.InitPipe]
312
        pop     ecx
313
; 6c. Release the mutex.
314
        push    eax
315
        call    mutex_unlock
316
        pop     eax
317
; 6d. If controller-specific code indicates failure,
318
; release the lock taken in step 5, free memory allocated in step 2
319
; and return zero.
320
        test    eax, eax
321
        jz      .fail
322
; 7. The pipe is initialized. If this is not the first pipe for the device,
323
; insert it to the tail of pipe list for the device,
324
; increment number of pipes,
325
; release the lock taken at step 5.
326
        mov     ecx, [edi+usb_pipe.DeviceData]
327
        test    ecx, ecx
328
        jz      @f
329
        mov     eax, [ebx+usb_pipe.PrevSibling]
330
        mov     [edi+usb_pipe.NextSibling], ebx
331
        mov     [edi+usb_pipe.PrevSibling], eax
332
        mov     [ebx+usb_pipe.PrevSibling], edi
333
        mov     [eax+usb_pipe.NextSibling], edi
334
        inc     [ecx+usb_device_data.NumPipes]
335
        call    mutex_unlock
336
@@:
337
; 8. Return pointer to usb_pipe.
338
        mov     eax, edi
339
.nothing:
340
        ret
341
endp
342
 
343
; This procedure is called several times during initial device configuration,
344
; when usb_device_data structure is reallocated.
345
; It (re)initializes all pointers in usb_device_data.
346
; ebx -> usb_pipe
347
proc usb_reinit_pipe_list
348
        push    eax
349
; 1. (Re)initialize the lock guarding pipe list.
350
        mov     ecx, [ebx+usb_pipe.DeviceData]
351
        call    mutex_init
352
; 2. Initialize list of opened pipes: two entries, the head and ebx.
353
        add     ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
354
        mov     [ecx+usb_pipe.NextSibling], ebx
355
        mov     [ecx+usb_pipe.PrevSibling], ebx
356
        mov     [ebx+usb_pipe.NextSibling], ecx
357
        mov     [ebx+usb_pipe.PrevSibling], ecx
358
; 3. Initialize list of closed pipes: empty list, only the head is present.
359
        add     ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
360
        mov     [ecx+usb_pipe.NextSibling], ecx
361
        mov     [ecx+usb_pipe.PrevSibling], ecx
362
        pop     eax
363
        ret
364
endp
365
 
366
; Part of API for drivers, see documentation for USBClosePipe.
367
proc usb_close_pipe
368
        push    ebx esi ; save used registers to be stdcall
369
virtual at esp
370
        rd      2       ; saved registers
371
        dd      ?       ; return address
372
.pipe   dd      ?
373
end virtual
374
; 1. Lock the pipe list for the device.
375
        mov     ebx, [.pipe]
376
        mov     esi, [ebx+usb_pipe.Controller]
377
        mov     ecx, [ebx+usb_pipe.DeviceData]
378
        call    mutex_lock
379
; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
380
        lea     ecx, [ebx+usb_pipe.Lock]
381
        call    mutex_lock
382
        or      [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
383
        call    mutex_unlock
384
; 3. Call the worker function.
385
        call    usb_close_pipe_nolock
386
; 4. Unlock the pipe list for the device.
387
        mov     ecx, [ebx+usb_pipe.DeviceData]
388
        call    mutex_unlock
389
; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
390
        push    edi
391
        call    usb_wakeup
392
        pop     edi
393
; 6. Return.
394
        pop     esi ebx ; restore used registers to be stdcall
395
        retn    4
396
endp
397
 
398
; Worker function for pipe closing. Called by usb_close_pipe API and
399
; from disconnect processing.
400
; The lock guarding pipe list for the device should be held by the caller.
401
; ebx -> usb_pipe, esi -> usb_controller
402
proc usb_close_pipe_nolock
403
; 1. Set the flag "pipe is closed, ignore new transfers".
404
; If it was already set, do nothing.
405
        lea     ecx, [ebx+usb_pipe.Lock]
406
        call    mutex_lock
407
        bts     dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
408
        jc      .closed
409
        call    mutex_unlock
410
; 2. Remove the pipe from the list of opened pipes.
411
        mov     eax, [ebx+usb_pipe.NextSibling]
412
        mov     edx, [ebx+usb_pipe.PrevSibling]
413
        mov     [eax+usb_pipe.PrevSibling], edx
414
        mov     [edx+usb_pipe.NextSibling], eax
415
; 3. Unlink the pipe from hardware structures.
416
; 3a. Acquire the corresponding lock.
417
        lea     edx, [esi+usb_controller.WaitPipeListAsync]
418
        lea     ecx, [esi+usb_controller.ControlLock]
419
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
420
        jb      @f      ; control pipe
421
        lea     ecx, [esi+usb_controller.BulkLock]
422
        jz      @f      ; bulk pipe
423
        add     edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
424
        lea     ecx, [esi+usb_controller.PeriodicLock]
425
@@:
426
        push    edx
427
        call    mutex_lock
428
        push    ecx
429
; 3b. Let the controller-specific code do its job.
430
        mov     eax, [esi+usb_controller.HardwareFunc]
431
        call    [eax+usb_hardware_func.UnlinkPipe]
432
; 3c. Release the corresponding lock.
433
        pop     ecx
434
        call    mutex_unlock
435
; 4. Put the pipe into wait queue.
436
        pop     edx
437
        cmp     [ebx+usb_pipe.NextWait], -1
438
        jz      .insert_new
439
        or      [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
440
        jmp     .inserted
441
.insert_new:
442
        mov     eax, [edx]
443
        mov     [ebx+usb_pipe.NextWait], eax
444
        mov     [edx], ebx
445
.inserted:
446
; 5. Return.
447
        ret
448
.closed:
449
        call    mutex_unlock
450
        xor     eax, eax
451
        ret
452
endp
453
 
454
; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
455
; corresponding wait list. It means that the hardware has fully forgot about it.
456
; ebx -> usb_pipe, esi -> usb_controller
457
proc usb_pipe_closed
458
        push    edi
459
        mov     edi, [esi+usb_controller.HardwareFunc]
460
; 1. Loop over all transfers, calling the driver with USB_STATUS_CLOSED
461
; and freeing all descriptors.
462
        mov     edx, [ebx+usb_pipe.LastTD]
463
        test    edx, edx
464
        jz      .no_transfer
465
        mov     edx, [edx+usb_gtd.NextVirt]
466
.transfer_loop:
467
        cmp     edx, [ebx+usb_pipe.LastTD]
468
        jz      .transfer_done
469
        mov     ecx, [edx+usb_gtd.Callback]
470
        test    ecx, ecx
471
        jz      .no_callback
472
        push    edx
473
        stdcall_verify ecx, ebx, USB_STATUS_CLOSED, \
474
                [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
475
        pop     edx
476
.no_callback:
477
        push    [edx+usb_gtd.NextVirt]
478
        stdcall [edi+usb_hardware_func.FreeTD], edx
479
        pop     edx
480
        jmp     .transfer_loop
481
.transfer_done:
482
        stdcall [edi+usb_hardware_func.FreeTD], edx
483
.no_transfer:
484
; 2. Decrement number of pipes for the device.
485
; If this pipe is the last pipe, go to 5.
486
        mov     ecx, [ebx+usb_pipe.DeviceData]
487
        call    mutex_lock
488
        dec     [ecx+usb_device_data.NumPipes]
489
        jz      .last_pipe
490
        call    mutex_unlock
491
; 3. If the flag "the driver has abandoned this pipe" is set,
492
; free memory and return.
493
        test    [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
494
        jz      .nofree
495
        stdcall [edi+usb_hardware_func.FreePipe], ebx
496
        pop     edi
497
        ret
498
; 4. Otherwise, add it to the list of closed pipes and return.
499
.nofree:
500
        add     ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
501
        mov     edx, [ecx+usb_pipe.PrevSibling]
502
        mov     [ebx+usb_pipe.NextSibling], ecx
503
        mov     [ebx+usb_pipe.PrevSibling], edx
504
        mov     [ecx+usb_pipe.PrevSibling], ebx
505
        mov     [edx+usb_pipe.NextSibling], ebx
506
        pop     edi
507
        ret
508
.last_pipe:
509
; That was the last pipe for the device.
510
; 5. Notify device driver(s) about disconnect.
511
        call    mutex_unlock
512
        movzx   eax, [ecx+usb_device_data.NumInterfaces]
513
        test    eax, eax
514
        jz      .notify_done
515
        add     ecx, [ecx+usb_device_data.Interfaces]
516
.notify_loop:
517
        mov     edx, [ecx+usb_interface_data.DriverFunc]
518
        test    edx, edx
519
        jz      @f
520
        mov     edx, [edx+USBSRV.usb_func]
521
        cmp     [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
522
        jb      @f
523
        mov     edx, [edx+USBFUNC.device_disconnect]
524
        test    edx, edx
525
        jz      @f
526
        push    eax ecx
527
        stdcall_verify edx, [ecx+usb_interface_data.DriverData]
528
        pop     ecx eax
529
@@:
530
        add     ecx, sizeof.usb_interface_data
531
        dec     eax
532
        jnz     .notify_loop
533
.notify_done:
534
; 6. Bus address, if assigned, can now be reused.
535
        call    [edi+usb_hardware_func.GetDeviceAddress]
536
        test    eax, eax
537
        jz      @f
538
        bts     [esi+usb_controller.ExistingAddresses], eax
539
@@:
540
        dbgstr 'USB device disconnected'
541
; 7. All drivers have returned from disconnect callback,
542
; so all drivers should not use any device-related pipes.
543
; Free the remaining pipes.
544
        mov     eax, [ebx+usb_pipe.DeviceData]
545
        add     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
546
        push    eax
547
        mov     eax, [eax+usb_pipe.NextSibling]
548
.free_loop:
549
        cmp     eax, [esp]
550
        jz      .free_done
551
        push    [eax+usb_pipe.NextSibling]
552
        stdcall [edi+usb_hardware_func.FreePipe], eax
553
        pop     eax
554
        jmp     .free_loop
555
.free_done:
556
        stdcall [edi+usb_hardware_func.FreePipe], ebx
557
        pop     eax
558
; 8. Free the usb_device_data structure.
559
        sub     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
560
        call    free
561
; 9. Return.
562
.nothing:
563
        pop     edi
564
        ret
565
endp
566
 
567
; Part of API for drivers, see documentation for USBNormalTransferAsync.
568
proc usb_normal_transfer_async stdcall uses ebx edi,\
569
 pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
570
; 1. Sanity check: callback must be nonzero.
571
; (It is important for other parts of code.)
572
        xor     eax, eax
573
        cmp     [callback], eax
574
        jz      .nothing
575
; 2. Lock the transfer queue.
576
        mov     ebx, [pipe]
577
        lea     ecx, [ebx+usb_pipe.Lock]
578
        call    mutex_lock
579
; 3. If the pipe has already been closed (presumably due to device disconnect),
580
; release the lock taken in step 2 and return zero.
581
        xor     eax, eax
582
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
583
        jnz     .unlock
584
; 4. Allocate and initialize TDs for the transfer.
585
        mov     edx, [ebx+usb_pipe.Controller]
586
        mov     edi, [edx+usb_controller.HardwareFunc]
587
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
588
; If failed, release the lock taken in step 2 and return zero.
589
        test    eax, eax
590
        jz      .unlock
591
; 5. Store callback and its parameters in the last descriptor for this transfer.
592
        mov     ecx, [eax+usb_gtd.PrevVirt]
593
        mov     edx, [callback]
594
        mov     [ecx+usb_gtd.Callback], edx
595
        mov     edx, [calldata]
596
        mov     [ecx+usb_gtd.UserData], edx
597
        mov     edx, [buffer]
598
        mov     [ecx+usb_gtd.Buffer], edx
599
; 6. Advance LastTD pointer and activate transfer.
600
        push    [ebx+usb_pipe.LastTD]
601
        mov     [ebx+usb_pipe.LastTD], eax
602
        call    [edi+usb_hardware_func.InsertTransfer]
603
        pop     eax
604
; 7. Release the lock taken in step 2 and
605
; return pointer to the first descriptor for the new transfer.
606
.unlock:
607
        push    eax
608
        lea     ecx, [ebx+usb_pipe.Lock]
609
        call    mutex_unlock
610
        pop     eax
611
.nothing:
612
        ret
613
endp
614
 
615
; Part of API for drivers, see documentation for USBControlTransferAsync.
616
proc usb_control_async stdcall uses ebx edi,\
617
 pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
618
locals
619
last_td         dd      ?
620
endl
621
; 1. Sanity check: callback must be nonzero.
622
; (It is important for other parts of code.)
623
        cmp     [callback], 0
624
        jz      .return0
625
; 2. Lock the transfer queue.
626
        mov     ebx, [pipe]
627
        lea     ecx, [ebx+usb_pipe.Lock]
628
        call    mutex_lock
629
; 3. If the pipe has already been closed (presumably due to device disconnect),
630
; release the lock taken in step 2 and return zero.
631
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
632
        jnz     .unlock_return0
633
; A control transfer contains two or three stages:
634
; Setup stage, optional Data stage, Status stage.
635
; 4. Allocate and initialize TDs for the Setup stage.
636
; Payload is 8 bytes from [config].
637
        mov     edx, [ebx+usb_pipe.Controller]
638
        mov     edi, [edx+usb_controller.HardwareFunc]
639
        stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
640
                ; short transfer is an error, direction is DATA0, token is SETUP
641
        mov     [last_td], eax
642
        test    eax, eax
643
        jz      .fail
644
; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
645
; Payload is [size] bytes from [buffer].
646
        mov     edx, [config]
647
        mov     ecx, (3 shl 2) + 1      ; DATA1, token is OUT
648
        cmp     byte [edx], 0
649
        jns     @f
650
        cmp     [size], 0
651
        jz      @f
652
        inc     ecx     ; token is IN
653
@@:
654
        cmp     [size], 0
655
        jz      .nodata
656
        push    ecx
657
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
658
        pop     ecx
659
        test    eax, eax
660
        jz      .fail
661
        mov     [last_td], eax
662
.nodata:
663
; 6. Allocate and initialize TDs for the Status stage.
664
; No payload.
665
        xor     ecx, 3  ; IN becomes OUT, OUT becomes IN
666
        stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
667
        test    eax, eax
668
        jz      .fail
669
; 7. Store callback and its parameters in the last descriptor for this transfer.
670
        mov     ecx, [eax+usb_gtd.PrevVirt]
671
        mov     edx, [callback]
672
        mov     [ecx+usb_gtd.Callback], edx
673
        mov     edx, [calldata]
674
        mov     [ecx+usb_gtd.UserData], edx
675
        mov     edx, [buffer]
676
        mov     [ecx+usb_gtd.Buffer], edx
677
; 8. Advance LastTD pointer and activate transfer.
678
        push    [ebx+usb_pipe.LastTD]
679
        mov     [ebx+usb_pipe.LastTD], eax
680
        call    [edi+usb_hardware_func.InsertTransfer]
681
; 9. Release the lock taken in step 2 and
682
; return pointer to the first descriptor for the new transfer.
683
        lea     ecx, [ebx+usb_pipe.Lock]
684
        call    mutex_unlock
685
        pop     eax
686
        ret
687
.fail:
688
        mov     eax, [last_td]
689
        test    eax, eax
690
        jz      .unlock_return0
691
        stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
692
.unlock_return0:
693
        lea     ecx, [ebx+usb_pipe.Lock]
694
        call    mutex_unlock
695
.return0:
696
        xor     eax, eax
697
        ret
698
endp
699
 
3745 clevermous 700
; Part of API for drivers, see documentation for USBGetParam.
701
proc usb_get_param
702
virtual at esp
703
                dd      ?       ; return address
704
.pipe           dd      ?
705
.param          dd      ?
706
end virtual
707
        mov     edx, [.param]
708
        mov     ecx, [.pipe]
709
        mov     eax, [ecx+usb_pipe.DeviceData]
710
        test    edx, edx
711
        jz      .get_device_descriptor
712
        dec     edx
713
        jz      .get_config_descriptor
714
        dec     edx
715
        jz      .get_speed
716
        or      eax, -1
717
        ret     8
718
.get_device_descriptor:
719
        add     eax, usb_device_data.DeviceDescriptor
720
        ret     8
721
.get_config_descriptor:
722
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
723
        lea     eax, [eax+ecx+usb_device_data.DeviceDescriptor]
724
        ret     8
725
.get_speed:
726
        movzx   eax, [eax+usb_device_data.Speed]
727
        ret     8
728
endp
729
 
3520 clevermous 730
; Initialize software part of usb_gtd. Called from controller-specific code
731
; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
732
; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
733
; current (initializing) usb_gtd.
734
; Returns ecx = [.td].
735
proc usb_init_transfer
736
virtual at ebp-4
737
.Size   dd      ?
738
        rd      2
739
.Buffer dd      ?
740
        dd      ?
741
.Flags  dd      ?
742
.td     dd      ?
743
end virtual
744
        mov     [eax+usb_gtd.Pipe], ebx
745
        mov     ecx, [.td]
746
        mov     [eax+usb_gtd.PrevVirt], ecx
747
        mov     edx, [ecx+usb_gtd.NextVirt]
748
        mov     [ecx+usb_gtd.NextVirt], eax
749
        mov     [eax+usb_gtd.NextVirt], edx
750
        mov     [edx+usb_gtd.PrevVirt], eax
751
        mov     edx, [.Size]
752
        mov     [ecx+usb_gtd.Length], edx
753
        xor     edx, edx
754
        mov     [ecx+usb_gtd.Callback], edx
755
        mov     [ecx+usb_gtd.UserData], edx
756
        ret
757
endp
758
 
759
; Free all TDs for the current transfer if something has failed
760
; during initialization (e.g. no memory for the next TD).
761
; Stdcall with one stack argument = first TD for the transfer
762
; and eax = last initialized TD for the transfer.
763
proc usb_undo_tds
764
        push    [eax+usb_gtd.NextVirt]
765
@@:
766
        cmp     eax, [esp+8]
767
        jz      @f
768
        push    [eax+usb_gtd.PrevVirt]
769
        stdcall [edi+usb_hardware_func.FreeTD], eax
770
        pop     eax
771
        jmp     @b
772
@@:
773
        pop     ecx
774
        mov     [eax+usb_gtd.NextVirt], ecx
775
        mov     [ecx+usb_gtd.PrevVirt], eax
776
        ret     4
777
endp
778
 
779
; Helper procedure for handling short packets in controller-specific code.
780
; Returns with CF cleared if this is the final packet in some stage:
781
; for control transfers that means one of Data and Status stages,
782
; for other transfers - the final packet in the only stage.
783
proc usb_is_final_packet
784
        cmp     [ebx+usb_gtd.Callback], 0
785
        jnz     .nothing
786
        mov     eax, [ebx+usb_gtd.NextVirt]
787
        cmp     [eax+usb_gtd.Callback], 0
788
        jz      .stc
789
        mov     eax, [ebx+usb_gtd.Pipe]
790
        cmp     [eax+usb_pipe.Type], CONTROL_PIPE
791
        jz      .nothing
792
.stc:
793
        stc
794
.nothing:
795
        ret
796
endp
797
 
798
; Helper procedure for controller-specific code:
799
; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
800
proc usb_unlink_td
801
        mov     ecx, [ebx+usb_gtd.Pipe]
802
        add     ecx, usb_pipe.Lock
803
        call    mutex_lock
804
        mov     eax, [ebx+usb_gtd.PrevVirt]
805
        mov     edx, [ebx+usb_gtd.NextVirt]
806
        mov     [edx+usb_gtd.PrevVirt], eax
807
        mov     [eax+usb_gtd.NextVirt], edx
808
        call    mutex_unlock
809
        ret
810
endp
811
 
812
if USB_STDCALL_VERIFY
813
proc verify_regs
814
virtual at esp
815
        dd      ?       ; return address
816
.edi    dd      ?
817
.esi    dd      ?
818
.ebp    dd      ?
819
.esp    dd      ?
820
.ebx    dd      ?
821
.edx    dd      ?
822
.ecx    dd      ?
823
.eax    dd      ?
824
end virtual
825
        cmp     ebx, [.ebx]
826
        jz      @f
827
        dbgstr 'ERROR!!! ebx changed'
828
@@:
829
        cmp     esi, [.esi]
830
        jz      @f
831
        dbgstr 'ERROR!!! esi changed'
832
@@:
833
        cmp     edi, [.edi]
834
        jz      @f
835
        dbgstr 'ERROR!!! edi changed'
836
@@:
837
        cmp     ebp, [.ebp]
838
        jz      @f
839
        dbgstr 'ERROR!!! ebp changed'
840
@@:
841
        ret
842
endp
843
end if