Subversion Repositories Kolibri OS

Rev

Rev 3626 | 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.         push    1
  135.         pop     ebx
  136.         mov     ecx, usb_thread_proc
  137.         xor     edx, edx
  138.         call    new_sys_threads
  139.         pop     edi
  140. ; If failed, say something to the debug board and return with ZF set.
  141.         test    eax, eax
  142.         jns     @f
  143.         DEBUGF 1,'K : cannot create kernel thread for USB, error %d\n',eax
  144. .clear:
  145.         xor     eax, eax
  146.         jmp     .nothing
  147. @@:
  148. ; 2. Wait while the USB thread initializes itself.
  149. @@:
  150.         call    change_task
  151.         cmp     [usb_event], 0
  152.         jz      @b
  153. ; 3. If initialization failed, the USB thread sets [usb_event] to -1.
  154. ; Return with ZF set or cleared corresponding to the result.
  155.         cmp     [usb_event], -1
  156.         jz      .clear
  157. .nothing:
  158.         ret
  159. endp
  160.  
  161. ; Helper function for IRQ handlers. Wakes the USB thread if ebx is nonzero.
  162. proc usb_wakeup_if_needed
  163.         test    ebx, ebx
  164.         jz      usb_wakeup.nothing
  165. usb_wakeup:
  166.         xor     edx, edx
  167.         mov     eax, [usb_event]
  168.         mov     ebx, [eax+EVENT.id]
  169.         xor     esi, esi
  170.         call    raise_event
  171. .nothing:
  172.         ret
  173. endp
  174.  
  175. ; Main loop of the USB thread.
  176. proc usb_thread_proc
  177. ; 1. Initialize: create event to allow wakeup by interrupt handlers.
  178.         xor     esi, esi
  179.         mov     ecx, MANUAL_DESTROY
  180.         call    create_event
  181.         test    eax, eax
  182.         jnz     @f
  183. ; If failed, set [usb_event] to -1 and terminate myself.
  184.         dbgstr 'cannot create event for USB thread'
  185.         or      [usb_event], -1
  186.         jmp     sys_end
  187. @@:
  188.         mov     [usb_event], eax
  189.         push    -1              ; initial timeout: infinite
  190. usb_thread_wait:
  191. ; 2. Main loop: wait for either wakeup event or timeout.
  192.         pop     ecx             ; get timeout
  193.         mov     eax, [usb_event]
  194.         mov     ebx, [eax+EVENT.id]
  195.         call    wait_event_timeout
  196.         push    -1              ; default timeout: infinite
  197. ; 3. Main loop: call worker functions of all controllers;
  198. ; if some function schedules wakeup in timeout less than the current value,
  199. ; replace that value with the returned timeout.
  200.         mov     esi, usb_controllers_list
  201. @@:
  202.         mov     esi, [esi+usb_controller.Next]
  203.         cmp     esi, usb_controllers_list
  204.         jz      .controllers_done
  205.         mov     eax, [esi+usb_controller.HardwareFunc]
  206.         call    [eax+usb_hardware_func.ProcessDeferred]
  207.         cmp     [esp], eax
  208.         jb      @b
  209.         mov     [esp], eax
  210.         jmp     @b
  211. .controllers_done:
  212. ; 4. Main loop: call hub worker function for all hubs,
  213. ; similarly calculating minimum of all returned timeouts.
  214. ; When done, continue to 2.
  215.         mov     esi, usb_hubs_list
  216. @@:
  217.         mov     esi, [esi+usb_hub.Next]
  218.         cmp     esi, usb_hubs_list
  219.         jz      usb_thread_wait
  220.         call    usb_hub_process_deferred
  221.         cmp     [esp], eax
  222.         jb      @b
  223.         mov     [esp], eax
  224.         jmp     @b
  225. endp
  226.  
  227. iglobal
  228. align 4
  229. usb_controllers_list:
  230.         dd      usb_controllers_list
  231.         dd      usb_controllers_list
  232. usb_hubs_list:
  233.         dd      usb_hubs_list
  234.         dd      usb_hubs_list
  235. endg
  236. uglobal
  237. align 4
  238. usb_controllers_list_mutex      MUTEX
  239. endg
  240.  
  241. include "memory.inc"
  242. include "hccommon.inc"
  243. include "pipe.inc"
  244. include "ohci.inc"
  245. include "uhci.inc"
  246. include "ehci.inc"
  247. include "protocol.inc"
  248. include "hub.inc"
  249. include "scheduler.inc"
  250.