Subversion Repositories Kolibri OS

Rev

Rev 3908 | 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. targetsmask     dd      ?       ; S-Mask for USB2
  220. bandwidth       dd      ?
  221. target          dd      ?
  222. endl
  223. ; 1. Verify type of pipe: it must be one of *_PIPE constants.
  224. ; Isochronous pipes are not supported yet.
  225.         mov     eax, [type]
  226.         cmp     eax, INTERRUPT_PIPE
  227.         ja      .badtype
  228.         cmp     al, ISOCHRONOUS_PIPE
  229.         jnz     .goodtype
  230. .badtype:
  231.         dbgstr 'unsupported type of USB pipe'
  232.         jmp     .return0
  233. .goodtype:
  234. ; 2. Allocate memory for pipe and transfer queue.
  235. ; Empty transfer queue consists of one inactive TD.
  236.         mov     ebx, [config_pipe]
  237.         mov     esi, [ebx+usb_pipe.Controller]
  238.         mov     edx, [esi+usb_controller.HardwareFunc]
  239.         call    [edx+usb_hardware_func.AllocPipe]
  240.         test    eax, eax
  241.         jz      .nothing
  242.         mov     edi, eax
  243.         mov     edx, [esi+usb_controller.HardwareFunc]
  244.         call    [edx+usb_hardware_func.AllocTD]
  245.         test    eax, eax
  246.         jz      .free_and_return0
  247. ; 3. Initialize transfer queue: pointer to transfer descriptor,
  248. ; pointers in transfer descriptor, queue lock.
  249.         mov     [edi+usb_pipe.LastTD], eax
  250.         mov     [eax+usb_gtd.NextVirt], eax
  251.         mov     [eax+usb_gtd.PrevVirt], eax
  252.         mov     [eax+usb_gtd.Pipe], edi
  253.         lea     ecx, [edi+usb_pipe.Lock]
  254.         call    mutex_init
  255. ; 4. Initialize software part of pipe structure, except device-related fields.
  256.         mov     al, byte [type]
  257.         mov     [edi+usb_pipe.Type], al
  258.         xor     eax, eax
  259.         mov     [edi+usb_pipe.Flags], al
  260.         mov     [edi+usb_pipe.DeviceData], eax
  261.         mov     [edi+usb_pipe.Controller], esi
  262.         or      [edi+usb_pipe.NextWait], -1
  263. ; 5. Initialize device-related fields:
  264. ; for zero endpoint, set .NextSibling = .PrevSibling = this;
  265. ; for other endpoins, copy device data, take the lock guarding pipe list
  266. ; for the device and verify that disconnect processing has not yet started
  267. ; for the device. (Since disconnect processing also takes that lock,
  268. ; either it has completed or it will not start until we release the lock.)
  269. ; Note: usb_device_disconnected should not see the new pipe until
  270. ; initialization is complete, so that lock will be held during next steps
  271. ; (disconnect processing should either not see it at all, or see fully
  272. ; initialized pipe).
  273.         cmp     [endpoint], eax
  274.         jz      .zero_endpoint
  275.         mov     ecx, [ebx+usb_pipe.DeviceData]
  276.         mov     [edi+usb_pipe.DeviceData], ecx
  277.         call    mutex_lock
  278.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  279.         jz      .common
  280. .fail:
  281. ; If disconnect processing has completed, unlock the mutex, free memory
  282. ; allocated in step 2 and return zero.
  283.         call    mutex_unlock
  284.         mov     edx, [esi+usb_controller.HardwareFunc]
  285.         stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
  286. .free_and_return0:
  287.         mov     edx, [esi+usb_controller.HardwareFunc]
  288.         stdcall [edx+usb_hardware_func.FreePipe], edi
  289. .return0:
  290.         xor     eax, eax
  291.         jmp     .nothing
  292. .zero_endpoint:
  293.         mov     [edi+usb_pipe.NextSibling], edi
  294.         mov     [edi+usb_pipe.PrevSibling], edi
  295. .common:
  296. ; 6. Initialize hardware part of pipe structure.
  297. ; 6a. Acquire the corresponding mutex.
  298.         lea     ecx, [esi+usb_controller.ControlLock]
  299.         cmp     [type], BULK_PIPE
  300.         jb      @f      ; control pipe
  301.         lea     ecx, [esi+usb_controller.BulkLock]
  302.         jz      @f      ; bulk pipe
  303.         lea     ecx, [esi+usb_controller.PeriodicLock]
  304. @@:
  305.         call    mutex_lock
  306. ; 6b. Let the controller-specific code do its job.
  307.         push    ecx
  308.         mov     edx, [esi+usb_controller.HardwareFunc]
  309.         mov     eax, [edi+usb_pipe.LastTD]
  310.         mov     ecx, [config_pipe]
  311.         call    [edx+usb_hardware_func.InitPipe]
  312.         pop     ecx
  313. ; 6c. Release the mutex.
  314.         push    eax
  315.         call    mutex_unlock
  316.         pop     eax
  317. ; 6d. If controller-specific code indicates failure,
  318. ; release the lock taken in step 5, free memory allocated in step 2
  319. ; and return zero.
  320.         test    eax, eax
  321.         jz      .fail
  322. ; 7. The pipe is initialized. If this is not the first pipe for the device,
  323. ; insert it to the tail of pipe list for the device,
  324. ; increment number of pipes,
  325. ; release the lock taken at step 5.
  326.         mov     ecx, [edi+usb_pipe.DeviceData]
  327.         test    ecx, ecx
  328.         jz      @f
  329.         mov     eax, [ebx+usb_pipe.PrevSibling]
  330.         mov     [edi+usb_pipe.NextSibling], ebx
  331.         mov     [edi+usb_pipe.PrevSibling], eax
  332.         mov     [ebx+usb_pipe.PrevSibling], edi
  333.         mov     [eax+usb_pipe.NextSibling], edi
  334.         inc     [ecx+usb_device_data.NumPipes]
  335.         call    mutex_unlock
  336. @@:
  337. ; 8. Return pointer to usb_pipe.
  338.         mov     eax, edi
  339. .nothing:
  340.         ret
  341. endp
  342.  
  343. ; This procedure is called several times during initial device configuration,
  344. ; when usb_device_data structure is reallocated.
  345. ; It (re)initializes all pointers in usb_device_data.
  346. ; ebx -> usb_pipe
  347. proc usb_reinit_pipe_list
  348.         push    eax
  349. ; 1. (Re)initialize the lock guarding pipe list.
  350.         mov     ecx, [ebx+usb_pipe.DeviceData]
  351.         call    mutex_init
  352. ; 2. Initialize list of opened pipes: two entries, the head and ebx.
  353.         add     ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
  354.         mov     [ecx+usb_pipe.NextSibling], ebx
  355.         mov     [ecx+usb_pipe.PrevSibling], ebx
  356.         mov     [ebx+usb_pipe.NextSibling], ecx
  357.         mov     [ebx+usb_pipe.PrevSibling], ecx
  358. ; 3. Initialize list of closed pipes: empty list, only the head is present.
  359.         add     ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
  360.         mov     [ecx+usb_pipe.NextSibling], ecx
  361.         mov     [ecx+usb_pipe.PrevSibling], ecx
  362.         pop     eax
  363.         ret
  364. endp
  365.  
  366. ; Part of API for drivers, see documentation for USBClosePipe.
  367. proc usb_close_pipe
  368.         push    ebx esi ; save used registers to be stdcall
  369. virtual at esp
  370.         rd      2       ; saved registers
  371.         dd      ?       ; return address
  372. .pipe   dd      ?
  373. end virtual
  374. ; 1. Lock the pipe list for the device.
  375.         mov     ebx, [.pipe]
  376.         mov     esi, [ebx+usb_pipe.Controller]
  377.         mov     ecx, [ebx+usb_pipe.DeviceData]
  378.         call    mutex_lock
  379. ; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
  380.         lea     ecx, [ebx+usb_pipe.Lock]
  381.         call    mutex_lock
  382.         or      [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
  383.         call    mutex_unlock
  384. ; 3. Call the worker function.
  385.         call    usb_close_pipe_nolock
  386. ; 4. Unlock the pipe list for the device.
  387.         mov     ecx, [ebx+usb_pipe.DeviceData]
  388.         call    mutex_unlock
  389. ; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
  390.         push    edi
  391.         call    usb_wakeup
  392.         pop     edi
  393. ; 6. Return.
  394.         pop     esi ebx ; restore used registers to be stdcall
  395.         retn    4
  396. endp
  397.  
  398. ; Worker function for pipe closing. Called by usb_close_pipe API and
  399. ; from disconnect processing.
  400. ; The lock guarding pipe list for the device should be held by the caller.
  401. ; ebx -> usb_pipe, esi -> usb_controller
  402. proc usb_close_pipe_nolock
  403. ; 1. Set the flag "pipe is closed, ignore new transfers".
  404. ; If it was already set, do nothing.
  405.         lea     ecx, [ebx+usb_pipe.Lock]
  406.         call    mutex_lock
  407.         bts     dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
  408.         jc      .closed
  409.         call    mutex_unlock
  410. ; 2. Remove the pipe from the list of opened pipes.
  411.         mov     eax, [ebx+usb_pipe.NextSibling]
  412.         mov     edx, [ebx+usb_pipe.PrevSibling]
  413.         mov     [eax+usb_pipe.PrevSibling], edx
  414.         mov     [edx+usb_pipe.NextSibling], eax
  415. ; 3. Unlink the pipe from hardware structures.
  416. ; 3a. Acquire the corresponding lock.
  417.         lea     edx, [esi+usb_controller.WaitPipeListAsync]
  418.         lea     ecx, [esi+usb_controller.ControlLock]
  419.         cmp     [ebx+usb_pipe.Type], BULK_PIPE
  420.         jb      @f      ; control pipe
  421.         lea     ecx, [esi+usb_controller.BulkLock]
  422.         jz      @f      ; bulk pipe
  423.         add     edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
  424.         lea     ecx, [esi+usb_controller.PeriodicLock]
  425. @@:
  426.         push    edx
  427.         call    mutex_lock
  428.         push    ecx
  429. ; 3b. Let the controller-specific code do its job.
  430.         mov     eax, [esi+usb_controller.HardwareFunc]
  431.         call    [eax+usb_hardware_func.UnlinkPipe]
  432. ; 3c. Release the corresponding lock.
  433.         pop     ecx
  434.         call    mutex_unlock
  435. ; 4. Put the pipe into wait queue.
  436.         pop     edx
  437.         cmp     [ebx+usb_pipe.NextWait], -1
  438.         jz      .insert_new
  439.         or      [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
  440.         jmp     .inserted
  441. .insert_new:
  442.         mov     eax, [edx]
  443.         mov     [ebx+usb_pipe.NextWait], eax
  444.         mov     [edx], ebx
  445. .inserted:
  446. ; 5. Return.
  447.         ret
  448. .closed:
  449.         call    mutex_unlock
  450.         xor     eax, eax
  451.         ret
  452. endp
  453.  
  454. ; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
  455. ; corresponding wait list. It means that the hardware has fully forgot about it.
  456. ; ebx -> usb_pipe, esi -> usb_controller
  457. proc usb_pipe_closed
  458.         push    edi
  459.         mov     edi, [esi+usb_controller.HardwareFunc]
  460. ; 1. Loop over all transfers, calling the driver with USB_STATUS_CLOSED
  461. ; and freeing all descriptors.
  462.         mov     edx, [ebx+usb_pipe.LastTD]
  463.         test    edx, edx
  464.         jz      .no_transfer
  465.         mov     edx, [edx+usb_gtd.NextVirt]
  466. .transfer_loop:
  467.         cmp     edx, [ebx+usb_pipe.LastTD]
  468.         jz      .transfer_done
  469.         mov     ecx, [edx+usb_gtd.Callback]
  470.         test    ecx, ecx
  471.         jz      .no_callback
  472.         push    edx
  473.         stdcall_verify ecx, ebx, USB_STATUS_CLOSED, \
  474.                 [edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
  475.         pop     edx
  476. .no_callback:
  477.         push    [edx+usb_gtd.NextVirt]
  478.         stdcall [edi+usb_hardware_func.FreeTD], edx
  479.         pop     edx
  480.         jmp     .transfer_loop
  481. .transfer_done:
  482.         stdcall [edi+usb_hardware_func.FreeTD], edx
  483. .no_transfer:
  484. ; 2. Decrement number of pipes for the device.
  485. ; If this pipe is the last pipe, go to 5.
  486.         mov     ecx, [ebx+usb_pipe.DeviceData]
  487.         call    mutex_lock
  488.         dec     [ecx+usb_device_data.NumPipes]
  489.         jz      .last_pipe
  490.         call    mutex_unlock
  491. ; 3. If the flag "the driver has abandoned this pipe" is set,
  492. ; free memory and return.
  493.         test    [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
  494.         jz      .nofree
  495.         stdcall [edi+usb_hardware_func.FreePipe], ebx
  496.         pop     edi
  497.         ret
  498. ; 4. Otherwise, add it to the list of closed pipes and return.
  499. .nofree:
  500.         add     ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  501.         mov     edx, [ecx+usb_pipe.PrevSibling]
  502.         mov     [ebx+usb_pipe.NextSibling], ecx
  503.         mov     [ebx+usb_pipe.PrevSibling], edx
  504.         mov     [ecx+usb_pipe.PrevSibling], ebx
  505.         mov     [edx+usb_pipe.NextSibling], ebx
  506.         pop     edi
  507.         ret
  508. .last_pipe:
  509. ; That was the last pipe for the device.
  510. ; 5. Notify device driver(s) about disconnect.
  511.         call    mutex_unlock
  512.         movzx   eax, [ecx+usb_device_data.NumInterfaces]
  513.         test    eax, eax
  514.         jz      .notify_done
  515.         add     ecx, [ecx+usb_device_data.Interfaces]
  516. .notify_loop:
  517.         mov     edx, [ecx+usb_interface_data.DriverFunc]
  518.         test    edx, edx
  519.         jz      @f
  520.         mov     edx, [edx+USBSRV.usb_func]
  521.         cmp     [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
  522.         jb      @f
  523.         mov     edx, [edx+USBFUNC.device_disconnect]
  524.         test    edx, edx
  525.         jz      @f
  526.         push    eax ecx
  527.         stdcall_verify edx, [ecx+usb_interface_data.DriverData]
  528.         pop     ecx eax
  529. @@:
  530.         add     ecx, sizeof.usb_interface_data
  531.         dec     eax
  532.         jnz     .notify_loop
  533. .notify_done:
  534. ; 6. Bus address, if assigned, can now be reused.
  535.         call    [edi+usb_hardware_func.GetDeviceAddress]
  536.         test    eax, eax
  537.         jz      @f
  538.         bts     [esi+usb_controller.ExistingAddresses], eax
  539. @@:
  540.         dbgstr 'USB device disconnected'
  541. ; 7. All drivers have returned from disconnect callback,
  542. ; so all drivers should not use any device-related pipes.
  543. ; Free the remaining pipes.
  544.         mov     eax, [ebx+usb_pipe.DeviceData]
  545.         add     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  546.         push    eax
  547.         mov     eax, [eax+usb_pipe.NextSibling]
  548. .free_loop:
  549.         cmp     eax, [esp]
  550.         jz      .free_done
  551.         push    [eax+usb_pipe.NextSibling]
  552.         stdcall [edi+usb_hardware_func.FreePipe], eax
  553.         pop     eax
  554.         jmp     .free_loop
  555. .free_done:
  556.         stdcall [edi+usb_hardware_func.FreePipe], ebx
  557.         pop     eax
  558. ; 8. Free the usb_device_data structure.
  559.         sub     eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
  560.         call    free
  561. ; 9. Return.
  562. .nothing:
  563.         pop     edi
  564.         ret
  565. endp
  566.  
  567. ; Part of API for drivers, see documentation for USBNormalTransferAsync.
  568. proc usb_normal_transfer_async stdcall uses ebx edi,\
  569.  pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
  570. ; 1. Sanity check: callback must be nonzero.
  571. ; (It is important for other parts of code.)
  572.         xor     eax, eax
  573.         cmp     [callback], eax
  574.         jz      .nothing
  575. ; 2. Lock the transfer queue.
  576.         mov     ebx, [pipe]
  577.         lea     ecx, [ebx+usb_pipe.Lock]
  578.         call    mutex_lock
  579. ; 3. If the pipe has already been closed (presumably due to device disconnect),
  580. ; release the lock taken in step 2 and return zero.
  581.         xor     eax, eax
  582.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  583.         jnz     .unlock
  584. ; 4. Allocate and initialize TDs for the transfer.
  585.         mov     edx, [ebx+usb_pipe.Controller]
  586.         mov     edi, [edx+usb_controller.HardwareFunc]
  587.         stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
  588. ; If failed, release the lock taken in step 2 and return zero.
  589.         test    eax, eax
  590.         jz      .unlock
  591. ; 5. Store callback and its parameters in the last descriptor for this transfer.
  592.         mov     ecx, [eax+usb_gtd.PrevVirt]
  593.         mov     edx, [callback]
  594.         mov     [ecx+usb_gtd.Callback], edx
  595.         mov     edx, [calldata]
  596.         mov     [ecx+usb_gtd.UserData], edx
  597.         mov     edx, [buffer]
  598.         mov     [ecx+usb_gtd.Buffer], edx
  599. ; 6. Advance LastTD pointer and activate transfer.
  600.         push    [ebx+usb_pipe.LastTD]
  601.         mov     [ebx+usb_pipe.LastTD], eax
  602.         call    [edi+usb_hardware_func.InsertTransfer]
  603.         pop     eax
  604. ; 7. Release the lock taken in step 2 and
  605. ; return pointer to the first descriptor for the new transfer.
  606. .unlock:
  607.         push    eax
  608.         lea     ecx, [ebx+usb_pipe.Lock]
  609.         call    mutex_unlock
  610.         pop     eax
  611. .nothing:
  612.         ret
  613. endp
  614.  
  615. ; Part of API for drivers, see documentation for USBControlTransferAsync.
  616. proc usb_control_async stdcall uses ebx edi,\
  617.  pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
  618. locals
  619. last_td         dd      ?
  620. endl
  621. ; 1. Sanity check: callback must be nonzero.
  622. ; (It is important for other parts of code.)
  623.         cmp     [callback], 0
  624.         jz      .return0
  625. ; 2. Lock the transfer queue.
  626.         mov     ebx, [pipe]
  627.         lea     ecx, [ebx+usb_pipe.Lock]
  628.         call    mutex_lock
  629. ; 3. If the pipe has already been closed (presumably due to device disconnect),
  630. ; release the lock taken in step 2 and return zero.
  631.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  632.         jnz     .unlock_return0
  633. ; A control transfer contains two or three stages:
  634. ; Setup stage, optional Data stage, Status stage.
  635. ; 4. Allocate and initialize TDs for the Setup stage.
  636. ; Payload is 8 bytes from [config].
  637.         mov     edx, [ebx+usb_pipe.Controller]
  638.         mov     edi, [edx+usb_controller.HardwareFunc]
  639.         stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
  640.                 ; short transfer is an error, direction is DATA0, token is SETUP
  641.         mov     [last_td], eax
  642.         test    eax, eax
  643.         jz      .fail
  644. ; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
  645. ; Payload is [size] bytes from [buffer].
  646.         mov     edx, [config]
  647.         mov     ecx, (3 shl 2) + 1      ; DATA1, token is OUT
  648.         cmp     byte [edx], 0
  649.         jns     @f
  650.         cmp     [size], 0
  651.         jz      @f
  652.         inc     ecx     ; token is IN
  653. @@:
  654.         cmp     [size], 0
  655.         jz      .nodata
  656.         push    ecx
  657.         stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
  658.         pop     ecx
  659.         test    eax, eax
  660.         jz      .fail
  661.         mov     [last_td], eax
  662. .nodata:
  663. ; 6. Allocate and initialize TDs for the Status stage.
  664. ; No payload.
  665.         xor     ecx, 3  ; IN becomes OUT, OUT becomes IN
  666.         stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
  667.         test    eax, eax
  668.         jz      .fail
  669. ; 7. Store callback and its parameters in the last descriptor for this transfer.
  670.         mov     ecx, [eax+usb_gtd.PrevVirt]
  671.         mov     edx, [callback]
  672.         mov     [ecx+usb_gtd.Callback], edx
  673.         mov     edx, [calldata]
  674.         mov     [ecx+usb_gtd.UserData], edx
  675.         mov     edx, [buffer]
  676.         mov     [ecx+usb_gtd.Buffer], edx
  677. ; 8. Advance LastTD pointer and activate transfer.
  678.         push    [ebx+usb_pipe.LastTD]
  679.         mov     [ebx+usb_pipe.LastTD], eax
  680.         call    [edi+usb_hardware_func.InsertTransfer]
  681. ; 9. Release the lock taken in step 2 and
  682. ; return pointer to the first descriptor for the new transfer.
  683.         lea     ecx, [ebx+usb_pipe.Lock]
  684.         call    mutex_unlock
  685.         pop     eax
  686.         ret
  687. .fail:
  688.         mov     eax, [last_td]
  689.         test    eax, eax
  690.         jz      .unlock_return0
  691.         stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
  692. .unlock_return0:
  693.         lea     ecx, [ebx+usb_pipe.Lock]
  694.         call    mutex_unlock
  695. .return0:
  696.         xor     eax, eax
  697.         ret
  698. endp
  699.  
  700. ; Initialize software part of usb_gtd. Called from controller-specific code
  701. ; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
  702. ; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
  703. ; current (initializing) usb_gtd.
  704. ; Returns ecx = [.td].
  705. proc usb_init_transfer
  706. virtual at ebp-4
  707. .Size   dd      ?
  708.         rd      2
  709. .Buffer dd      ?
  710.         dd      ?
  711. .Flags  dd      ?
  712. .td     dd      ?
  713. end virtual
  714.         mov     [eax+usb_gtd.Pipe], ebx
  715.         mov     ecx, [.td]
  716.         mov     [eax+usb_gtd.PrevVirt], ecx
  717.         mov     edx, [ecx+usb_gtd.NextVirt]
  718.         mov     [ecx+usb_gtd.NextVirt], eax
  719.         mov     [eax+usb_gtd.NextVirt], edx
  720.         mov     [edx+usb_gtd.PrevVirt], eax
  721.         mov     edx, [.Size]
  722.         mov     [ecx+usb_gtd.Length], edx
  723.         xor     edx, edx
  724.         mov     [ecx+usb_gtd.Callback], edx
  725.         mov     [ecx+usb_gtd.UserData], edx
  726.         ret
  727. endp
  728.  
  729. ; Free all TDs for the current transfer if something has failed
  730. ; during initialization (e.g. no memory for the next TD).
  731. ; Stdcall with one stack argument = first TD for the transfer
  732. ; and eax = last initialized TD for the transfer.
  733. proc usb_undo_tds
  734.         push    [eax+usb_gtd.NextVirt]
  735. @@:
  736.         cmp     eax, [esp+8]
  737.         jz      @f
  738.         push    [eax+usb_gtd.PrevVirt]
  739.         stdcall [edi+usb_hardware_func.FreeTD], eax
  740.         pop     eax
  741.         jmp     @b
  742. @@:
  743.         pop     ecx
  744.         mov     [eax+usb_gtd.NextVirt], ecx
  745.         mov     [ecx+usb_gtd.PrevVirt], eax
  746.         ret     4
  747. endp
  748.  
  749. ; Helper procedure for handling short packets in controller-specific code.
  750. ; Returns with CF cleared if this is the final packet in some stage:
  751. ; for control transfers that means one of Data and Status stages,
  752. ; for other transfers - the final packet in the only stage.
  753. proc usb_is_final_packet
  754.         cmp     [ebx+usb_gtd.Callback], 0
  755.         jnz     .nothing
  756.         mov     eax, [ebx+usb_gtd.NextVirt]
  757.         cmp     [eax+usb_gtd.Callback], 0
  758.         jz      .stc
  759.         mov     eax, [ebx+usb_gtd.Pipe]
  760.         cmp     [eax+usb_pipe.Type], CONTROL_PIPE
  761.         jz      .nothing
  762. .stc:
  763.         stc
  764. .nothing:
  765.         ret
  766. endp
  767.  
  768. ; Helper procedure for controller-specific code:
  769. ; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
  770. proc usb_unlink_td
  771.         mov     ecx, [ebx+usb_gtd.Pipe]
  772.         add     ecx, usb_pipe.Lock
  773.         call    mutex_lock
  774.         mov     eax, [ebx+usb_gtd.PrevVirt]
  775.         mov     edx, [ebx+usb_gtd.NextVirt]
  776.         mov     [edx+usb_gtd.PrevVirt], eax
  777.         mov     [eax+usb_gtd.NextVirt], edx
  778.         call    mutex_unlock
  779.         ret
  780. endp
  781.  
  782. if USB_STDCALL_VERIFY
  783. proc verify_regs
  784. virtual at esp
  785.         dd      ?       ; return address
  786. .edi    dd      ?
  787. .esi    dd      ?
  788. .ebp    dd      ?
  789. .esp    dd      ?
  790. .ebx    dd      ?
  791. .edx    dd      ?
  792. .ecx    dd      ?
  793. .eax    dd      ?
  794. end virtual
  795.         cmp     ebx, [.ebx]
  796.         jz      @f
  797.         dbgstr 'ERROR!!! ebx changed'
  798. @@:
  799.         cmp     esi, [.esi]
  800.         jz      @f
  801.         dbgstr 'ERROR!!! esi changed'
  802. @@:
  803.         cmp     edi, [.edi]
  804.         jz      @f
  805.         dbgstr 'ERROR!!! edi changed'
  806. @@:
  807.         cmp     ebp, [.ebp]
  808.         jz      @f
  809.         dbgstr 'ERROR!!! ebp changed'
  810. @@:
  811.         ret
  812. endp
  813. end if
  814.