Subversion Repositories Kolibri OS

Rev

Rev 3728 | Rev 3826 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3520 clevermous 1
; Implementation of periodic transaction scheduler for USB.
2
; Bandwidth dedicated to periodic transactions is limited, so
3
; different pipes should be scheduled as uniformly as possible.
4
 
5
; USB1 scheduler.
6
; Algorithm is simple:
7
; when adding a pipe, optimize the following quantity:
8
;  * for every millisecond, take all bandwidth scheduled to periodic transfers,
9
;  * calculate maximum over all milliseconds,
10
;  * select a variant which minimizes that maximum;
11
; when removing a pipe, do nothing (except for bookkeeping).
12
 
13
; sanity check: structures in UHCI and OHCI should be the same
14
if (sizeof.ohci_static_ep=sizeof.uhci_static_ep)&(ohci_static_ep.SoftwarePart=uhci_static_ep.SoftwarePart)&(ohci_static_ep.NextList=uhci_static_ep.NextList)
15
; Select a list for a new pipe.
16
; in: esi -> usb_controller, maxpacket, type, interval can be found in the stack
17
; in: ecx = 2 * maximal interval = total number of periodic lists + 1
18
; in: edx -> {u|o}hci_static_ep for the first list
19
; in: eax -> byte past {u|o}hci_static_ep for the last list in the first group
20
; out: edx -> usb_static_ep for the selected list or zero if failed
21
proc usb1_select_interrupt_list
22
; inherit some variables from usb_open_pipe
3816 clevermous 23
virtual at ebp-12
24
.speed          db      ?
25
                rb      3
3520 clevermous 26
.bandwidth      dd      ?
27
.target         dd      ?
28
                dd      ?
29
                dd      ?
30
.config_pipe    dd      ?
31
.endpoint       dd      ?
32
.maxpacket      dd      ?
33
.type           dd      ?
34
.interval       dd      ?
35
end virtual
36
        push    ebx edi         ; save used registers to be stdcall
37
        push    eax             ; save eax for checks in step 3
38
; 1. Only intervals 2^k ms can be supported.
39
; The core specification says that the real interval should not be greater
40
; than the interval given by the endpoint descriptor, but can be less.
41
; Determine the actual interval as 2^k ms.
42
        mov     eax, ecx
43
; 1a. Set [.interval] to 1 if it was zero; leave it as is otherwise
44
        cmp     [.interval], 1
45
        adc     [.interval], 0
46
; 1b. Divide ecx by two while it is strictly greater than [.interval].
47
@@:
48
        shr     ecx, 1
49
        cmp     [.interval], ecx
50
        jb      @b
51
; ecx = the actual interval
52
;
53
; For example, let ecx = 8, eax = 64.
54
; The scheduler space is 32 milliseconds,
55
; we need to schedule something every 8 ms;
56
; there are 8 variants: schedule at times 0,8,16,24,
57
; schedule at times 1,9,17,25,..., schedule at times 7,15,23,31.
58
; Now concentrate: there are three nested loops,
59
; * the innermost loop calculates the total periodic bandwidth scheduled
60
;   in the given millisecond,
61
; * the intermediate loop calculates the maximum over all milliseconds
62
;   in the given variant, that is the quantity we're trying to minimize,
63
; * the outermost loop checks all variants.
64
; 2. Calculate offset between the first list and the first list for the
65
; selected interval, in bytes; save in the stack for step 4.
66
        sub     eax, ecx
67
        sub     eax, ecx
68
        imul    eax, sizeof.ohci_static_ep
69
        push    eax
70
        imul    ebx, ecx, sizeof.ohci_static_ep
71
; 3. Select the best variant.
72
; 3a. The outermost loop.
73
; Prepare for the loop: set the current optimal bandwidth to maximum
74
; possible value (so that any variant will pass the first comparison),
75
; calculate delta for the intermediate loop.
76
        or      [.bandwidth], -1
