Subversion Repositories Kolibri OS

Rev

Rev 4423 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4423 Rev 5201
Line -... Line 1...
-
 
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: 5177 $
-
 
9
 
-
 
10
 
1
; Implementation of the USB protocol for device enumeration.
11
; Implementation of the USB protocol for device enumeration.
2
; Manage a USB device when it becomes ready for USB commands:
12
; Manage a USB device when it becomes ready for USB commands:
3
; configure, enumerate, load the corresponding driver(s),
13
; configure, enumerate, load the corresponding driver(s),
4
; pass device information to the driver.
14
; pass device information to the driver.
Line 31... Line 41...
31
 
41
 
32
; Compile-time setting. If set, the code will dump all descriptors as they are
42
; Compile-time setting. If set, the code will dump all descriptors as they are
33
; read to the debug board.
43
; read to the debug board.
Line -... Line 44...
-
 
44
USB_DUMP_DESCRIPTORS = 1
-
 
45
 
-
 
46
; According to the USB specification (9.2.6.3),
-
 
47
; any device must response to SET_ADDRESS in 50 ms, or 5 timer ticks.
-
 
48
; Of course, our world is far from ideal.
-
 
49
; I have seen devices that just NAK everything when being reset from working
-
 
50
; state, but start to work after second reset.
-
 
51
; Our strategy is as follows: give 2 seconds for the first attempt,
-
 
52
; this should be enough for normal devices and not too long to detect buggy ones.
-
 
53
; If the device continues NAKing, reset it and retry several times,
-
 
54
; doubling the interval: 2s -> 4s -> 8s -> 16s. Give up after that.
-
 
55
; Numbers are quite arbitrary.
-
 
56
TIMEOUT_SET_ADDRESS_INITIAL = 200
34
USB_DUMP_DESCRIPTORS = 1
57
TIMEOUT_SET_ADDRESS_LAST    = 1600
35
 
58
 
36
; =============================================================================
59
; =============================================================================
37
; ================================ Structures =================================
60
; ================================ Structures =================================
38
; =============================================================================
61
; =============================================================================
Line 177... Line 200...
177
; in: [esi+usb_controller.ResettingSpeed] is the speed of the device, one of
200
; in: [esi+usb_controller.ResettingSpeed] is the speed of the device, one of
178
;     USB_SPEED_xx.
201
;     USB_SPEED_xx.
179
; out: eax = 0 <=> failed, the caller should disable the port.
202
; out: eax = 0 <=> failed, the caller should disable the port.
180
proc usb_new_device
203
proc usb_new_device
181
        push    ebx edi         ; save used registers to be stdcall
204
        push    ebx edi         ; save used registers to be stdcall
-
 
205
; 1. Check whether we're here because we were trying to reset
-
 
206
; already-registered device in hope to fix something serious.
-
 
207
; If so, skip allocation and go to 6.
-
 
208
        movzx   eax, [esi+usb_controller.ResettingPort]
-
 
209
        mov     edx, [esi+usb_controller.ResettingHub]
-
 
210
        test    edx, edx
-
 
211
        jz      .test_roothub
-
 
212
        mov     edx, [edx+usb_hub.ConnectedDevicesPtr]
-
 
213
        mov     ebx, [edx+eax*4]
-
 
214
        jmp     @f
-
 
215
.test_roothub:
-
 
216
        mov     ebx, [esi+usb_controller.DevicesByPort+eax*4]
-
 
217
@@:
-
 
218
        test    ebx, ebx
-
 
219
        jnz     .try_set_address
182
; 1. Allocate resources. Any device uses the following resources:
220
; 2. Allocate resources. Any device uses the following resources:
183
; - device address in the bus
221
; - device address in the bus
184
; - memory for device data
222
; - memory for device data
185
; - pipe for zero endpoint
223
; - pipe for zero endpoint
186
; If some allocation fails, we must undo our actions. Closing the pipe
224
; If some allocation fails, we must undo our actions. Closing the pipe
187
; is a hard task, so we avoid it and open the pipe as the last resource.
225
; is a hard task, so we avoid it and open the pipe as the last resource.
188
; The order for other two allocations is quite arbitrary.
226
; The order for other two allocations is quite arbitrary.
189
; 1a. Allocate a bus address.
227
; 2a. Allocate a bus address.
190
        push    ecx
228
        push    ecx
191
        call    usb_set_address_request
229
        call    usb_set_address_request
192
        pop     ecx
230
        pop     ecx
193
; 1b. If failed, just return zero.
231
; 2b. If failed, just return zero.
194
        test    eax, eax
232
        test    eax, eax
195
        jz      .nothing
233
        jz      .nothing
