Subversion Repositories Kolibri OS

Rev

Rev 4850 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4850 Rev 5363
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
2
;;                                                              ;;
3
;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
3
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
4
;; Distributed under terms of the GNU General Public License    ;;
4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
7
 
8
$Revision: 4850 $
8
$Revision: 5363 $
9
 
9
 
10
 
10
 
11
; Functions for USB pipe manipulation: opening/closing, sending data etc.
11
; Functions for USB pipe manipulation: opening/closing, sending data etc.
12
;
12
;
13
USB_STDCALL_VERIFY = 1
13
USB_STDCALL_VERIFY = 1
14
macro stdcall_verify [arg]
14
macro stdcall_verify [arg]
15
{
15
{
16
common
16
common
17
if USB_STDCALL_VERIFY
17
if USB_STDCALL_VERIFY
18
        pushad
18
        pushad
19
        stdcall arg
19
        stdcall arg
20
        call    verify_regs
20
        call    verify_regs
21
        popad
21
        popad
22
else
22
else
23
        stdcall arg
23
        stdcall arg
24
end if
24
end if
25
}
25
}
26
if USB_STDCALL_VERIFY
26
if USB_STDCALL_VERIFY
27
STDCALL_VERIFY_EXTRA = 20h
27
STDCALL_VERIFY_EXTRA = 20h
28
else
28
else
29
STDCALL_VERIFY_EXTRA = 0
29
STDCALL_VERIFY_EXTRA = 0
30
end if
30
end if
31
 
31
 
32
; Initialization of usb_static_ep structure,
32
; Initialization of usb_static_ep structure,
33
; called from controller-specific initialization; edi -> usb_static_ep
33
; called from controller-specific initialization; edi -> usb_static_ep
34
proc usb_init_static_endpoint
34
proc usb_init_static_endpoint
35
        mov     [edi+usb_static_ep.NextVirt], edi
35
        mov     [edi+usb_static_ep.NextVirt], edi
36
        mov     [edi+usb_static_ep.PrevVirt], edi
36
        mov     [edi+usb_static_ep.PrevVirt], edi
37
        ret
37
        ret
38
endp
38
endp
39
 
39
 
40
; Part of API for drivers, see documentation for USBOpenPipe.
40
; Part of API for drivers, see documentation for USBOpenPipe.
41
proc usb_open_pipe stdcall uses ebx esi edi,\
41
proc usb_open_pipe stdcall uses ebx esi edi,\
42
 config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
42
 config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
43
locals
43
locals
44
tt_vars         rd      24      ; should be enough for ehci_select_tt_interrupt_list
44
tt_vars         rd      24      ; should be enough for ehci_select_tt_interrupt_list
45
targetsmask     dd      ?       ; S-Mask for USB2
45
targetsmask     dd      ?       ; S-Mask for USB2
46
bandwidth       dd      ?
46
bandwidth       dd      ?
47
target          dd      ?
47
target          dd      ?
48
endl
48
endl
49
; 1. Verify type of pipe: it must be one of *_PIPE constants.
49
; 1. Verify type of pipe: it must be one of *_PIPE constants.
50
; Isochronous pipes are not supported yet.
50
; Isochronous pipes are not supported yet.
51
        mov     eax, [type]
51
        mov     eax, [type]
52
        cmp     eax, INTERRUPT_PIPE
52
        cmp     eax, INTERRUPT_PIPE
53
        ja      .badtype
53
        ja      .badtype
54
        cmp     al, ISOCHRONOUS_PIPE
54
        cmp     al, ISOCHRONOUS_PIPE
55
        jnz     .goodtype
55
        jnz     .goodtype
56
.badtype:
56
.badtype:
57
        dbgstr 'unsupported type of USB pipe'
57
        dbgstr 'unsupported type of USB pipe'
58
        jmp     .return0
58
        jmp     .return0
59
.goodtype:
59
.goodtype:
60
; 2. Allocate memory for pipe and transfer queue.
60
; 2. Allocate memory for pipe and transfer queue.
61
; Empty transfer queue consists of one inactive TD.
61
; Empty transfer queue consists of one inactive TD.
62
        mov     ebx, [config_pipe]
62
        mov     ebx, [config_pipe]
63
        mov     esi, [ebx+usb_pipe.Controller]
63
        mov     esi, [ebx+usb_pipe.Controller]
64
        mov     edx, [esi+usb_controller.HardwareFunc]
64
        mov     edx, [esi+usb_controller.HardwareFunc]
65
        call    [edx+usb_hardware_func.AllocPipe]
65
        call    [edx+usb_hardware_func.AllocPipe]
66
        test    eax, eax
66
        test    eax, eax
67
        jz      .nothing
67
        jz      .nothing
68
        mov     edi, eax
68
        mov     edi, eax
69
        mov     edx, [esi+usb_controller.HardwareFunc]
69
        mov     edx, [esi+usb_controller.HardwareFunc]
70
        call    [edx+usb_hardware_func.AllocTD]
70
        call    [edx+usb_hardware_func.AllocTD]
71
        test    eax, eax
71
        test    eax, eax
72
        jz      .free_and_return0
72
        jz      .free_and_return0
73
; 3. Initialize transfer queue: pointer to transfer descriptor,
73
; 3. Initialize transfer queue: pointer to transfer descriptor,
74
; pointers in transfer descriptor, queue lock.
74
; pointers in transfer descriptor, queue lock.
75
        mov     [edi+usb_pipe.LastTD], eax
75
        mov     [edi+usb_pipe.LastTD], eax
76
        mov     [eax+usb_gtd.NextVirt], eax
76
        mov     [eax+usb_gtd.NextVirt], eax
77
        mov     [eax+usb_gtd.PrevVirt], eax
77
        mov     [eax+usb_gtd.PrevVirt], eax
78
        mov     [eax+usb_gtd.Pipe], edi
78
        mov     [eax+usb_gtd.Pipe], edi
79
        lea     ecx, [edi+usb_pipe.Lock]
79
        lea     ecx, [edi+usb_pipe.Lock]
80
        call    mutex_init
80
        call    mutex_init
81
; 4. Initialize software part of pipe structure, except device-related fields.
81
; 4. Initialize software part of pipe structure, except device-related fields.
82
        mov     al, byte [type]
82
        mov     al, byte [type]
83
        mov     [edi+usb_pipe.Type], al
83
        mov     [edi+usb_pipe.Type], al
84
        xor     eax, eax
84
        xor     eax, eax
85
        mov     [edi+usb_pipe.Flags], al
85
        mov     [edi+usb_pipe.Flags], al
86
        mov     [edi+usb_pipe.DeviceData], eax
86
        mov     [edi+usb_pipe.DeviceData], eax
87
        mov     [edi+usb_pipe.Controller], esi
87
        mov     [edi+usb_pipe.Controller], esi
88
        or      [edi+usb_pipe.NextWait], -1
88
        or      [edi+usb_pipe.NextWait], -1
89
; 5. Initialize device-related fields:
89
; 5. Initialize device-related fields:
90
; for zero endpoint, set .NextSibling = .PrevSibling = this;
90
; for zero endpoint, set .NextSibling = .PrevSibling = this;
91
; for other endpoins, copy device data, take the lock guarding pipe list
91
; for other endpoins, copy device data, take the lock guarding pipe list
92
; for the device and verify that disconnect processing has not yet started
92
; for the device and verify that disconnect processing has not yet started
93
; for the device. (Since disconnect processing also takes that lock,
93
; for the device. (Since disconnect processing also takes that lock,
94
; either it has completed or it will not start until we release the lock.)
94
; either it has completed or it will not start until we release the lock.)
95
; Note: usb_device_disconnected should not see the new pipe until
95
; Note: usb_device_disconnected should not see the new pipe until
96
; initialization is complete, so that lock will be held during next steps
96
; initialization is complete, so that lock will be held during next steps
97
; (disconnect processing should either not see it at all, or see fully
97
; (disconnect processing should either not see it at all, or see fully
98
; initialized pipe).
98
; initialized pipe).
99
        cmp     [endpoint], eax
99
        cmp     [endpoint], eax
100
        jz      .zero_endpoint
100
        jz      .zero_endpoint
101
        mov     ecx, [ebx+usb_pipe.DeviceData]
101
        mov     ecx, [ebx+usb_pipe.DeviceData]
102
        mov     [edi+usb_pipe.DeviceData], ecx
102
        mov     [edi+usb_pipe.DeviceData], ecx
103
        call    mutex_lock
103
        call    mutex_lock
104
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
104
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
105
        jz      .common
105
        jz      .common
106
.fail:
106
.fail:
107
; If disconnect processing has completed, unlock the mutex, free memory
107
; If disconnect processing has completed, unlock the mutex, free memory
108
; allocated in step 2 and return zero.
108
; allocated in step 2 and return zero.
109
        call    mutex_unlock