77
.varloop:
78
; 3b. The intermediate loop.
79
; Prepare for the loop: set the maximum to be calculated to zero,
80
; save counter of the outermost loop.
81
        xor     edi, edi
82
        push    edx
83
virtual at esp
84
.cur_variant    dd      ?       ; step 3b
85
.result_delta   dd      ?       ; step 2
86
.group1_limit   dd      ?       ; function prolog
87
end virtual
88
.calc_max_bandwidth:
89
; 3c. The innermost loop. Sum over all lists.
90
        xor     eax, eax
91
        push    edx
92
.calc_bandwidth:
93
        add     eax, [edx+ohci_static_ep.SoftwarePart+usb_static_ep.Bandwidth]
94
        mov     edx, [edx+ohci_static_ep.NextList]
95
        test    edx, edx
96
        jnz     .calc_bandwidth
97
        pop     edx
98
; 3d. The intermediate loop continued: update maximum.
99
        cmp     eax, edi
100
        jb      @f
101
        mov     edi, eax
102
@@:
103
; 3e. The intermediate loop continued: advance counter.
104
        add     edx, ebx
105
        cmp     edx, [.group1_limit]
106
        jb      .calc_max_bandwidth
107
; 3e. The intermediate loop done: restore counter of the outermost loop.
108
        pop     edx
109
; 3f. The outermost loop continued: if the current variant is
110
; better (maybe not strictly) then the previous optimum, update
111
; the optimal bandwidth and resulting list.
112
        cmp     edi, [.bandwidth]
113
        ja      @f
114
        mov     [.bandwidth], edi
115
        mov     [.target], edx
116
@@:
117
; 3g. The outermost loop continued: advance counter.
118
        add     edx, sizeof.ohci_static_ep
119
        dec     ecx
120
        jnz     .varloop
3816 clevermous 121
; 4. Calculate bandwidth for the new pipe.
122
        mov     eax, [.maxpacket]
123
        mov     cl, [.speed]
124
        mov     ch, byte [.endpoint]
125
        and     ch, 80h
126
        call    calc_usb1_bandwidth
127
; 5. Get the pointer to the best list.
3520 clevermous 128
        pop     edx             ; restore value from step 2
3816 clevermous 129
        pop     ecx             ; purge stack var from prolog
3520 clevermous 130
        add     edx, [.target]
3816 clevermous 131
; 6. Check that bandwidth for the new pipe plus old bandwidth
132
; still fits to maximum allowed by the core specification, 90% of 12000 bits.
133
        mov     ecx, eax
134
        add     ecx, [.bandwidth]
135
        cmp     ecx, 10800
136
        ja      .no_bandwidth
3520 clevermous 137
; 7. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return.
138
        add     edx, ohci_static_ep.SoftwarePart
139
        add     [edx+usb_static_ep.Bandwidth], eax
140
        pop     edi ebx         ; restore used registers to be stdcall
141
        ret
3816 clevermous 142
.no_bandwidth:
143
        dbgstr 'Periodic bandwidth limit reached'
144
        xor     edx, edx
145
        pop     edi ebx
146
        ret
3520 clevermous 147
endp
148
; sanity check, part 2
149
else
150
.err select_interrupt_list must be different for UHCI and OHCI
151
end if
152
 
153
; Pipe is removing, update the corresponding lists.
154
; We do not reorder anything, so just update book-keeping variable
155
; in the list header.
156
proc usb1_interrupt_list_unlink
157
virtual at esp
158
                dd      ?       ; return address
159
.maxpacket      dd      ?
160
.lowspeed       db      ?
161
.direction      db      ?
162
                rb      2
163
end virtual
3816 clevermous 164
; calculate bandwidth on the bus
165
        mov     eax, [.maxpacket]
166
        mov     ecx, dword [.lowspeed]
167
        call    calc_usb1_bandwidth
3520 clevermous 168
; find list header
169
        mov     edx, ebx
