Subversion Repositories Kolibri OS

Rev

Rev 3745 | Rev 4547 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ; Functions for USB pipe manipulation: opening/closing, sending data etc.
  2. ;
  3. ; =============================================================================
  4. ; ================================= Constants =================================
  5. ; =============================================================================
  6. ; USB pipe types
  7. CONTROL_PIPE = 0
  8. ISOCHRONOUS_PIPE = 1
  9. BULK_PIPE = 2
  10. INTERRUPT_PIPE = 3
  11.  
  12. ; Status codes for transfer callbacks.
  13. ; Taken from OHCI as most verbose controller in this sense.
  14. USB_STATUS_OK           = 0     ; no error
  15. USB_STATUS_CRC          = 1     ; CRC error
  16. USB_STATUS_BITSTUFF     = 2     ; bit stuffing violation
  17. USB_STATUS_TOGGLE       = 3     ; data toggle mismatch
  18. USB_STATUS_STALL        = 4     ; device returned STALL
  19. USB_STATUS_NORESPONSE   = 5     ; device not responding
  20. USB_STATUS_PIDCHECK     = 6     ; invalid PID check bits
  21. USB_STATUS_WRONGPID     = 7     ; unexpected PID value
  22. USB_STATUS_OVERRUN      = 8     ; too many data from endpoint
  23. USB_STATUS_UNDERRUN     = 9     ; too few data from endpoint
  24. USB_STATUS_BUFOVERRUN   = 12    ; overflow of internal controller buffer
  25. USB_STATUS_BUFUNDERRUN  = 13    ; underflow of internal controller buffer
  26. USB_STATUS_CLOSED       = 16    ; pipe closed
  27.                                 ; either explicitly with USBClosePipe
  28.                                 ; or implicitly due to device disconnect
  29.  
  30. ; flags for usb_pipe.Flags
  31. USB_FLAG_CLOSED     = 1         ; pipe is closed, no new transfers
  32. ; pipe is closed, return error instead of submitting any new transfer
  33. USB_FLAG_CAN_FREE   = 2
  34. ; pipe is closed via explicit call to USBClosePipe, so it can be freed without
  35. ; any driver notification; if this flag is not set, then the pipe is closed due
  36. ; to device disconnect, so it must remain valid until return from disconnect
  37. ; callback provided by the driver
  38. USB_FLAG_EXTRA_WAIT = 4
  39. ; The pipe was in wait list, while another event occured;
  40. ; when the first wait will be done, reinsert the pipe to wait list
  41. USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
  42.  
  43. ; =============================================================================
  44. ; ================================ Structures =================================
  45. ; =============================================================================
  46.  
  47. ; Pipe descriptor.
  48. ; * An USB pipe is described by two structures, for hardware and for software.
  49. ; * This is the software part. The hardware part is defined in a driver
  50. ;   of the corresponding controller.
  51. ; * The hardware part is located immediately before usb_pipe,
  52. ;   both are allocated at once by controller-specific code
  53. ;   (it knows the total length, which depends on the hardware part).
  54. struct usb_pipe
  55. Controller      dd      ?
  56. ; Pointer to usb_controller structure corresponding to this pipe.
  57. ; Must be the first dword after hardware part, see *hci_new_device.
  58. ;
  59. ; Every endpoint is included into one of processing lists:
  60. ; * Bulk list contains all Bulk endpoints.
  61. ; * Control list contains all Control endpoints.
  62. ; * Several Periodic lists serve Interrupt endpoints with different interval.
  63. ;   - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
  64. ;     in the frames 0,N,2N,..., another is processed in the frames
  65. ;     1,1+N,1+2N,... and so on. The hardware starts processing of periodic
  66. ;     endpoints in every frame from the list identified by lower n bits of the
  67. ;     frame number; the addresses of these N lists are written to the
  68. ;     controller data area during the initialization.
  69. ;   - We assume that n=5, N=32 to simplify the code and compact the data.
  70. ;     OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
  71. ;     but this is an overkill for interrupt endpoints; the large value of N is
  72. ;     useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
  73. ;     initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
  74. ;     giving essentially N=32.
  75. ;     This restriction means that the actual maximum interval of polling any
  76. ;     interrupt endpoint is 32ms, which seems to be a reasonable value.
  77. ;   - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
  78. ;     interval and so on. Finally, there is one list for 1ms interval. Their
  79. ;     addresses are not directly known to the controller.
  80. ;   - The hardware serves endpoints following a physical link from the hardware
  81. ;     part.
  82. ;   - The hardware links are organized as follows. If the list item is not the
  83. ;     last, it's hardware link points to the next item. The hardware link of
  84. ;     the last item points to the first item of the "next" list.
  85. ;   - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
  86. ;     is the k-th periodic list for interval M ms, M >= 1. In this scheme,
  87. ;     if two "previous" lists are served in the frames k,k+2M,k+4M,...
  88. ;     and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
  89. ;     the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
  90. ;   - The links between Periodic, Control, Bulk lists and the processing of
  91. ;     Isochronous endpoints are controller-specific.
  92. ; * The head of every processing list is a static entry which does not
  93. ;   correspond to any real pipe. It is described by usb_static_ep
  94. ;   structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
  95. ;   sizeof hardware part is 20h, the total number of lists is
  96. ;   32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
  97. ;   leaving space for other data. This is another reason for 32ms limit.
  98. ; * Static endpoint descriptors are kept in *hci_controller structure.
  99. ; * All items in every processing list, including the static head, are
  100. ;   organized in a double-linked list using .NextVirt and .PrevVirt fields.
  101. ; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
  102. NextVirt        dd      ?
  103. ; Next endpoint in the processing list.
  104. ; See also PrevVirt field and the description before NextVirt field.
  105. PrevVirt        dd      ?
  106. ; Previous endpoint in the processing list.
  107. ; See also NextVirt field and the description before NextVirt field.
  108. ;
  109. ; Every pipe has the associated transfer queue, that is, the double-linked
  110. ; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
  111. ; endpoints this list consists of usb_gtd structures
  112. ; (GTD = General Transfer Descriptors), for Isochronous endpoints
  113. ; this list consists of usb_itd structures, which are not developed yet.
  114. ; The pipe needs to know only the last TD; the first TD can be
  115. ; obtained as [[pipe.LastTD].NextVirt].
  116. LastTD          dd      ?
  117. ; Last TD in the transfer queue.
  118. ;
  119. ; All opened pipes corresponding to the same physical device are organized in
  120. ; the double-linked list using .NextSibling and .PrevSibling fields.
  121. ; The head of this list is kept in usb_device_data structure (OpenedPipeList).
  122. ; This list is used when the device is disconnected and all pipes for the
  123. ; device should be closed.
  124. ; Also, all pipes closed due to disconnect must remain valid at least until
  125. ; driver-provided disconnect function returns; all should-be-freed-but-not-now
  126. ; pipes for one device are organized in another double-linked list with
  127. ; the head in usb_device_data.ClosedPipeList; this list uses the same link
  128. ; fields, one pipe can never be in both lists.
  129. NextSibling     dd      ?
  130. ; Next pipe for the physical device.
  131. PrevSibling     dd      ?
  132. ; Previous pipe for the physical device.
  133. ;
  134. ; When hardware part of pipe is changed, some time is needed before further
  135. ; actions so that hardware reacts on this change. During that time,
  136. ; all changed pipes are organized in single-linked list with the head
  137. ; usb_controller.WaitPipeList* and link field NextWait.
  138. ; Currently there are two possible reasons to change:
  139. ; change of address/packet size in initial configuration,
  140. ; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
  141. NextWait        dd      ?
  142. Lock            MUTEX
  143. ; Mutex that guards operations with transfer queue for this pipe.
  144. Type            db      ?
  145. ; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
  146. Flags           db      ?
  147. ; Combination of flags, USB_FLAG_*.
  148.                 rb      2       ; dword alignment
  149. DeviceData      dd      ?
  150. ; Pointer to usb_device_data, common for all pipes for one device.
  151. ends
  152.  
  153. ; This structure describes the static head of every list of pipes.
  154. struct usb_static_ep
  155. ; software fields
  156. Bandwidth       dd      ?
  157. ; valid only for interrupt/isochronous USB1 lists
  158. ; The offsets of the following two fields must be the same in this structure
  159. ; and in usb_pipe.
  160. NextVirt        dd      ?
  161. PrevVirt        dd      ?
  162. ends
  163.  
  164. ; This structure represents one transfer descriptor
  165. ; ('g' stands for "general" as opposed to isochronous usb_itd).
  166. ; Note that one transfer can have several descriptors:
  167. ; a control transfer has three stages.
  168. ; Additionally, every controller has a limit on transfer length with
  169. ; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
  170. ; large transfers must be split into individual packets according to that limit.
  171. struct usb_gtd
  172. Callback        dd      ?
  173. ; Zero for intermediate descriptors, pointer to callback function
  174. ; for final descriptor. See the docs for description of the callback.
  175. UserData        dd      ?
  176. ; Dword which is passed to Callback as is, not used by USB code itself.
  177. ; Two following fields organize all descriptors for one pipe in
  178. ; the linked list.
  179. NextVirt        dd      ?
  180. PrevVirt        dd      ?
  181. Pipe            dd      ?
  182. ; Pointer to the parent usb_pipe.
  183. Buffer          dd      ?
  184. ; Pointer to data for this descriptor.
  185. Length          dd      ?
  186. ; Length of data for this descriptor.
  187. ends
  188.  
  189. ; =============================================================================
  190. ; =================================== Code ====================================
  191. ; =============================================================================
  192.  
  193. USB_STDCALL_VERIFY = 1
  194. macro stdcall_verify [arg]
  195. {
  196. common
  197. if USB_STDCALL_VERIFY
  198.         pushad
  199.         stdcall arg
  200.         call    verify_regs
  201.         popad
  202. else
  203.         stdcall arg
  204. end if
  205. }
  206.  
  207. ; Initialization of usb_static_ep structure,
  208. ; called from controller-specific initialization; edi -> usb_static_ep
  209. proc usb_init_static_endpoint
  210.         mov     [edi+usb_static_ep.NextVirt], edi
  211.         mov     [edi+usb_static_ep.PrevVirt], edi
  212.         ret
  213. endp
  214.  
  215. ; Part of API for drivers, see documentation for USBOpenPipe.
  216. proc usb_open_pipe stdcall uses ebx esi edi,\
  217.  config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
  218. locals
  219. tt_vars         rd      (ehci_select_tt_interrupt_list.local_vars_size + 3) / 4
  220. targetsmask     dd      ?       ; S-Mask for USB2
  221. bandwidth       dd      ?
  222. target          dd      ?
  223. endl
  224. ; 1. Verify type of pipe: it must be one of *_PIPE constants.
  225. ; Isochronous pipes are not supported yet.
  226.         mov     eax, [type]
  227.         cmp     eax, INTERRUPT_PIPE
  228.         ja      .badtype
  229.         cmp     al, ISOCHRONOUS_PIPE
  230.         jnz     .goodtype
  231. .badtype:
  232.         dbgstr 'unsupported type of USB pipe'
  233.         jmp     .return0
  234. .goodtype:
  235. ; 2. Allocate memory for pipe and transfer queue.
  236. ; Empty transfer queue consists of one inactive TD.
  237.         mov     ebx, [config_pipe]
  238.         mov     esi, [ebx+usb_pipe.Controller]
  239.         mov     edx, [esi+usb_controller.HardwareFunc]
  240.         call    [edx+usb_hardware_func.AllocPipe]
  241.         test    eax, eax
  242.         jz      .nothing
  243.         mov     edi, eax
  244.         mov     edx, [esi+usb_controller.HardwareFunc]
  245.         call    [edx+usb_hardware_func.AllocTD]
  246.         test    eax, eax
  247.         jz      .free_and_return0
  248. ; 3. Initialize transfer queue: pointer to transfer descriptor,
  249. ; pointers in transfer descriptor, queue lock.
  250.         mov     [edi+usb_pipe.LastTD], eax
  251.         mov     [eax+usb_gtd.NextVirt], eax
  252.         mov     [eax+usb_gtd.PrevVirt], eax
  253.         mov     [eax+usb_gtd.Pipe], edi
  254.         lea     ecx, [edi+usb_pipe.Lock]
  255.         call    mutex_init
  256. ; 4. Initialize software part of pipe structure, except device-related fields.
  257.         mov     al, byte [type]
  258.         mov     [edi+usb_pipe.Type], al
  259.         xor     eax, eax
  260.         mov     [edi+usb_pipe.Flags], al
  261.         mov     [edi+usb_pipe.DeviceData], eax
  262.         mov     [edi+usb_pipe.Controller], esi
  263.         or      [edi+usb_pipe.NextWait], -1
  264. ; 5. Initialize device-related fields:
  265. ; for zero endpoint, set .NextSibling = .PrevSibling = this;
  266. ; for other endpoins, copy device data, take the lock guarding pipe list
  267. ; for the device and verify that disconnect processing has not yet started
  268. ; for the device. (Since disconnect processing also takes that lock,
  269. ; either it has completed or it will not start until we release the lock.)
  270. ; Note: usb_device_disconnected should not see the new pipe until
  271. ; initialization is complete, so that lock will be held during next steps
  272. ; (disconnect processing should either not see it at all, or see fully
  273. ; initialized pipe).
  274.         cmp     [endpoint], eax
  275.         jz      .zero_endpoint
  276.         mov     ecx, [ebx+usb_pipe.DeviceData]
  277.         mov     [edi+usb_pipe.DeviceData], ecx
  278.         call    mutex_lock
  279.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  280.         jz      .common
  281. .fail:
  282. ; If disconnect processing has completed, unlock the mutex, free memory
  283. ; allocated in step 2 and return zero.
  284.         call    mutex_unlock
  285.         mov     edx, [esi+usb_controller.HardwareFunc]
  286.         stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
  287. .free_and_return0:
  288.         mov     edx, [esi+usb_controller.HardwareFunc]
  289.         stdcall [edx+usb_hardware_func.FreePipe], edi
  290. .return0:
  291.         xor     eax, eax
  292.         jmp     .nothing
  293. .zero_endpoint:
  294.         mov     [edi+usb_pipe.NextSibling], edi
  295.         mov     [edi+usb_pipe.PrevSibling], edi
  296. .common:
  297. ; 6. Initialize hardware part of pipe structure.
  298. ; 6a. Acquire the corresponding mutex.
  299.         lea     ecx, [esi+usb_controller.ControlLock]
  300.         cmp     [type], BULK_PIPE
  301.         jb      @f      ; control pipe
  302.         lea     ecx, [esi+usb_controller.BulkLock]
  303.         jz      @f      ; bulk pipe
  304.         lea     ecx, [esi+usb_controller.PeriodicLock]
  305. @@:
  306.         call    mutex_lock
  307. ; 6b. Let the controller-specific code do its job.
  308.         push    ecx
  309.         mov     edx, [esi+usb_controller.HardwareFunc]
  310.         mov     eax, [edi+usb_pipe.LastTD]
  311.         mov     ecx, [config_pipe]
  312.         call    [edx+usb_hardware_func.InitPipe]
  313.         pop     ecx
  314. ; 6c. Release the mutex.
  315.         push    eax
  316.         call    mutex_unlock
  317.         pop     eax
  318. ; 6d. If controller-specific code indicates failure,
  319. ; release the lock taken in step 5, free memory allocated in step 2
  320. ; and return zero.
  321.         test    eax, eax
  322.         jz      .fail
  323. ; 7. The pipe is initialized. If this is not the first pipe for the device,
  324. ; insert it to the tail of pipe list for the device,
  325. ; increment number of pipes,
  326. ; release the lock taken at step 5.
  327.         mov     ecx, [edi+usb_pipe.DeviceData]
  328.         test    ecx, ecx
  329.         jz      @f
  330.         mov     eax, [ebx+usb_pipe.PrevSibling]
  331.         mov     [edi+usb_pipe.NextSibling], ebx
  332.         mov     [edi+usb_pipe.PrevSibling], eax
  333.         mov     [ebx+usb_pipe.PrevSibling], edi
  334.         mov     [eax+usb_pipe.NextSibling], edi
  335.         inc     [ecx+usb_device_data.NumPipes]
  336.         call    mutex_unlock
  337. @@:
  338. ; 8. Return pointer to usb_pipe.
  339.         mov     eax, edi
  340. .nothing:
  341.         ret
  342. endp
  343.  
  344. ; This procedure is called several times during initial device configuration,
  345. ; when usb_device_data structure is reallocated.
  346. ; It (re)initializes all pointers in usb_device_data.
  347. ; ebx -> usb_pipe
  348. proc usb_reinit_pipe_list
  349.         push    eax
  350. ; 1. (Re)initialize the lock guarding pipe list.
  351.         mov     ecx, [ebx+usb_pipe.DeviceData]
  352.         call    mutex_init
  353. ; 2. Initialize list of opened pipes: two entries, the head and ebx.
  354.         add     ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
  355.         mov     [ecx+usb_pipe.NextSibling], ebx
  356.         mov     [ecx+usb_pipe.PrevSibling], ebx
  357.         mov     [ebx+usb_pipe.NextSibling], ecx
  358.         mov     [ebx+usb_pipe.PrevSibling], ecx
  359. ; 3. Initialize list of closed pipes: empty list, only the head is present.
  360.         add     ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
  361.         mov     [ecx+usb_pipe.NextSibling], ecx
  362.         mov     [ecx+usb_pipe.PrevSibling], ecx
  363.         pop     eax
  364.         ret
  365. endp
  366.  
  367. ; Part of API for drivers, see documentation for USBClosePipe.
  368. proc usb_close_pipe
  369.         push    ebx esi ; save used registers to be stdcall
  370. virtual at esp
  371.         rd      2       ; saved registers
  372.         dd      ?       ; return address
  373. .pipe   dd      ?
  374. end virtual
  375. ; 1. Lock the pipe list for the device.
  376.         mov     ebx, [.pipe]
  377.         mov     esi, [ebx+usb_pipe.Controller]
  378.         mov     ecx, [ebx+usb_pipe.DeviceData]
  379.         call    mutex_lock
  380. ; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
  381.         lea     ecx, [ebx+usb_pipe.Lock]
  382.         call    mutex_lock
  383.         or      [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
  384.         call    mutex_unlock
  385. ; 3. Call the worker function.
  386.         call    usb_close_pipe_nolock
  387. ; 4. Unlock the pipe list for the device.
  388.         mov     ecx, [ebx+usb_pipe.DeviceData]
  389.         call    mutex_unlock
  390. ; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
  391.         push    edi
  392.         call    usb_wakeup
  393.         pop     edi
  394. ; 6. Return.
  395.         pop     esi ebx ; restore used registers to be stdcall
  396.         retn    4
  397. endp
  398.  
  399. ; Worker function for pipe closing. Called by usb_close_pipe API and
  400. ; from disconnect processing.
  401. ; The lock guarding pipe list for the device should be held by the caller.
  402. ; ebx -> usb_pipe, esi -> usb_controller
  403. proc usb_close_pipe_nolock
  404. ; 1. Set the flag "pipe is closed, ignore new transfers".
  405. ; If it was already set, do nothing.
  406.         lea     ecx, [ebx+usb_pipe.Lock]
  407.         call    mutex_lock
  408.         bts     dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
  409.         jc      .closed
  410.         call    mutex_unlock
  411. ; 2. Remove the pipe from the list of opened pipes.
  412.         mov     eax, [ebx+usb_pipe.NextSibling]
  413.         mov     edx, [ebx+usb_pipe.PrevSibling]
  414.         mov     [eax+usb_pipe.PrevSibling], edx
  415.         mov     [edx+usb_pipe.NextSibling], eax
  416. ; 3. Unlink the pipe from hardware structures.
  417. ; 3a. Acquire the corresponding lock.
  418.         lea     edx, [esi+usb_controller.WaitPipeListAsync]
  419.         lea     ecx, [esi+usb_controller.ControlLock]
  420.         cmp     [ebx+usb_pipe.Type], BULK_PIPE
  421.         jb      @f      ; control pipe
  422.         lea     ecx, [esi+usb_controller.BulkLock]
  423.         jz      @f      ; bulk pipe
  424.         add     edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
  425.         lea     ecx, [esi+usb_controller.PeriodicLock]
  426. @@:
  427.         push    edx
  428.         call    mutex_lock
  429.         push    ecx
  430. ; 3b. Let the controller-specific code do its job.
  431.         mov     eax, [esi+usb_controller.HardwareFunc]
  432.         call    [eax+usb_hardware_func.UnlinkPipe]
  433. ; 3c. Release the corresponding lock.
  434.         pop     ecx
  435.         call    mutex_unlock
  436. ; 4. Put the pipe into wait queue.
  437.         pop     edx
  438.         cmp     [ebx+usb_pipe.NextWait], -1
  439.         jz      .insert_new
  440.         or      [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
  441.         jmp     .inserted
  442. .insert_new:
  443.         mov     eax, [edx]
  444.         mov     [ebx+usb_pipe.NextWait], eax
  445.         mov     [edx], ebx
  446. .inserted:
  447. ; 5. Return.
  448.         ret
  449. .closed:
  450.         call    mutex_unlock
  451.         xor     eax, eax
  452.         ret
  453. endp
  454.  
  455. ; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
  456. ; corresponding wait list. It means that the hardware has fully forgot about it.
  457. ; ebx -> usb_pipe, esi -> usb_controller
  458. proc usb_pipe_closed
  459.         push    edi
  460.         mov     edi, [esi+usb_controller.HardwareFunc]
  461. ; 1. Loop over all transfers, calling the driver with USB_STATUS_CLOSED
  462. ; and freeing all descriptors.
  463.         mov     edx, [ebx+usb_pipe.LastTD]
  464.         test    edx, edx
  465.         jz      .no_transfer
  466.         mov     edx, [edx+usb_gtd.NextVirt]
  467. .transfer_loop:
  468.         cmp     edx, [ebx+usb_pipe.LastTD]
  469.         jz      .transfer_done
  470.         mov     ecx, [edx+usb_gtd.Callback]
  471.         test    ecx, ecx
  472.         jz      .no_callback
  473.         push    edx
  474.         stdcall_verify ecx, ebx, USB_STATUS_CLOSED, \
  475.                 [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
  476.         pop     edx
  477. .no_callback:
  478.         push    [edx+usb_gtd.NextVirt]
  479.         stdcall [edi+usb_hardware_func.FreeTD], edx
  480.         pop     edx
  481.         jmp     .transfer_loop
  482. .transfer_done:
  483.         stdcall [edi+usb_hardware_func.FreeTD], edx
  484. .no_transfer:
  485. ; 2. Decrement number of pipes for the device.
  486. ; If this pipe is the last pipe, go to 5.
  487.         mov     ecx, [ebx+usb_pipe.DeviceData]
  488.         call    mutex_lock
  489.         dec     [ecx+usb_device_data.NumPipes]
  490.         jz      .last_pipe
  491.         call    mutex_unlock
  492. ; 3. If the flag "the driver has abandoned this pipe" is set,
  493. ; free memory and return.
  494.         test    [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
  495.         jz      .nofree
  496.         stdcall [edi+usb_hardware_func.FreePipe], ebx
  497.         pop     edi
  498.         ret
  499. ; 4. Otherwise, add it to the list of closed pipes and return.
  500. .nofree:
  501.         add     ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  502.         mov     edx, [ecx+usb_pipe.PrevSibling]
  503.         mov     [ebx+usb_pipe.NextSibling], ecx
  504.         mov     [ebx+usb_pipe.PrevSibling], edx
  505.         mov     [ecx+usb_pipe.PrevSibling], ebx
  506.         mov     [edx+usb_pipe.NextSibling], ebx
  507.         pop     edi
  508.         ret
  509. .last_pipe:
  510. ; That was the last pipe for the device.
  511. ; 5. Notify device driver(s) about disconnect.
  512.         call    mutex_unlock
  513.         mov     eax, [ecx+usb_device_data.NumInterfaces]
  514.         test    eax, eax
  515.         jz      .notify_done
  516.         add     ecx, [ecx+usb_device_data.Interfaces]
  517. .notify_loop:
  518.         mov     edx, [ecx+usb_interface_data.DriverFunc]
  519.         test    edx, edx
  520.         jz      @f
  521.         mov     edx, [edx+USBSRV.usb_func]
  522.         cmp     [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
  523.         jb      @f
  524.         mov     edx, [edx+USBFUNC.device_disconnect]
  525.         test    edx, edx
  526.         jz      @f
  527.         push    eax ecx
  528.         stdcall_verify edx, [ecx+usb_interface_data.DriverData]
  529.         pop     ecx eax
  530. @@:
  531.         add     ecx, sizeof.usb_interface_data
  532.         dec     eax
  533.         jnz     .notify_loop
  534. .notify_done:
  535. ; 6. Bus address, if assigned, can now be reused.
  536.         call    [edi+usb_hardware_func.GetDeviceAddress]
  537.         test    eax, eax
  538.         jz      @f
  539.         bts     [esi+usb_controller.ExistingAddresses], eax
  540. @@:
  541.         dbgstr 'USB device disconnected'
  542. ; 7. All drivers have returned from disconnect callback,
  543. ; so all drivers should not use any device-related pipes.
  544. ; Free the remaining pipes.
  545.         mov     eax, [ebx+usb_pipe.DeviceData]
  546.         add     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  547.         push    eax
  548.         mov     eax, [eax+usb_pipe.NextSibling]
  549. .free_loop:
  550.         cmp     eax, [esp]
  551.         jz      .free_done
  552.         push    [eax+usb_pipe.NextSibling]
  553.         stdcall [edi+usb_hardware_func.FreePipe], eax
  554.         pop     eax
  555.         jmp     .free_loop
  556. .free_done:
  557.         stdcall [edi+usb_hardware_func.FreePipe], ebx
  558.         pop     eax
  559. ; 8. Free the usb_device_data structure.
  560.         sub     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  561.         call    free
  562. ; 9. Return.
  563. .nothing:
  564.         pop     edi
  565.         ret
  566. endp
  567.  
  568. ; Part of API for drivers, see documentation for USBNormalTransferAsync.
  569. proc usb_normal_transfer_async stdcall uses ebx edi,\
  570.  pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
  571. ; 1. Sanity check: callback must be nonzero.
  572. ; (It is important for other parts of code.)
  573.         xor     eax, eax
  574.         cmp     [callback], eax
  575.         jz      .nothing
  576. ; 2. Lock the transfer queue.
  577.         mov     ebx, [pipe]
  578.         lea     ecx, [ebx+usb_pipe.Lock]
  579.         call    mutex_lock
  580. ; 3. If the pipe has already been closed (presumably due to device disconnect),
  581. ; release the lock taken in step 2 and return zero.
  582.         xor     eax, eax
  583.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  584.         jnz     .unlock
  585. ; 4. Allocate and initialize TDs for the transfer.
  586.         mov     edx, [ebx+usb_pipe.Controller]
  587.         mov     edi, [edx+usb_controller.HardwareFunc]
  588.         stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
  589. ; If failed, release the lock taken in step 2 and return zero.
  590.         test    eax, eax
  591.         jz      .unlock
  592. ; 5. Store callback and its parameters in the last descriptor for this transfer.
  593.         mov     ecx, [eax+usb_gtd.PrevVirt]
  594.         mov     edx, [callback]
  595.         mov     [ecx+usb_gtd.Callback], edx
  596.         mov     edx, [calldata]
  597.         mov     [ecx+usb_gtd.UserData], edx
  598.         mov     edx, [buffer]
  599.         mov     [ecx+usb_gtd.Buffer], edx
  600. ; 6. Advance LastTD pointer and activate transfer.
  601.         push    [ebx+usb_pipe.LastTD]
  602.         mov     [ebx+usb_pipe.LastTD], eax
  603.         call    [edi+usb_hardware_func.InsertTransfer]
  604.         pop     eax
  605. ; 7. Release the lock taken in step 2 and
  606. ; return pointer to the first descriptor for the new transfer.
  607. .unlock:
  608.         push    eax
  609.         lea     ecx, [ebx+usb_pipe.Lock]
  610.         call    mutex_unlock
  611.         pop     eax
  612. .nothing:
  613.         ret
  614. endp
  615.  
  616. ; Part of API for drivers, see documentation for USBControlTransferAsync.
  617. proc usb_control_async stdcall uses ebx edi,\
  618.  pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
  619. locals
  620. last_td         dd      ?
  621. endl
  622. ; 1. Sanity check: callback must be nonzero.
  623. ; (It is important for other parts of code.)
  624.         cmp     [callback], 0
  625.         jz      .return0
  626. ; 2. Lock the transfer queue.
  627.         mov     ebx, [pipe]
  628.         lea     ecx, [ebx+usb_pipe.Lock]
  629.         call    mutex_lock
  630. ; 3. If the pipe has already been closed (presumably due to device disconnect),
  631. ; release the lock taken in step 2 and return zero.
  632.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  633.         jnz     .unlock_return0
  634. ; A control transfer contains two or three stages:
  635. ; Setup stage, optional Data stage, Status stage.
  636. ; 4. Allocate and initialize TDs for the Setup stage.
  637. ; Payload is 8 bytes from [config].
  638.         mov     edx, [ebx+usb_pipe.Controller]
  639.         mov     edi, [edx+usb_controller.HardwareFunc]
  640.         stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
  641.                 ; short transfer is an error, direction is DATA0, token is SETUP
  642.         mov     [last_td], eax
  643.         test    eax, eax
  644.         jz      .fail
  645. ; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
  646. ; Payload is [size] bytes from [buffer].
  647.         mov     edx, [config]
  648.         mov     ecx, (3 shl 2) + 1      ; DATA1, token is OUT
  649.         cmp     byte [edx], 0
  650.         jns     @f
  651.         cmp     [size], 0
  652.         jz      @f
  653.         inc     ecx     ; token is IN
  654. @@:
  655.         cmp     [size], 0
  656.         jz      .nodata
  657.         push    ecx
  658.         stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
  659.         pop     ecx
  660.         test    eax, eax
  661.         jz      .fail
  662.         mov     [last_td], eax
  663. .nodata:
  664. ; 6. Allocate and initialize TDs for the Status stage.
  665. ; No payload.
  666.         xor     ecx, 3  ; IN becomes OUT, OUT becomes IN
  667.         stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
  668.         test    eax, eax
  669.         jz      .fail
  670. ; 7. Store callback and its parameters in the last descriptor for this transfer.
  671.         mov     ecx, [eax+usb_gtd.PrevVirt]
  672.         mov     edx, [callback]
  673.         mov     [ecx+usb_gtd.Callback], edx
  674.         mov     edx, [calldata]
  675.         mov     [ecx+usb_gtd.UserData], edx
  676.         mov     edx, [buffer]
  677.         mov     [ecx+usb_gtd.Buffer], edx
  678. ; 8. Advance LastTD pointer and activate transfer.
  679.         push    [ebx+usb_pipe.LastTD]
  680.         mov     [ebx+usb_pipe.LastTD], eax
  681.         call    [edi+usb_hardware_func.InsertTransfer]
  682. ; 9. Release the lock taken in step 2 and
  683. ; return pointer to the first descriptor for the new transfer.
  684.         lea     ecx, [ebx+usb_pipe.Lock]
  685.         call    mutex_unlock
  686.         pop     eax
  687.         ret
  688. .fail:
  689.         mov     eax, [last_td]
  690.         test    eax, eax
  691.         jz      .unlock_return0
  692.         stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
  693. .unlock_return0:
  694.         lea     ecx, [ebx+usb_pipe.Lock]
  695.         call    mutex_unlock
  696. .return0:
  697.         xor     eax, eax
  698.         ret
  699. endp
  700.  
  701. ; Part of API for drivers, see documentation for USBGetParam.
  702. proc usb_get_param
  703. virtual at esp
  704.                 dd      ?       ; return address
  705. .pipe           dd      ?
  706. .param          dd      ?
  707. end virtual
  708.         mov     edx, [.param]
  709.         mov     ecx, [.pipe]
  710.         mov     eax, [ecx+usb_pipe.DeviceData]
  711.         test    edx, edx
  712.         jz      .get_device_descriptor
  713.         dec     edx
  714.         jz      .get_config_descriptor
  715.         dec     edx
  716.         jz      .get_speed
  717.         or      eax, -1
  718.         ret     8
  719. .get_device_descriptor:
  720.         add     eax, usb_device_data.DeviceDescriptor
  721.         ret     8
  722. .get_config_descriptor:
  723.         movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
  724.         lea     eax, [eax+ecx+usb_device_data.DeviceDescriptor]
  725.         ret     8
  726. .get_speed:
  727.         movzx   eax, [eax+usb_device_data.Speed]
  728.         ret     8
  729. endp
  730.  
  731. ; Initialize software part of usb_gtd. Called from controller-specific code
  732. ; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
  733. ; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
  734. ; current (initializing) usb_gtd.
  735. ; Returns ecx = [.td].
  736. proc usb_init_transfer
  737. virtual at ebp-4
  738. .Size   dd      ?
  739.         rd      2
  740. .Buffer dd      ?
  741.         dd      ?
  742. .Flags  dd      ?
  743. .td     dd      ?
  744. end virtual
  745.         mov     [eax+usb_gtd.Pipe], ebx
  746.         mov     ecx, [.td]
  747.         mov     [eax+usb_gtd.PrevVirt], ecx
  748.         mov     edx, [ecx+usb_gtd.NextVirt]
  749.         mov     [ecx+usb_gtd.NextVirt], eax
  750.         mov     [eax+usb_gtd.NextVirt], edx
  751.         mov     [edx+usb_gtd.PrevVirt], eax
  752.         mov     edx, [.Size]
  753.         mov     [ecx+usb_gtd.Length], edx
  754.         xor     edx, edx
  755.         mov     [ecx+usb_gtd.Callback], edx
  756.         mov     [ecx+usb_gtd.UserData], edx
  757.         ret
  758. endp
  759.  
  760. ; Free all TDs for the current transfer if something has failed
  761. ; during initialization (e.g. no memory for the next TD).
  762. ; Stdcall with one stack argument = first TD for the transfer
  763. ; and eax = last initialized TD for the transfer.
  764. proc usb_undo_tds
  765.         push    [eax+usb_gtd.NextVirt]
  766. @@:
  767.         cmp     eax, [esp+8]
  768.         jz      @f
  769.         push    [eax+usb_gtd.PrevVirt]
  770.         stdcall [edi+usb_hardware_func.FreeTD], eax
  771.         pop     eax
  772.         jmp     @b
  773. @@:
  774.         pop     ecx
  775.         mov     [eax+usb_gtd.NextVirt], ecx
  776.         mov     [ecx+usb_gtd.PrevVirt], eax
  777.         ret     4
  778. endp
  779.  
  780. ; Helper procedure for handling short packets in controller-specific code.
  781. ; Returns with CF cleared if this is the final packet in some stage:
  782. ; for control transfers that means one of Data and Status stages,
  783. ; for other transfers - the final packet in the only stage.
  784. proc usb_is_final_packet
  785.         cmp     [ebx+usb_gtd.Callback], 0
  786.         jnz     .nothing
  787.         mov     eax, [ebx+usb_gtd.NextVirt]
  788.         cmp     [eax+usb_gtd.Callback], 0
  789.         jz      .stc
  790.         mov     eax, [ebx+usb_gtd.Pipe]
  791.         cmp     [eax+usb_pipe.Type], CONTROL_PIPE
  792.         jz      .nothing
  793. .stc:
  794.         stc
  795. .nothing:
  796.         ret
  797. endp
  798.  
  799. ; Helper procedure for controller-specific code:
  800. ; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
  801. proc usb_unlink_td
  802.         mov     ecx, [ebx+usb_gtd.Pipe]
  803.         add     ecx, usb_pipe.Lock
  804.         call    mutex_lock
  805.         mov     eax, [ebx+usb_gtd.PrevVirt]
  806.         mov     edx, [ebx+usb_gtd.NextVirt]
  807.         mov     [edx+usb_gtd.PrevVirt], eax
  808.         mov     [eax+usb_gtd.NextVirt], edx
  809.         call    mutex_unlock
  810.         ret
  811. endp
  812.  
  813. if USB_STDCALL_VERIFY
  814. proc verify_regs
  815. virtual at esp
  816.         dd      ?       ; return address
  817. .edi    dd      ?
  818. .esi    dd      ?
  819. .ebp    dd      ?
  820. .esp    dd      ?
  821. .ebx    dd      ?
  822. .edx    dd      ?
  823. .ecx    dd      ?
  824. .eax    dd      ?
  825. end virtual
  826.         cmp     ebx, [.ebx]
  827.         jz      @f
  828.         dbgstr 'ERROR!!! ebx changed'
  829. @@:
  830.         cmp     esi, [.esi]
  831.         jz      @f
  832.         dbgstr 'ERROR!!! esi changed'
  833. @@:
  834.         cmp     edi, [.edi]
  835.         jz      @f
  836.         dbgstr 'ERROR!!! edi changed'
  837. @@:
  838.         cmp     ebp, [.ebp]
  839.         jz      @f
  840.         dbgstr 'ERROR!!! ebp changed'
  841. @@:
  842.         ret
  843. endp
  844. end if
  845.