Subversion Repositories Kolibri OS

Rev

Rev 3908 | Rev 5201 | 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. iglobal
  33. uhci_service_name:
  34.         db      'UHCI',0
  35. ohci_service_name:
  36.         db      'OHCI',0
  37. ehci_service_name:
  38.         db      'EHCI',0
  39. endg
  40.  
  41. ; Initializes the USB subsystem.
  42. proc usb_init
  43. ; 1. Initialize all locks.
  44.         mov     ecx, usb_controllers_list_mutex
  45.         call    mutex_init
  46. ; 2. Kick off BIOS from all USB controllers, calling the corresponding function
  47. ; *hci_kickoff_bios. Also count USB controllers for the next step.
  48. ; Note: USB1 companion(s) must go before the corresponding EHCI controller,
  49. ; otherwise BIOS could see a device moving from EHCI to a companion;
  50. ; first, this always wastes time;
  51. ; second, some BIOSes are buggy, do not expect that move and try to refer to
  52. ; previously-assigned controller instead of actual; sometimes that leads to
  53. ; hangoff.
  54. ; Thus, process controllers in PCI order.
  55.         mov     esi, pcidev_list
  56.         push    0
  57. .kickoff:
  58.         mov     esi, [esi+PCIDEV.list.next]
  59.         cmp     esi, pcidev_list
  60.         jz      .done_kickoff
  61.         cmp     word [esi+PCIDEV.class+1], 0x0C03
  62.         jnz     .kickoff
  63.         mov     ebx, uhci_service_name
  64.         cmp     byte [esi+PCIDEV.class], 0x00
  65.         jz      .do_kickoff
  66.         mov     ebx, ohci_service_name
  67.         cmp     byte [esi+PCIDEV.class], 0x10
  68.         jz      .do_kickoff
  69.         mov     ebx, ehci_service_name
  70.         cmp     byte [esi+PCIDEV.class], 0x20
  71.         jnz     .kickoff
  72. .do_kickoff:
  73.         inc     dword [esp]
  74.         push    ebx esi
  75.         stdcall get_service, ebx
  76.         pop     esi ebx
  77.         test    eax, eax
  78.         jz      .driver_fail
  79.         mov     edx, [eax+USBSRV.usb_func]
  80.         cmp     [edx+usb_hardware_func.Version], USBHC_VERSION
  81.         jnz     .driver_invalid
  82.         mov     [esi+PCIDEV.owner], eax
  83.         call    [edx+usb_hardware_func.BeforeInit]
  84.         jmp     .kickoff
  85. .driver_fail:
  86.         DEBUGF 1,'K : failed to load driver %s\n',ebx
  87.         jmp     .kickoff
  88. .driver_invalid:
  89.         DEBUGF 1,'K : driver %s has wrong version\n',ebx
  90.         jmp     .kickoff
  91. .done_kickoff:
  92.         pop     eax
  93. ; 3. If no controllers were found, exit.
  94. ; Otherwise, run the USB thread.
  95.         test    eax, eax
  96.         jz      .nothing
  97.         call    create_usb_thread
  98.         jz      .nothing
  99. ; 4. Initialize all USB controllers, calling usb_init_controller for each.
  100. ; Note: USB1 companion(s) should go before the corresponding EHCI controller,
  101. ; although this is not strictly necessary (this way, a companion would not try
  102. ; to initialize high-speed device only to see a disconnect when EHCI takes
  103. ; control).
  104. ; Thus, process all EHCI controllers in the first loop, all USB1 controllers
  105. ; in the second loop. (One loop in reversed PCI order could also be used,
  106. ; but seems less natural.)
  107. ; 4a. Loop over all PCI devices, call usb_init_controller
  108. ; for all EHCI controllers.
  109.         mov     eax, pcidev_list
  110. .scan_ehci:
  111.         mov     eax, [eax+PCIDEV.list.next]
  112.         cmp     eax, pcidev_list
  113.         jz      .done_ehci
  114.         cmp     [eax+PCIDEV.class], 0x0C0320
  115.         jnz     .scan_ehci
  116.         call    usb_init_controller
  117.         jmp     .scan_ehci
  118. .done_ehci:
  119. ; 4b. Loop over all PCI devices, call usb_init_controller
  120. ; for all UHCI and OHCI controllers.
  121.         mov     eax, pcidev_list
  122. .scan_usb1:
  123.         mov     eax, [eax+PCIDEV.list.next]
  124.         cmp     eax, pcidev_list
  125.         jz      .done_usb1
  126.         cmp     [eax+PCIDEV.class], 0x0C0300
  127.         jz      @f
  128.         cmp     [eax+PCIDEV.class], 0x0C0310
  129.         jnz     .scan_usb1
  130. @@:
  131.         call    usb_init_controller
  132.         jmp     .scan_usb1
  133. .done_usb1:
  134. .nothing:
  135.         ret
  136. endp
  137.  
  138. uglobal
  139. align 4
  140. usb_event       dd      ?
  141. endg
  142.  
  143. ; Helper function for usb_init. Creates and initializes the USB thread.
  144. proc create_usb_thread
  145. ; 1. Create the thread.
  146.         push    edi
  147.         movi    ebx, 1
  148.         mov     ecx, usb_thread_proc
  149.         xor     edx, edx
  150.         call    new_sys_threads
  151.         pop     edi
  152. ; If failed, say something to the debug board and return with ZF set.
  153.         test    eax, eax
  154.         jns     @f
  155.         DEBUGF 1,'K : cannot create kernel thread for USB, error %d\n',eax
  156. .clear:
  157.         xor     eax, eax
  158.         jmp     .nothing
  159. @@:
  160. ; 2. Wait while the USB thread initializes itself.
  161. @@:
  162.         call    change_task
  163.         cmp     [usb_event], 0
  164.         jz      @b
  165. ; 3. If initialization failed, the USB thread sets [usb_event] to -1.
  166. ; Return with ZF set or cleared corresponding to the result.
  167.         cmp     [usb_event], -1
  168.         jz      .clear
  169. .nothing:
  170.         ret
  171. endp
  172.  
  173. ; Helper function for IRQ handlers. Wakes the USB thread if ebx is nonzero.
  174. proc usb_wakeup_if_needed
  175.         test    ebx, ebx
  176.         jz      usb_wakeup.nothing
  177. usb_wakeup:
  178.         xor     edx, edx
  179.         mov     eax, [usb_event]
  180.         mov     ebx, [eax+EVENT.id]
  181.         xor     esi, esi
  182.         call    raise_event
  183. .nothing:
  184.         ret
  185. endp
  186.  
  187. ; Main loop of the USB thread.
  188. proc usb_thread_proc
  189. ; 1. Initialize: create event to allow wakeup by interrupt handlers.
  190.         xor     esi, esi
  191.         mov     ecx, MANUAL_DESTROY
  192.         call    create_event
  193.         test    eax, eax
  194.         jnz     @f
  195. ; If failed, set [usb_event] to -1 and terminate myself.
  196.         dbgstr 'cannot create event for USB thread'
  197.         or      [usb_event], -1
  198.         jmp     sys_end
  199. @@:
  200.         mov     [usb_event], eax
  201.         push    -1              ; initial timeout: infinite
  202. usb_thread_wait:
  203. ; 2. Main loop: wait for either wakeup event or timeout.
  204.         pop     ecx             ; get timeout
  205.         mov     eax, [usb_event]
  206.         mov     ebx, [eax+EVENT.id]
  207.         call    wait_event_timeout
  208.         push    -1              ; default timeout: infinite
  209. ; 3. Main loop: call worker functions of all controllers;
  210. ; if some function schedules wakeup in timeout less than the current value,
  211. ; replace that value with the returned timeout.
  212.         mov     esi, usb_controllers_list
  213. @@:
  214.         mov     esi, [esi+usb_controller.Next]
  215.         cmp     esi, usb_controllers_list
  216.         jz      .controllers_done
  217.         mov     eax, [esi+usb_controller.HardwareFunc]
  218.         call    [eax+usb_hardware_func.ProcessDeferred]
  219.         cmp     [esp], eax
  220.         jb      @b
  221.         mov     [esp], eax
  222.         jmp     @b
  223. .controllers_done:
  224. ; 4. Main loop: call hub worker function for all hubs,
  225. ; similarly calculating minimum of all returned timeouts.
  226. ; When done, continue to 2.
  227.         mov     esi, usb_hubs_list
  228. @@:
  229.         mov     esi, [esi+usb_hub.Next]
  230.         cmp     esi, usb_hubs_list
  231.         jz      usb_thread_wait
  232.         call    usb_hub_process_deferred
  233.         cmp     [esp], eax
  234.         jb      @b
  235.         mov     [esp], eax
  236.         jmp     @b
  237. endp
  238.  
  239. iglobal
  240. align 4
  241. usb_controllers_list:
  242.         dd      usb_controllers_list
  243.         dd      usb_controllers_list
  244. usb_hubs_list:
  245.         dd      usb_hubs_list
  246.         dd      usb_hubs_list
  247. endg
  248. uglobal
  249. align 4
  250. usb_controllers_list_mutex      MUTEX
  251. endg
  252.  
  253. include "memory.inc"
  254. include "common.inc"
  255. include "hccommon.inc"
  256. include "pipe.inc"
  257. include "protocol.inc"
  258. include "hub.inc"
  259.