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