170
@@:
171
        mov     edx, [edx+usb_pipe.NextVirt]
172
        cmp     [edx+usb_pipe.Controller], esi
3728 clevermous 173
        jz      @b
3520 clevermous 174
; subtract pipe bandwidth
175
        sub     [edx+usb_static_ep.Bandwidth], eax
176
        ret     8
177
endp
178
 
3816 clevermous 179
; Helper procedure for USB1 scheduler: calculate bandwidth on the bus.
180
; in: low 11 bits of eax = payload size in bytes
181
; in: cl = 0 - full-speed, nonzero - high-speed
182
; in: ch = 0 - OUT, nonzero - IN
183
; out: eax = maximal bandwidth in FS-bits
184
proc calc_usb1_bandwidth
185
        and     eax, (1 shl 11) - 1     ; get payload for one transaction
186
        add     eax, 3  ; add 3 bytes for other fields in data packet, PID+CRC16
187
        test    cl, cl
188
        jnz     .low_speed
189
; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing
190
; and by 401/400 for IN transfers to accomodate timers difference
191
; 9+107/300 for IN transfers, 9+1/3 for OUT transfers
192
; For 0 <= eax < 09249355h, floor(eax * 107/300) = floor(eax * 5B4E81B5h / 2^32).
193
; For 0 <= eax < 80000000h, floor(eax / 3) = floor(eax * 55555556h / 2^32).
194
        mov     edx, 55555556h
195
        test    ch, ch
196
        jz      @f
197
        mov     edx, 5B4E81B5h
198
@@:
199
        lea     ecx, [eax*9]
200
        mul     edx
201
; Add 93 extra bits: 39 bits for Token packet (8 for SYNC, 24 for token+address,
202
; 4 extra bits for possible bit stuffing in token+address, 3 for EOP),
203
; 18 bits for bus turn-around, 11 bits for SYNC+EOP in Data packet plus 1 bit
204
; for possible timers difference, 2 bits for inter-packet delay, 20 bits for
205
; Handshake packet, 2 bits for another inter-packet delay.
206
        lea     eax, [ecx+edx+93]
207
        ret
208
.low_speed:
209
; Multiply by 8 for bytes -> bits, by 7/6 to accomodate bit stuffing,
210
; by 8 for LS -> FS and by 406/50 for IN transfers to accomodate timers difference.
211
; 75+59/75 for IN transfers, 74+2/3 for OUT transfers.
212
        mov     edx, 0AAAAAABh
213
        test    ch, ch
214
        mov     ecx, 74
215
        jz      @f
216
        mov     edx, 0C962FC97h
217
        inc     ecx
218
@@:
219
        imul    ecx, eax
220
        mul     edx
221
; Add 778 extra bits:
222
; 16 bits for PRE packet, 4 bits for hub delay, 8*39 bits for Token packet
223
; 8*18 bits for bus turn-around
224
; (406/50)*11 bits for SYNC+EOP in Data packet,
225
; 8*2 bits for inter-packet delay,
226
; 16 bits for PRE packet, 4 bits for hub delay, 8*20 bits for Handshake packet,
227
; 8*2 bits for another inter-packet delay.
228
        lea     eax, [ecx+edx+778]
229
        ret
230
endp
231
 
3520 clevermous 232
; USB2 scheduler.
233
; There are two parts: high-speed pipes and split-transaction pipes.
234
; Split-transaction scheduler is currently a stub.
235
; High-speed scheduler uses the same algorithm as USB1 scheduler:
236
; when adding a pipe, optimize the following quantity:
237
;  * for every microframe, take all bandwidth scheduled to periodic transfers,
238
;  * calculate maximum over all microframe,
239
;  * select a variant which minimizes that maximum;
240
; when removing a pipe, do nothing (except for bookkeeping).
241
; in: esi -> usb_controller
242
; out: edx -> usb_static_ep, eax = S-Mask
243
proc ehci_select_hs_interrupt_list
244
; inherit some variables from usb_open_pipe
245
virtual at ebp-12
246
.targetsmask    dd      ?
247
.bandwidth      dd      ?
248
.target         dd      ?
249
                dd      ?
