Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
4850 mario79 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5363 yogev_ezra 3
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
4850 mario79 4
;; Distributed under terms of the GNU General Public License    ;;
5
;;                                                              ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
8
$Revision: 8037 $
9
 
10
 
3520 clevermous 11
; USB Host Controller support code: hardware-independent part,
12
; common for all controller types.
13
 
4418 clevermous 14
iglobal
15
; USB HC support: some functions interesting only for *HCI-drivers.
16
align 4
17
usb_hc_func:
18
        dd      usb_process_gtd
19
        dd      usb_init_static_endpoint
20
        dd      usb_wakeup_if_needed
21
        dd      usb_subscribe_control
22
        dd      usb_subscription_done
8037 dunkaist 23
        dd      slab_alloc
24
        dd      slab_free
4418 clevermous 25
        dd      usb_td_to_virt
26
        dd      usb_init_transfer
27
        dd      usb_undo_tds
28
        dd      usb_test_pending_port
29
        dd      usb_get_tt
30
        dd      usb_get_tt_think_time
31
        dd      usb_new_device
32
        dd      usb_disconnect_stage2
33
        dd      usb_process_wait_lists
34
        dd      usb_unlink_td
35
        dd      usb_is_final_packet
36
        dd      usb_find_ehci_companion
37
endg
3520 clevermous 38
 
39
; Initializes one controller, called by usb_init for every controller.
4418 clevermous 40
; eax -> PCIDEV structure for the device.
3520 clevermous 41
proc usb_init_controller
42
        push    ebp
43
        mov     ebp, esp
44
; 1. Store in the stack PCI coordinates and save pointer to PCIDEV:
45
; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs.
46
        push    dword [eax+PCIDEV.devfn]
47
        push    eax
4418 clevermous 48
        mov     edi, [eax+PCIDEV.owner]
49
        test    edi, edi
50
        jz      .nothing
51
        mov     edi, [edi+USBSRV.usb_func]
3520 clevermous 52
; 2. Allocate *hci_controller + usb_controller.
53
        mov     ebx, [edi+usb_hardware_func.DataSize]
54
        add     ebx, sizeof.usb_controller
55
        stdcall kernel_alloc, ebx
56
        test    eax, eax
57
        jz      .nothing
58
; 3. Zero-initialize both structures.
59
        push    edi eax
60
        mov     ecx, ebx
61
        shr     ecx, 2
62
        xchg    edi, eax
63
        xor     eax, eax
64
        rep stosd
65
; 4. Initialize usb_controller structure,
66
; except data known only to controller-specific code (like NumPorts)
67
; and link fields
68
; (this structure will be inserted to the overall list at step 6).
69
        dec     eax
70
        mov     [edi+usb_controller.ExistingAddresses+4-sizeof.usb_controller], eax
71
        mov     [edi+usb_controller.ExistingAddresses+8-sizeof.usb_controller], eax
72
        mov     [edi+usb_controller.ExistingAddresses+12-sizeof.usb_controller], eax
73
        mov     [edi+usb_controller.ResettingPort-sizeof.usb_controller], al    ; no resetting port
74
        dec     eax     ; don't allocate zero address
75
        mov     [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax
4418 clevermous 76
        mov     eax, [ebp-4]
77
        mov     [edi+usb_controller.PCICoordinates-sizeof.usb_controller], eax
3520 clevermous 78
        lea     ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller]
79
        call    mutex_init
80
        add     ecx, usb_controller.ControlLock - usb_controller.PeriodicLock
81
        call    mutex_init
82
        add     ecx, usb_controller.BulkLock - usb_controller.ControlLock
83
        call    mutex_init
84
        pop     eax edi
85
        mov     [eax+ebx-sizeof.usb_controller+usb_controller.HardwareFunc], edi
86
        push    eax
87
; 5. Call controller-specific initialization.
88
; If failed, free memory allocated in step 2 and return.
89
        call    [edi+usb_hardware_func.Init]
90
        test    eax, eax
91
        jz      .fail
92
        pop     ecx
93
; 6. Insert the controller to the global list.
94
        xchg    eax, ebx
95
        mov     ecx, usb_controllers_list_mutex
96
        call    mutex_lock
97
        mov     edx, usb_controllers_list
98
        mov     eax, [edx+usb_controller.Prev]
99
        mov     [ebx+usb_controller.Next], edx
100
        mov     [ebx+usb_controller.Prev], eax
101
        mov     [edx+usb_controller.Prev], ebx
102
        mov     [eax+usb_controller.Next], ebx
103
        call    mutex_unlock
104
; 7. Wakeup USB thread to call ProcessDeferred.
105
        call    usb_wakeup
106
.nothing:
107
; 8. Restore pointer to PCIDEV saved in step 1 and return.
108
        pop     eax
109
        leave
110
        ret
111
.fail:
112
        call    kernel_free
113
        jmp     .nothing
114
endp
115
 
116
; Helper function, calculates physical address including offset in page.
117
proc get_phys_addr
118
        push    ecx
119
        mov     ecx, eax
