Subversion Repositories Kolibri OS

Rev

Rev 4587 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2013-2014. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 4850 $
  9.  
  10.  
  11. ; USB Host Controller support code: hardware-independent part,
  12. ; common for all controller types.
  13.  
  14. iglobal
  15. ; USB HC support: some functions interesting only for *HCI-drivers.
  16. align 4
  17. usb_hc_func:
  18.         dd      usb_process_gtd
  19.         dd      usb_init_static_endpoint
  20.         dd      usb_wakeup_if_needed
  21.         dd      usb_subscribe_control
  22.         dd      usb_subscription_done
  23.         dd      usb_allocate_common
  24.         dd      usb_free_common
  25.         dd      usb_td_to_virt
  26.         dd      usb_init_transfer
  27.         dd      usb_undo_tds
  28.         dd      usb_test_pending_port
  29.         dd      usb_get_tt
  30.         dd      usb_get_tt_think_time
  31.         dd      usb_new_device
  32.         dd      usb_disconnect_stage2
  33.         dd      usb_process_wait_lists
  34.         dd      usb_unlink_td
  35.         dd      usb_is_final_packet
  36.         dd      usb_find_ehci_companion
  37. endg
  38.  
  39. ; Initializes one controller, called by usb_init for every controller.
  40. ; eax -> PCIDEV structure for the device.
  41. proc usb_init_controller
  42.         push    ebp
  43.         mov     ebp, esp
  44. ; 1. Store in the stack PCI coordinates and save pointer to PCIDEV:
  45. ; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs.
  46.         push    dword [eax+PCIDEV.devfn]
  47.         push    eax
  48.         mov     edi, [eax+PCIDEV.owner]
  49.         test    edi, edi
  50.         jz      .nothing
  51.         mov     edi, [edi+USBSRV.usb_func]
  52. ; 2. Allocate *hci_controller + usb_controller.
  53.         mov     ebx, [edi+usb_hardware_func.DataSize]
  54.         add     ebx, sizeof.usb_controller
  55.         stdcall kernel_alloc, ebx
  56.         test    eax, eax
  57.         jz      .nothing
  58. ; 3. Zero-initialize both structures.
  59.         push    edi eax
  60.         mov     ecx, ebx
  61.         shr     ecx, 2
  62.         xchg    edi, eax
  63.         xor     eax, eax
  64.         rep stosd
  65. ; 4. Initialize usb_controller structure,
  66. ; except data known only to controller-specific code (like NumPorts)
  67. ; and link fields
  68. ; (this structure will be inserted to the overall list at step 6).
  69.         dec     eax
  70.         mov     [edi+usb_controller.ExistingAddresses+4-sizeof.usb_controller], eax
  71.         mov     [edi+usb_controller.ExistingAddresses+8-sizeof.usb_controller], eax
  72.         mov     [edi+usb_controller.ExistingAddresses+12-sizeof.usb_controller], eax
  73.         mov     [edi+usb_controller.ResettingPort-sizeof.usb_controller], al    ; no resetting port
  74.         dec     eax     ; don't allocate zero address
  75.         mov     [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax
  76.         mov     eax, [ebp-4]
  77.         mov     [edi+usb_controller.PCICoordinates-sizeof.usb_controller], eax
  78.         lea     ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller]
  79.         call    mutex_init
  80.         add     ecx, usb_controller.ControlLock - usb_controller.PeriodicLock
  81.         call    mutex_init
  82.         add     ecx, usb_controller.BulkLock - usb_controller.ControlLock
  83.         call    mutex_init
  84.         pop     eax edi
  85.         mov     [eax+ebx-sizeof.usb_controller+usb_controller.HardwareFunc], edi
  86.         push    eax
  87. ; 5. Call controller-specific initialization.
  88. ; If failed, free memory allocated in step 2 and return.
  89.         call    [edi+usb_hardware_func.Init]
  90.         test    eax, eax
  91.         jz      .fail
  92.         pop     ecx
  93. ; 6. Insert the controller to the global list.
  94.         xchg    eax, ebx
  95.         mov     ecx, usb_controllers_list_mutex
  96.         call    mutex_lock
  97.         mov     edx, usb_controllers_list
  98.         mov     eax, [edx+usb_controller.Prev]
  99.         mov     [ebx+usb_controller.Next], edx
  100.         mov     [ebx+usb_controller.Prev], eax
  101.         mov     [edx+usb_controller.Prev], ebx
  102.         mov     [eax+usb_controller.Next], ebx
  103.         call    mutex_unlock
  104. ; 7. Wakeup USB thread to call ProcessDeferred.
  105.         call    usb_wakeup
  106. .nothing:
  107. ; 8. Restore pointer to PCIDEV saved in step 1 and return.
  108.         pop     eax
  109.         leave
  110.         ret
  111. .fail:
  112.         call    kernel_free
  113.         jmp     .nothing
  114. endp
  115.  
  116. ; Helper function, calculates physical address including offset in page.
  117. proc get_phys_addr
  118.         push    ecx
  119.         mov     ecx, eax
  120.         and     ecx, 0xFFF
  121.         call    get_pg_addr
  122.         add     eax, ecx
  123.         pop     ecx
  124.         ret
  125. endp
  126.  
  127. ; Put the given control/bulk pipe in the wait list;
  128. ; called when the pipe structure is changed and a possible hardware cache
  129. ; needs to be synchronized. When it will be known that the cache is updated,
  130. ; usb_subscription_done procedure will be called.
  131. proc usb_subscribe_control
  132.         cmp     [ebx+usb_pipe.NextWait], -1
  133.         jnz     @f
  134.         mov     eax, [esi+usb_controller.WaitPipeListAsync]
  135.         mov     [ebx+usb_pipe.NextWait], eax
  136.         mov     [esi+usb_controller.WaitPipeListAsync], ebx
  137. @@:
  138.         ret
  139. endp
  140.  
  141. ; Same as usb_subscribe_control, but for interrupt/isochronous pipe.
  142. proc usb_subscribe_periodic
  143.         cmp     [ebx+usb_pipe.NextWait], -1
  144.         jnz     @f
  145.         mov     eax, [esi+usb_controller.WaitPipeListPeriodic]
  146.         mov     [ebx+usb_pipe.NextWait], eax
  147.         mov     [esi+usb_controller.WaitPipeListPeriodic], ebx
  148. @@:
  149.         ret
  150. endp
  151.  
  152. ; Called after synchronization of hardware cache with software changes.
  153. ; Continues process of device enumeration based on when it was delayed
  154. ; due to call to usb_subscribe_control.
  155. proc usb_subscription_done
  156.         mov     eax, [ebx+usb_pipe.DeviceData]
  157.         cmp     [eax+usb_device_data.DeviceDescrSize], 0
  158.         jz      usb_after_set_address
  159.         jmp     usb_after_set_endpoint_size
  160. endp
  161.  
  162. ; This function is called when a new device has either passed
  163. ; or failed first stages of configuration, so the next device
  164. ; can enter configuration process.
  165. proc usb_test_pending_port
  166.         mov     [esi+usb_controller.ResettingPort], -1
  167.         cmp     [esi+usb_controller.PendingPorts], 0
  168.         jz      .nothing
  169.         bsf     ecx, [esi+usb_controller.PendingPorts]
  170.         btr     [esi+usb_controller.PendingPorts], ecx
  171.         mov     eax, [esi+usb_controller.HardwareFunc]
  172.         jmp     [eax+usb_hardware_func.InitiateReset]
  173. .nothing:
  174.         ret
  175. endp
  176.  
  177. ; This procedure is regularly called from controller-specific ProcessDeferred,
  178. ; it checks whether there are disconnected events and if so, process them.
  179. proc usb_disconnect_stage2
  180.         bsf     ecx, [esi+usb_controller.NewDisconnected]
  181.         jz      .nothing
  182.         lock btr [esi+usb_controller.NewDisconnected], ecx
  183.         btr     [esi+usb_controller.PendingPorts], ecx
  184.         xor     ebx, ebx
  185.         xchg    ebx, [esi+usb_controller.DevicesByPort+ecx*4]
  186.         test    ebx, ebx
  187.         jz      usb_disconnect_stage2
  188.         call    usb_device_disconnected
  189.         jmp     usb_disconnect_stage2
  190. .nothing:
  191.         ret
  192. endp
  193.  
  194. ; Initial stage of disconnect processing: called when device is disconnected.
  195. proc usb_device_disconnected
  196. ; Loop over all pipes, close everything, wait until hardware reacts.
  197. ; The final handling is done in usb_pipe_closed.
  198.         push    ebx
  199.         mov     ecx, [ebx+usb_pipe.DeviceData]
  200.         call    mutex_lock
  201.         lea     eax, [ecx+usb_device_data.OpenedPipeList-usb_pipe.NextSibling]
  202.         push    eax
  203.         mov     ebx, [eax+usb_pipe.NextSibling]
  204. .pipe_loop:
  205.         call    usb_close_pipe_nolock
  206.         mov     ebx, [ebx+usb_pipe.NextSibling]
  207.         cmp     ebx, [esp]
  208.         jnz     .pipe_loop
  209.         pop     eax
  210.         pop     ebx
  211.         mov     ecx, [ebx+usb_pipe.DeviceData]
  212.         call    mutex_unlock
  213.         ret
  214. endp
  215.  
  216. ; Called from controller-specific ProcessDeferred,
  217. ; processes wait-pipe-done notifications,
  218. ; returns whether there are more items in wait queues.
  219. ; in: esi -> usb_controller
  220. ; out: eax = bitmask of pipe types with non-empty wait queue
  221. proc usb_process_wait_lists
  222.         xor     edx, edx
  223.         push    edx
  224.         call    usb_process_one_wait_list
  225.         jnc     @f
  226.         or      byte [esp], 1 shl CONTROL_PIPE
  227. @@:
  228.         movi    edx, 4
  229.         call    usb_process_one_wait_list
  230.         jnc     @f
  231.         or      byte [esp], 1 shl INTERRUPT_PIPE
  232. @@:
  233.         xor     edx, edx
  234.         call    usb_process_one_wait_list
  235.         jnc     @f
  236.         or      byte [esp], 1 shl CONTROL_PIPE
  237. @@:
  238.         pop     eax
  239.         ret
  240. endp
  241.  
  242. ; Helper procedure for usb_process_wait_lists;
  243. ; does the same for one wait queue.
  244. ; in: esi -> usb_controller,
  245. ; edx=0 for *Async, edx=4 for *Periodic list
  246. ; out: CF = issue new request
  247. proc usb_process_one_wait_list
  248. ; 1. Check whether there is a pending request. If so, do nothing.
  249.         mov     ebx, [esi+usb_controller.WaitPipeRequestAsync+edx]
  250.         cmp     ebx, [esi+usb_controller.ReadyPipeHeadAsync+edx]
  251.         clc
  252.         jnz     .nothing
  253. ; 2. Check whether there are new data. If so, issue a new request.
  254.         cmp     ebx, [esi+usb_controller.WaitPipeListAsync+edx]
  255.         stc
  256.         jnz     .nothing
  257.         test    ebx, ebx
  258.         jz      .nothing
  259. ; 3. Clear all lists.
  260.         xor     ecx, ecx
  261.         mov     [esi+usb_controller.WaitPipeListAsync+edx], ecx
  262.         mov     [esi+usb_controller.WaitPipeRequestAsync+edx], ecx
  263.         mov     [esi+usb_controller.ReadyPipeHeadAsync+edx], ecx
  264. ; 4. Loop over all pipes from the wait list.
  265. .pipe_loop:
  266. ; For every pipe:
  267. ; 5. Save edx and next pipe in the list.
  268.         push    edx
  269.         push    [ebx+usb_pipe.NextWait]
  270. ; 6. If USB_FLAG_EXTRA_WAIT is set, reinsert the pipe to the list and continue.
  271.         test    [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
  272.         jz      .process
  273.         mov     eax, [esi+usb_controller.WaitPipeListAsync+edx]
  274.         mov     [ebx+usb_pipe.NextWait], eax
  275.         mov     [esi+usb_controller.WaitPipeListAsync+edx], ebx
  276.         jmp     .continue
  277. .process:
  278. ; 7. Call the handler depending on USB_FLAG_CLOSED and USB_FLAG_DISABLED.
  279.         or      [ebx+usb_pipe.NextWait], -1
  280.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  281.         jz      .nodisconnect
  282.         call    usb_pipe_closed
  283.         jmp     .continue
  284. .nodisconnect:
  285.         test    [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
  286.         jz      .nodisabled
  287.         call    usb_pipe_disabled
  288.         jmp     .continue
  289. .nodisabled:
  290.         call    usb_subscription_done
  291. .continue:
  292. ; 8. Restore edx and next pipe saved in step 5 and continue the loop.
  293.         pop     ebx
  294.         pop     edx
  295.         test    ebx, ebx
  296.         jnz     .pipe_loop
  297. .check_new_work:
  298. ; 9. Set CF depending on whether WaitPipeList* is nonzero.
  299.         cmp     [esi+usb_controller.WaitPipeListAsync+edx], 1
  300.         cmc
  301. .nothing:
  302.         ret
  303. endp
  304.  
  305. ; Called from USB1 controller-specific initialization.
  306. ; Finds EHCI companion controller for given USB1 controller.
  307. ; in: bl = PCI device:function for USB1 controller, bh = PCI bus
  308. ; out: eax -> usb_controller for EHCI companion
  309. proc usb_find_ehci_companion
  310. ; 1. Loop over all registered controllers.
  311.         mov     eax, usb_controllers_list
  312. .next:
  313.         mov     eax, [eax+usb_controller.Next]
  314.         cmp     eax, usb_controllers_list
  315.         jz      .notfound
  316. ; 2. For every controller, check the type, ignore everything that is not EHCI.
  317.         mov     edx, [eax+usb_controller.HardwareFunc]
  318.         cmp     [edx+usb_hardware_func.ID], 'EHCI'
  319.         jnz     .next
  320. ; 3. For EHCI controller, compare PCI coordinates with input data:
  321. ; bus and device must be the same, function can be different.
  322.         mov     edx, [eax+usb_controller.PCICoordinates]
  323.         xor     edx, ebx
  324.         cmp     dx, 8
  325.         jae     .next
  326.         ret
  327. .notfound:
  328.         xor     eax, eax
  329.         ret
  330. endp
  331.  
  332. ; Find Transaction Translator hub and port for the given device.
  333. ; in: edx = parent hub for the device, ecx = port for the device
  334. ; out: edx = TT hub for the device, ecx = TT port for the device.
  335. proc usb_get_tt
  336. ; If the parent hub is high-speed, it is TT for the device.
  337. ; Otherwise, the parent hub itself is behind TT, and the device
  338. ; has the same TT hub+port as the parent hub.
  339.         mov     eax, [edx+usb_hub.ConfigPipe]
  340.         mov     eax, [eax+usb_pipe.DeviceData]
  341.         cmp     [eax+usb_device_data.Speed], USB_SPEED_HS
  342.         jz      @f
  343.         movzx   ecx, [eax+usb_device_data.TTPort]
  344.         mov     edx, [eax+usb_device_data.TTHub]
  345. @@:
  346.         mov     edx, [edx+usb_hub.ConfigPipe]
  347.         ret
  348. endp
  349.