250
                dd      ?
251
.config_pipe    dd      ?
252
.endpoint       dd      ?
253
.maxpacket      dd      ?
254
.type           dd      ?
255
.interval       dd      ?
256
end virtual
257
; prolog, initialize local vars
258
        or      [.bandwidth], -1
259
        or      [.target], -1
260
        or      [.targetsmask], -1
261
        push    ebx edi         ; save used registers to be stdcall
262
; 1. In EHCI, every list describes one millisecond = 8 microframes.
263
; Thus, there are two significantly different branches:
264
; for pipes with interval >= 8 microframes, advance to 2,
265
; for pipes which should be planned in every frame (one or more microframes),
266
; go to 9.
267
; Note: the actual interval for high-speed devices is 2^([.interval]-1),
268
; (the core specification forbids [.interval] == 0)
269
        mov     ecx, [.interval]
270
        dec     ecx
271
        cmp     ecx, 3
272
        jb      .every_frame
273
; 2. Determine the actual interval in milliseconds.
274
        sub     ecx, 3
275
        cmp     ecx, 5  ; maximum 32ms
276
        jbe     @f
3598 clevermous 277
        movi    ecx, 5
3520 clevermous 278
@@:
279
; There are four nested loops,
280
; * Loop #4 (the innermost one) calculates the total periodic bandwidth
281
;   scheduled in the given microframe of the given millisecond.
282
; * Loop #3 calculates the maximum over all milliseconds
283
;   in the given variant, that is the quantity we're trying to minimize.
284
; * Loops #1 and #2 check all variants;
285
;   loop #1 is responsible for the target millisecond,
286
;   loop #2 is responsible for the microframe within millisecond.
287
; 3. Prepare for loops.
288
; ebx = number of iterations of loop #1
289
; [esp] = delta of counter for loop #3, in bytes
290
; [esp+4] = delta between the first group and the target group, in bytes
3598 clevermous 291
        movi    ebx, 1
292
        movi    edx, sizeof.ehci_static_ep
3520 clevermous 293
        shl     ebx, cl
294
        shl     edx, cl
295
        mov     eax, 64*sizeof.ehci_static_ep
296
        sub     eax, edx
297
        sub     eax, edx
298
        push    eax
299
        push    edx
300
; 4. Select the best variant.
301
; 4a. Loop #1: initialize counter = pointer to ehci_static_ep for
302
; the target millisecond in the first group.
303
        lea     edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller]
304
.varloop0:
305
; 4b. Loop #2: initialize counter = microframe within the target millisecond.
306
        xor     ecx, ecx
307
.varloop:
308
; 4c. Loop #3: save counter of loop #1,
309
; initialize counter with the value of loop #1 counter,
310
; initialize maximal bandwidth = zero.
311
        xor     edi, edi
312
        push    edx
313
virtual at esp
314
.saved_counter1         dd      ?       ; step 4c
315
.loop3_delta            dd      ?       ; step 3
316
.target_delta           dd      ?       ; step 3
317
end virtual
318
.calc_max_bandwidth:
319
; 4d. Loop #4: initialize counter with the value of loop #3 counter,
320
; initialize total bandwidth = zero.
321
        xor     eax, eax
322
        push    edx
323
.calc_bandwidth:
324
; 4e. Loop #4: add the bandwidth from the current list
325
; and advance to the next list, while there is one.
326
        add     ax, [edx+ehci_static_ep.Bandwidths+ecx*2]
327
        mov     edx, [edx+ehci_static_ep.NextList]
328
        test    edx, edx
329
        jnz     .calc_bandwidth
330
; 4f. Loop #4 end: restore counter of loop #3.
331
        pop     edx
332
; 4g. Loop #3: update maximal bandwidth.
333
        cmp     eax, edi