109
        call    mutex_unlock
110
        mov     edx, [esi+usb_controller.HardwareFunc]
110
        mov     edx, [esi+usb_controller.HardwareFunc]
111
        stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
111
        stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
112
.free_and_return0:
112
.free_and_return0:
113
        mov     edx, [esi+usb_controller.HardwareFunc]
113
        mov     edx, [esi+usb_controller.HardwareFunc]
114
        stdcall [edx+usb_hardware_func.FreePipe], edi
114
        stdcall [edx+usb_hardware_func.FreePipe], edi
115
.return0:
115
.return0:
116
        xor     eax, eax
116
        xor     eax, eax
117
        jmp     .nothing
117
        jmp     .nothing
118
.zero_endpoint:
118
.zero_endpoint:
119
        mov     [edi+usb_pipe.NextSibling], edi
119
        mov     [edi+usb_pipe.NextSibling], edi
120
        mov     [edi+usb_pipe.PrevSibling], edi
120
        mov     [edi+usb_pipe.PrevSibling], edi
121
.common:
121
.common:
122
; 6. Initialize hardware part of pipe structure.
122
; 6. Initialize hardware part of pipe structure.
123
; 6a. Acquire the corresponding mutex.
123
; 6a. Acquire the corresponding mutex.
124
        lea     ecx, [esi+usb_controller.ControlLock]
124
        lea     ecx, [esi+usb_controller.ControlLock]
125
        cmp     [type], BULK_PIPE
125
        cmp     [type], BULK_PIPE
126
        jb      @f      ; control pipe
126
        jb      @f      ; control pipe
127
        lea     ecx, [esi+usb_controller.BulkLock]
127
        lea     ecx, [esi+usb_controller.BulkLock]
128
        jz      @f      ; bulk pipe
128
        jz      @f      ; bulk pipe
129
        lea     ecx, [esi+usb_controller.PeriodicLock]
129
        lea     ecx, [esi+usb_controller.PeriodicLock]
130
@@:
130
@@:
131
        call    mutex_lock
131
        call    mutex_lock
132
; 6b. Let the controller-specific code do its job.
132
; 6b. Let the controller-specific code do its job.
133
        push    ecx
133
        push    ecx
134
        mov     edx, [esi+usb_controller.HardwareFunc]
134
        mov     edx, [esi+usb_controller.HardwareFunc]
135
        mov     eax, [edi+usb_pipe.LastTD]
135
        mov     eax, [edi+usb_pipe.LastTD]
136
        mov     ecx, [config_pipe]
136
        mov     ecx, [config_pipe]
137
        call    [edx+usb_hardware_func.InitPipe]
137
        call    [edx+usb_hardware_func.InitPipe]
138
        pop     ecx
138
        pop     ecx
139
; 6c. Release the mutex.
139
; 6c. Release the mutex.
140
        push    eax
140
        push    eax
141
        call    mutex_unlock
141
        call    mutex_unlock
142
        pop     eax
142
        pop     eax
143
; 6d. If controller-specific code indicates failure,
143
; 6d. If controller-specific code indicates failure,
144
; release the lock taken in step 5, free memory allocated in step 2
144
; release the lock taken in step 5, free memory allocated in step 2
145
; and return zero.
145
; and return zero.
146
        test    eax, eax
146
        test    eax, eax
147
        jz      .fail
147
        jz      .fail
148
; 7. The pipe is initialized. If this is not the first pipe for the device,
148
; 7. The pipe is initialized. If this is not the first pipe for the device,
149
; insert it to the tail of pipe list for the device,
149
; insert it to the tail of pipe list for the device,
150
; increment number of pipes,
150
; increment number of pipes,
151
; release the lock taken at step 5.
151
; release the lock taken at step 5.
152
        mov     ecx, [edi+usb_pipe.DeviceData]
152
        mov     ecx, [edi+usb_pipe.DeviceData]
153
        test    ecx, ecx
153
        test    ecx, ecx
154
        jz      @f
154
        jz      @f
155
        mov     eax, [ebx+usb_pipe.PrevSibling]
155
        mov     eax, [ebx+usb_pipe.PrevSibling]
156
        mov     [edi+usb_pipe.NextSibling], ebx
156
        mov     [edi+usb_pipe.NextSibling], ebx
157
        mov     [edi+usb_pipe.PrevSibling], eax
157
        mov     [edi+usb_pipe.PrevSibling], eax
158
        mov     [ebx+usb_pipe.PrevSibling], edi
158
        mov     [ebx+usb_pipe.PrevSibling], edi
159
        mov     [eax+usb_pipe.NextSibling], edi
159
        mov     [eax+usb_pipe.NextSibling], edi
160
        inc     [ecx+usb_device_data.NumPipes]
160
        inc     [ecx+usb_device_data.NumPipes]
161
        call    mutex_unlock
161
        call    mutex_unlock
162
@@:
162
@@:
163
; 8. Return pointer to usb_pipe.
163
; 8. Return pointer to usb_pipe.
164
        mov     eax, edi
164
        mov     eax, edi
165
.nothing:
165
.nothing:
166
        ret
166
        ret
167
endp
167
endp
168
 
168
 
169
; This procedure is called several times during initial device configuration,
169
; This procedure is called several times during initial device configuration,
170
; when usb_device_data structure is reallocated.
170
; when usb_device_data structure is reallocated.
171
; It (re)initializes all pointers in usb_device_data.
171
; It (re)initializes all pointers in usb_device_data.
172
; ebx -> usb_pipe
172
; ebx -> usb_pipe
173
proc usb_reinit_pipe_list
173
proc usb_reinit_pipe_list
174
        push    eax
174
        push    eax
175
; 1. (Re)initialize the lock guarding pipe list.
175
; 1. (Re)initialize the lock guarding pipe list.
176
        mov     ecx, [ebx+usb_pipe.DeviceData]
176
        mov     ecx, [ebx+usb_pipe.DeviceData]
177
        call    mutex_init
177
        call    mutex_init
178
; 2. Initialize list of opened pipes: two entries, the head and ebx.
178
; 2. Initialize list of opened pipes: two entries, the head and ebx.
179
        add     ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
179
        add     ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
180
        mov     [ecx+usb_pipe.NextSibling], ebx
180
        mov     [ecx+usb_pipe.NextSibling], ebx
181
        mov     [ecx+usb_pipe.PrevSibling], ebx
181
        mov     [ecx+usb_pipe.PrevSibling], ebx
182
        mov     [ebx+usb_pipe.NextSibling], ecx
182
        mov     [ebx+usb_pipe.NextSibling], ecx
183
        mov     [ebx+usb_pipe.PrevSibling], ecx
183
        mov     [ebx+usb_pipe.PrevSibling], ecx
184
; 3. Initialize list of closed pipes: empty list, only the head is present.
184
; 3. Initialize list of closed pipes: empty list, only the head is present.
185
        add     ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
185
        add     ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
186
        mov     [ecx+usb_pipe.NextSibling], ecx
186
        mov     [ecx+usb_pipe.NextSibling], ecx
187
        mov     [ecx+usb_pipe.PrevSibling], ecx
187
        mov     [ecx+usb_pipe.PrevSibling], ecx
188
        pop     eax
188
        pop     eax
189
        ret
189
        ret
190
endp
190
endp
191
 
191
 
192
; Part of API for drivers, see documentation for USBClosePipe.
192
; Part of API for drivers, see documentation for USBClosePipe.
193
proc usb_close_pipe
193
proc usb_close_pipe
194
        push    ebx esi ; save used registers to be stdcall
194
        push    ebx esi ; save used registers to be stdcall
195
virtual at esp
195
virtual at esp
196
        rd      2       ; saved registers
196
        rd      2       ; saved registers
197
        dd      ?       ; return address
197
        dd      ?       ; return address
198
.pipe   dd      ?
198
.pipe   dd      ?
199
end virtual
199
end virtual
200
; 1. Lock the pipe list for the device.
200
; 1. Lock the pipe list for the device.
201
        mov     ebx, [.pipe]
201
        mov     ebx, [.pipe]
202
        mov     esi, [ebx+usb_pipe.Controller]
202
        mov     esi, [ebx+usb_pipe.Controller]
203
        mov     ecx, [ebx+usb_pipe.DeviceData]
203
        mov     ecx, [ebx+usb_pipe.DeviceData]
204
        call    mutex_lock
204
        call    mutex_lock
205
; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
205
; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
206
        lea     ecx, [ebx+usb_pipe.Lock]
206
        lea     ecx, [ebx+usb_pipe.Lock]
207
        call    mutex_lock
207
        call    mutex_lock