196
; 1c. Allocate memory for device data.
234
; 2c. Allocate memory for device data.
197
; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR
235
; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR
198
; input and output, see usb_after_set_address. Later we will reallocate it
236
; input and output, see usb_after_set_address. Later we will reallocate it
199
; to actual size needed for descriptors.
237
; to actual size needed for descriptors.
200
        movi    eax, sizeof.usb_device_data + 8
238
        movi    eax, sizeof.usb_device_data + 8
201
        push    ecx
239
        push    ecx
202
        call    malloc
240
        call    malloc
203
        pop     ecx
241
        pop     ecx
204
; 1d. If failed, free the bus address and return zero.
242
; 2d. If failed, free the bus address and return zero.
205
        test    eax, eax
243
        test    eax, eax
206
        jz      .nomemory
244
        jz      .nomemory
207
; 1e. Open pipe for endpoint zero.
245
; 2e. Open pipe for endpoint zero.
208
; For now, we do not know the actual maximum packet size;
246
; For now, we do not know the actual maximum packet size;
209
; for full-speed devices it can be any of 8, 16, 32, 64 bytes,
247
; for full-speed devices it can be any of 8, 16, 32, 64 bytes,
210
; low-speed devices must have 8 bytes, high-speed devices must have 64 bytes.
248
; low-speed devices must have 8 bytes, high-speed devices must have 64 bytes.
211
; Thus, we must use some fake "maximum packet size" until the actual size
249
; Thus, we must use some fake "maximum packet size" until the actual size
212
; will be known. However, the maximum packet size must be at least 8, and
250
; will be known. However, the maximum packet size must be at least 8, and
Line 225... Line 263...
225
        xor     edi, edi
263
        xor     edi, edi
226
        stdcall usb_open_pipe, ecx, edi, 64, edi, edi
264
        stdcall usb_open_pipe, ecx, edi, 64, edi, edi
227
; Put pointer to pipe into ebx. "xchg eax,reg" is one byte, mov is two bytes.
265
; Put pointer to pipe into ebx. "xchg eax,reg" is one byte, mov is two bytes.
228
        xchg    eax, ebx
266
        xchg    eax, ebx
229
        pop     eax
267
        pop     eax
230
; 1f. If failed, free the memory, the bus address and return zero.
268
; 2f. If failed, free the memory, the bus address and return zero.
231
        test    ebx, ebx
269
        test    ebx, ebx
232
        jz      .freememory
270
        jz      .freememory
233
; 2. Store pointer to device data in the pipe structure.
271
; 3. Store pointer to device data in the pipe structure.
234
        mov     [ebx+usb_pipe.DeviceData], eax
272
        mov     [ebx+usb_pipe.DeviceData], eax
235
; 3. Init device data, using usb_controller.Resetting* variables.
273
; 4. Init device data, using usb_controller.Resetting* variables.
-
 
274
        mov     [eax+usb_device_data.Timer], edi
-
 
275
        mov     dword [eax+usb_device_data.DeviceDescriptor], TIMEOUT_SET_ADDRESS_INITIAL
236
        mov     [eax+usb_device_data.TTHub], edi
276
        mov     [eax+usb_device_data.TTHub], edi
237
        mov     [eax+usb_device_data.TTPort], 0
277
        mov     [eax+usb_device_data.TTPort], 0
238
        mov     [eax+usb_device_data.NumInterfaces], edi
278
        mov     [eax+usb_device_data.NumInterfaces], edi
239
        mov     [eax+usb_device_data.DeviceDescrSize], 0
279
        mov     [eax+usb_device_data.DeviceDescrSize], 0
240
        mov     dl, [esi+usb_controller.ResettingSpeed]
280
        mov     dl, [esi+usb_controller.ResettingSpeed]
Line 266... Line 306...
266
        mov     [eax+usb_device_data.Interfaces], edi
306
        mov     [eax+usb_device_data.Interfaces], edi
267
        movzx   ecx, [esi+usb_controller.ResettingPort]
307
        movzx   ecx, [esi+usb_controller.ResettingPort]
268
        mov     [eax+usb_device_data.Port], cl
308
        mov     [eax+usb_device_data.Port], cl
269
        mov     edx, [esi+usb_controller.ResettingHub]
309
        mov     edx, [esi+usb_controller.ResettingHub]
270
        mov     [eax+usb_device_data.Hub], edx
310
        mov     [eax+usb_device_data.Hub], edx
271
; 4. Store pointer to the config pipe in the hub data.
311
; 5. Store pointer to the config pipe in the hub data.
272
; Config pipe serves as device identifier.
312
; Config pipe serves as device identifier.
273
; Root hubs use the array inside usb_controller structure,
313
; Root hubs use the array inside usb_controller structure,
274
; non-root hubs use the array immediately after usb_hub structure.
314
; non-root hubs use the array immediately after usb_hub structure.
275
        test    edx, edx
315
        test    edx, edx
276
        jz      .roothub
316
        jz      .roothub
