Subversion Repositories Kolibri OS

Rev

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

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