Subversion Repositories Kolibri OS

Rev

Rev 4418 | Rev 5363 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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