Subversion Repositories Kolibri OS

Rev

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

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