120
        and     ecx, 0xFFF
121
        call    get_pg_addr
122
        add     eax, ecx
123
        pop     ecx
124
        ret
125
endp
126
 
4547 clevermous 127
; Put the given control/bulk pipe in the wait list;
3520 clevermous 128
; called when the pipe structure is changed and a possible hardware cache
129
; needs to be synchronized. When it will be known that the cache is updated,
130
; usb_subscription_done procedure will be called.
131
proc usb_subscribe_control
132
        cmp     [ebx+usb_pipe.NextWait], -1
133
        jnz     @f
134
        mov     eax, [esi+usb_controller.WaitPipeListAsync]
135
        mov     [ebx+usb_pipe.NextWait], eax
136
        mov     [esi+usb_controller.WaitPipeListAsync], ebx
137
@@:
138
        ret
139
endp
140
 
4547 clevermous 141
; Same as usb_subscribe_control, but for interrupt/isochronous pipe.
142
proc usb_subscribe_periodic
143
        cmp     [ebx+usb_pipe.NextWait], -1
144
        jnz     @f
145
        mov     eax, [esi+usb_controller.WaitPipeListPeriodic]
146
        mov     [ebx+usb_pipe.NextWait], eax
147
        mov     [esi+usb_controller.WaitPipeListPeriodic], ebx
148
@@:
149
        ret
150
endp
151
 
3520 clevermous 152
; Called after synchronization of hardware cache with software changes.
153
; Continues process of device enumeration based on when it was delayed
154
; due to call to usb_subscribe_control.
155
proc usb_subscription_done
156
        mov     eax, [ebx+usb_pipe.DeviceData]
157
        cmp     [eax+usb_device_data.DeviceDescrSize], 0
158
        jz      usb_after_set_address
159
        jmp     usb_after_set_endpoint_size
160
endp
161
 
162
; This function is called when a new device has either passed
163
; or failed first stages of configuration, so the next device
164
; can enter configuration process.
165
proc usb_test_pending_port
166
        mov     [esi+usb_controller.ResettingPort], -1
167
        cmp     [esi+usb_controller.PendingPorts], 0
168
        jz      .nothing
169
        bsf     ecx, [esi+usb_controller.PendingPorts]
170
        btr     [esi+usb_controller.PendingPorts], ecx
171
        mov     eax, [esi+usb_controller.HardwareFunc]
172
        jmp     [eax+usb_hardware_func.InitiateReset]
173
.nothing:
174
        ret
175
endp
176
 
177
; This procedure is regularly called from controller-specific ProcessDeferred,
178
; it checks whether there are disconnected events and if so, process them.
179
proc usb_disconnect_stage2
180
        bsf     ecx, [esi+usb_controller.NewDisconnected]
181
        jz      .nothing
182
        lock btr [esi+usb_controller.NewDisconnected], ecx
183
        btr     [esi+usb_controller.PendingPorts], ecx
184
        xor     ebx, ebx
185
        xchg    ebx, [esi+usb_controller.DevicesByPort+ecx*4]
186
        test    ebx, ebx
187
        jz      usb_disconnect_stage2
188
        call    usb_device_disconnected
189
        jmp     usb_disconnect_stage2
190
.nothing:
191
        ret
192
endp
193
 
194
; Initial stage of disconnect processing: called when device is disconnected.
195
proc usb_device_disconnected
196
; Loop over all pipes, close everything, wait until hardware reacts.
197
; The final handling is done in usb_pipe_closed.
198
        push    ebx
199
        mov     ecx, [ebx+usb_pipe.DeviceData]
200
        call    mutex_lock
201
        lea     eax, [ecx+usb_device_data.OpenedPipeList-usb_pipe.NextSibling]
202
        push    eax
203
        mov     ebx, [eax+usb_pipe.NextSibling]
204
.pipe_loop:
205
        call    usb_close_pipe_nolock
206
        mov     ebx, [ebx+usb_pipe.NextSibling]
207
        cmp     ebx, [esp]
208
        jnz     .pipe_loop
209
        pop     eax
210
        pop     ebx
211
        mov     ecx, [ebx+usb_pipe.DeviceData]
212
        call    mutex_unlock
213
        ret
214
endp
215
 
216
; Called from controller-specific ProcessDeferred,
217
; processes wait-pipe-done notifications,
218
; returns whether there are more items in wait queues.
219
; in: esi -> usb_controller
220
; out: eax = bitmask of pipe types with non-empty wait queue
221
proc usb_process_wait_lists
222
        xor     edx, edx
223
        push    edx
224
        call    usb_process_one_wait_list
225
        jnc     @f
226
        or      byte [esp], 1 shl CONTROL_PIPE
227
@@:
3598 clevermous 228
        movi    edx, 4
3520 clevermous 229
        call    usb_process_one_wait_list
230
        jnc     @f
231
        or      byte [esp], 1 shl INTERRUPT_PIPE
232
@@:
233
        xor     edx, edx
234
        call    usb_process_one_wait_list
235
        jnc     @f
236
        or      byte [esp], 1 shl CONTROL_PIPE