208
        or      [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
208
        or      [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
209
        call    mutex_unlock
209
        call    mutex_unlock
210
; 3. Call the worker function.
210
; 3. Call the worker function.
211
        call    usb_close_pipe_nolock
211
        call    usb_close_pipe_nolock
212
; 4. Unlock the pipe list for the device.
212
; 4. Unlock the pipe list for the device.
213
        mov     ecx, [ebx+usb_pipe.DeviceData]
213
        mov     ecx, [ebx+usb_pipe.DeviceData]
214
        call    mutex_unlock
214
        call    mutex_unlock
215
; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
215
; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
216
        push    edi
216
        push    edi
217
        call    usb_wakeup
217
        call    usb_wakeup
218
        pop     edi
218
        pop     edi
219
; 6. Return.
219
; 6. Return.
220
        pop     esi ebx ; restore used registers to be stdcall
220
        pop     esi ebx ; restore used registers to be stdcall
221
        retn    4
221
        retn    4
222
endp
222
endp
223
 
223
 
224
; Worker function for pipe closing. Called by usb_close_pipe API and
224
; Worker function for pipe closing. Called by usb_close_pipe API and
225
; from disconnect processing.
225
; from disconnect processing.
226
; The lock guarding pipe list for the device should be held by the caller.
226
; The lock guarding pipe list for the device should be held by the caller.
227
; ebx -> usb_pipe, esi -> usb_controller
227
; ebx -> usb_pipe, esi -> usb_controller
228
proc usb_close_pipe_nolock
228
proc usb_close_pipe_nolock
229
; 1. Set the flag "pipe is closed, ignore new transfers".
229
; 1. Set the flag "pipe is closed, ignore new transfers".
230
; If it was already set, do nothing.
230
; If it was already set, do nothing.
231
        lea     ecx, [ebx+usb_pipe.Lock]
231
        lea     ecx, [ebx+usb_pipe.Lock]
232
        call    mutex_lock
232
        call    mutex_lock
233
        bts     dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
233
        bts     dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
234
        jc      .closed
234
        jc      .closed
235
        call    mutex_unlock
235
        call    mutex_unlock
236
; 2. Remove the pipe from the list of opened pipes.
236
; 2. Remove the pipe from the list of opened pipes.
237
        mov     eax, [ebx+usb_pipe.NextSibling]
237
        mov     eax, [ebx+usb_pipe.NextSibling]
238
        mov     edx, [ebx+usb_pipe.PrevSibling]
238
        mov     edx, [ebx+usb_pipe.PrevSibling]
239
        mov     [eax+usb_pipe.PrevSibling], edx
239
        mov     [eax+usb_pipe.PrevSibling], edx
240
        mov     [edx+usb_pipe.NextSibling], eax
240
        mov     [edx+usb_pipe.NextSibling], eax
241
; 3. Unlink the pipe from hardware structures.
241
; 3. Unlink the pipe from hardware structures.
242
; 3a. Acquire the corresponding lock.
242
; 3a. Acquire the corresponding lock.
243
        lea     edx, [esi+usb_controller.WaitPipeListAsync]
243
        lea     edx, [esi+usb_controller.WaitPipeListAsync]
244
        lea     ecx, [esi+usb_controller.ControlLock]
244
        lea     ecx, [esi+usb_controller.ControlLock]
245
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
245
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
246
        jb      @f      ; control pipe
246
        jb      @f      ; control pipe
247
        lea     ecx, [esi+usb_controller.BulkLock]
247
        lea     ecx, [esi+usb_controller.BulkLock]
248
        jz      @f      ; bulk pipe
248
        jz      @f      ; bulk pipe
249
        add     edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
249
        add     edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
250
        lea     ecx, [esi+usb_controller.PeriodicLock]
250
        lea     ecx, [esi+usb_controller.PeriodicLock]
251
@@:
251
@@:
252
        push    edx
252
        push    edx
253
        call    mutex_lock
253
        call    mutex_lock
254
        push    ecx
254
        push    ecx
255
; 3b. Let the controller-specific code do its job.
255
; 3b. Let the controller-specific code do its job.
256
        test    [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
256
        test    [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
257
        jnz     @f
257
        jnz     @f
258
        mov     eax, [esi+usb_controller.HardwareFunc]
258
        mov     eax, [esi+usb_controller.HardwareFunc]
259
        call    [eax+usb_hardware_func.DisablePipe]
259
        call    [eax+usb_hardware_func.DisablePipe]
260
@@:
260
@@:
261
        mov     eax, [esi+usb_controller.HardwareFunc]
261
        mov     eax, [esi+usb_controller.HardwareFunc]
262
        call    [eax+usb_hardware_func.UnlinkPipe]
262
        call    [eax+usb_hardware_func.UnlinkPipe]
263
        mov     edx, [ebx+usb_pipe.NextVirt]
263
        mov     edx, [ebx+usb_pipe.NextVirt]
264
        mov     eax, [ebx+usb_pipe.PrevVirt]
264
        mov     eax, [ebx+usb_pipe.PrevVirt]
265
        mov     [edx+usb_pipe.PrevVirt], eax
265
        mov     [edx+usb_pipe.PrevVirt], eax
266
        mov     [eax+usb_pipe.NextVirt], edx
266
        mov     [eax+usb_pipe.NextVirt], edx
267
; 3c. Release the corresponding lock.
267
; 3c. Release the corresponding lock.
268
        pop     ecx
268
        pop     ecx
269
        call    mutex_unlock
269
        call    mutex_unlock
270
; 4. Put the pipe into wait queue.
270
; 4. Put the pipe into wait queue.
271
        pop     edx
271
        pop     edx
272
        cmp     [ebx+usb_pipe.NextWait], -1
272
        cmp     [ebx+usb_pipe.NextWait], -1
273
        jz      .insert_new
273
        jz      .insert_new
274
        or      [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
274
        or      [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
275
        jmp     .inserted
275
        jmp     .inserted
276
.insert_new:
276
.insert_new:
277
        mov     eax, [edx]
277
        mov     eax, [edx]
278
        mov     [ebx+usb_pipe.NextWait], eax
278
        mov     [ebx+usb_pipe.NextWait], eax
279
        mov     [edx], ebx
279
        mov     [edx], ebx
280
.inserted:
280
.inserted:
281
; 5. Return.
281
; 5. Return.
282
        ret
282
        ret
283
.closed:
283
.closed:
284
        call    mutex_unlock
284
        call    mutex_unlock
285
        xor     eax, eax
285
        xor     eax, eax
286
        ret
286
        ret
287
endp
287
endp
288
 
288
 
289
; This procedure is called when all transfers are aborted
289
; This procedure is called when all transfers are aborted
290
; either due to call to usb_abort_pipe or due to pipe closing.
290
; either due to call to usb_abort_pipe or due to pipe closing.
291
; It notifies all callbacks and frees all transfer descriptors.
291
; It notifies all callbacks and frees all transfer descriptors.
292
; ebx -> usb_pipe, esi -> usb_controller, edi -> usb_hardware_func
292
; ebx -> usb_pipe, esi -> usb_controller, edi -> usb_hardware_func
293
; three stack parameters: status code for callback functions
293
; three stack parameters: status code for callback functions
294
; and descriptors where to start and stop.
294
; and descriptors where to start and stop.
295
proc usb_pipe_aborted
295
proc usb_pipe_aborted
296
virtual at esp
296
virtual at esp
297
                dd      ?       ; return address
297
                dd      ?       ; return address
298
.status         dd      ?       ; USB_STATUS_CLOSED or USB_STATUS_CANCELLED
298
.status         dd      ?       ; USB_STATUS_CLOSED or USB_STATUS_CANCELLED
299
.first_td       dd      ?
299
.first_td       dd      ?
300
.last_td        dd      ?
300
.last_td        dd      ?
301
end virtual
301
end virtual
302
; Loop over all transfers, calling the driver with the given status
302
; Loop over all transfers, calling the driver with the given status
303
; and freeing all descriptors except the last one.
303
; and freeing all descriptors except the last one.
304
.loop:
304
.loop:
305
        mov     edx, [.first_td]
305
        mov     edx, [.first_td]
306
        cmp     edx, [.last_td]
306
        cmp     edx, [.last_td]
307
        jz      .done
307
        jz      .done
308
        mov     ecx, [edx+usb_gtd.Callback]
308
        mov     ecx, [edx+usb_gtd.Callback]
309
        test    ecx, ecx
309
        test    ecx, ecx
310
        jz      .no_callback
310
        jz      .no_callback
311
        stdcall_verify ecx, ebx, [.status+12+STDCALL_VERIFY_EXTRA], \
311
        stdcall_verify ecx, ebx, [.status+12+STDCALL_VERIFY_EXTRA], \
312
                [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
312
                [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
313
        mov     edx, [.first_td]
313
        mov     edx, [.first_td]
314
.no_callback:
314
.no_callback:
315
        mov     eax, [edx+usb_gtd.NextVirt]
315
        mov     eax, [edx+usb_gtd.NextVirt]
316
        mov     [.first_td], eax
316
        mov     [.first_td], eax
317
        stdcall [edi+usb_hardware_func.FreeTD], edx
317
        stdcall [edi+usb_hardware_func.FreeTD], edx
318
        jmp     .loop
318
        jmp     .loop
319
.done:
319
.done:
320
        ret     12
320
        ret     12
321
endp
321
endp
322
 
322
 
323
; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
323
; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
324
; corresponding wait list. It means that the hardware has fully forgot about it.
324
; corresponding wait list. It means that the hardware has fully forgot about it.
325
; ebx -> usb_pipe, esi -> usb_controller
325
; ebx -> usb_pipe, esi -> usb_controller
326
proc usb_pipe_closed
326
proc usb_pipe_closed
327
        push    edi
327
        push    edi
328
        mov     edi, [esi+usb_controller.HardwareFunc]
328
        mov     edi, [esi+usb_controller.HardwareFunc]
329
; 1. Notify all registered callbacks with status USB_STATUS_CLOSED, if any,
329
; 1. Notify all registered callbacks with status USB_STATUS_CLOSED, if any,
330
; and free all transfer descriptors, including the last one.
330
; and free all transfer descriptors, including the last one.
331
        lea     ecx, [ebx+usb_pipe.Lock]
331
        lea     ecx, [ebx+usb_pipe.Lock]
332
        call    mutex_lock
332
        call    mutex_lock
333
        mov     edx, [ebx+usb_pipe.LastTD]
333
        mov     edx, [ebx+usb_pipe.LastTD]
334
        test    edx, edx
334
        test    edx, edx
335
        jz      .no_transfer
335
        jz      .no_transfer
336
        mov     eax, [edx+usb_gtd.NextVirt]
336
        mov     eax, [edx+usb_gtd.NextVirt]
337
        push    edx
337
        push    edx
338
        push    eax
338
        push    eax
339
        call    mutex_unlock
339
        call    mutex_unlock
340
        push    USB_STATUS_CLOSED
340
        push    USB_STATUS_CLOSED
341
        call    usb_pipe_aborted
341
        call    usb_pipe_aborted
342
; It is safe to free LastTD here:
342
; It is safe to free LastTD here:
343
; usb_*_transfer_async do not enqueue new transfers if USB_FLAG_CLOSED is set.
343
; usb_*_transfer_async do not enqueue new transfers if USB_FLAG_CLOSED is set.
344
        stdcall [edi+usb_hardware_func.FreeTD], [ebx+usb_pipe.LastTD]
344
        stdcall [edi+usb_hardware_func.FreeTD], [ebx+usb_pipe.LastTD]
345
        jmp     @f
345
        jmp     @f
346
.no_transfer:
346
.no_transfer:
347
        call    mutex_unlock
347
        call    mutex_unlock
348
@@:
348
@@:
349
; 2. Decrement number of pipes for the device.
349
; 2. Decrement number of pipes for the device.
350
; If this pipe is the last pipe, go to 5.
350
; If this pipe is the last pipe, go to 5.
351
        mov     ecx, [ebx+usb_pipe.DeviceData]
351
        mov     ecx, [ebx+usb_pipe.DeviceData]
352
        call    mutex_lock
352
        call    mutex_lock
353
        dec     [ecx+usb_device_data.NumPipes]
353
        dec     [ecx+usb_device_data.NumPipes]
354
        jz      .last_pipe
354
        jz      .last_pipe
355
        call    mutex_unlock
355
        call    mutex_unlock
356
; 3. If the flag "the driver has abandoned this pipe" is set,
356
; 3. If the flag "the driver has abandoned this pipe" is set,
357
; free memory and return.
357
; free memory and return.
358
        test    [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
358
        test    [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
359
        jz      .nofree
359
        jz      .nofree
360
        stdcall [edi+usb_hardware_func.FreePipe], ebx
360
        stdcall [edi+usb_hardware_func.FreePipe], ebx
361
        pop     edi
361
        pop     edi
362
        ret
362
        ret
363
; 4. Otherwise, add it to the list of closed pipes and return.
363
; 4. Otherwise, add it to the list of closed pipes and return.
364
.nofree:
364
.nofree:
365
        add     ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
365
        add     ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
366
        mov     edx, [ecx+usb_pipe.PrevSibling]
366
        mov     edx, [ecx+usb_pipe.PrevSibling]
367
        mov     [ebx+usb_pipe.NextSibling], ecx
367
        mov     [ebx+usb_pipe.NextSibling], ecx
368
        mov     [ebx+usb_pipe.PrevSibling], edx
368
        mov     [ebx+usb_pipe.PrevSibling], edx
369
        mov     [ecx+usb_pipe.PrevSibling], ebx
369
        mov     [ecx+usb_pipe.PrevSibling], ebx
370
        mov     [edx+usb_pipe.NextSibling], ebx
370
        mov     [edx+usb_pipe.NextSibling], ebx
371
        pop     edi
371
        pop     edi
372
        ret
372
        ret
373
.last_pipe:
373
.last_pipe:
374
; That was the last pipe for the device.
374
; That was the last pipe for the device.
375
; 5. Notify device driver(s) about disconnect.
375
; 5. Notify device driver(s) about disconnect.
376
        call    mutex_unlock
376
        call    mutex_unlock
377
        mov     eax, [ecx+usb_device_data.NumInterfaces]
377
        mov     eax, [ecx+usb_device_data.NumInterfaces]
378
        test    eax, eax
378
        test    eax, eax
379
        jz      .notify_done
379
        jz      .notify_done
380
        add     ecx, [ecx+usb_device_data.Interfaces]
380
        add     ecx, [ecx+usb_device_data.Interfaces]
381
.notify_loop:
381
.notify_loop:
382
        mov     edx, [ecx+usb_interface_data.DriverFunc]
382
        mov     edx, [ecx+usb_interface_data.DriverFunc]
383
        test    edx, edx
383
        test    edx, edx
384
        jz      @f
384
        jz      @f
385
        mov     edx, [edx+USBSRV.usb_func]
385
        mov     edx, [edx+USBSRV.usb_func]
386
        cmp     [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
386
        cmp     [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
387
        jb      @f
387
        jb      @f
388
        mov     edx, [edx+USBFUNC.device_disconnect]
388
        mov     edx, [edx+USBFUNC.device_disconnect]
389
        test    edx, edx
389
        test    edx, edx
390
        jz      @f
390
        jz      @f
391
        push    eax ecx
391
        push    eax ecx
392
        stdcall_verify edx, [ecx+usb_interface_data.DriverData]
392
        stdcall_verify edx, [ecx+usb_interface_data.DriverData]
393
        pop     ecx eax
393
        pop     ecx eax
394
@@:
394
@@:
395
        add     ecx, sizeof.usb_interface_data
395
        add     ecx, sizeof.usb_interface_data
396
        dec     eax
396
        dec     eax
397
        jnz     .notify_loop
397
        jnz     .notify_loop
398
.notify_done:
398
.notify_done:
399
; 6. Kill the timer, if active.
399
; 6. Kill the timer, if active.
400
; (Usually not; possible if device is disconnected
400
; (Usually not; possible if device is disconnected
401
; while processing SET_ADDRESS request).
401
; while processing SET_ADDRESS request).
402
        mov     eax, [ebx+usb_pipe.DeviceData]
402
        mov     eax, [ebx+usb_pipe.DeviceData]
403
        cmp     [eax+usb_device_data.Timer], 0
403
        cmp     [eax+usb_device_data.Timer], 0
404
        jz      @f
404
        jz      @f
405
        stdcall cancel_timer_hs, [eax+usb_device_data.Timer]
405
        stdcall cancel_timer_hs, [eax+usb_device_data.Timer]
406
        mov     [eax+usb_device_data.Timer], 0
406
        mov     [eax+usb_device_data.Timer], 0
407
@@:
407
@@:
408
; 7. Bus address, if assigned, can now be reused.
408
; 7. Bus address, if assigned, can now be reused.
409
        call    [edi+usb_hardware_func.GetDeviceAddress]
409
        call    [edi+usb_hardware_func.GetDeviceAddress]
410
        test    eax, eax
410
        test    eax, eax
411
        jz      @f
411
        jz      @f
412
        bts     [esi+usb_controller.ExistingAddresses], eax
412
        bts     [esi+usb_controller.ExistingAddresses], eax
413
@@:
413
@@:
414
        dbgstr 'USB device disconnected'
414
        dbgstr 'USB device disconnected'
415
; 8. All drivers have returned from disconnect callback,
415
; 8. All drivers have returned from disconnect callback,
416
; so all drivers should not use any device-related pipes.
416
; so all drivers should not use any device-related pipes.
417
; Free the remaining pipes.
417
; Free the remaining pipes.
418
        mov     eax, [ebx+usb_pipe.DeviceData]
418
        mov     eax, [ebx+usb_pipe.DeviceData]
419
        add     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
419
        add     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
420
        push    eax
420
        push    eax
421
        mov     eax, [eax+usb_pipe.NextSibling]
421
        mov     eax, [eax+usb_pipe.NextSibling]
422
.free_loop:
422
.free_loop:
423
        cmp     eax, [esp]
423
        cmp     eax, [esp]
424
        jz      .free_done
424
        jz      .free_done
425
        push    [eax+usb_pipe.NextSibling]
425
        push    [eax+usb_pipe.NextSibling]
426
        stdcall [edi+usb_hardware_func.FreePipe], eax
426
        stdcall [edi+usb_hardware_func.FreePipe], eax
427
        pop     eax
427
        pop     eax
428
        jmp     .free_loop
428
        jmp     .free_loop
429
.free_done:
429
.free_done:
430
        stdcall [edi+usb_hardware_func.FreePipe], ebx
430
        stdcall [edi+usb_hardware_func.FreePipe], ebx
431
        pop     eax
431
        pop     eax
432
; 9. Free the usb_device_data structure.
432
; 9. Free the usb_device_data structure.
433
        sub     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
433
        sub     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
434
        call    free
434
        call    free
435
; 10. Return.
435
; 10. Return.
436
.nothing:
436
.nothing:
437
        pop     edi
437
        pop     edi
438
        ret
438
        ret
439
endp
439
endp
440
 
440
 
441
; This procedure is called when a pipe with USB_FLAG_DISABLED is removed from the
441
; This procedure is called when a pipe with USB_FLAG_DISABLED is removed from the
442
; corresponding wait list. It means that the hardware has fully forgot about it.
442
; corresponding wait list. It means that the hardware has fully forgot about it.
443
; ebx -> usb_pipe, esi -> usb_controller
443
; ebx -> usb_pipe, esi -> usb_controller
444
proc usb_pipe_disabled
444
proc usb_pipe_disabled
445
        push    edi
445
        push    edi
446
        mov     edi, [esi+usb_controller.HardwareFunc]
446
        mov     edi, [esi+usb_controller.HardwareFunc]
447
; 1. Acquire pipe lock.
447
; 1. Acquire pipe lock.
448
        lea     ecx, [ebx+usb_pipe.Lock]
448
        lea     ecx, [ebx+usb_pipe.Lock]
449
        call    mutex_lock
449
        call    mutex_lock
450
; 2. Clear USB_FLAG_DISABLED in pipe state.
450
; 2. Clear USB_FLAG_DISABLED in pipe state.
451
        and     [ebx+usb_pipe.Flags], not USB_FLAG_DISABLED
451
        and     [ebx+usb_pipe.Flags], not USB_FLAG_DISABLED
452
; 3. Sanity check: ignore uninitialized pipes.
452
; 3. Sanity check: ignore uninitialized pipes.
453
        cmp     [ebx+usb_pipe.LastTD], 0
453
        cmp     [ebx+usb_pipe.LastTD], 0
454
        jz      .no_transfer
454
        jz      .no_transfer
455
; 4. Acquire the first and last to-be-cancelled transfer descriptor,
455
; 4. Acquire the first and last to-be-cancelled transfer descriptor,
456
; save them in stack for the step 6,
456
; save them in stack for the step 6,
457
; ask the controller driver to enable the pipe for hardware,
457
; ask the controller driver to enable the pipe for hardware,
458
; removing transfers between first and last to-be-cancelled descriptors.
458
; removing transfers between first and last to-be-cancelled descriptors.
459
        lea     ecx, [esi+usb_controller.ControlLock]
459
        lea     ecx, [esi+usb_controller.ControlLock]
460
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
460
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
461
        jb      @f      ; control pipe
461
        jb      @f      ; control pipe
462
        lea     ecx, [esi+usb_controller.BulkLock]
462
        lea     ecx, [esi+usb_controller.BulkLock]
463
        jz      @f      ; bulk pipe
463
        jz      @f      ; bulk pipe
464
        lea     ecx, [esi+usb_controller.PeriodicLock]
464
        lea     ecx, [esi+usb_controller.PeriodicLock]
465
@@:
465
@@:
466
        call    mutex_lock
466
        call    mutex_lock
467
        mov     eax, [ebx+usb_pipe.BaseList]
467
        mov     eax, [ebx+usb_pipe.BaseList]
468
        mov     edx, [eax+usb_pipe.NextVirt]
468
        mov     edx, [eax+usb_pipe.NextVirt]
469
        mov     [ebx+usb_pipe.NextVirt], edx
469
        mov     [ebx+usb_pipe.NextVirt], edx
470
        mov     [ebx+usb_pipe.PrevVirt], eax
470
        mov     [ebx+usb_pipe.PrevVirt], eax
471
        mov     [edx+usb_pipe.PrevVirt], ebx
471
        mov     [edx+usb_pipe.PrevVirt], ebx
472
        mov     [eax+usb_pipe.NextVirt], ebx
472
        mov     [eax+usb_pipe.NextVirt], ebx
473
        mov     eax, [ebx+usb_pipe.LastTD]
473
        mov     eax, [ebx+usb_pipe.LastTD]
474
        mov     edx, [eax+usb_gtd.NextVirt]
474
        mov     edx, [eax+usb_gtd.NextVirt]
475
        mov     [eax+usb_gtd.NextVirt], eax
475
        mov     [eax+usb_gtd.NextVirt], eax
476
        mov     [eax+usb_gtd.PrevVirt], eax
476
        mov     [eax+usb_gtd.PrevVirt], eax
477
        push    eax
477
        push    eax
478
        push    edx
478
        push    edx
479
        push    ecx
479
        push    ecx
480
        call    [edi+usb_hardware_func.EnablePipe]
480
        call    [edi+usb_hardware_func.EnablePipe]
481
        pop     ecx
481
        pop     ecx
482
        call    mutex_unlock
482
        call    mutex_unlock
483
; 5. Release pipe lock acquired at step 1.
483
; 5. Release pipe lock acquired at step 1.
484
; Callbacks called at step 6 can insert new transfers,
484
; Callbacks called at step 6 can insert new transfers,
485
; so we cannot call usb_pipe_aborted while holding pipe lock.
485
; so we cannot call usb_pipe_aborted while holding pipe lock.
486
        lea     ecx, [ebx+usb_pipe.Lock]
486
        lea     ecx, [ebx+usb_pipe.Lock]
487
        call    mutex_unlock
487
        call    mutex_unlock
488
; 6. Notify all registered callbacks with status USB_STATUS_CANCELLED, if any.
488
; 6. Notify all registered callbacks with status USB_STATUS_CANCELLED, if any.
489
; Two arguments describing transfers range were pushed at step 4.
489
; Two arguments describing transfers range were pushed at step 4.
490
        push    USB_STATUS_CANCELLED
490
        push    USB_STATUS_CANCELLED
491
        call    usb_pipe_aborted
491
        call    usb_pipe_aborted
492
        pop     edi
492
        pop     edi
493
        ret
493
        ret
494
.no_transfer:
494
.no_transfer:
495
        call    mutex_unlock
495
        call    mutex_unlock
496
        pop     edi
496
        pop     edi
497
        ret
497
        ret
498
endp
498
endp
499
 
499
 
500
; Part of API for drivers, see documentation for USBNormalTransferAsync.
500
; Part of API for drivers, see documentation for USBNormalTransferAsync.
501
proc usb_normal_transfer_async stdcall uses ebx edi,\
501
proc usb_normal_transfer_async stdcall uses ebx edi,\
502
 pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
502
 pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
503
; 1. Sanity check: callback must be nonzero.
503
; 1. Sanity check: callback must be nonzero.
504
; (It is important for other parts of code.)
504
; (It is important for other parts of code.)
505
        xor     eax, eax
505
        xor     eax, eax
506
        cmp     [callback], eax
506
        cmp     [callback], eax
507
        jz      .nothing
507
        jz      .nothing
508
; 2. Lock the transfer queue.
508
; 2. Lock the transfer queue.
509
        mov     ebx, [pipe]
509
        mov     ebx, [pipe]
510
        lea     ecx, [ebx+usb_pipe.Lock]
510
        lea     ecx, [ebx+usb_pipe.Lock]
511
        call    mutex_lock
511
        call    mutex_lock
512
; 3. If the pipe has already been closed (presumably due to device disconnect),
512
; 3. If the pipe has already been closed (presumably due to device disconnect),
513
; release the lock taken in step 2 and return zero.
513
; release the lock taken in step 2 and return zero.
514
        xor     eax, eax
514
        xor     eax, eax
515
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
515
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
516
        jnz     .unlock
516
        jnz     .unlock
517
; 4. Allocate and initialize TDs for the transfer.
517
; 4. Allocate and initialize TDs for the transfer.
518
        mov     edx, [ebx+usb_pipe.Controller]
518
        mov     edx, [ebx+usb_pipe.Controller]
519
        mov     edi, [edx+usb_controller.HardwareFunc]
519
        mov     edi, [edx+usb_controller.HardwareFunc]
520
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
520
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
521
; If failed, release the lock taken in step 2 and return zero.
521
; If failed, release the lock taken in step 2 and return zero.
522
        test    eax, eax
522
        test    eax, eax
523
        jz      .unlock
523
        jz      .unlock
524
; 5. Store callback and its parameters in the last descriptor for this transfer.
524
; 5. Store callback and its parameters in the last descriptor for this transfer.
525
        mov     ecx, [eax+usb_gtd.PrevVirt]
525
        mov     ecx, [eax+usb_gtd.PrevVirt]
526
        mov     edx, [callback]
526
        mov     edx, [callback]
527
        mov     [ecx+usb_gtd.Callback], edx
527
        mov     [ecx+usb_gtd.Callback], edx
528
        mov     edx, [calldata]
528
        mov     edx, [calldata]
529
        mov     [ecx+usb_gtd.UserData], edx
529
        mov     [ecx+usb_gtd.UserData], edx
530
        mov     edx, [buffer]
530
        mov     edx, [buffer]
531
        mov     [ecx+usb_gtd.Buffer], edx
531
        mov     [ecx+usb_gtd.Buffer], edx
532
; 6. Advance LastTD pointer and activate transfer.
532
; 6. Advance LastTD pointer and activate transfer.
533
        push    [ebx+usb_pipe.LastTD]
533
        push    [ebx+usb_pipe.LastTD]
534
        mov     [ebx+usb_pipe.LastTD], eax
534
        mov     [ebx+usb_pipe.LastTD], eax
535
        call    [edi+usb_hardware_func.InsertTransfer]
535
        call    [edi+usb_hardware_func.InsertTransfer]
536
        pop     eax
536
        pop     eax
537
; 7. Release the lock taken in step 2 and
537
; 7. Release the lock taken in step 2 and
538
; return pointer to the first descriptor for the new transfer.
538
; return pointer to the first descriptor for the new transfer.
539
.unlock:
539
.unlock:
540
        push    eax
540
        push    eax
541
        lea     ecx, [ebx+usb_pipe.Lock]
541
        lea     ecx, [ebx+usb_pipe.Lock]
542
        call    mutex_unlock
542
        call    mutex_unlock
543
        pop     eax
543
        pop     eax
544
.nothing:
544
.nothing:
545
        ret
545
        ret
546
endp
546
endp
547
 
547
 
548
; Part of API for drivers, see documentation for USBControlTransferAsync.
548
; Part of API for drivers, see documentation for USBControlTransferAsync.
549
proc usb_control_async stdcall uses ebx edi,\
549
proc usb_control_async stdcall uses ebx edi,\
550
 pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
550
 pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
551
locals
551
locals
552
last_td         dd      ?
552
last_td         dd      ?
553
endl
553
endl
554
; 1. Sanity check: callback must be nonzero.
554
; 1. Sanity check: callback must be nonzero.
555
; (It is important for other parts of code.)
555
; (It is important for other parts of code.)
556
        cmp     [callback], 0
556
        cmp     [callback], 0
557
        jz      .return0
557
        jz      .return0
558
; 2. Lock the transfer queue.
558
; 2. Lock the transfer queue.
559
        mov     ebx, [pipe]
559
        mov     ebx, [pipe]
560
        lea     ecx, [ebx+usb_pipe.Lock]
560
        lea     ecx, [ebx+usb_pipe.Lock]
561
        call    mutex_lock
561
        call    mutex_lock
562
; 3. If the pipe has already been closed (presumably due to device disconnect),
562
; 3. If the pipe has already been closed (presumably due to device disconnect),
563
; release the lock taken in step 2 and return zero.
563
; release the lock taken in step 2 and return zero.
564
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
564
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
565
        jnz     .unlock_return0
565
        jnz     .unlock_return0
566
; A control transfer contains two or three stages:
566
; A control transfer contains two or three stages:
567
; Setup stage, optional Data stage, Status stage.
567
; Setup stage, optional Data stage, Status stage.
568
; 4. Allocate and initialize TDs for the Setup stage.
568
; 4. Allocate and initialize TDs for the Setup stage.
569
; Payload is 8 bytes from [config].
569
; Payload is 8 bytes from [config].
570
        mov     edx, [ebx+usb_pipe.Controller]
570
        mov     edx, [ebx+usb_pipe.Controller]
571
        mov     edi, [edx+usb_controller.HardwareFunc]
571
        mov     edi, [edx+usb_controller.HardwareFunc]
572
        stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
572
        stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
573
                ; short transfer is an error, direction is DATA0, token is SETUP
573
                ; short transfer is an error, direction is DATA0, token is SETUP
574
        mov     [last_td], eax
574
        mov     [last_td], eax
575
        test    eax, eax
575
        test    eax, eax
576
        jz      .fail
576
        jz      .fail
577
; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
577
; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
578
; Payload is [size] bytes from [buffer].
578
; Payload is [size] bytes from [buffer].
579
        mov     edx, [config]
579
        mov     edx, [config]
580
        mov     ecx, (3 shl 2) + 1      ; DATA1, token is OUT
580
        mov     ecx, (3 shl 2) + 1      ; DATA1, token is OUT
581
        cmp     byte [edx], 0
581
        cmp     byte [edx], 0
582
        jns     @f
582
        jns     @f
583
        cmp     [size], 0
583
        cmp     [size], 0
584
        jz      @f
584
        jz      @f
585
        inc     ecx     ; token is IN
585
        inc     ecx     ; token is IN
586
@@:
586
@@:
587
        cmp     [size], 0
587
        cmp     [size], 0
588
        jz      .nodata
588
        jz      .nodata
589
        push    ecx
589
        push    ecx
590
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
590
        stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
591
        pop     ecx
591
        pop     ecx
592
        test    eax, eax
592
        test    eax, eax
593
        jz      .fail
593
        jz      .fail
594
        mov     [last_td], eax
594
        mov     [last_td], eax
595
.nodata:
595
.nodata:
596
; 6. Allocate and initialize TDs for the Status stage.
596
; 6. Allocate and initialize TDs for the Status stage.
597
; No payload.
597
; No payload.
598
        xor     ecx, 3  ; IN becomes OUT, OUT becomes IN
598
        xor     ecx, 3  ; IN becomes OUT, OUT becomes IN
599
        stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
599
        stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
600
        test    eax, eax
600
        test    eax, eax
601
        jz      .fail
601
        jz      .fail
602
; 7. Store callback and its parameters in the last descriptor for this transfer.
602
; 7. Store callback and its parameters in the last descriptor for this transfer.
603
        mov     ecx, [eax+usb_gtd.PrevVirt]
603
        mov     ecx, [eax+usb_gtd.PrevVirt]
604
        mov     edx, [callback]
604
        mov     edx, [callback]
605
        mov     [ecx+usb_gtd.Callback], edx
605
        mov     [ecx+usb_gtd.Callback], edx
606
        mov     edx, [calldata]
606
        mov     edx, [calldata]
607
        mov     [ecx+usb_gtd.UserData], edx
607
        mov     [ecx+usb_gtd.UserData], edx
608
        mov     edx, [buffer]
608
        mov     edx, [buffer]
609
        mov     [ecx+usb_gtd.Buffer], edx
609
        mov     [ecx+usb_gtd.Buffer], edx
610
; 8. Advance LastTD pointer and activate transfer.
610
; 8. Advance LastTD pointer and activate transfer.
611
        push    [ebx+usb_pipe.LastTD]
611
        push    [ebx+usb_pipe.LastTD]
612
        mov     [ebx+usb_pipe.LastTD], eax
612
        mov     [ebx+usb_pipe.LastTD], eax
613
        call    [edi+usb_hardware_func.InsertTransfer]
613
        call    [edi+usb_hardware_func.InsertTransfer]
614
; 9. Release the lock taken in step 2 and
614
; 9. Release the lock taken in step 2 and
615
; return pointer to the first descriptor for the new transfer.
615
; return pointer to the first descriptor for the new transfer.
616
        lea     ecx, [ebx+usb_pipe.Lock]
616
        lea     ecx, [ebx+usb_pipe.Lock]
617
        call    mutex_unlock
617
        call    mutex_unlock
618
        pop     eax
618
        pop     eax
619
        ret
619
        ret
620
.fail:
620
.fail:
621
        mov     eax, [last_td]
621
        mov     eax, [last_td]
622
        test    eax, eax
622
        test    eax, eax
623
        jz      .unlock_return0
623
        jz      .unlock_return0
624
        stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
624
        stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
625
.unlock_return0:
625
.unlock_return0:
626
        lea     ecx, [ebx+usb_pipe.Lock]
626
        lea     ecx, [ebx+usb_pipe.Lock]
627
        call    mutex_unlock
627
        call    mutex_unlock
628
.return0:
628
.return0:
629
        xor     eax, eax
629
        xor     eax, eax
630
        ret
630
        ret
631
endp
631
endp
632
 
632
 
633
; Part of API for drivers, see documentation for USBAbortPipe.
633
; Part of API for drivers, see documentation for USBAbortPipe.
634
proc usb_abort_pipe
634
proc usb_abort_pipe
635
        push    ebx esi ; save used registers to be stdcall
635
        push    ebx esi ; save used registers to be stdcall
636
virtual at esp
636
virtual at esp
637
                rd      2 ; saved registers
637
                rd      2 ; saved registers
638
                dd      ? ; return address
638
                dd      ? ; return address
639
.pipe           dd      ?
639
.pipe           dd      ?
640
end virtual
640
end virtual
641
        mov     ebx, [.pipe]
641
        mov     ebx, [.pipe]
642
; 1. Acquire pipe lock.
642
; 1. Acquire pipe lock.
643
        lea     ecx, [ebx+usb_pipe.Lock]
643
        lea     ecx, [ebx+usb_pipe.Lock]
644
        call    mutex_lock
644
        call    mutex_lock
645
; 2. If the pipe is already closed or abort is in progress,
645
; 2. If the pipe is already closed or abort is in progress,
646
; just release pipe lock and return.
646
; just release pipe lock and return.
647
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED + USB_FLAG_DISABLED
647
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED + USB_FLAG_DISABLED
648
        jnz     .nothing
648
        jnz     .nothing
649
; 3. Mark the pipe as aborting.
649
; 3. Mark the pipe as aborting.
650
        or      [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
650
        or      [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
651
; 4. We cannot do anything except adding new transfers concurrently with hardware.
651
; 4. We cannot do anything except adding new transfers concurrently with hardware.
652
; Ask the controller driver to (temporarily) remove the pipe from hardware queue.
652
; Ask the controller driver to (temporarily) remove the pipe from hardware queue.
653
        mov     esi, [ebx+usb_pipe.Controller]
653
        mov     esi, [ebx+usb_pipe.Controller]
654
; 4a. Acquire queue lock.
654
; 4a. Acquire queue lock.
655
        lea     ecx, [esi+usb_controller.ControlLock]
655
        lea     ecx, [esi+usb_controller.ControlLock]
656
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
656
        cmp     [ebx+usb_pipe.Type], BULK_PIPE
657
        jb      @f      ; control pipe
657
        jb      @f      ; control pipe
658
        lea     ecx, [esi+usb_controller.BulkLock]
658
        lea     ecx, [esi+usb_controller.BulkLock]
659
        jz      @f      ; bulk pipe
659
        jz      @f      ; bulk pipe
660
        lea     ecx, [esi+usb_controller.PeriodicLock]
660
        lea     ecx, [esi+usb_controller.PeriodicLock]
661
@@:
661
@@:
662
        call    mutex_lock
662
        call    mutex_lock
663
        push    ecx
663
        push    ecx
664
; 4b. Call the driver.
664
; 4b. Call the driver.
665
        mov     eax, [esi+usb_controller.HardwareFunc]
665
        mov     eax, [esi+usb_controller.HardwareFunc]
666
        call    [eax+usb_hardware_func.DisablePipe]
666
        call    [eax+usb_hardware_func.DisablePipe]
667
; 4c. Remove the pipe from software list.
667
; 4c. Remove the pipe from software list.
668
        mov     eax, [ebx+usb_pipe.NextVirt]
668
        mov     eax, [ebx+usb_pipe.NextVirt]
669
        mov     edx, [ebx+usb_pipe.PrevVirt]
669
        mov     edx, [ebx+usb_pipe.PrevVirt]
670
        mov     [eax+usb_pipe.PrevVirt], edx
670
        mov     [eax+usb_pipe.PrevVirt], edx
671
        mov     [edx+usb_pipe.NextVirt], eax
671
        mov     [edx+usb_pipe.NextVirt], eax
672
; 4c. Register the pipe in corresponding wait list.
672
; 4c. Register the pipe in corresponding wait list.
673
        test    [ebx+usb_pipe.Type], 1
673
        test    [ebx+usb_pipe.Type], 1
674
        jz      .control_bulk
674
        jz      .control_bulk
675
        call    usb_subscribe_periodic
675
        call    usb_subscribe_periodic
676
        jmp     @f
676
        jmp     @f
677
.control_bulk:
677
.control_bulk:
678
        call    usb_subscribe_control
678
        call    usb_subscribe_control
679
@@:
679
@@:
680
; 4d. Release queue lock.
680
; 4d. Release queue lock.
681
        pop     ecx
681
        pop     ecx
682
        call    mutex_unlock
682
        call    mutex_unlock
683
; 4e. Notify the USB thread about new work.
683
; 4e. Notify the USB thread about new work.
684
        push    ebx esi edi
684
        push    ebx esi edi
685
        call    usb_wakeup
685
        call    usb_wakeup
686
        pop     edi esi ebx
686
        pop     edi esi ebx
687
; That's all for now. To be continued in usb_pipe_disabled.
687
; That's all for now. To be continued in usb_pipe_disabled.
688
; 5. Release pipe lock acquired at step 1 and return.
688
; 5. Release pipe lock acquired at step 1 and return.
689
.nothing:
689
.nothing:
690
        lea     ecx, [ebx+usb_pipe.Lock]
690
        lea     ecx, [ebx+usb_pipe.Lock]
691
        call    mutex_unlock
691
        call    mutex_unlock
692
        pop     esi ebx
692
        pop     esi ebx
693
        ret     4
693
        ret     4
694
endp
694
endp
695
 
695
 
696
; Part of API for drivers, see documentation for USBGetParam.
696
; Part of API for drivers, see documentation for USBGetParam.
697
proc usb_get_param
697
proc usb_get_param
698
virtual at esp
698
virtual at esp
699
                dd      ?       ; return address
699
                dd      ?       ; return address
700
.pipe           dd      ?
700
.pipe           dd      ?
701
.param          dd      ?
701
.param          dd      ?
702
end virtual
702
end virtual
703
        mov     edx, [.param]
703
        mov     edx, [.param]
704
        mov     ecx, [.pipe]
704
        mov     ecx, [.pipe]
705
        mov     eax, [ecx+usb_pipe.DeviceData]
705
        mov     eax, [ecx+usb_pipe.DeviceData]
706
        test    edx, edx
706
        test    edx, edx
707
        jz      .get_device_descriptor
707
        jz      .get_device_descriptor
708
        dec     edx
708
        dec     edx
709
        jz      .get_config_descriptor
709
        jz      .get_config_descriptor
710
        dec     edx
710
        dec     edx
711
        jz      .get_speed
711
        jz      .get_speed
712
        or      eax, -1
712
        or      eax, -1
713
        ret     8
713
        ret     8
714
.get_device_descriptor:
714
.get_device_descriptor:
715
        add     eax, usb_device_data.DeviceDescriptor
715
        add     eax, usb_device_data.DeviceDescriptor
716
        ret     8
716
        ret     8
717
.get_config_descriptor:
717
.get_config_descriptor:
718
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
718
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
719
        lea     eax, [eax+ecx+usb_device_data.DeviceDescriptor]
719
        lea     eax, [eax+ecx+usb_device_data.DeviceDescriptor]
720
        ret     8
720
        ret     8
721
.get_speed:
721
.get_speed:
722
        movzx   eax, [eax+usb_device_data.Speed]
722
        movzx   eax, [eax+usb_device_data.Speed]
723
        ret     8
723
        ret     8
724
endp
724
endp
725
 
725
 
726
; Initialize software part of usb_gtd. Called from controller-specific code
726
; Initialize software part of usb_gtd. Called from controller-specific code
727
; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
727
; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
728
; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
728
; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
729
; current (initializing) usb_gtd.
729
; current (initializing) usb_gtd.
730
; Returns ecx = [.td].
730
; Returns ecx = [.td].
731
proc usb_init_transfer
731
proc usb_init_transfer
732
virtual at ebp-4
732
virtual at ebp-4
733
.Size   dd      ?
733
.Size   dd      ?
734
        rd      2
734
        rd      2
735
.Buffer dd      ?
735
.Buffer dd      ?
736
        dd      ?
736
        dd      ?
737
.Flags  dd      ?
737
.Flags  dd      ?
738
.td     dd      ?
738
.td     dd      ?
739
end virtual
739
end virtual
740
        mov     [eax+usb_gtd.Pipe], ebx
740
        mov     [eax+usb_gtd.Pipe], ebx
741
        mov     ecx, [.td]
741
        mov     ecx, [.td]
742
        mov     [eax+usb_gtd.PrevVirt], ecx
742
        mov     [eax+usb_gtd.PrevVirt], ecx
743
        mov     edx, [ecx+usb_gtd.NextVirt]
743
        mov     edx, [ecx+usb_gtd.NextVirt]
744
        mov     [ecx+usb_gtd.NextVirt], eax
744
        mov     [ecx+usb_gtd.NextVirt], eax
745
        mov     [eax+usb_gtd.NextVirt], edx
745
        mov     [eax+usb_gtd.NextVirt], edx
746
        mov     [edx+usb_gtd.PrevVirt], eax
746
        mov     [edx+usb_gtd.PrevVirt], eax
747
        mov     edx, [.Size]
747
        mov     edx, [.Size]
748
        mov     [ecx+usb_gtd.Length], edx
748
        mov     [ecx+usb_gtd.Length], edx
749
        xor     edx, edx
749
        xor     edx, edx
750
        mov     [ecx+usb_gtd.Callback], edx
750
        mov     [ecx+usb_gtd.Callback], edx
751
        mov     [ecx+usb_gtd.UserData], edx
751
        mov     [ecx+usb_gtd.UserData], edx
752
        ret
752
        ret
753
endp
753
endp
754
 
754
 
755
; Free all TDs for the current transfer if something has failed
755
; Free all TDs for the current transfer if something has failed
756
; during initialization (e.g. no memory for the next TD).
756
; during initialization (e.g. no memory for the next TD).
757
; Stdcall with one stack argument = first TD for the transfer
757
; Stdcall with one stack argument = first TD for the transfer
758
; and eax = last initialized TD for the transfer.
758
; and eax = last initialized TD for the transfer.
759
proc usb_undo_tds
759
proc usb_undo_tds
760
        push    [eax+usb_gtd.NextVirt]
760
        push    [eax+usb_gtd.NextVirt]
761
@@:
761
@@:
762
        cmp     eax, [esp+8]
762
        cmp     eax, [esp+8]
763
        jz      @f
763
        jz      @f
764
        push    [eax+usb_gtd.PrevVirt]
764
        push    [eax+usb_gtd.PrevVirt]
765
        stdcall [edi+usb_hardware_func.FreeTD], eax
765
        stdcall [edi+usb_hardware_func.FreeTD], eax
766
        pop     eax
766
        pop     eax
767
        jmp     @b
767
        jmp     @b
768
@@:
768
@@:
769
        pop     ecx
769
        pop     ecx
770
        mov     [eax+usb_gtd.NextVirt], ecx
770
        mov     [eax+usb_gtd.NextVirt], ecx
771
        mov     [ecx+usb_gtd.PrevVirt], eax
771
        mov     [ecx+usb_gtd.PrevVirt], eax
772
        ret     4
772
        ret     4
773
endp
773
endp
774
 
774
 
775
; Helper procedure for handling short packets in controller-specific code.
775
; Helper procedure for handling short packets in controller-specific code.
776
; Returns with CF cleared if this is the final packet in some stage:
776
; Returns with CF cleared if this is the final packet in some stage:
777
; for control transfers that means one of Data and Status stages,
777
; for control transfers that means one of Data and Status stages,
778
; for other transfers - the final packet in the only stage.
778
; for other transfers - the final packet in the only stage.
779
proc usb_is_final_packet
779
proc usb_is_final_packet
780
        cmp     [ebx+usb_gtd.Callback], 0
780
        cmp     [ebx+usb_gtd.Callback], 0
781
        jnz     .nothing
781
        jnz     .nothing
782
        mov     eax, [ebx+usb_gtd.NextVirt]
782
        mov     eax, [ebx+usb_gtd.NextVirt]
783
        cmp     [eax+usb_gtd.Callback], 0
783
        cmp     [eax+usb_gtd.Callback], 0
784
        jz      .stc
784
        jz      .stc
785
        mov     eax, [ebx+usb_gtd.Pipe]
785
        mov     eax, [ebx+usb_gtd.Pipe]
786
        cmp     [eax+usb_pipe.Type], CONTROL_PIPE
786
        cmp     [eax+usb_pipe.Type], CONTROL_PIPE
787
        jz      .nothing
787
        jz      .nothing
788
.stc:
788
.stc:
789
        stc
789
        stc
790
.nothing:
790
.nothing:
791
        ret
791
        ret
792
endp
792
endp
793
 
793
 
794
; Helper procedure for controller-specific code:
794
; Helper procedure for controller-specific code:
795
; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
795
; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
796
proc usb_unlink_td
796
proc usb_unlink_td
797
        mov     ecx, [ebx+usb_gtd.Pipe]
797
        mov     ecx, [ebx+usb_gtd.Pipe]
798
        add     ecx, usb_pipe.Lock
798
        add     ecx, usb_pipe.Lock
799
        call    mutex_lock
799
        call    mutex_lock
800
        mov     eax, [ebx+usb_gtd.PrevVirt]
800
        mov     eax, [ebx+usb_gtd.PrevVirt]
801
        mov     edx, [ebx+usb_gtd.NextVirt]
801
        mov     edx, [ebx+usb_gtd.NextVirt]
802
        mov     [edx+usb_gtd.PrevVirt], eax
802
        mov     [edx+usb_gtd.PrevVirt], eax
803
        mov     [eax+usb_gtd.NextVirt], edx
803
        mov     [eax+usb_gtd.NextVirt], edx
804
        call    mutex_unlock
804
        call    mutex_unlock
805
        ret
805
        ret
806
endp
806
endp
807
 
807
 
808
; One part of transfer is completed, run the associated callback
808
; One part of transfer is completed, run the associated callback
809
; or update total length in the next part of transfer.
809
; or update total length in the next part of transfer.
810
; in: ebx -> usb_gtd, ecx = status, edx = length
810
; in: ebx -> usb_gtd, ecx = status, edx = length
811
proc usb_process_gtd
811
proc usb_process_gtd
812
; 1. Test whether it is the last descriptor in the transfer
812
; 1. Test whether it is the last descriptor in the transfer
813
; <=> it has an associated callback.
813
; <=> it has an associated callback.
814
        mov     eax, [ebx+usb_gtd.Callback]
814
        mov     eax, [ebx+usb_gtd.Callback]
815
        test    eax, eax
815
        test    eax, eax
816
        jz      .nocallback
816
        jz      .nocallback
817
; 2. It has an associated callback; call it with corresponding parameters.
817
; 2. It has an associated callback; call it with corresponding parameters.
818
        stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \
818
        stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \
819
                [ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData]
819
                [ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData]
820
        ret
820
        ret
821
.nocallback:
821
.nocallback:
822
; 3. It is an intermediate descriptor. Add its length to the length
822
; 3. It is an intermediate descriptor. Add its length to the length
823
; in the following descriptor.
823
; in the following descriptor.
824
        mov     eax, [ebx+usb_gtd.NextVirt]
824
        mov     eax, [ebx+usb_gtd.NextVirt]
825
        add     [eax+usb_gtd.Length], edx
825
        add     [eax+usb_gtd.Length], edx
826
        ret
826
        ret
827
endp
827
endp
828
 
828
 
829
if USB_STDCALL_VERIFY
829
if USB_STDCALL_VERIFY
830
proc verify_regs
830
proc verify_regs
831
virtual at esp
831
virtual at esp
832
        dd      ?       ; return address
832
        dd      ?       ; return address
833
.edi    dd      ?
833
.edi    dd      ?
834
.esi    dd      ?
834
.esi    dd      ?
835
.ebp    dd      ?
835
.ebp    dd      ?
836
.esp    dd      ?
836
.esp    dd      ?
837
.ebx    dd      ?
837
.ebx    dd      ?
838
.edx    dd      ?
838
.edx    dd      ?
839
.ecx    dd      ?
839
.ecx    dd      ?
840
.eax    dd      ?
840
.eax    dd      ?
841
end virtual
841
end virtual
842
        cmp     ebx, [.ebx]
842
        cmp     ebx, [.ebx]
843
        jz      @f
843
        jz      @f
844
        dbgstr 'ERROR!!! ebx changed'
844
        dbgstr 'ERROR!!! ebx changed'
845
@@:
845
@@:
846
        cmp     esi, [.esi]
846
        cmp     esi, [.esi]
847
        jz      @f
847
        jz      @f
848
        dbgstr 'ERROR!!! esi changed'
848
        dbgstr 'ERROR!!! esi changed'
849
@@:
849
@@:
850
        cmp     edi, [.edi]
850
        cmp     edi, [.edi]
851
        jz      @f
851
        jz      @f
852
        dbgstr 'ERROR!!! edi changed'
852
        dbgstr 'ERROR!!! edi changed'
853
@@:
853
@@:
854
        cmp     ebp, [.ebp]
854
        cmp     ebp, [.ebp]
855
        jz      @f
855
        jz      @f
856
        dbgstr 'ERROR!!! ebp changed'
856
        dbgstr 'ERROR!!! ebp changed'
857
@@:
857
@@:
858
        ret
858
        ret
859
endp
859
endp
860
end if
860
end if