Subversion Repositories Kolibri OS

Rev

Rev 3826 | Rev 4547 | 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 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. ; Called after synchronization of hardware cache with software changes.
  132. ; Continues process of device enumeration based on when it was delayed
  133. ; due to call to usb_subscribe_control.
  134. proc usb_subscription_done
  135.         mov     eax, [ebx+usb_pipe.DeviceData]
  136.         cmp     [eax+usb_device_data.DeviceDescrSize], 0
  137.         jz      usb_after_set_address
  138.         jmp     usb_after_set_endpoint_size
  139. endp
  140.  
  141. ; This function is called when a new device has either passed
  142. ; or failed first stages of configuration, so the next device
  143. ; can enter configuration process.
  144. proc usb_test_pending_port
  145.         mov     [esi+usb_controller.ResettingPort], -1
  146.         cmp     [esi+usb_controller.PendingPorts], 0
  147.         jz      .nothing
  148.         bsf     ecx, [esi+usb_controller.PendingPorts]
  149.         btr     [esi+usb_controller.PendingPorts], ecx
  150.         mov     eax, [esi+usb_controller.HardwareFunc]
  151.         jmp     [eax+usb_hardware_func.InitiateReset]
  152. .nothing:
  153.         ret
  154. endp
  155.  
  156. ; This procedure is regularly called from controller-specific ProcessDeferred,
  157. ; it checks whether there are disconnected events and if so, process them.
  158. proc usb_disconnect_stage2
  159.         bsf     ecx, [esi+usb_controller.NewDisconnected]
  160.         jz      .nothing
  161.         lock btr [esi+usb_controller.NewDisconnected], ecx
  162.         btr     [esi+usb_controller.PendingPorts], ecx
  163.         xor     ebx, ebx
  164.         xchg    ebx, [esi+usb_controller.DevicesByPort+ecx*4]
  165.         test    ebx, ebx
  166.         jz      usb_disconnect_stage2
  167.         call    usb_device_disconnected
  168.         jmp     usb_disconnect_stage2
  169. .nothing:
  170.         ret
  171. endp
  172.  
  173. ; Initial stage of disconnect processing: called when device is disconnected.
  174. proc usb_device_disconnected
  175. ; Loop over all pipes, close everything, wait until hardware reacts.
  176. ; The final handling is done in usb_pipe_closed.
  177.         push    ebx
  178.         mov     ecx, [ebx+usb_pipe.DeviceData]
  179.         call    mutex_lock
  180.         lea     eax, [ecx+usb_device_data.OpenedPipeList-usb_pipe.NextSibling]
  181.         push    eax
  182.         mov     ebx, [eax+usb_pipe.NextSibling]
  183. .pipe_loop:
  184.         call    usb_close_pipe_nolock
  185.         mov     ebx, [ebx+usb_pipe.NextSibling]
  186.         cmp     ebx, [esp]
  187.         jnz     .pipe_loop
  188.         pop     eax
  189.         pop     ebx
  190.         mov     ecx, [ebx+usb_pipe.DeviceData]
  191.         call    mutex_unlock
  192.         ret
  193. endp
  194.  
  195. ; Called from controller-specific ProcessDeferred,
  196. ; processes wait-pipe-done notifications,
  197. ; returns whether there are more items in wait queues.
  198. ; in: esi -> usb_controller
  199. ; out: eax = bitmask of pipe types with non-empty wait queue
  200. proc usb_process_wait_lists
  201.         xor     edx, edx
  202.         push    edx
  203.         call    usb_process_one_wait_list
  204.         jnc     @f
  205.         or      byte [esp], 1 shl CONTROL_PIPE
  206. @@:
  207.         movi    edx, 4
  208.         call    usb_process_one_wait_list
  209.         jnc     @f
  210.         or      byte [esp], 1 shl INTERRUPT_PIPE
  211. @@:
  212.         xor     edx, edx
  213.         call    usb_process_one_wait_list
  214.         jnc     @f
  215.         or      byte [esp], 1 shl CONTROL_PIPE
  216. @@:
  217.         pop     eax
  218.         ret
  219. endp
  220.  
  221. ; Helper procedure for usb_process_wait_lists;
  222. ; does the same for one wait queue.
  223. ; in: esi -> usb_controller,
  224. ; edx=0 for *Async, edx=4 for *Periodic list
  225. ; out: CF = issue new request
  226. proc usb_process_one_wait_list
  227. ; 1. Check whether there is a pending request. If so, do nothing.
  228.         mov     ebx, [esi+usb_controller.WaitPipeRequestAsync+edx]
  229.         cmp     ebx, [esi+usb_controller.ReadyPipeHeadAsync+edx]
  230.         clc
  231.         jnz     .nothing
  232. ; 2. Check whether there are new data. If so, issue a new request.
  233.         cmp     ebx, [esi+usb_controller.WaitPipeListAsync+edx]
  234.         stc
  235.         jnz     .nothing
  236.         test    ebx, ebx
  237.         jz      .nothing
  238. ; 3. Clear all lists.
  239.         xor     ecx, ecx
  240.         mov     [esi+usb_controller.WaitPipeListAsync+edx], ecx
  241.         mov     [esi+usb_controller.WaitPipeRequestAsync+edx], ecx
  242.         mov     [esi+usb_controller.ReadyPipeHeadAsync+edx], ecx
  243. ; 4. Loop over all pipes from the wait list.
  244. .pipe_loop:
  245. ; For every pipe:
  246. ; 5. Save edx and next pipe in the list.
  247.         push    edx
  248.         push    [ebx+usb_pipe.NextWait]
  249. ; 6. If USB_FLAG_EXTRA_WAIT is set, reinsert the pipe to the list and continue.
  250.         test    [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
  251.         jz      .process
  252.         mov     eax, [esi+usb_controller.WaitPipeListAsync+edx]
  253.         mov     [ebx+usb_pipe.NextWait], eax
  254.         mov     [esi+usb_controller.WaitPipeListAsync+edx], ebx
  255.         jmp     .continue
  256. .process:
  257. ; 7. Call the handler depending on USB_FLAG_CLOSED.
  258.         or      [ebx+usb_pipe.NextWait], -1
  259.         test    [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
  260.         jz      .nodisconnect
  261.         call    usb_pipe_closed
  262.         jmp     .continue
  263. .nodisconnect:
  264.         call    usb_subscription_done
  265. .continue:
  266. ; 8. Restore edx and next pipe saved in step 5 and continue the loop.
  267.         pop     ebx
  268.         pop     edx
  269.         test    ebx, ebx
  270.         jnz     .pipe_loop
  271. .check_new_work:
  272. ; 9. Set CF depending on whether WaitPipeList* is nonzero.
  273.         cmp     [esi+usb_controller.WaitPipeListAsync+edx], 1
  274.         cmc
  275. .nothing:
  276.         ret
  277. endp
  278.  
  279. ; Called from USB1 controller-specific initialization.
  280. ; Finds EHCI companion controller for given USB1 controller.
  281. ; in: bl = PCI device:function for USB1 controller, bh = PCI bus
  282. ; out: eax -> usb_controller for EHCI companion
  283. proc usb_find_ehci_companion
  284. ; 1. Loop over all registered controllers.
  285.         mov     eax, usb_controllers_list
  286. .next:
  287.         mov     eax, [eax+usb_controller.Next]
  288.         cmp     eax, usb_controllers_list
  289.         jz      .notfound
  290. ; 2. For every controller, check the type, ignore everything that is not EHCI.
  291.         mov     edx, [eax+usb_controller.HardwareFunc]
  292.         cmp     [edx+usb_hardware_func.ID], 'EHCI'
  293.         jnz     .next
  294. ; 3. For EHCI controller, compare PCI coordinates with input data:
  295. ; bus and device must be the same, function can be different.
  296.         mov     edx, [eax+usb_controller.PCICoordinates]
  297.         xor     edx, ebx
  298.         cmp     dx, 8
  299.         jae     .next
  300.         ret
  301. .notfound:
  302.         xor     eax, eax
  303.         ret
  304. endp
  305.  
  306. ; Find Transaction Translator hub and port for the given device.
  307. ; in: edx = parent hub for the device, ecx = port for the device
  308. ; out: edx = TT hub for the device, ecx = TT port for the device.
  309. proc usb_get_tt
  310. ; If the parent hub is high-speed, it is TT for the device.
  311. ; Otherwise, the parent hub itself is behind TT, and the device
  312. ; has the same TT hub+port as the parent hub.
  313.         mov     eax, [edx+usb_hub.ConfigPipe]
  314.         mov     eax, [eax+usb_pipe.DeviceData]
  315.         cmp     [eax+usb_device_data.Speed], USB_SPEED_HS
  316.         jz      @f
  317.         movzx   ecx, [eax+usb_device_data.TTPort]
  318.         mov     edx, [eax+usb_device_data.TTHub]
  319. @@:
  320.         mov     edx, [edx+usb_hub.ConfigPipe]
  321.         ret
  322. endp
  323.