Subversion Repositories Kolibri OS

Rev

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

  1. ; Initialization of the USB subsystem.
  2. ; Provides usb_init procedure, includes all needed files.
  3.  
  4. ; General notes:
  5. ; * There is one entry point for external kernel code: usb_init is called
  6. ;   from initialization code and initializes USB subsystem.
  7. ; * There are several entry points for API; see the docs for description.
  8. ; * There are several functions which are called from controller-specific
  9. ;   parts of USB subsystem. The most important is usb_new_device,
  10. ;   which is called when a new device has been connected (over some time),
  11. ;   has been reset and is ready to start configuring.
  12. ; * IRQ handlers are very restricted. They can not take any locks,
  13. ;   since otherwise a deadlock is possible: imagine that a code has taken the
  14. ;   lock and was interrupted by IRQ handler. Now IRQ handler would wait for
  15. ;   releasing the lock, and a lock owner would wait for exiting IRQ handler
  16. ;   to get the control.
  17. ; * Thus, there is the special USB thread which processes almost all activity.
  18. ;   IRQ handlers do the minimal processing and wake this thread.
  19. ; * Also the USB thread wakes occasionally to process tasks which can be
  20. ;   predicted without interrupts. These include e.g. a periodic roothub
  21. ;   scanning in UHCI and initializing in USB_CONNECT_DELAY ticks
  22. ;   after connecting a new device.
  23. ; * The main procedure of USB thread, usb_thread_proc, does all its work
  24. ;   by querying usb_hardware_func.ProcessDeferred for every controller
  25. ;   and usb_hub_process_deferred for every hub.
  26. ;   ProcessDeferred does controller-specific actions and calculates the time
  27. ;   when it should be invoked again, possibly infinite.
  28. ;   usb_thread_proc selects the minimum from all times returned by
  29. ;   ProcessDeferred and sleeps until this moment is reached or the thread
  30. ;   is awakened by IRQ handler.
  31.  
  32. ; Initializes the USB subsystem.
  33. proc usb_init
  34. ; 1. Initialize all locks.
  35.         mov     ecx, usb_controllers_list_mutex
  36.         call    mutex_init
  37.         mov     ecx, usb1_ep_mutex
  38.         call    mutex_init
  39.         mov     ecx, usb_gtd_mutex
  40.         call    mutex_init
  41.         mov     ecx, ehci_ep_mutex
  42.         call    mutex_init
  43.         mov     ecx, ehci_gtd_mutex
  44.         call    mutex_init
  45. ; 2. Kick off BIOS from all USB controllers, calling the corresponding function
  46. ; *hci_kickoff_bios. Also count USB controllers for the next step.
  47. ; Note: USB1 companion(s) must go before the corresponding EHCI controller,
  48. ; otherwise BIOS could see a device moving from EHCI to a companion;
  49. ; first, this always wastes time;
  50. ; second, some BIOSes are buggy, do not expect that move and try to refer to
  51. ; previously-assigned controller instead of actual; sometimes that leads to
  52. ; hangoff.
  53. ; Thus, process controllers in PCI order.
  54.         mov     esi, pcidev_list
  55.         push    0
  56. .kickoff:
  57.         mov     esi, [esi+PCIDEV.fd]
  58.         cmp     esi, pcidev_list
  59.         jz      .done_kickoff
  60.         cmp     word [esi+PCIDEV.class+1], 0x0C03
  61.         jnz     .kickoff
  62.         mov     eax, uhci_kickoff_bios
  63.         cmp     byte [esi+PCIDEV.class], 0x00
  64.         jz      .do_kickoff
  65.         mov     eax, ohci_kickoff_bios
  66.         cmp     byte [esi+PCIDEV.class], 0x10
  67.         jz      .do_kickoff
  68.         mov     eax, ehci_kickoff_bios
  69.         cmp     byte [esi+PCIDEV.class], 0x20
  70.         jnz     .kickoff
  71. .do_kickoff:
  72.         inc     dword [esp]
  73.         call    eax
  74.         jmp     .kickoff
  75. .done_kickoff:
  76.         pop     eax
  77. ; 3. If no controllers were found, exit.
  78. ; Otherwise, run the USB thread.
  79.         test    eax, eax
  80.         jz      .nothing
  81.         call    create_usb_thread
  82.         jz      .nothing
  83. ; 4. Initialize all USB controllers, calling usb_init_controller for each.
  84. ; Note: USB1 companion(s) should go before the corresponding EHCI controller,
  85. ; although this is not strictly necessary (this way, a companion would not try
  86. ; to initialize high-speed device only to see a disconnect when EHCI takes
  87. ; control).
  88. ; Thus, process all EHCI controllers in the first loop, all USB1 controllers
  89. ; in the second loop. (One loop in reversed PCI order could also be used,
  90. ; but seems less natural.)
  91. ; 4a. Loop over all PCI devices, call usb_init_controller
  92. ; for all EHCI controllers.
  93.         mov     eax, pcidev_list
  94. .scan_ehci:
  95.         mov     eax, [eax+PCIDEV.fd]
  96.         cmp     eax, pcidev_list
  97.         jz      .done_ehci
  98.         cmp     [eax+PCIDEV.class], 0x0C0320
  99.         jnz     .scan_ehci
  100.         mov     edi, ehci_hardware_func
  101.         call    usb_init_controller
  102.         jmp     .scan_ehci
  103. .done_ehci:
  104. ; 4b. Loop over all PCI devices, call usb_init_controller
  105. ; for all UHCI and OHCI controllers.
  106.         mov     eax, pcidev_list
  107. .scan_usb1:
  108.         mov     eax, [eax+PCIDEV.fd]
  109.         cmp     eax, pcidev_list
  110.         jz      .done_usb1
  111.         mov     edi, uhci_hardware_func
  112.         cmp     [eax+PCIDEV.class], 0x0C0300
  113.         jz      @f
  114.         mov     edi, ohci_hardware_func
  115.         cmp     [eax+PCIDEV.class], 0x0C0310
  116.         jnz     .scan_usb1
  117. @@:
  118.         call    usb_init_controller
  119.         jmp     .scan_usb1
  120. .done_usb1:
  121. .nothing:
  122.         ret
  123. endp
  124.  
  125. uglobal
  126. align 4
  127. usb_event       dd      ?
  128. endg
  129.  
  130. ; Helper function for usb_init. Creates and initializes the USB thread.
  131. proc create_usb_thread
  132. ; 1. Create the thread.
  133.         push    edi
  134.         movi    ebx, 1
  135.         mov     ecx, usb_thread_proc
  136.         xor     edx, edx
  137.         call    new_sys_threads
  138.         pop     edi
  139. ; If failed, say something to the debug board and return with ZF set.
  140.         test    eax, eax
  141.         jns     @f
  142.         DEBUGF 1,'K : cannot create kernel thread for USB, error %d\n',eax
  143. .clear:
  144.         xor     eax, eax
  145.         jmp     .nothing
  146. @@:
  147. ; 2. Wait while the USB thread initializes itself.
  148. @@:
  149.         call    change_task
  150.         cmp     [usb_event], 0
  151.         jz      @b
  152. ; 3. If initialization failed, the USB thread sets [usb_event] to -1.
  153. ; Return with ZF set or cleared corresponding to the result.
  154.         cmp     [usb_event], -1
  155.         jz      .clear
  156. .nothing:
  157.         ret
  158. endp
  159.  
  160. ; Helper function for IRQ handlers. Wakes the USB thread if ebx is nonzero.
  161. proc usb_wakeup_if_needed
  162.         test    ebx, ebx
  163.         jz      usb_wakeup.nothing
  164. usb_wakeup:
  165.         xor     edx, edx
  166.         mov     eax, [usb_event]
  167.         mov     ebx, [eax+EVENT.id]
  168.         xor     esi, esi
  169.         call    raise_event
  170. .nothing:
  171.         ret
  172. endp
  173.  
  174. ; Main loop of the USB thread.
  175. proc usb_thread_proc
  176. ; 1. Initialize: create event to allow wakeup by interrupt handlers.
  177.         xor     esi, esi
  178.         mov     ecx, MANUAL_DESTROY
  179.         call    create_event
  180.         test    eax, eax
  181.         jnz     @f
  182. ; If failed, set [usb_event] to -1 and terminate myself.
  183.         dbgstr 'cannot create event for USB thread'
  184.         or      [usb_event], -1
  185.         jmp     sys_end
  186. @@:
  187.         mov     [usb_event], eax
  188.         push    -1              ; initial timeout: infinite
  189. usb_thread_wait:
  190. ; 2. Main loop: wait for either wakeup event or timeout.
  191.         pop     ecx             ; get timeout
  192.         mov     eax, [usb_event]
  193.         mov     ebx, [eax+EVENT.id]
  194.         call    wait_event_timeout
  195.         push    -1              ; default timeout: infinite
  196. ; 3. Main loop: call worker functions of all controllers;
  197. ; if some function schedules wakeup in timeout less than the current value,
  198. ; replace that value with the returned timeout.
  199.         mov     esi, usb_controllers_list
  200. @@:
  201.         mov     esi, [esi+usb_controller.Next]
  202.         cmp     esi, usb_controllers_list
  203.         jz      .controllers_done
  204.         mov     eax, [esi+usb_controller.HardwareFunc]
  205.         call    [eax+usb_hardware_func.ProcessDeferred]
  206.         cmp     [esp], eax
  207.         jb      @b
  208.         mov     [esp], eax
  209.         jmp     @b
  210. .controllers_done:
  211. ; 4. Main loop: call hub worker function for all hubs,
  212. ; similarly calculating minimum of all returned timeouts.
  213. ; When done, continue to 2.
  214.         mov     esi, usb_hubs_list
  215. @@:
  216.         mov     esi, [esi+usb_hub.Next]
  217.         cmp     esi, usb_hubs_list
  218.         jz      usb_thread_wait
  219.         call    usb_hub_process_deferred
  220.         cmp     [esp], eax
  221.         jb      @b
  222.         mov     [esp], eax
  223.         jmp     @b
  224. endp
  225.  
  226. iglobal
  227. align 4
  228. usb_controllers_list:
  229.         dd      usb_controllers_list
  230.         dd      usb_controllers_list
  231. usb_hubs_list:
  232.         dd      usb_hubs_list
  233.         dd      usb_hubs_list
  234. endg
  235. uglobal
  236. align 4
  237. usb_controllers_list_mutex      MUTEX
  238. endg
  239.  
  240. include "memory.inc"
  241. include "hccommon.inc"
  242. include "pipe.inc"
  243. include "ohci.inc"
  244. include "uhci.inc"
  245. include "ehci.inc"
  246. include "protocol.inc"
  247. include "hub.inc"
  248. include "scheduler.inc"
  249.