237
@@:
238
        pop     eax
239
        ret
240
endp
241
 
242
; Helper procedure for usb_process_wait_lists;
243
; does the same for one wait queue.
244
; in: esi -> usb_controller,
245
; edx=0 for *Async, edx=4 for *Periodic list
246
; out: CF = issue new request
247
proc usb_process_one_wait_list
248
; 1. Check whether there is a pending request. If so, do nothing.
249
        mov     ebx, [esi+usb_controller.WaitPipeRequestAsync+edx]
250
        cmp     ebx, [esi+usb_controller.ReadyPipeHeadAsync+edx]
251
        clc
252
        jnz     .nothing
253
; 2. Check whether there are new data. If so, issue a new request.
254
        cmp     ebx, [esi+usb_controller.WaitPipeListAsync+edx]
255
        stc
256
        jnz     .nothing
257
        test    ebx, ebx
258
        jz      .nothing
259
; 3. Clear all lists.
260
        xor     ecx, ecx
261
        mov     [esi+usb_controller.WaitPipeListAsync+edx], ecx
262
        mov     [esi+usb_controller.WaitPipeRequestAsync+edx], ecx
263
        mov     [esi+usb_controller.ReadyPipeHeadAsync+edx], ecx
264
; 4. Loop over all pipes from the wait list.
265
.pipe_loop:
266
; For every pipe:
267
; 5. Save edx and next pipe in the list.
268
        push    edx
269
        push    [ebx+usb_pipe.NextWait]
270
; 6. If USB_FLAG_EXTRA_WAIT is set, reinsert the pipe to the list and continue.
271
        test    [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
272
        jz      .process
273
        mov     eax, [esi+usb_controller.WaitPipeListAsync+edx]
274
        mov     [ebx+usb_pipe.NextWait], eax
275
        mov     [esi+usb_controller.WaitPipeListAsync+edx], ebx
276
        jmp     .continue
277
.process:
4547 clevermous 278
; 7. Call the handler depending on USB_FLAG_CLOSED and USB_FLAG_DISABLED.
3520 clevermous 279
        or      [ebx+usb_pipe.NextWait], -1
280
        test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
281
        jz      .nodisconnect
282
        call    usb_pipe_closed
283
        jmp     .continue
284
.nodisconnect:
4547 clevermous 285
        test    [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
286
        jz      .nodisabled
287
        call    usb_pipe_disabled
288
        jmp     .continue
289
.nodisabled:
3520 clevermous 290
        call    usb_subscription_done
291
.continue:
292
; 8. Restore edx and next pipe saved in step 5 and continue the loop.
293
        pop     ebx
294
        pop     edx
295
        test    ebx, ebx
296
        jnz     .pipe_loop
297
.check_new_work:
298
; 9. Set CF depending on whether WaitPipeList* is nonzero.
299
        cmp     [esi+usb_controller.WaitPipeListAsync+edx], 1
300
        cmc
301
.nothing:
302
        ret
303
endp
4418 clevermous 304
 
305
; Called from USB1 controller-specific initialization.
306
; Finds EHCI companion controller for given USB1 controller.
307
; in: bl = PCI device:function for USB1 controller, bh = PCI bus
308
; out: eax -> usb_controller for EHCI companion
309
proc usb_find_ehci_companion
310
; 1. Loop over all registered controllers.
311
        mov     eax, usb_controllers_list
312
.next:
313
        mov     eax, [eax+usb_controller.Next]
314
        cmp     eax, usb_controllers_list
315
        jz      .notfound
316
; 2. For every controller, check the type, ignore everything that is not EHCI.
317
        mov     edx, [eax+usb_controller.HardwareFunc]
318
        cmp     [edx+usb_hardware_func.ID], 'EHCI'
319
        jnz     .next
320
; 3. For EHCI controller, compare PCI coordinates with input data:
321
; bus and device must be the same, function can be different.
322
        mov     edx, [eax+usb_controller.PCICoordinates]
323
        xor     edx, ebx
324
        cmp     dx, 8
325
        jae     .next
326
        ret
327
.notfound:
328
        xor     eax, eax
329
        ret
330
endp
331
 
332
; Find Transaction Translator hub and port for the given device.
333
; in: edx = parent hub for the device, ecx = port for the device
334
; out: edx = TT hub for the device, ecx = TT port for the device.
335
proc usb_get_tt
336
; If the parent hub is high-speed, it is TT for the device.
337
; Otherwise, the parent hub itself is behind TT, and the device
338
; has the same TT hub+port as the parent hub.
339
        mov     eax, [edx+usb_hub.ConfigPipe]
340
        mov     eax, [eax+usb_pipe.DeviceData]
341
        cmp     [eax+usb_device_data.Speed], USB_SPEED_HS
342
        jz      @f
343
        movzx   ecx, [eax+usb_device_data.TTPort]
344
        mov     edx, [eax+usb_device_data.TTHub]
345
@@:
346
        mov     edx, [edx+usb_hub.ConfigPipe]
347
        ret
348
endp