Subversion Repositories Kolibri OS

Rev

Rev 3728 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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
  23. virtual at ebp-12
  24. .speed          db      ?
  25.                 rb      3
  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
  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.
  128.         pop     edx             ; restore value from step 2
  129.         pop     ecx             ; purge stack var from prolog
  130.         add     edx, [.target]
  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
  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
  142. .no_bandwidth:
  143.         dbgstr 'Periodic bandwidth limit reached'
  144.         xor     edx, edx
  145.         pop     edi ebx
  146.         ret
  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
  164. ; calculate bandwidth on the bus
  165.         mov     eax, [.maxpacket]
  166.         mov     ecx, dword [.lowspeed]
  167.         call    calc_usb1_bandwidth
  168. ; find list header
  169.         mov     edx, ebx
  170. @@:
  171.         mov     edx, [edx+usb_pipe.NextVirt]
  172.         cmp     [edx+usb_pipe.Controller], esi
  173.         jz      @b
  174. ; subtract pipe bandwidth
  175.         sub     [edx+usb_static_ep.Bandwidth], eax
  176.         ret     8
  177. endp
  178.  
  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.  
  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
  277.         movi    ecx, 5
  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
  291.         movi    ebx, 1
  292.         movi    edx, sizeof.ehci_static_ep
  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
  350.         movi    eax, 1
  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
  363. ; 5. Calculate bandwidth for the new pipe.
  364.         mov     eax, [.maxpacket]
  365.         call    calc_hs_bandwidth
  366.         mov     ecx, [.maxpacket]
  367.         shr     ecx, 11
  368.         inc     ecx
  369.         and     ecx, 3
  370.         imul    eax, ecx
  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
  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
  379.         mov     ecx, [.bandwidth]
  380.         add     ecx, eax
  381.         cmp     ecx, 48000
  382.         ja      .no_bandwidth
  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
  387.         movi    eax, 1
  388.         shl     eax, cl
  389.         pop     edi ebx         ; restore used registers to be stdcall
  390.         ret
  391. .no_bandwidth:
  392.         dbgstr 'Periodic bandwidth limit reached'
  393.         xor     eax, eax
  394.         xor     edx, edx
  395.         pop     edi ebx
  396.         ret
  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
  446.         movi    edx, 0x11
  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]
  480. ; 13. Calculate bandwidth on the bus.
  481.         mov     eax, [.maxpacket]
  482.         call    calc_hs_bandwidth
  483.         mov     ecx, [.maxpacket]
  484.         shr     ecx, 11
  485.         inc     ecx
  486.         and     ecx, 3
  487.         imul    eax, ecx
  488. ; 14. Check that current [.bandwidth] + new bandwidth <= limit;
  489. ; USB2 specification allows maximum 60000*80% bit times for periodic microframe.
  490.         mov     ecx, [.bandwidth]
  491.         add     ecx, eax
  492.         cmp     ecx, 48000
  493.         ja      .no_bandwidth
  494. ; 15. Update bandwidths including the new pipe.
  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
  505. ; 16. Return target list and target S-Mask.
  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
  516.         mov     edx, [ebx+ehci_pipe.BaseList-sizeof.ehci_pipe]
  517.         movzx   eax, word [ebx+ehci_pipe.Token-sizeof.ehci_pipe+2]
  518. ; calculate bandwidth
  519.         call    calc_hs_bandwidth
  520.         mov     ecx, [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
  521.         shr     ecx, 30
  522.         imul    eax, ecx
  523.         movzx   ecx, byte [ebx+ehci_pipe.Flags-sizeof.ehci_pipe]
  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.  
  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.  
  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
  604.