334
        jb      @f
335
        mov     edi, eax
336
@@:
337
; 4h. Loop #3: advance the counter and repeat while within the first group.
338
        lea     eax, [esi+ehci_controller.IntEDs+32*sizeof.ehci_static_ep-sizeof.ehci_controller]
339
        add     edx, [.loop3_delta]
340
        cmp     edx, eax
341
        jb      .calc_max_bandwidth
342
; 4i. Loop #3 end: restore counter of loop #1.
343
        pop     edx
344
; 4j. Loop #2: if the current variant is better (maybe not strictly)
345
; then the previous optimum, update the optimal bandwidth and the target.
346
        cmp     edi, [.bandwidth]
347
        ja      @f
348
        mov     [.bandwidth], edi
349
        mov     [.target], edx
3598 clevermous 350
        movi    eax, 1
3520 clevermous 351
        shl     eax, cl
352
        mov     [.targetsmask], eax
353
@@:
354
; 4k. Loop #2: continue 8 times for every microframe.
355
        inc     ecx
356
        cmp     ecx, 8
357
        jb      .varloop
358
; 4l. Loop #1: advance counter and repeat ebx times,
359
; ebx was calculated in step 3.
360
        add     edx, sizeof.ehci_static_ep
361
        dec     ebx
362
        jnz     .varloop0
3816 clevermous 363
; 5. Calculate bandwidth for the new pipe.
3520 clevermous 364
        mov     eax, [.maxpacket]
3816 clevermous 365
        call    calc_hs_bandwidth
366
        mov     ecx, [.maxpacket]
3520 clevermous 367
        shr     ecx, 11
368
        inc     ecx
369
        and     ecx, 3
370
        imul    eax, ecx
3816 clevermous 371
; 6. Get the pointer to the best list.
372
        pop     edx             ; restore value from step 3
373
        pop     edx             ; get delta calculated in step 3
374
        add     edx, [.target]
375
; 7. Check that bandwidth for the new pipe plus old bandwidth
3520 clevermous 376
; still fits to maximum allowed by the core specification
377
; current [.bandwidth] + new bandwidth <= limit;
378
; USB2 specification allows maximum 60000*80% bit times for periodic microframe
3816 clevermous 379
        mov     ecx, [.bandwidth]
380
        add     ecx, eax
381
        cmp     ecx, 48000
382
        ja      .no_bandwidth
3520 clevermous 383
; 8. Convert {o|u}hci_static_ep to usb_static_ep, update bandwidth and return.
384
        mov     ecx, [.targetsmask]
385
        add     [edx+ehci_static_ep.Bandwidths+ecx*2], ax
386
        add     edx, ehci_static_ep.SoftwarePart
3598 clevermous 387
        movi    eax, 1
3520 clevermous 388
        shl     eax, cl
389
        pop     edi ebx         ; restore used registers to be stdcall
390
        ret
3816 clevermous 391
.no_bandwidth:
392
        dbgstr 'Periodic bandwidth limit reached'
393
        xor     eax, eax
394
        xor     edx, edx
395
        pop     edi ebx
396
        ret
3520 clevermous 397
.every_frame:
398
; The pipe should be scheduled every frame in two or more microframes.
399
; 9. Calculate maximal bandwidth for every microframe: three nested loops.
400
; 9a. The outermost loop: ebx = microframe to calculate.
401
        xor     ebx, ebx
402
.calc_all_bandwidths:
403
; 9b. The intermediate loop:
404
; edx = pointer to ehci_static_ep in the first group, [esp] = counter,
405
; edi = maximal bandwidth
406
        lea     edx, [esi+ehci_controller.IntEDs-sizeof.ehci_controller]
407
        xor     edi, edi
408
        push    32
409
.calc_max_bandwidth2:
410
; 9c. The innermost loop: calculate bandwidth for the given microframe
411
; in the given frame.
412
        xor     eax, eax
413
        push    edx