Line 279... Line 319...
279
        jmp     @f
319
        jmp     @f
280
.roothub:
320
.roothub:
281
        mov     [esi+usb_controller.DevicesByPort+ecx*4], ebx
321
        mov     [esi+usb_controller.DevicesByPort+ecx*4], ebx
282
@@:
322
@@:
283
        call    usb_reinit_pipe_list
323
        call    usb_reinit_pipe_list
284
; 5. Issue SET_ADDRESS control request, using buffer filled in step 1a.
324
; 6. Issue SET_ADDRESS control request, using buffer filled in step 2a.
285
; Use the return value from usb_control_async as our return value;
325
; 6a. Configure timer to force reset after timeout.
-
 
326
; Note: we can't use self-destructing timer, because we need to be able to cancel it,
-
 
327
; and for self-destructing timer we could have race condition in cancelling/destructing.
-
 
328
;        DEBUGF 1,'K : pipe %x\n',ebx
-
 
329
.try_set_address:
-
 
330
        xor     edi, edi
-
 
331
        mov     edx, [ebx+usb_pipe.DeviceData]
-
 
332
        stdcall timer_hs, [edx+usb_device_data.DeviceDescriptor], 7FFFFFFFh, usb_abort_pipe, ebx
-
 
333
        test    eax, eax
-
 
334
        jz      .nothing
-
 
335
        mov     edx, [ebx+usb_pipe.DeviceData]
-
 
336
        mov     [edx+usb_device_data.Timer], eax
286
; if it is zero, then something has failed.
337
; 6b. If it succeeded, setup timer to configure wait timeout.
287
        lea     eax, [esi+usb_controller.SetAddressBuffer]
338
        lea     eax, [esi+usb_controller.SetAddressBuffer]
288
        stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
339
        stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
-
 
340
; Use the return value from usb_control_async as our return value;
-
 
341
; if it is zero, then something has failed.
289
.nothing:
342
.nothing:
290
; 6. Return.
343
; 7. Return.
291
        pop     edi ebx         ; restore used registers to be stdcall
344
        pop     edi ebx         ; restore used registers to be stdcall
292
        ret
345
        ret
293
; Handlers of failures in steps 1b, 1d, 1f.
346
; Handlers of failures in steps 2b, 2d, 2f.
294
.freememory:
347
.freememory:
295
        call    free
348
        call    free
296
        jmp     .freeaddr
349
        jmp     .freeaddr
297
.nomemory:
350
.nomemory:
298
        dbgstr 'No memory for device data'
351
        dbgstr 'No memory for device data'
Line 347... Line 400...
347
; This procedure is called by USB stack when SET_ADDRESS request initiated by
400
; This procedure is called by USB stack when SET_ADDRESS request initiated by
348
; usb_new_device is completed, either successfully or unsuccessfully.
401
; usb_new_device is completed, either successfully or unsuccessfully.
349
; Note that USB stack uses esi = pointer to usb_controller.
402
; Note that USB stack uses esi = pointer to usb_controller.
350
proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
403
proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
351
        push    ebx     ; save ebx to be stdcall
404
        push    ebx     ; save ebx to be stdcall
352
; Load data to registers for further references.
-
 
353
        mov     ebx, [pipe]
405
        mov     ebx, [pipe]
-
 
406
; 1. In any case, cancel the timer.
-
 
407
        mov     eax, [ebx+usb_pipe.DeviceData]
-
 
408
        stdcall cancel_timer_hs, [eax+usb_device_data.Timer]
-
 
409
        mov     eax, [ebx+usb_pipe.DeviceData]
-
 
410
        mov     [eax+usb_device_data.Timer], 0
-
 
411
; Load data to registers for further references.
354
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
412
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
355
        mov     eax, [esi+usb_controller.HardwareFunc]
413
        mov     eax, [esi+usb_controller.HardwareFunc]
356
; 1. Check whether the device has accepted new address. If so, proceed to 2.
414
; 2. Check whether the device has accepted new address. If so, proceed to 3.
-
 
415
; Otherwise, go to 4 if killed by usb_set_address_timeout or to 5 otherwise.
-
 
416
        cmp     [status], USB_STATUS_CANCELLED
357
; Otherwise, go to 3.
417
        jz      .timeout
358
        cmp     [status], 0
418
        cmp     [status], 0
359
        jnz     .error
419
        jnz     .error
360
; 2. Address accepted.
420
; 3. Address accepted.
361
; 2a. The controller-specific structure for the control pipe still uses
421
; 3a. The controller-specific structure for the control pipe still uses
362
; zero address. Call the controller-specific function to change it to
422
; zero address. Call the controller-specific function to change it to
363
; the actual address.
423
; the actual address.
364
; Note that the hardware could cache the controller-specific structure,
424
; Note that the hardware could cache the controller-specific structure,
365
; so setting the address could take some time until the cache is evicted.
425
; so setting the address could take some time until the cache is evicted.
366
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
426
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
367
; be safe to continue.
427
; be safe to continue.
368
;        dbgstr 'address set in device'
428
;        dbgstr 'address set in device'
369
        call    [eax+usb_hardware_func.SetDeviceAddress]
