Subversion Repositories Kolibri OS

Rev

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

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