414
.calc_bandwidth2:
415
        add     ax, [edx+ehci_static_ep.Bandwidths+ebx*2]
416
        mov     edx, [edx+ehci_static_ep.NextList]
417
        test    edx, edx
418
        jnz     .calc_bandwidth2
419
        pop     edx
420
; 9d. The intermediate loop continued: update maximal bandwidth.
421
        cmp     eax, edi
422
        jb      @f
423
        mov     edi, eax
424
@@:
425
        add     edx, sizeof.ehci_static_ep
426
        dec     dword [esp]
427
        jnz     .calc_max_bandwidth2
428
        pop     eax
429
; 9e. Push the calculated maximal bandwidth and continue the outermost loop.
430
        push    edi
431
        inc     ebx
432
        cmp     ebx, 8
433
        jb      .calc_all_bandwidths
434
virtual at esp
435
.bandwidth7     dd      ?
436
.bandwidth6     dd      ?
437
.bandwidth5     dd      ?
438
.bandwidth4     dd      ?
439
.bandwidth3     dd      ?
440
.bandwidth2     dd      ?
441
.bandwidth1     dd      ?
442
.bandwidth0     dd      ?
443
end virtual
444
; 10. Select the best variant.
445
; edx = S-Mask = bitmask of scheduled microframes
3598 clevermous 446
        movi    edx, 0x11
3520 clevermous 447
        cmp     ecx, 1
448
        ja      @f
449
        mov     dl, 0x55
450
        jz      @f
451
        mov     dl, 0xFF
452
@@:
453
; try all variants edx, edx shl 1, edx shl 2, ...
454
; until they fit in the lower byte (8 microframes per frame)
455
.select_best_mframe:
456
        xor     edi, edi
457
        mov     ecx, edx
458
        mov     eax, esp
459
.calc_mframe:
460
        add     cl, cl
461
        jnc     @f
462
        cmp     edi, [eax]
463
        jae     @f
464
        mov     edi, [eax]
465
@@:
466
        add     eax, 4
467
        test    cl, cl
468
        jnz     .calc_mframe
469
        cmp     [.bandwidth], edi
470
        jb      @f
471
        mov     [.bandwidth], edi
472
        mov     [.targetsmask], edx
473
@@:
474
        add     dl, dl
475
        jnc     .select_best_mframe
476
; 11. Restore stack after step 9.
477
        add     esp, 8*4
478
; 12. Get the pointer to the target list (responsible for every microframe).
479
        lea     edx, [esi+ehci_controller.IntEDs.SoftwarePart+62*sizeof.ehci_static_ep-sizeof.ehci_controller]
3816 clevermous 480
; 13. Calculate bandwidth on the bus.
3520 clevermous 481
        mov     eax, [.maxpacket]
3816 clevermous 482
        call    calc_hs_bandwidth
483
        mov     ecx, [.maxpacket]
3520 clevermous 484
        shr     ecx, 11
485
        inc     ecx
486
        and     ecx, 3
487
        imul    eax, ecx
3816 clevermous 488
; 14. Check that current [.bandwidth] + new bandwidth <= limit;
3520 clevermous 489
; USB2 specification allows maximum 60000*80% bit times for periodic microframe.
3816 clevermous 490
        mov     ecx, [.bandwidth]
491
        add     ecx, eax
492
        cmp     ecx, 48000
493
        ja      .no_bandwidth
494
; 15. Update bandwidths including the new pipe.
3520 clevermous 495
        mov     ecx, [.targetsmask]
496
        lea     edi, [edx+ehci_static_ep.Bandwidths-ehci_static_ep.SoftwarePart]
497
.update_bandwidths:
498
        shr     ecx, 1
499
        jnc     @f
500
        add     [edi], ax
501
@@:
502
        add     edi, 2
503
        test    ecx, ecx
504
        jnz     .update_bandwidths
3816 clevermous 505
; 16. Return target list and target S-Mask.
3520 clevermous 506
        mov     eax, [.targetsmask]