429
        call    [eax+usb_hardware_func.SetDeviceAddress]
370
; 2b. If the port is in non-root hub, clear 'reset in progress' flag.
430
; 3b. If the port is in non-root hub, clear 'reset in progress' flag.
371
; In any case, proceed to 4.
431
; In any case, proceed to 6.
372
        mov     eax, [esi+usb_controller.ResettingHub]
432
        mov     eax, [esi+usb_controller.ResettingHub]
373
        test    eax, eax
433
        test    eax, eax
374
        jz      .return
434
        jz      .return
375
        and     [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
435
        and     [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
376
.return:
436
.return:
377
; 4. Address configuration done, we can proceed with other ports.
437
; 6. Address configuration done, we can proceed with other ports.
378
; Call the worker function for that.
438
; Call the worker function for that.
379
        call    usb_test_pending_port
439
        call    usb_test_pending_port
-
 
440
.wakeup:
-
 
441
        push    esi edi
-
 
442
        call    usb_wakeup
-
 
443
        pop     edi esi
380
.nothing:
444
.nothing:
381
        pop     ebx     ; restore ebx to be stdcall
445
        pop     ebx     ; restore ebx to be stdcall
382
        ret
446
        ret
-
 
447
.timeout:
-
 
448
; 4. Device continues to NAK the request. Reset it and retry.
-
 
449
        mov     edx, [ebx+usb_pipe.DeviceData]
-
 
450
        mov     ecx, [edx+usb_device_data.DeviceDescriptor]
-
 
451
        add     ecx, ecx
-
 
452
        cmp     ecx, TIMEOUT_SET_ADDRESS_LAST
-
 
453
        ja      .error
-
 
454
        mov     [edx+usb_device_data.DeviceDescriptor], ecx
-
 
455
        dbgstr 'Timeout in USB device initialization, trying to reset...'
-
 
456
        cmp     [esi+usb_controller.ResettingHub], 0
-
 
457
        jz      .reset_roothub
-
 
458
        push    esi
-
 
459
        mov     esi, [esi+usb_controller.ResettingHub]
-
 
460
        call    usb_hub_initiate_reset
-
 
461
        pop     esi
-
 
462
        jmp     .nothing
-
 
463
.reset_roothub:
-
 
464
        movzx   ecx, [esi+usb_controller.ResettingPort]
-
 
465
        call    [eax+usb_hardware_func.InitiateReset]
-
 
466
        jmp     .wakeup
383
.error:
467
.error:
384
; 3. Device error: device not responding, disconnect etc.
468
; 5. Device error: device not responding, disconnect etc.
385
        DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
469
        DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
386
; 3a. The address has not been accepted. Mark it as free.
470
; 5a. The address has not been accepted. Mark it as free.
387
        bts     dword [esi+usb_controller.ExistingAddresses], ecx
471
        bts     dword [esi+usb_controller.ExistingAddresses], ecx
388
; 3b. Disable the port with bad device.
472
; 5b. Disable the port with bad device.
389
; For the root hub, call the controller-specific function and go to 6.
473
; For the root hub, call the controller-specific function and go to 6.
390
; For non-root hubs, let the hub code do its work and return (the request
474
; For non-root hubs, let the hub code do its work and return (the request
391
; could take some time, the hub code is responsible for proceeding).
475
; could take some time, the hub code is responsible for proceeding).
392
        cmp     [esi+usb_controller.ResettingHub], 0
476
        cmp     [esi+usb_controller.ResettingHub], 0
393
        jz      .roothub
477
        jz      .roothub
Line 640... Line 724...
640
        pop     edi esi
724
        pop     edi esi
641
        call    usb_reinit_pipe_list
725
        call    usb_reinit_pipe_list
642
; 3d. Free old memory.
726
; 3d. Free old memory.
643
        call    free
727
        call    free
644
        pop     eax
728
        pop     eax
645
; 4. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
729
; 4. Issue control transfer GET_DESCRIPTOR(CONFIGURATION) for full descriptor.
646
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
730
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
647
        mov     edx, [eax+usb_device_data.ConfigDataSize]
731
        mov     edx, [eax+usb_device_data.ConfigDataSize]
648
        lea     eax, [eax+ecx+sizeof.usb_device_data]
732
        lea     eax, [eax+ecx+sizeof.usb_device_data]
649
        mov     dword [eax], \
733
        mov     dword [eax], \
650
                80h + \         ; device-to-host, standard, device-wide
734
                80h + \         ; device-to-host, standard, device-wide