Subversion Repositories Kolibri OS

Rev

Rev 4850 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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