507
        pop     edi ebx         ; restore used registers to be stdcall
508
        ret
509
endp
510
 
511
; Pipe is removing, update the corresponding lists.
512
; We do not reorder anything, so just update book-keeping variable
513
; in the list header.
514
proc ehci_hs_interrupt_list_unlink
515
; get target list
3653 clevermous 516
        mov     edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe]
517
        movzx   eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2]
3816 clevermous 518
; calculate bandwidth
519
        call    calc_hs_bandwidth
3653 clevermous 520
        mov     ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
3520 clevermous 521
        shr     ecx, 30
522
        imul    eax, ecx
3653 clevermous 523
        movzx   ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
3520 clevermous 524
        add     edx, ehci_static_ep.Bandwidths - ehci_static_ep.SoftwarePart
525
; update bandwidth
526
.dec_bandwidth:
527
        shr     ecx, 1
528
        jnc     @f
529
        sub     [edx], ax
530
@@:
531
        add     edx, 2
532
        test    ecx, ecx
533
        jnz     .dec_bandwidth
534
; return
535
        ret
536
endp
537
 
3816 clevermous 538
; Helper procedure for USB2 scheduler: calculate bandwidth on the bus.
539
; in: low 11 bits of eax = payload size in bytes
540
; out: eax = maximal bandwidth in HS-bits
541
proc calc_hs_bandwidth
542
        and     eax, (1 shl 11) - 1     ; get payload for one transaction
543
        add     eax, 3  ; add 3 bytes for other fields in data packet, PID+CRC16
544
; Multiply by 8 for bytes -> bits and then by 7/6 to accomodate bit stuffing;
545
; total 28/3 = 9+1/3
546
        mov     edx, 55555556h
547
        lea     ecx, [eax*9]
548
        mul     edx
549
; Add 989 extra bits: 68 bits for Token packet (32 for SYNC, 24 for token+address,
550
; 4 extra bits for possible bit stuffing in token+address, 8 for EOP),
551
; 736 bits for bus turn-around, 40 bits for SYNC+EOP in Data packet,
552
; 8 bits for inter-packet delay, 49 bits for Handshake packet,
553
; 88 bits for another inter-packet delay.
554
        lea     eax, [ecx+edx+989]
555
        ret
556
endp
557
 
3520 clevermous 558
uglobal
559
ehci_last_fs_alloc      dd      ?
560
endg
561
 
562
; This needs to be rewritten. Seriously.
563
; It schedules everything to the first microframe of some frame,
564
; frame is spinned out of thin air.
565
; This works while you have one keyboard and one mouse...
566
; maybe even ten keyboards and ten mice... but give any serious stress,
567
; and this would break.
568
proc ehci_select_fs_interrupt_list
569
virtual at ebp-12
570
.targetsmask    dd      ?
571
.bandwidth      dd      ?
572
.target         dd      ?
573
                dd      ?
574
                dd      ?
575
.config_pipe    dd      ?
576
.endpoint       dd      ?
577
.maxpacket      dd      ?
578
.type           dd      ?
579
.interval       dd      ?
580
end virtual
581
        cmp     [.interval], 1
582
        adc     [.interval], 0
583
        mov     ecx, 64
584
        mov     eax, ecx
585
@@:
586
        shr     ecx, 1
587
        cmp     [.interval], ecx
588
        jb      @b
589
        sub     eax, ecx
590
        sub     eax, ecx
591
        dec     ecx
592
        and     ecx, [ehci_last_fs_alloc]
593
        inc     [ehci_last_fs_alloc]
594
        add     eax, ecx
595
        imul    eax, sizeof.ehci_static_ep
596
        lea     edx, [esi+ehci_controller.IntEDs.SoftwarePart+eax-sizeof.ehci_controller]
597
        mov     ax, 1C01h
598
        ret
599
endp
600
 
601
proc ehci_fs_interrupt_list_unlink
602
        ret
603
endp