Rev 4418 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4418 | Rev 4547 | ||
---|---|---|---|
1 | ; Implementation of periodic transaction scheduler for USB. |
1 | ; Implementation of periodic transaction scheduler for USB. |
2 | ; Bandwidth dedicated to periodic transactions is limited, so |
2 | ; Bandwidth dedicated to periodic transactions is limited, so |
3 | ; different pipes should be scheduled as uniformly as possible. |
3 | ; different pipes should be scheduled as uniformly as possible. |
4 | 4 | ||
5 | ; USB2 scheduler. |
5 | ; USB2 scheduler. |
6 | ; There are two parts: high-speed pipes and split-transaction pipes. |
6 | ; There are two parts: high-speed pipes and split-transaction pipes. |
7 | ; |
7 | ; |
8 | ; High-speed scheduler uses the same algorithm as USB1 scheduler: |
8 | ; High-speed scheduler uses the same algorithm as USB1 scheduler: |
9 | ; when adding a pipe, optimize the following quantity: |
9 | ; when adding a pipe, optimize the following quantity: |
10 | ; * for every microframe, take all bandwidth scheduled to periodic transfers, |
10 | ; * for every microframe, take all bandwidth scheduled to periodic transfers, |
11 | ; * calculate maximum over all microframes, |
11 | ; * calculate maximum over all microframes, |
12 | ; * select a variant which minimizes that maximum; |
12 | ; * select a variant which minimizes that maximum; |
13 | ; * if there are several such variants, |
13 | ; * if there are several such variants, |
14 | ; prefer those that are closer to end of frame |
14 | ; prefer those that are closer to end of frame |
15 | ; to minimize collisions with split transactions; |
15 | ; to minimize collisions with split transactions; |
16 | ; when removing a pipe, do nothing (except for bookkeeping). |
16 | ; when removing a pipe, do nothing (except for bookkeeping). |
17 | ; in: esi -> usb_controller |
17 | ; in: esi -> usb_controller |
18 | ; out: edx -> usb_static_ep, eax = S-Mask |
18 | ; out: edx -> usb_static_ep, eax = S-Mask |
19 | proc ehci_select_hs_interrupt_list |
19 | proc ehci_select_hs_interrupt_list |
20 | ; inherit some variables from usb_open_pipe |
20 | ; inherit some variables from usb_open_pipe |
21 | virtual at ebp-12 |
21 | virtual at ebp-12 |
22 | .targetsmask dd ? |
22 | .targetsmask dd ? |
23 | .bandwidth dd ? |
23 | .bandwidth dd ? |
24 | .target dd ? |
24 | .target dd ? |
25 | dd ? |
25 | dd ? |
26 | dd ? |
26 | dd ? |
27 | .config_pipe dd ? |
27 | .config_pipe dd ? |
28 | .endpoint dd ? |
28 | .endpoint dd ? |
29 | .maxpacket dd ? |
29 | .maxpacket dd ? |
30 | .type dd ? |
30 | .type dd ? |
31 | .interval dd ? |
31 | .interval dd ? |
32 | end virtual |
32 | end virtual |
33 | ; prolog, initialize local vars |
33 | ; prolog, initialize local vars |
34 | or [.bandwidth], -1 |
34 | or [.bandwidth], -1 |
35 | or [.target], -1 |
35 | or [.target], -1 |
36 | or [.targetsmask], -1 |
36 | or [.targetsmask], -1 |
37 | push ebx edi ; save used registers to be stdcall |
37 | push ebx edi ; save used registers to be stdcall |
38 | ; 1. In EHCI, every list describes one millisecond = 8 microframes. |
38 | ; 1. In EHCI, every list describes one millisecond = 8 microframes. |
39 | ; Thus, there are two significantly different branches: |
39 | ; Thus, there are two significantly different branches: |
40 | ; for pipes with interval >= 8 microframes, advance to 2, |
40 | ; for pipes with interval >= 8 microframes, advance to 2, |
41 | ; for pipes which should be planned in every frame (one or more microframes), |
41 | ; for pipes which should be planned in every frame (one or more microframes), |
42 | ; go to 9. |
42 | ; go to 9. |
43 | ; Note: the actual interval for high-speed devices is 2^([.interval]-1), |
43 | ; Note: the actual interval for high-speed devices is 2^([.interval]-1), |
44 | ; (the core specification forbids [.interval] == 0) |
44 | ; (the core specification forbids [.interval] == 0) |
45 | mov ecx, [.interval] |
45 | mov ecx, [.interval] |
46 | dec ecx |
46 | dec ecx |
47 | cmp ecx, 3 |
47 | cmp ecx, 3 |
48 | jb .every_frame |
48 | jb .every_frame |
49 | ; 2. Determine the actual interval in milliseconds. |
49 | ; 2. Determine the actual interval in milliseconds. |
50 | sub ecx, 3 |
50 | sub ecx, 3 |
51 | cmp ecx, 5 ; maximum 32ms |
51 | cmp ecx, 5 ; maximum 32ms |
52 | jbe @f |
52 | jbe @f |
53 | movi ecx, 5 |
53 | movi ecx, 5 |
54 | @@: |
54 | @@: |
55 | ; There are four nested loops, |
55 | ; There are four nested loops, |
56 | ; * Loop #4 (the innermost one) calculates the total periodic bandwidth |
56 | ; * Loop #4 (the innermost one) calculates the total periodic bandwidth |
57 | ; scheduled in the given microframe of the given millisecond. |
57 | ; scheduled in the given microframe of the given millisecond. |
58 | ; * Loop #3 calculates the maximum over all milliseconds |
58 | ; * Loop #3 calculates the maximum over all milliseconds |
59 | ; in the given variant, that is the quantity we're trying to minimize. |
59 | ; in the given variant, that is the quantity we're trying to minimize. |
60 | ; * Loops #1 and #2 check all variants; |
60 | ; * Loops #1 and #2 check all variants; |
61 | ; loop #1 is responsible for the target millisecond, |
61 | ; loop #1 is responsible for the target millisecond, |
62 | ; loop #2 is responsible for the microframe within millisecond. |
62 | ; loop #2 is responsible for the microframe within millisecond. |
63 | ; 3. Prepare for loops. |
63 | ; 3. Prepare for loops. |
64 | ; ebx = number of iterations of loop #1 |
64 | ; ebx = number of iterations of loop #1 |
65 | ; [esp] = delta of counter for loop #3, in bytes |
65 | ; [esp] = delta of counter for loop #3, in bytes |
66 | ; [esp+4] = delta between the first group and the target group, in bytes |
66 | ; [esp+4] = delta between the first group and the target group, in bytes |
67 | movi ebx, 1 |
67 | movi ebx, 1 |
68 | movi edx, sizeof.ehci_static_ep |
68 | movi edx, sizeof.ehci_static_ep |
69 | shl ebx, cl |
69 | shl ebx, cl |
70 | shl edx, cl |
70 | shl edx, cl |
71 | mov eax, 64*sizeof.ehci_static_ep |
71 | mov eax, 64*sizeof.ehci_static_ep |
72 | sub eax, edx |
72 | sub eax, edx |
73 | sub eax, edx |
73 | sub eax, edx |
74 | push eax |
74 | push eax |
75 | push edx |
75 | push edx |
76 | ; 4. Select the best variant. |
76 | ; 4. Select the best variant. |
77 | ; 4a. Loop #1: initialize counter = pointer to ehci_static_ep for |
77 | ; 4a. Loop #1: initialize counter = pointer to ehci_static_ep for |
78 | ; the target millisecond in the first group. |
78 | ; the target millisecond in the first group. |
79 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
79 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
80 | .varloop0: |
80 | .varloop0: |
81 | ; 4b. Loop #2: initialize counter = microframe within the target millisecond. |
81 | ; 4b. Loop #2: initialize counter = microframe within the target millisecond. |
82 | xor ecx, ecx |
82 | xor ecx, ecx |
83 | .varloop: |
83 | .varloop: |
84 | ; 4c. Loop #3: save counter of loop #1, |
84 | ; 4c. Loop #3: save counter of loop #1, |
85 | ; initialize counter with the value of loop #1 counter, |
85 | ; initialize counter with the value of loop #1 counter, |
86 | ; initialize maximal bandwidth = zero. |
86 | ; initialize maximal bandwidth = zero. |
87 | xor edi, edi |
87 | xor edi, edi |
88 | push edx |
88 | push edx |
89 | virtual at esp |
89 | virtual at esp |
90 | .saved_counter1 dd ? ; step 4c |
90 | .saved_counter1 dd ? ; step 4c |
91 | .loop3_delta dd ? ; step 3 |
91 | .loop3_delta dd ? ; step 3 |
92 | .target_delta dd ? ; step 3 |
92 | .target_delta dd ? ; step 3 |
93 | end virtual |
93 | end virtual |
94 | .calc_max_bandwidth: |
94 | .calc_max_bandwidth: |
95 | ; 4d. Loop #4: initialize counter with the value of loop #3 counter, |
95 | ; 4d. Loop #4: initialize counter with the value of loop #3 counter, |
96 | ; initialize total bandwidth = zero. |
96 | ; initialize total bandwidth = zero. |
97 | xor eax, eax |
97 | xor eax, eax |
98 | push edx |
98 | push edx |
99 | .calc_bandwidth: |
99 | .calc_bandwidth: |
100 | ; 4e. Loop #4: add the bandwidth from the current list |
100 | ; 4e. Loop #4: add the bandwidth from the current list |
101 | ; and advance to the next list, while there is one. |
101 | ; and advance to the next list, while there is one. |
102 | add ax, [edx+ehci_static_ep.Bandwidths+ecx*2] |
102 | add ax, [edx+ehci_static_ep.Bandwidths+ecx*2] |
103 | mov edx, [edx+ehci_static_ep.NextList] |
103 | mov edx, [edx+ehci_static_ep.NextList] |
104 | test edx, edx |
104 | test edx, edx |
105 | jnz .calc_bandwidth |
105 | jnz .calc_bandwidth |
106 | ; 4f. Loop #4 end: restore counter of loop #3. |
106 | ; 4f. Loop #4 end: restore counter of loop #3. |
107 | pop edx |
107 | pop edx |
108 | ; 4g. Loop #3: update maximal bandwidth. |
108 | ; 4g. Loop #3: update maximal bandwidth. |
109 | cmp eax, edi |
109 | cmp eax, edi |
110 | jb @f |
110 | jb @f |
111 | mov edi, eax |
111 | mov edi, eax |
112 | @@: |
112 | @@: |
113 | ; 4h. Loop #3: advance the counter and repeat while within the first group. |
113 | ; 4h. Loop #3: advance the counter and repeat while within the first group. |
114 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
114 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
115 | add edx, [.loop3_delta] |
115 | add edx, [.loop3_delta] |
116 | cmp edx, eax |
116 | cmp edx, eax |
117 | jb .calc_max_bandwidth |
117 | jb .calc_max_bandwidth |
118 | ; 4i. Loop #3 end: restore counter of loop #1. |
118 | ; 4i. Loop #3 end: restore counter of loop #1. |
119 | pop edx |
119 | pop edx |
120 | ; 4j. Loop #2: if the current variant is better (maybe not strictly) |
120 | ; 4j. Loop #2: if the current variant is better (maybe not strictly) |
121 | ; then the previous optimum, update the optimal bandwidth and the target. |
121 | ; then the previous optimum, update the optimal bandwidth and the target. |
122 | cmp edi, [.bandwidth] |
122 | cmp edi, [.bandwidth] |
123 | ja @f |
123 | ja @f |
124 | jb .update |
124 | jb .update |
125 | cmp ecx, [.targetsmask] |
125 | cmp ecx, [.targetsmask] |
126 | jb @f |
126 | jb @f |
127 | .update: |
127 | .update: |
128 | mov [.bandwidth], edi |
128 | mov [.bandwidth], edi |
129 | mov [.target], edx |
129 | mov [.target], edx |
130 | mov [.targetsmask], ecx |
130 | mov [.targetsmask], ecx |
131 | @@: |
131 | @@: |
132 | ; 4k. Loop #2: continue 8 times for every microframe. |
132 | ; 4k. Loop #2: continue 8 times for every microframe. |
133 | inc ecx |
133 | inc ecx |
134 | cmp ecx, 8 |
134 | cmp ecx, 8 |
135 | jb .varloop |
135 | jb .varloop |
136 | ; 4l. Loop #1: advance counter and repeat ebx times, |
136 | ; 4l. Loop #1: advance counter and repeat ebx times, |
137 | ; ebx was calculated in step 3. |
137 | ; ebx was calculated in step 3. |
138 | add edx, sizeof.ehci_static_ep |
138 | add edx, sizeof.ehci_static_ep |
139 | dec ebx |
139 | dec ebx |
140 | jnz .varloop0 |
140 | jnz .varloop0 |
141 | ; 5. Calculate bandwidth for the new pipe. |
141 | ; 5. Calculate bandwidth for the new pipe. |
142 | mov eax, [.maxpacket] |
142 | mov eax, [.maxpacket] |
143 | call calc_hs_bandwidth |
143 | call calc_hs_bandwidth |
144 | mov ecx, [.maxpacket] |
144 | mov ecx, [.maxpacket] |
145 | shr ecx, 11 |
145 | shr ecx, 11 |
146 | inc ecx |
146 | inc ecx |
147 | and ecx, 3 |
147 | and ecx, 3 |
148 | imul eax, ecx |
148 | imul eax, ecx |
149 | ; 6. Get the pointer to the best list. |
149 | ; 6. Get the pointer to the best list. |
150 | pop edx ; restore value from step 3 |
150 | pop edx ; restore value from step 3 |
151 | pop edx ; get delta calculated in step 3 |
151 | pop edx ; get delta calculated in step 3 |
152 | add edx, [.target] |
152 | add edx, [.target] |
153 | ; 7. Check that bandwidth for the new pipe plus old bandwidth |
153 | ; 7. Check that bandwidth for the new pipe plus old bandwidth |
154 | ; still fits to maximum allowed by the core specification |
154 | ; still fits to maximum allowed by the core specification |
155 | ; current [.bandwidth] + new bandwidth <= limit; |
155 | ; current [.bandwidth] + new bandwidth <= limit; |
156 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe |
156 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe |
157 | mov ecx, [.bandwidth] |
157 | mov ecx, [.bandwidth] |
158 | add ecx, eax |
158 | add ecx, eax |
159 | cmp ecx, 48000 |
159 | cmp ecx, 48000 |
160 | ja .no_bandwidth |
160 | ja .no_bandwidth |
161 | ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
161 | ; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return. |
162 | mov ecx, [.targetsmask] |
162 | mov ecx, [.targetsmask] |
163 | add [edx+ehci_static_ep.Bandwidths+ecx*2], ax |
163 | add [edx+ehci_static_ep.Bandwidths+ecx*2], ax |
164 | add edx, ehci_static_ep.SoftwarePart |
164 | add edx, ehci_static_ep.SoftwarePart |
165 | movi eax, 1 |
165 | movi eax, 1 |
166 | shl eax, cl |
166 | shl eax, cl |
167 | pop edi ebx ; restore used registers to be stdcall |
167 | pop edi ebx ; restore used registers to be stdcall |
168 | ret |
168 | ret |
169 | .no_bandwidth: |
169 | .no_bandwidth: |
170 | dbgstr 'Periodic bandwidth limit reached' |
170 | dbgstr 'Periodic bandwidth limit reached' |
171 | xor eax, eax |
171 | xor eax, eax |
172 | xor edx, edx |
172 | xor edx, edx |
173 | pop edi ebx |
173 | pop edi ebx |
174 | ret |
174 | ret |
175 | .every_frame: |
175 | .every_frame: |
176 | ; The pipe should be scheduled every frame in two or more microframes. |
176 | ; The pipe should be scheduled every frame in two or more microframes. |
177 | ; 9. Calculate maximal bandwidth for every microframe: three nested loops. |
177 | ; 9. Calculate maximal bandwidth for every microframe: three nested loops. |
178 | ; 9a. The outermost loop: ebx = microframe to calculate. |
178 | ; 9a. The outermost loop: ebx = microframe to calculate. |
179 | xor ebx, ebx |
179 | xor ebx, ebx |
180 | .calc_all_bandwidths: |
180 | .calc_all_bandwidths: |
181 | ; 9b. The intermediate loop: |
181 | ; 9b. The intermediate loop: |
182 | ; edx = pointer to ehci_static_ep in the first group, [esp] = counter, |
182 | ; edx = pointer to ehci_static_ep in the first group, [esp] = counter, |
183 | ; edi = maximal bandwidth |
183 | ; edi = maximal bandwidth |
184 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
184 | lea edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
185 | xor edi, edi |
185 | xor edi, edi |
186 | push 32 |
186 | push 32 |
187 | .calc_max_bandwidth2: |
187 | .calc_max_bandwidth2: |
188 | ; 9c. The innermost loop: calculate bandwidth for the given microframe |
188 | ; 9c. The innermost loop: calculate bandwidth for the given microframe |
189 | ; in the given frame. |
189 | ; in the given frame. |
190 | xor eax, eax |
190 | xor eax, eax |
191 | push edx |
191 | push edx |
192 | .calc_bandwidth2: |
192 | .calc_bandwidth2: |
193 | add ax, [edx+ehci_static_ep.Bandwidths+ebx*2] |
193 | add ax, [edx+ehci_static_ep.Bandwidths+ebx*2] |
194 | mov edx, [edx+ehci_static_ep.NextList] |
194 | mov edx, [edx+ehci_static_ep.NextList] |
195 | test edx, edx |
195 | test edx, edx |
196 | jnz .calc_bandwidth2 |
196 | jnz .calc_bandwidth2 |
197 | pop edx |
197 | pop edx |
198 | ; 9d. The intermediate loop continued: update maximal bandwidth. |
198 | ; 9d. The intermediate loop continued: update maximal bandwidth. |
199 | cmp eax, edi |
199 | cmp eax, edi |
200 | jb @f |
200 | jb @f |
201 | mov edi, eax |
201 | mov edi, eax |
202 | @@: |
202 | @@: |
203 | add edx, sizeof.ehci_static_ep |
203 | add edx, sizeof.ehci_static_ep |
204 | dec dword [esp] |
204 | dec dword [esp] |
205 | jnz .calc_max_bandwidth2 |
205 | jnz .calc_max_bandwidth2 |
206 | pop eax |
206 | pop eax |
207 | ; 9e. Push the calculated maximal bandwidth and continue the outermost loop. |
207 | ; 9e. Push the calculated maximal bandwidth and continue the outermost loop. |
208 | push edi |
208 | push edi |
209 | inc ebx |
209 | inc ebx |
210 | cmp ebx, 8 |
210 | cmp ebx, 8 |
211 | jb .calc_all_bandwidths |
211 | jb .calc_all_bandwidths |
212 | virtual at esp |
212 | virtual at esp |
213 | .bandwidth7 dd ? |
213 | .bandwidth7 dd ? |
214 | .bandwidth6 dd ? |
214 | .bandwidth6 dd ? |
215 | .bandwidth5 dd ? |
215 | .bandwidth5 dd ? |
216 | .bandwidth4 dd ? |
216 | .bandwidth4 dd ? |
217 | .bandwidth3 dd ? |
217 | .bandwidth3 dd ? |
218 | .bandwidth2 dd ? |
218 | .bandwidth2 dd ? |
219 | .bandwidth1 dd ? |
219 | .bandwidth1 dd ? |
220 | .bandwidth0 dd ? |
220 | .bandwidth0 dd ? |
221 | end virtual |
221 | end virtual |
222 | ; 10. Select the best variant. |
222 | ; 10. Select the best variant. |
223 | ; edx = S-Mask = bitmask of scheduled microframes |
223 | ; edx = S-Mask = bitmask of scheduled microframes |
224 | movi edx, 0x11 |
224 | movi edx, 0x11 |
225 | cmp ecx, 1 |
225 | cmp ecx, 1 |
226 | ja @f |
226 | ja @f |
227 | mov dl, 0x55 |
227 | mov dl, 0x55 |
228 | jz @f |
228 | jz @f |
229 | mov dl, 0xFF |
229 | mov dl, 0xFF |
230 | @@: |
230 | @@: |
231 | ; try all variants edx, edx shl 1, edx shl 2, ... |
231 | ; try all variants edx, edx shl 1, edx shl 2, ... |
232 | ; while they fit in the lower byte (8 microframes per frame) |
232 | ; while they fit in the lower byte (8 microframes per frame) |
233 | .select_best_mframe: |
233 | .select_best_mframe: |
234 | xor edi, edi |
234 | xor edi, edi |
235 | mov ecx, edx |
235 | mov ecx, edx |
236 | mov eax, esp |
236 | mov eax, esp |
237 | .calc_mframe: |
237 | .calc_mframe: |
238 | add cl, cl |
238 | add cl, cl |
239 | jnc @f |
239 | jnc @f |
240 | cmp edi, [eax] |
240 | cmp edi, [eax] |
241 | jae @f |
241 | jae @f |
242 | mov edi, [eax] |
242 | mov edi, [eax] |
243 | @@: |
243 | @@: |
244 | add eax, 4 |
244 | add eax, 4 |
245 | test cl, cl |
245 | test cl, cl |
246 | jnz .calc_mframe |
246 | jnz .calc_mframe |
247 | cmp [.bandwidth], edi |
247 | cmp [.bandwidth], edi |
248 | jb @f |
248 | jb @f |
249 | mov [.bandwidth], edi |
249 | mov [.bandwidth], edi |
250 | mov [.targetsmask], edx |
250 | mov [.targetsmask], edx |
251 | @@: |
251 | @@: |
252 | add dl, dl |
252 | add dl, dl |
253 | jnc .select_best_mframe |
253 | jnc .select_best_mframe |
254 | ; 11. Restore stack after step 9. |
254 | ; 11. Restore stack after step 9. |
255 | add esp, 8*4 |
255 | add esp, 8*4 |
256 | ; 12. Get the pointer to the target list (responsible for every microframe). |
256 | ; 12. Get the pointer to the target list (responsible for every microframe). |
257 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] |
257 | lea edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller] |
258 | ; 13. Calculate bandwidth on the bus. |
258 | ; 13. Calculate bandwidth on the bus. |
259 | mov eax, [.maxpacket] |
259 | mov eax, [.maxpacket] |
260 | call calc_hs_bandwidth |
260 | call calc_hs_bandwidth |
261 | mov ecx, [.maxpacket] |
261 | mov ecx, [.maxpacket] |
262 | shr ecx, 11 |
262 | shr ecx, 11 |
263 | inc ecx |
263 | inc ecx |
264 | and ecx, 3 |
264 | and ecx, 3 |
265 | imul eax, ecx |
265 | imul eax, ecx |
266 | ; 14. Check that current [.bandwidth] + new bandwidth <= limit; |
266 | ; 14. Check that current [.bandwidth] + new bandwidth <= limit; |
267 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
267 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
268 | mov ecx, [.bandwidth] |
268 | mov ecx, [.bandwidth] |
269 | add ecx, eax |
269 | add ecx, eax |
270 | cmp ecx, 48000 |
270 | cmp ecx, 48000 |
271 | ja .no_bandwidth |
271 | ja .no_bandwidth |
272 | ; 15. Update bandwidths including the new pipe. |
272 | ; 15. Update bandwidths including the new pipe. |
273 | mov ecx, [.targetsmask] |
273 | mov ecx, [.targetsmask] |
274 | lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] |
274 | lea edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart] |
275 | .update_bandwidths: |
275 | .update_bandwidths: |
276 | shr ecx, 1 |
276 | shr ecx, 1 |
277 | jnc @f |
277 | jnc @f |
278 | add [edi], ax |
278 | add [edi], ax |
279 | @@: |
279 | @@: |
280 | add edi, 2 |
280 | add edi, 2 |
281 | test ecx, ecx |
281 | test ecx, ecx |
282 | jnz .update_bandwidths |
282 | jnz .update_bandwidths |
283 | ; 16. Return target list and target S-Mask. |
283 | ; 16. Return target list and target S-Mask. |
284 | mov eax, [.targetsmask] |
284 | mov eax, [.targetsmask] |
285 | pop edi ebx ; restore used registers to be stdcall |
285 | pop edi ebx ; restore used registers to be stdcall |
286 | ret |
286 | ret |
287 | endp |
287 | endp |
288 | 288 | ||
289 | ; Pipe is removing, update the corresponding lists. |
289 | ; Pipe is removing, update the corresponding lists. |
290 | ; We do not reorder anything, so just update book-keeping variable |
290 | ; We do not reorder anything, so just update book-keeping variable |
291 | ; in the list header. |
291 | ; in the list header. |
292 | proc ehci_hs_interrupt_list_unlink |
292 | proc ehci_hs_interrupt_list_unlink |
293 | movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
293 | movzx eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2] |
294 | ; calculate bandwidth |
294 | ; calculate bandwidth |
295 | call calc_hs_bandwidth |
295 | call calc_hs_bandwidth |
296 | mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
296 | mov ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
297 | shr ecx, 30 |
297 | shr ecx, 30 |
298 | imul eax, ecx |
298 | imul eax, ecx |
299 | movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
299 | movzx ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
300 | ; get target list |
300 | ; get target list |
301 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
301 | mov edx, [ebx+usb_pipe.BaseList] |
302 | ; update bandwidth |
302 | ; update bandwidth |
303 | .dec_bandwidth: |
303 | .dec_bandwidth: |
304 | shr ecx, 1 |
304 | shr ecx, 1 |
305 | jnc @f |
305 | jnc @f |
306 | sub word [edx+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
306 | sub word [edx+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
307 | @@: |
307 | @@: |
308 | add edx, 2 |
308 | add edx, 2 |
309 | test ecx, ecx |
309 | test ecx, ecx |
310 | jnz .dec_bandwidth |
310 | jnz .dec_bandwidth |
311 | ; return |
311 | ; return |
312 | ret |
312 | ret |
313 | endp |
313 | endp |
314 | 314 | ||
315 | ; Helper procedure for USB2 scheduler: calculate bandwidth on the bus. |
315 | ; Helper procedure for USB2 scheduler: calculate bandwidth on the bus. |
316 | ; in: low 11 bits of eax = payload size in bytes |
316 | ; in: low 11 bits of eax = payload size in bytes |
317 | ; out: eax = maximal bandwidth in HS-bits |
317 | ; out: eax = maximal bandwidth in HS-bits |
318 | proc calc_hs_bandwidth |
318 | proc calc_hs_bandwidth |
319 | and eax, (1 shl 11) - 1 ; get payload for one transaction |
319 | and eax, (1 shl 11) - 1 ; get payload for one transaction |
320 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
320 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
321 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
321 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
322 | ; total 28/3 = 9+1/3 |
322 | ; total 28/3 = 9+1/3 |
323 | mov edx, 55555556h |
323 | mov edx, 55555556h |
324 | lea ecx, [eax*9] |
324 | lea ecx, [eax*9] |
325 | mul edx |
325 | mul edx |
326 | ; Add 989 extra bits: 68 bits for Token packet (32 for SYNC, 24 for token+address, |
326 | ; Add 989 extra bits: 68 bits for Token packet (32 for SYNC, 24 for token+address, |
327 | ; 4 extra bits for possible bit stuffing in token+address, 8 for EOP), |
327 | ; 4 extra bits for possible bit stuffing in token+address, 8 for EOP), |
328 | ; 736 bits for bus turn-around, 40 bits for SYNC+EOP in Data packet, |
328 | ; 736 bits for bus turn-around, 40 bits for SYNC+EOP in Data packet, |
329 | ; 8 bits for inter-packet delay, 49 bits for Handshake packet, |
329 | ; 8 bits for inter-packet delay, 49 bits for Handshake packet, |
330 | ; 88 bits for another inter-packet delay. |
330 | ; 88 bits for another inter-packet delay. |
331 | lea eax, [ecx+edx+989] |
331 | lea eax, [ecx+edx+989] |
332 | ret |
332 | ret |
333 | endp |
333 | endp |
334 | 334 | ||
335 | ; Split-transaction scheduler (aka TT scheduler, TT stands for Transaction |
335 | ; Split-transaction scheduler (aka TT scheduler, TT stands for Transaction |
336 | ; Translator, section 11.14 of the core spec) needs to schedule three event |
336 | ; Translator, section 11.14 of the core spec) needs to schedule three event |
337 | ; types on two buses: Start-Split and Complete-Split on HS bus and normal |
337 | ; types on two buses: Start-Split and Complete-Split on HS bus and normal |
338 | ; transaction on FS/LS bus. |
338 | ; transaction on FS/LS bus. |
339 | ; Assume that FS/LS bus is more restricted and more important to be scheduled |
339 | ; Assume that FS/LS bus is more restricted and more important to be scheduled |
340 | ; uniformly, so select the variant which minimizes maximal used bandwidth |
340 | ; uniformly, so select the variant which minimizes maximal used bandwidth |
341 | ; on FS/LS bus and does not overflow HS bus. |
341 | ; on FS/LS bus and does not overflow HS bus. |
342 | ; If there are several such variants, prefer variants which is closest to |
342 | ; If there are several such variants, prefer variants which is closest to |
343 | ; start of frame, and within the same microframe consider HS bandwidth |
343 | ; start of frame, and within the same microframe consider HS bandwidth |
344 | ; utilization as a last criteria. |
344 | ; utilization as a last criteria. |
345 | 345 | ||
346 | ; The procedure ehci_select_tt_interrupt_list has been splitted into several |
346 | ; The procedure ehci_select_tt_interrupt_list has been splitted into several |
347 | ; macro, each representing a logical step of the procedure, |
347 | ; macro, each representing a logical step of the procedure, |
348 | ; to simplify understanding what is going on. Consider all the following macro |
348 | ; to simplify understanding what is going on. Consider all the following macro |
349 | ; as logical parts of one procedure, they are meaningless outside the context. |
349 | ; as logical parts of one procedure, they are meaningless outside the context. |
350 | 350 | ||
351 | ; Given a frame, calculate bandwidth occupied by already opened pipes |
351 | ; Given a frame, calculate bandwidth occupied by already opened pipes |
352 | ; in every microframe. |
352 | ; in every microframe. |
353 | ; Look for both HS and FS/LS buses: there are 16 words of information, |
353 | ; Look for both HS and FS/LS buses: there are 16 words of information, |
354 | ; 8 for HS bus, 8 for FS/LS bus, for every microframe. |
354 | ; 8 for HS bus, 8 for FS/LS bus, for every microframe. |
355 | ; Since we count already opened pipes, the total bandwidth in every microframe |
355 | ; Since we count already opened pipes, the total bandwidth in every microframe |
356 | ; is less than 60000 bits (and even 60000*80% bits), otherwise the scheduler |
356 | ; is less than 60000 bits (and even 60000*80% bits), otherwise the scheduler |
357 | ; would not allow to open those pipes. |
357 | ; would not allow to open those pipes. |
358 | ; edi -> first list for the frame |
358 | ; edi -> first list for the frame |
359 | macro tt_calc_bandwidth_in_frame |
359 | macro tt_calc_bandwidth_in_frame |
360 | { |
360 | { |
361 | local .lists, .pipes, .pipes_done, .carry |
361 | local .lists, .pipes, .pipes_done, .carry |
362 | ; 1. Zero everything. |
362 | ; 1. Zero everything. |
363 | xor eax, eax |
363 | xor eax, eax |
364 | mov edx, edi |
364 | mov edx, edi |
365 | repeat 4 |
365 | repeat 4 |
366 | mov dword [.budget+(%-1)*4], eax |
366 | mov dword [.budget+(%-1)*4], eax |
367 | end repeat |
367 | end repeat |
368 | repeat 4 |
368 | repeat 4 |
369 | mov dword [.hs_bandwidth+(%-1)*4], eax |
369 | mov dword [.hs_bandwidth+(%-1)*4], eax |
370 | end repeat |
370 | end repeat |
371 | mov [.total_budget], ax |
371 | mov [.total_budget], ax |
372 | ; Loop over all lists for the given frame. |
372 | ; Loop over all lists for the given frame. |
373 | .lists: |
373 | .lists: |
374 | ; 2. Total HS bandwidth for all pipes in one list is kept inside list header, |
374 | ; 2. Total HS bandwidth for all pipes in one list is kept inside list header, |
375 | ; add it. Note that overflow is impossible, so we may add entire dwords. |
375 | ; add it. Note that overflow is impossible, so we may add entire dwords. |
376 | mov ebx, [edx+ehci_static_ep.SoftwarePart+usb_static_ep.NextVirt] |
376 | mov ebx, [edx+ehci_static_ep.SoftwarePart+usb_static_ep.NextVirt] |
377 | repeat 4 |
377 | repeat 4 |
378 | mov eax, dword [edx+ehci_static_ep.Bandwidths+(%-1)*4] |
378 | mov eax, dword [edx+ehci_static_ep.Bandwidths+(%-1)*4] |
379 | add dword [.hs_bandwidth+(%-1)*4], eax |
379 | add dword [.hs_bandwidth+(%-1)*4], eax |
380 | end repeat |
380 | end repeat |
381 | ; Loop over all pipes in the given list. |
381 | ; Loop over all pipes in the given list. |
382 | add edx, ehci_static_ep.SoftwarePart |
382 | add edx, ehci_static_ep.SoftwarePart |
383 | .pipes: |
383 | .pipes: |
384 | cmp ebx, edx |
384 | cmp ebx, edx |
385 | jz .pipes_done |
385 | jz .pipes_done |
386 | ; 3. For every pipe in every list for the given frame: |
386 | ; 3. For every pipe in every list for the given frame: |
387 | ; 3a. Check whether the pipe resides on the same FS/LS bus as the new pipe. |
387 | ; 3a. Check whether the pipe resides on the same FS/LS bus as the new pipe. |
388 | ; If not, skip this pipe. |
388 | ; If not, skip this pipe. |
389 | mov eax, [ebx+usb_pipe.DeviceData] |
389 | mov eax, [ebx+usb_pipe.DeviceData] |
390 | mov eax, [eax+usb_device_data.TTHub] |
390 | mov eax, [eax+usb_device_data.TTHub] |
391 | cmp eax, [.tthub] |
391 | cmp eax, [.tthub] |
392 | jnz @f |
392 | jnz @f |
393 | ; 3b. Calculate FS/LS budget for the opened pipe. |
393 | ; 3b. Calculate FS/LS budget for the opened pipe. |
394 | ; Note that eax = TTHub after 3a. |
394 | ; Note that eax = TTHub after 3a. |
395 | call tt_calc_budget |
395 | call tt_calc_budget |
396 | ; 3c. Update total budget: add the value from 3b |
396 | ; 3c. Update total budget: add the value from 3b |
397 | ; to the budget of the first microframe scheduled for this pipe. |
397 | ; to the budget of the first microframe scheduled for this pipe. |
398 | bsf ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
398 | bsf ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe] |
399 | add [.budget+ecx*2], ax |
399 | add [.budget+ecx*2], ax |
400 | @@: |
400 | @@: |
401 | mov ebx, [ebx+usb_pipe.NextVirt] |
401 | mov ebx, [ebx+usb_pipe.NextVirt] |
402 | jmp .pipes |
402 | jmp .pipes |
403 | .pipes_done: |
403 | .pipes_done: |
404 | mov edx, [edx+ehci_static_ep.NextList-ehci_static_ep.SoftwarePart] |
404 | mov edx, [edx+ehci_static_ep.NextList-ehci_static_ep.SoftwarePart] |
405 | test edx, edx |
405 | test edx, edx |
406 | jnz .lists |
406 | jnz .lists |
407 | ; 4. If the budget for some microframe is exceeded, carry it to the following |
407 | ; 4. If the budget for some microframe is exceeded, carry it to the following |
408 | ; microframe(s). The actual size of one microframe is 187.5 raw bytes; |
408 | ; microframe(s). The actual size of one microframe is 187.5 raw bytes; |
409 | ; the core spec says that 188 bytes should be scheduled in every microframe. |
409 | ; the core spec says that 188 bytes should be scheduled in every microframe. |
410 | xor eax, eax |
410 | xor eax, eax |
411 | xor ecx, ecx |
411 | xor ecx, ecx |
412 | .carry: |
412 | .carry: |
413 | xor edx, edx |
413 | xor edx, edx |
414 | add ax, [.budget+ecx*2] |
414 | add ax, [.budget+ecx*2] |
415 | cmp ax, 188 |
415 | cmp ax, 188 |
416 | jbe @f |
416 | jbe @f |
417 | mov dx, ax |
417 | mov dx, ax |
418 | mov ax, 188 |
418 | mov ax, 188 |
419 | sub dx, ax |
419 | sub dx, ax |
420 | @@: |
420 | @@: |
421 | mov [.budget+ecx*2], ax |
421 | mov [.budget+ecx*2], ax |
422 | add [.total_budget], ax |
422 | add [.total_budget], ax |
423 | mov ax, dx |
423 | mov ax, dx |
424 | inc ecx |
424 | inc ecx |
425 | cmp ecx, 8 |
425 | cmp ecx, 8 |
426 | jb .carry |
426 | jb .carry |
427 | } |
427 | } |
428 | 428 | ||
429 | ; Checks whether the new pipe fits in the existing FS budget |
429 | ; Checks whether the new pipe fits in the existing FS budget |
430 | ; starting from the given microframe. If not, mark the microframe |
430 | ; starting from the given microframe. If not, mark the microframe |
431 | ; as impossible for scheduling. |
431 | ; as impossible for scheduling. |
432 | ; in: ecx = microframe |
432 | ; in: ecx = microframe |
433 | macro tt_exclude_microframe_if_no_budget |
433 | macro tt_exclude_microframe_if_no_budget |
434 | { |
434 | { |
435 | local .loop, .good, .bad |
435 | local .loop, .good, .bad |
436 | ; 1. If the new budget plus the current budget does not exceed 188 bytes, |
436 | ; 1. If the new budget plus the current budget does not exceed 188 bytes, |
437 | ; the variant is possible. |
437 | ; the variant is possible. |
438 | mov ax, [.budget+ecx*2] |
438 | mov ax, [.budget+ecx*2] |
439 | mov edx, ecx |
439 | mov edx, ecx |
440 | add ax, [.new_budget] |
440 | add ax, [.new_budget] |
441 | sub ax, 188 |
441 | sub ax, 188 |
442 | jbe .good |
442 | jbe .good |
443 | ; 2. Otherwise, |
443 | ; 2. Otherwise, |
444 | ; a) nothing should be scheduled in some following microframes, |
444 | ; a) nothing should be scheduled in some following microframes, |
445 | ; b) after adding the new budget everything should fit in first 6 microframes, |
445 | ; b) after adding the new budget everything should fit in first 6 microframes, |
446 | ; this guarantees that even in the worst case 90% limit is satisfied. |
446 | ; this guarantees that even in the worst case 90% limit is satisfied. |
447 | .loop: |
447 | .loop: |
448 | cmp edx, 5 |
448 | cmp edx, 5 |
449 | jae .bad |
449 | jae .bad |
450 | cmp [.budget+(edx+1)*2], 0 |
450 | cmp [.budget+(edx+1)*2], 0 |
451 | jnz .bad |
451 | jnz .bad |
452 | inc edx |
452 | inc edx |
453 | sub ax, 188 |
453 | sub ax, 188 |
454 | ja .loop |
454 | ja .loop |
455 | .bad: |
455 | .bad: |
456 | btr [.possible_microframes], ecx |
456 | btr [.possible_microframes], ecx |
457 | .good: |
457 | .good: |
458 | } |
458 | } |
459 | 459 | ||
460 | ; Calculate data corresponding to the particular scheduling variant for the new pipe. |
460 | ; Calculate data corresponding to the particular scheduling variant for the new pipe. |
461 | ; Data describe the current scheduling state collected over all frames touched |
461 | ; Data describe the current scheduling state collected over all frames touched |
462 | ; by the given variant: maximal HS bandwidth, maximal FS/LS budget, |
462 | ; by the given variant: maximal HS bandwidth, maximal FS/LS budget, |
463 | ; which microframes fit in the current FS/LS budget for all frames. |
463 | ; which microframes fit in the current FS/LS budget for all frames. |
464 | macro tt_calc_statistics_for_one_variant |
464 | macro tt_calc_statistics_for_one_variant |
465 | { |
465 | { |
466 | local .frames, .microframes |
466 | local .frames, .microframes |
467 | ; 1. Initialize: zero maximal bandwidth, |
467 | ; 1. Initialize: zero maximal bandwidth, |
468 | ; first 6 microframes are possible for scheduling. |
468 | ; first 6 microframes are possible for scheduling. |
469 | xor eax, eax |
469 | xor eax, eax |
470 | repeat 4 |
470 | repeat 4 |
471 | mov dword [.max_hs_bandwidth+(%-1)*4], eax |
471 | mov dword [.max_hs_bandwidth+(%-1)*4], eax |
472 | end repeat |
472 | end repeat |
473 | mov [.max_fs_bandwidth], ax |
473 | mov [.max_fs_bandwidth], ax |
474 | mov [.possible_microframes], 0x3F |
474 | mov [.possible_microframes], 0x3F |
475 | ; Loop over all frames starting with [.variant] advancing by [.variant_delta]. |
475 | ; Loop over all frames starting with [.variant] advancing by [.variant_delta]. |
476 | mov edi, [.variant] |
476 | mov edi, [.variant] |
477 | .frames: |
477 | .frames: |
478 | ; 2. Calculate statistics for one frame. |
478 | ; 2. Calculate statistics for one frame. |
479 | tt_calc_bandwidth_in_frame |
479 | tt_calc_bandwidth_in_frame |
480 | ; 3. Update maximal FS budget. |
480 | ; 3. Update maximal FS budget. |
481 | mov ax, [.total_budget] |
481 | mov ax, [.total_budget] |
482 | cmp ax, [.max_fs_bandwidth] |
482 | cmp ax, [.max_fs_bandwidth] |
483 | jb @f |
483 | jb @f |
484 | mov [.max_fs_bandwidth], ax |
484 | mov [.max_fs_bandwidth], ax |
485 | @@: |
485 | @@: |
486 | ; 4. For every microframe, update maximal HS bandwidth |
486 | ; 4. For every microframe, update maximal HS bandwidth |
487 | ; and check whether the microframe is allowed for scheduling. |
487 | ; and check whether the microframe is allowed for scheduling. |
488 | xor ecx, ecx |
488 | xor ecx, ecx |
489 | .microframes: |
489 | .microframes: |
490 | mov ax, [.hs_bandwidth+ecx*2] |
490 | mov ax, [.hs_bandwidth+ecx*2] |
491 | cmp ax, [.max_hs_bandwidth+ecx*2] |
491 | cmp ax, [.max_hs_bandwidth+ecx*2] |
492 | jb @f |
492 | jb @f |
493 | mov [.max_hs_bandwidth+ecx*2], ax |
493 | mov [.max_hs_bandwidth+ecx*2], ax |
494 | @@: |
494 | @@: |
495 | tt_exclude_microframe_if_no_budget |
495 | tt_exclude_microframe_if_no_budget |
496 | inc ecx |
496 | inc ecx |
497 | cmp ecx, 8 |
497 | cmp ecx, 8 |
498 | jb .microframes |
498 | jb .microframes |
499 | ; Stop loop when outside of first descriptor group. |
499 | ; Stop loop when outside of first descriptor group. |
500 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
500 | lea eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller] |
501 | add edi, [.variant_delta] |
501 | add edi, [.variant_delta] |
502 | cmp edi, eax |
502 | cmp edi, eax |
503 | jb .frames |
503 | jb .frames |
504 | } |
504 | } |
505 | 505 | ||
506 | struct usb_split_info |
506 | struct usb_split_info |
507 | microframe_mask dd ? ; lower byte is S-mask, second byte is C-mask |
507 | microframe_mask dd ? ; lower byte is S-mask, second byte is C-mask |
508 | ssplit_bandwidth dd ? |
508 | ssplit_bandwidth dd ? |
509 | csplit_bandwidth dd ? |
509 | csplit_bandwidth dd ? |
510 | ends |
510 | ends |
511 | 511 | ||
512 | ; Check whether the current variant and the current microframe are allowed |
512 | ; Check whether the current variant and the current microframe are allowed |
513 | ; for scheduling. If so, check whether they are better than the previously |
513 | ; for scheduling. If so, check whether they are better than the previously |
514 | ; selected variant+microframe, if any. If so, update the previously selected |
514 | ; selected variant+microframe, if any. If so, update the previously selected |
515 | ; variant+microframe to current ones. |
515 | ; variant+microframe to current ones. |
516 | ; ecx = microframe, [.variant] = variant |
516 | ; ecx = microframe, [.variant] = variant |
517 | macro tt_check_variant_microframe |
517 | macro tt_check_variant_microframe |
518 | { |
518 | { |
519 | local .nothing, .update, .ssplit, .csplit, .csplit_done |
519 | local .nothing, .update, .ssplit, .csplit, .csplit_done |
520 | ; 1. If the current microframe does not fit in existing FS budget, do nothing. |
520 | ; 1. If the current microframe does not fit in existing FS budget, do nothing. |
521 | bt [.possible_microframes], ecx |
521 | bt [.possible_microframes], ecx |
522 | jnc .nothing |
522 | jnc .nothing |
523 | ; 2. Calculate maximal HS bandwidth over all affected microframes. |
523 | ; 2. Calculate maximal HS bandwidth over all affected microframes. |
524 | ; 2a. Start-split phase: one or more microframes starting with ecx, |
524 | ; 2a. Start-split phase: one or more microframes starting with ecx, |
525 | ; coded in lower byte of .info.microframe_mask. |
525 | ; coded in lower byte of .info.microframe_mask. |
526 | xor ebx, ebx |
526 | xor ebx, ebx |
527 | xor edx, edx |
527 | xor edx, edx |
528 | .ssplit: |
528 | .ssplit: |
529 | lea eax, [ecx+edx] |
529 | lea eax, [ecx+edx] |
530 | movzx eax, [.max_hs_bandwidth+eax*2] |
530 | movzx eax, [.max_hs_bandwidth+eax*2] |
531 | add eax, [.info.ssplit_bandwidth] |
531 | add eax, [.info.ssplit_bandwidth] |
532 | cmp ebx, eax |
532 | cmp ebx, eax |
533 | ja @f |
533 | ja @f |
534 | mov ebx, eax |
534 | mov ebx, eax |
535 | @@: |
535 | @@: |
536 | inc edx |
536 | inc edx |
537 | bt [.info.microframe_mask], edx |
537 | bt [.info.microframe_mask], edx |
538 | jc .ssplit |
538 | jc .ssplit |
539 | ; 2b. Complete-split phase: zero or more microframes starting with |
539 | ; 2b. Complete-split phase: zero or more microframes starting with |
540 | ; ecx+(last start-split microframe)+2, |
540 | ; ecx+(last start-split microframe)+2, |
541 | ; coded in second byte of .info.microframe_mask. |
541 | ; coded in second byte of .info.microframe_mask. |
542 | add edx, 8 |
542 | add edx, 8 |
543 | .csplit: |
543 | .csplit: |
544 | inc edx |
544 | inc edx |
545 | bt [.info.microframe_mask], edx |
545 | bt [.info.microframe_mask], edx |
546 | jnc .csplit_done |
546 | jnc .csplit_done |
547 | lea eax, [ecx+edx] |
547 | lea eax, [ecx+edx] |
548 | cmp eax, 8 |
548 | cmp eax, 8 |
549 | jae .csplit_done |
549 | jae .csplit_done |
550 | movzx eax, [.max_hs_bandwidth+(eax-8)*2] |
550 | movzx eax, [.max_hs_bandwidth+(eax-8)*2] |
551 | add eax, [.info.csplit_bandwidth] |
551 | add eax, [.info.csplit_bandwidth] |
552 | cmp ebx, eax |
552 | cmp ebx, eax |
553 | ja .csplit |
553 | ja .csplit |
554 | mov ebx, eax |
554 | mov ebx, eax |
555 | jmp .csplit |
555 | jmp .csplit |
556 | .csplit_done: |
556 | .csplit_done: |
557 | ; 3. Check that current HS bandwidth + new bandwidth <= limit; |
557 | ; 3. Check that current HS bandwidth + new bandwidth <= limit; |
558 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
558 | ; USB2 specification allows maximum 60000*80% bit times for periodic microframe. |
559 | cmp ebx, 48000 |
559 | cmp ebx, 48000 |
560 | ja .nothing |
560 | ja .nothing |
561 | ; 4. This variant is possible for scheduling. |
561 | ; 4. This variant is possible for scheduling. |
562 | ; Check whether it is better than the currently selected one. |
562 | ; Check whether it is better than the currently selected one. |
563 | ; 4a. The primary criteria: FS/LS bandwidth. |
563 | ; 4a. The primary criteria: FS/LS bandwidth. |
564 | mov ax, [.max_fs_bandwidth] |
564 | mov ax, [.max_fs_bandwidth] |
565 | cmp ax, [.best_fs_bandwidth] |
565 | cmp ax, [.best_fs_bandwidth] |
566 | ja .nothing |
566 | ja .nothing |
567 | jb .update |
567 | jb .update |
568 | ; 4b. The secondary criteria: prefer microframes which are closer to start of frame. |
568 | ; 4b. The secondary criteria: prefer microframes which are closer to start of frame. |
569 | cmp ecx, [.targetsmask] |
569 | cmp ecx, [.targetsmask] |
570 | ja .nothing |
570 | ja .nothing |
571 | jb .update |
571 | jb .update |
572 | ; 4c. The last criteria: HS bandwidth. |
572 | ; 4c. The last criteria: HS bandwidth. |
573 | cmp ebx, [.bandwidth] |
573 | cmp ebx, [.bandwidth] |
574 | ja .nothing |
574 | ja .nothing |
575 | .update: |
575 | .update: |
576 | ; 5. This variant is better than the previously selected. |
576 | ; 5. This variant is better than the previously selected. |
577 | ; Update the best variant with current data. |
577 | ; Update the best variant with current data. |
578 | mov [.best_fs_bandwidth], ax |
578 | mov [.best_fs_bandwidth], ax |
579 | mov [.bandwidth], ebx |
579 | mov [.bandwidth], ebx |
580 | mov [.targetsmask], ecx |
580 | mov [.targetsmask], ecx |
581 | mov eax, [.variant] |
581 | mov eax, [.variant] |
582 | mov [.target], eax |
582 | mov [.target], eax |
583 | .nothing: |
583 | .nothing: |
584 | } |
584 | } |
585 | 585 | ||
586 | ; TT scheduler: add new pipe. |
586 | ; TT scheduler: add new pipe. |
587 | ; in: esi -> usb_controller, edi -> usb_pipe |
587 | ; in: esi -> usb_controller, edi -> usb_pipe |
588 | ; out: edx -> usb_static_ep, eax = S-Mask |
588 | ; out: edx -> usb_static_ep, eax = S-Mask |
589 | proc ehci_select_tt_interrupt_list |
589 | proc ehci_select_tt_interrupt_list |
590 | virtual at ebp-12-.local_vars_size |
590 | virtual at ebp-12-.local_vars_size |
591 | .local_vars_start: |
591 | .local_vars_start: |
592 | .info usb_split_info |
592 | .info usb_split_info |
593 | .new_budget dw ? |
593 | .new_budget dw ? |
594 | .total_budget dw ? |
594 | .total_budget dw ? |
595 | .possible_microframes dd ? |
595 | .possible_microframes dd ? |
596 | .tthub dd ? |
596 | .tthub dd ? |
597 | .budget rw 8 |
597 | .budget rw 8 |
598 | .hs_bandwidth rw 8 |
598 | .hs_bandwidth rw 8 |
599 | .max_hs_bandwidth rw 8 |
599 | .max_hs_bandwidth rw 8 |
600 | .max_fs_bandwidth dw ? |
600 | .max_fs_bandwidth dw ? |
601 | .best_fs_bandwidth dw ? |
601 | .best_fs_bandwidth dw ? |
602 | .variant dd ? |
602 | .variant dd ? |
603 | .variant_delta dd ? |
603 | .variant_delta dd ? |
604 | .target_delta dd ? |
604 | .target_delta dd ? |
605 | .local_vars_size = $ - .local_vars_start |
605 | .local_vars_size = $ - .local_vars_start |
606 | if .local_vars_size > 24*4 |
606 | if .local_vars_size > 24*4 |
607 | err Modify stack frame size in |
607 | err Modify stack frame size in |
608 | end if |
608 | end if |
609 | 609 | ||
610 | .targetsmask dd ? |
610 | .targetsmask dd ? |
611 | .bandwidth dd ? |
611 | .bandwidth dd ? |
612 | .target dd ? |
612 | .target dd ? |
613 | dd ? |
613 | dd ? |
614 | dd ? |
614 | dd ? |
615 | .config_pipe dd ? |
615 | .config_pipe dd ? |
616 | .endpoint dd ? |
616 | .endpoint dd ? |
617 | .maxpacket dd ? |
617 | .maxpacket dd ? |
618 | .type dd ? |
618 | .type dd ? |
619 | .interval dd ? |
619 | .interval dd ? |
620 | end virtual |
620 | end virtual |
621 | mov eax, [edi+ehci_pipe.Token-sizeof.ehci_pipe] |
621 | mov eax, [edi+ehci_pipe.Token-sizeof.ehci_pipe] |
622 | shr eax, 16 |
622 | shr eax, 16 |
623 | and eax, (1 shl 11) - 1 |
623 | and eax, (1 shl 11) - 1 |
624 | push ebx edi |
624 | push ebx edi |
625 | ; 1. Compute the real interval. FS/LS devices encode the interval as |
625 | ; 1. Compute the real interval. FS/LS devices encode the interval as |
626 | ; number of milliseconds. Use the maximal power of two that is not greater than |
626 | ; number of milliseconds. Use the maximal power of two that is not greater than |
627 | ; the given interval and EHCI scheduling area = 32 frames. |
627 | ; the given interval and EHCI scheduling area = 32 frames. |
628 | cmp [.interval], 1 |
628 | cmp [.interval], 1 |
629 | adc [.interval], 0 |
629 | adc [.interval], 0 |
630 | mov ecx, 64 |
630 | mov ecx, 64 |
631 | mov eax, 64 * sizeof.ehci_static_ep |
631 | mov eax, 64 * sizeof.ehci_static_ep |
632 | @@: |
632 | @@: |
633 | shr ecx, 1 |
633 | shr ecx, 1 |
634 | cmp [.interval], ecx |
634 | cmp [.interval], ecx |
635 | jb @b |
635 | jb @b |
636 | mov [.interval], ecx |
636 | mov [.interval], ecx |
637 | ; 2. Compute variables for further calculations. |
637 | ; 2. Compute variables for further calculations. |
638 | ; 2a. [.variant_delta] is delta between two lists from the first group |
638 | ; 2a. [.variant_delta] is delta between two lists from the first group |
639 | ; that correspond to the same variant. |
639 | ; that correspond to the same variant. |
640 | imul ecx, sizeof.ehci_static_ep |
640 | imul ecx, sizeof.ehci_static_ep |
641 | mov [.variant_delta], ecx |
641 | mov [.variant_delta], ecx |
642 | ; 2b. [.target_delta] is delta between the final answer from the group |
642 | ; 2b. [.target_delta] is delta between the final answer from the group |
643 | ; corresponding to [.interval] and the item from the first group. |
643 | ; corresponding to [.interval] and the item from the first group. |
644 | sub eax, ecx |
644 | sub eax, ecx |
645 | sub eax, ecx |
645 | sub eax, ecx |
646 | mov [.target_delta], eax |
646 | mov [.target_delta], eax |
647 | ; 2c. [.variant] is the first list from the first group that corresponds |
647 | ; 2c. [.variant] is the first list from the first group that corresponds |
648 | ; to the current variant. |
648 | ; to the current variant. |
649 | lea eax, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
649 | lea eax, [esi+ehci_controller.IntEDs-sizeof.ehci_controller] |
650 | mov [.variant], eax |
650 | mov [.variant], eax |
651 | ; 2d. [.tthub] identifies TT hub for new pipe, [.new_budget] is FS budget |
651 | ; 2d. [.tthub] identifies TT hub for new pipe, [.new_budget] is FS budget |
652 | ; for new pipe. |
652 | ; for new pipe. |
653 | mov eax, [edi+usb_pipe.DeviceData] |
653 | mov eax, [edi+usb_pipe.DeviceData] |
654 | mov eax, [eax+usb_device_data.TTHub] |
654 | mov eax, [eax+usb_device_data.TTHub] |
655 | mov ebx, edi |
655 | mov ebx, edi |
656 | mov [.tthub], eax |
656 | mov [.tthub], eax |
657 | call tt_calc_budget |
657 | call tt_calc_budget |
658 | mov [.new_budget], ax |
658 | mov [.new_budget], ax |
659 | ; 2e. [.usb_split_info] describes bandwidth used by new pipe on HS bus. |
659 | ; 2e. [.usb_split_info] describes bandwidth used by new pipe on HS bus. |
660 | lea edi, [.info] |
660 | lea edi, [.info] |
661 | call tt_fill_split_info |
661 | call tt_fill_split_info |
662 | test eax, eax |
662 | test eax, eax |
663 | jz .no_bandwidth |
663 | jz .no_bandwidth |
664 | ; 2f. There is no best variant yet, put maximal possible values, |
664 | ; 2f. There is no best variant yet, put maximal possible values, |
665 | ; so any variant would be better than the "current". |
665 | ; so any variant would be better than the "current". |
666 | or [.best_fs_bandwidth], -1 |
666 | or [.best_fs_bandwidth], -1 |
667 | or [.target], -1 |
667 | or [.target], -1 |
668 | or [.bandwidth], -1 |
668 | or [.bandwidth], -1 |
669 | or [.targetsmask], -1 |
669 | or [.targetsmask], -1 |
670 | ; 3. Loop over all variants, for every variant decide whether it is acceptable, |
670 | ; 3. Loop over all variants, for every variant decide whether it is acceptable, |
671 | ; select the best variant from all acceptable variants. |
671 | ; select the best variant from all acceptable variants. |
672 | .check_variants: |
672 | .check_variants: |
673 | tt_calc_statistics_for_one_variant |
673 | tt_calc_statistics_for_one_variant |
674 | xor ecx, ecx |
674 | xor ecx, ecx |
675 | .check_microframes: |
675 | .check_microframes: |
676 | tt_check_variant_microframe |
676 | tt_check_variant_microframe |
677 | inc ecx |
677 | inc ecx |
678 | cmp ecx, 6 |
678 | cmp ecx, 6 |
679 | jb .check_microframes |
679 | jb .check_microframes |
680 | add [.variant], sizeof.ehci_static_ep |
680 | add [.variant], sizeof.ehci_static_ep |
681 | dec [.interval] |
681 | dec [.interval] |
682 | jnz .check_variants |
682 | jnz .check_variants |
683 | ; 4. If there is no acceptable variants, return error. |
683 | ; 4. If there is no acceptable variants, return error. |
684 | mov ecx, [.targetsmask] |
684 | mov ecx, [.targetsmask] |
685 | mov edx, [.target] |
685 | mov edx, [.target] |
686 | cmp ecx, -1 |
686 | cmp ecx, -1 |
687 | jz .no_bandwidth |
687 | jz .no_bandwidth |
688 | ; 5. Calculate the answer: edx -> selected list, eax = S-Mask and C-Mask. |
688 | ; 5. Calculate the answer: edx -> selected list, eax = S-Mask and C-Mask. |
689 | mov eax, [.info.microframe_mask] |
689 | mov eax, [.info.microframe_mask] |
690 | add edx, [.target_delta] |
690 | add edx, [.target_delta] |
691 | shl eax, cl |
691 | shl eax, cl |
692 | and eax, 0xFFFF |
692 | and eax, 0xFFFF |
693 | ; 6. Update HS bandwidths in the selected list. |
693 | ; 6. Update HS bandwidths in the selected list. |
694 | xor ecx, ecx |
694 | xor ecx, ecx |
695 | mov ebx, [.info.ssplit_bandwidth] |
695 | mov ebx, [.info.ssplit_bandwidth] |
696 | .update_ssplit: |
696 | .update_ssplit: |
697 | bt eax, ecx |
697 | bt eax, ecx |
698 | jnc @f |
698 | jnc @f |
699 | add [edx+ehci_static_ep.Bandwidths+ecx*2], bx |
699 | add [edx+ehci_static_ep.Bandwidths+ecx*2], bx |
700 | @@: |
700 | @@: |
701 | inc ecx |
701 | inc ecx |
702 | cmp ecx, 8 |
702 | cmp ecx, 8 |
703 | jb .update_ssplit |
703 | jb .update_ssplit |
704 | mov ebx, [.info.csplit_bandwidth] |
704 | mov ebx, [.info.csplit_bandwidth] |
705 | .update_csplit: |
705 | .update_csplit: |
706 | bt eax, ecx |
706 | bt eax, ecx |
707 | jnc @f |
707 | jnc @f |
708 | add [edx+ehci_static_ep.Bandwidths+(ecx-8)*2], bx |
708 | add [edx+ehci_static_ep.Bandwidths+(ecx-8)*2], bx |
709 | @@: |
709 | @@: |
710 | inc ecx |
710 | inc ecx |
711 | cmp ecx, 16 |
711 | cmp ecx, 16 |
712 | jb .update_csplit |
712 | jb .update_csplit |
713 | ; 7. Return. |
713 | ; 7. Return. |
714 | add edx, ehci_static_ep.SoftwarePart |
714 | add edx, ehci_static_ep.SoftwarePart |
715 | pop edi ebx |
715 | pop edi ebx |
716 | ret |
716 | ret |
717 | .no_bandwidth: |
717 | .no_bandwidth: |
718 | dbgstr 'Periodic bandwidth limit reached' |
718 | dbgstr 'Periodic bandwidth limit reached' |
719 | xor eax, eax |
719 | xor eax, eax |
720 | xor edx, edx |
720 | xor edx, edx |
721 | pop edi ebx |
721 | pop edi ebx |
722 | ret |
722 | ret |
723 | endp |
723 | endp |
724 | 724 | ||
725 | ; Pipe is removing, update the corresponding lists. |
725 | ; Pipe is removing, update the corresponding lists. |
726 | ; We do not reorder anything, so just update book-keeping variable |
726 | ; We do not reorder anything, so just update book-keeping variable |
727 | ; in the list header. |
727 | ; in the list header. |
728 | proc ehci_fs_interrupt_list_unlink |
728 | proc ehci_fs_interrupt_list_unlink |
729 | ; calculate bandwidth |
729 | ; calculate bandwidth |
730 | push edi |
730 | push edi |
731 | sub esp, sizeof.usb_split_info |
731 | sub esp, sizeof.usb_split_info |
732 | mov edi, esp |
732 | mov edi, esp |
733 | call tt_fill_split_info |
733 | call tt_fill_split_info |
734 | ; get target list |
734 | ; get target list |
735 | mov edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe] |
735 | mov edx, [ebx+usb_pipe.BaseList] |
736 | ; update bandwidth for Start-Split |
736 | ; update bandwidth for Start-Split |
737 | mov eax, [edi+usb_split_info.ssplit_bandwidth] |
737 | mov eax, [edi+usb_split_info.ssplit_bandwidth] |
738 | xor ecx, ecx |
738 | xor ecx, ecx |
739 | .dec_bandwidth_1: |
739 | .dec_bandwidth_1: |
740 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
740 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
741 | jnc @f |
741 | jnc @f |
742 | sub word [edx+ecx*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
742 | sub word [edx+ecx*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
743 | @@: |
743 | @@: |
744 | inc ecx |
744 | inc ecx |
745 | cmp ecx, 8 |
745 | cmp ecx, 8 |
746 | jb .dec_bandwidth_1 |
746 | jb .dec_bandwidth_1 |
747 | ; update bandwidth for Complete-Split |
747 | ; update bandwidth for Complete-Split |
748 | mov eax, [edi+usb_split_info.csplit_bandwidth] |
748 | mov eax, [edi+usb_split_info.csplit_bandwidth] |
749 | .dec_bandwidth_2: |
749 | .dec_bandwidth_2: |
750 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
750 | bt [ebx+ehci_pipe.Flags-sizeof.ehci_pipe], ecx |
751 | jnc @f |
751 | jnc @f |
752 | sub word [edx+(ecx-8)*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
752 | sub word [edx+(ecx-8)*2+ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart], ax |
753 | @@: |
753 | @@: |
754 | inc ecx |
754 | inc ecx |
755 | cmp ecx, 16 |
755 | cmp ecx, 16 |
756 | jb .dec_bandwidth_2 |
756 | jb .dec_bandwidth_2 |
757 | add esp, sizeof.usb_split_info |
757 | add esp, sizeof.usb_split_info |
758 | pop edi |
758 | pop edi |
759 | ret |
759 | ret |
760 | endp |
760 | endp |
761 | 761 | ||
762 | ; Helper procedure for ehci_select_tt_interrupt_list. |
762 | ; Helper procedure for ehci_select_tt_interrupt_list. |
763 | ; Calculates "best-case budget" according to the core spec, |
763 | ; Calculates "best-case budget" according to the core spec, |
764 | ; that is, number of bytes (not bits) corresponding to "optimistic" transaction |
764 | ; that is, number of bytes (not bits) corresponding to "optimistic" transaction |
765 | ; time, including inter-packet delays/bus turn-around time, |
765 | ; time, including inter-packet delays/bus turn-around time, |
766 | ; but without bit stuffing and timers drift. |
766 | ; but without bit stuffing and timers drift. |
767 | ; One extra TT-specific delay is added: TT think time from the hub descriptor. |
767 | ; One extra TT-specific delay is added: TT think time from the hub descriptor. |
768 | ; Similar to calc_usb1_bandwidth with corresponding changes. |
768 | ; Similar to calc_usb1_bandwidth with corresponding changes. |
769 | ; eax -> usb_hub with TT, ebx -> usb_pipe |
769 | ; eax -> usb_hub with TT, ebx -> usb_pipe |
770 | proc tt_calc_budget |
770 | proc tt_calc_budget |
771 | invoke usbhc_api.usb_get_tt_think_time ; ecx = TT think time in FS-bytes |
771 | invoke usbhc_api.usb_get_tt_think_time ; ecx = TT think time in FS-bytes |
772 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
772 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
773 | shr eax, 16 |
773 | shr eax, 16 |
774 | and eax, (1 shl 11) - 1 ; get data length |
774 | and eax, (1 shl 11) - 1 ; get data length |
775 | bt [ebx+ehci_pipe.Token-sizeof.ehci_pipe], 12 |
775 | bt [ebx+ehci_pipe.Token-sizeof.ehci_pipe], 12 |
776 | jc .low_speed |
776 | jc .low_speed |
777 | ; Full-speed interrupt IN/OUT: |
777 | ; Full-speed interrupt IN/OUT: |
778 | ; 33 bits for Token packet (8 for SYNC, 24 for token+address, 3 for EOP), |
778 | ; 33 bits for Token packet (8 for SYNC, 24 for token+address, 3 for EOP), |
779 | ; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet, |
779 | ; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet, |
780 | ; 2 bits for inter-packet delay, 19 bits for Handshake packet, |
780 | ; 2 bits for inter-packet delay, 19 bits for Handshake packet, |
781 | ; 2 bits for another inter-packet delay. 85 bits total, pad to 11 bytes. |
781 | ; 2 bits for another inter-packet delay. 85 bits total, pad to 11 bytes. |
782 | lea eax, [eax+11+ecx] |
782 | lea eax, [eax+11+ecx] |
783 | ; 1 byte is minimal TT think time in addition to ecx. |
783 | ; 1 byte is minimal TT think time in addition to ecx. |
784 | ret |
784 | ret |
785 | .low_speed: |
785 | .low_speed: |
786 | ; Low-speed interrupt IN/OUT: |
786 | ; Low-speed interrupt IN/OUT: |
787 | ; multiply by 8 for LS -> FS, |
787 | ; multiply by 8 for LS -> FS, |
788 | ; add 85 bytes as in full-speed interrupt and extra 5 bytes for two PRE packets |
788 | ; add 85 bytes as in full-speed interrupt and extra 5 bytes for two PRE packets |
789 | ; and two hub delays. |
789 | ; and two hub delays. |
790 | ; 1 byte is minimal TT think time in addition to ecx. |
790 | ; 1 byte is minimal TT think time in addition to ecx. |
791 | lea eax, [eax*8+90+ecx] |
791 | lea eax, [eax*8+90+ecx] |
792 | ret |
792 | ret |
793 | endp |
793 | endp |
794 | 794 | ||
795 | ; Helper procedure for TT scheduler. |
795 | ; Helper procedure for TT scheduler. |
796 | ; Calculates Start-Split/Complete-Split masks and HS bandwidths. |
796 | ; Calculates Start-Split/Complete-Split masks and HS bandwidths. |
797 | ; ebx -> usb_pipe, edi -> usb_split_info |
797 | ; ebx -> usb_pipe, edi -> usb_split_info |
798 | proc tt_fill_split_info |
798 | proc tt_fill_split_info |
799 | ; Interrupt endpoints. |
799 | ; Interrupt endpoints. |
800 | ; The core spec says in 5.7.3 "Interrupt Transfer Packet Size Constraints" that: |
800 | ; The core spec says in 5.7.3 "Interrupt Transfer Packet Size Constraints" that: |
801 | ; The maximum allowable interrupt data payload size is 64 bytes or less for full-speed. |
801 | ; The maximum allowable interrupt data payload size is 64 bytes or less for full-speed. |
802 | ; Low-speed devices are limited to eight bytes or less maximum data payload size. |
802 | ; Low-speed devices are limited to eight bytes or less maximum data payload size. |
803 | ; This is important for scheduling, it guarantees that in any case transaction fits |
803 | ; This is important for scheduling, it guarantees that in any case transaction fits |
804 | ; in two microframes (usually one, two if transaction has started too late in the first |
804 | ; in two microframes (usually one, two if transaction has started too late in the first |
805 | ; microframe), so check it. |
805 | ; microframe), so check it. |
806 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
806 | mov eax, [ebx+ehci_pipe.Token-sizeof.ehci_pipe] |
807 | mov ecx, 8 |
807 | mov ecx, 8 |
808 | bt eax, 12 |
808 | bt eax, 12 |
809 | jc @f |
809 | jc @f |
810 | mov ecx, 64 |
810 | mov ecx, 64 |
811 | @@: |
811 | @@: |
812 | shr eax, 16 |
812 | shr eax, 16 |
813 | and eax, (1 shl 11) - 1 ; get data length |
813 | and eax, (1 shl 11) - 1 ; get data length |
814 | cmp eax, ecx |
814 | cmp eax, ecx |
815 | ja .error |
815 | ja .error |
816 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
816 | add eax, 3 ; add 3 bytes for other fields in data packet, PID+CRC16 |
817 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
817 | ; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing; |
818 | ; total 28/3 = 9+1/3 |
818 | ; total 28/3 = 9+1/3 |
819 | mov edx, 55555556h |
819 | mov edx, 55555556h |
820 | lea ecx, [eax*9] |
820 | lea ecx, [eax*9] |
821 | mul edx |
821 | mul edx |
822 | ; One start-split, three complete-splits (unless the last is too far, |
822 | ; One start-split, three complete-splits (unless the last is too far, |
823 | ; but this is handled by the caller). |
823 | ; but this is handled by the caller). |
824 | mov eax, [ebx+usb_pipe.LastTD] |
824 | mov eax, [ebx+usb_pipe.LastTD] |
825 | mov [edi+usb_split_info.microframe_mask], 0x1C01 |
825 | mov [edi+usb_split_info.microframe_mask], 0x1C01 |
826 | ; Structure and HS bandwidth of packets depends on the direction. |
826 | ; Structure and HS bandwidth of packets depends on the direction. |
827 | bt [eax+ehci_gtd.Token-sizeof.ehci_gtd], 8 |
827 | bt [eax+ehci_gtd.Token-sizeof.ehci_gtd], 8 |
828 | jc .interrupt_in |
828 | jc .interrupt_in |
829 | .interrupt_out: |
829 | .interrupt_out: |
830 | ; Start-Split phase: |
830 | ; Start-Split phase: |
831 | ; 77 bits for SPLIT packet (32 for SYNC, 8 for EOP, 32 for data, 5 for bit stuffing), |
831 | ; 77 bits for SPLIT packet (32 for SYNC, 8 for EOP, 32 for data, 5 for bit stuffing), |
832 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
832 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
833 | ; 88 bits for inter-packet delay, 40 bits for SYNC+EOP in Data packet, |
833 | ; 88 bits for inter-packet delay, 40 bits for SYNC+EOP in Data packet, |
834 | ; 88 bits for last inter-packet delay, total 449 bits. |
834 | ; 88 bits for last inter-packet delay, total 449 bits. |
835 | lea eax, [edx+ecx+449] |
835 | lea eax, [edx+ecx+449] |
836 | mov [edi+usb_split_info.ssplit_bandwidth], eax |
836 | mov [edi+usb_split_info.ssplit_bandwidth], eax |
837 | ; Complete-Split phase: |
837 | ; Complete-Split phase: |
838 | ; 77 bits for SPLIT packet, |
838 | ; 77 bits for SPLIT packet, |
839 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
839 | ; 88 bits for inter-packet delay, 68 bits for Token packet, |
840 | ; 736 bits for bus turn-around, 49 bits for Handshake packet, |
840 | ; 736 bits for bus turn-around, 49 bits for Handshake packet, |
841 | ; 8 bits for inter-packet delay, total 1026 bits. |
841 | ; 8 bits for inter-packet delay, total 1026 bits. |
842 | mov [edi+usb_split_info.csplit_bandwidth], 1026 |
842 | mov [edi+usb_split_info.csplit_bandwidth], 1026 |
843 | ret |
843 | ret |
844 | .interrupt_in: |
844 | .interrupt_in: |
845 | ; Start-Split phase: |
845 | ; Start-Split phase: |
846 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
846 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
847 | ; 68 bits for Token packet, 88 bits for another inter-packet delay, |
847 | ; 68 bits for Token packet, 88 bits for another inter-packet delay, |
848 | ; total 321 bits. |
848 | ; total 321 bits. |
849 | mov [edi+usb_split_info.ssplit_bandwidth], 321 |
849 | mov [edi+usb_split_info.ssplit_bandwidth], 321 |
850 | ; Complete-Split phase: |
850 | ; Complete-Split phase: |
851 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
851 | ; 77 bits for SPLIT packet, 88 bits for inter-packet delay, |
852 | ; 68 bits for Token packet, 736 bits for bus turn-around, |
852 | ; 68 bits for Token packet, 736 bits for bus turn-around, |
853 | ; 40 bits for SYNC+EOP in Data packet, 8 bits for inter-packet delay, |
853 | ; 40 bits for SYNC+EOP in Data packet, 8 bits for inter-packet delay, |
854 | ; total 1017 bits. |
854 | ; total 1017 bits. |
855 | lea eax, [edx+ecx+1017] |
855 | lea eax, [edx+ecx+1017] |
856 | mov [edi+usb_split_info.csplit_bandwidth], eax |
856 | mov [edi+usb_split_info.csplit_bandwidth], eax |
857 | ret |
857 | ret |
858 | .error: |
858 | .error: |
859 | xor eax, eax |
859 | xor eax, eax |
860 | ret |
860 | ret |
861 | endp=>=>=> |
861 | endp=>=>=> |