Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3520 clevermous 1
; Implementation of the USB protocol for device enumeration.
2
; Manage a USB device when it becomes ready for USB commands:
3
; configure, enumerate, load the corresponding driver(s),
4
; pass device information to the driver.
5
 
6
; =============================================================================
7
; ================================= Constants =================================
8
; =============================================================================
9
; USB standard request codes
10
USB_GET_STATUS        = 0
11
USB_CLEAR_FEATURE     = 1
12
USB_SET_FEATURE       = 3
13
USB_SET_ADDRESS       = 5
14
USB_GET_DESCRIPTOR    = 6
15
USB_SET_DESCRIPTOR    = 7
16
USB_GET_CONFIGURATION = 8
17
USB_SET_CONFIGURATION = 9
18
USB_GET_INTERFACE     = 10
19
USB_SET_INTERFACE     = 11
20
USB_SYNCH_FRAME       = 12
21
 
22
; USB standard descriptor types
23
USB_DEVICE_DESCR             = 1
24
USB_CONFIG_DESCR             = 2
25
USB_STRING_DESCR             = 3
26
USB_INTERFACE_DESCR          = 4
27
USB_ENDPOINT_DESCR           = 5
28
USB_DEVICE_QUALIFIER_DESCR   = 6
29
USB_OTHER_SPEED_CONFIG_DESCR = 7
30
USB_INTERFACE_POWER_DESCR    = 8
31
 
32
; Compile-time setting. If set, the code will dump all descriptors as they are
33
; read to the debug board.
34
USB_DUMP_DESCRIPTORS = 1
35
 
4547 clevermous 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
47
TIMEOUT_SET_ADDRESS_LAST    = 1600
48
 
3520 clevermous 49
; =============================================================================
50
; ================================ Structures =================================
51
; =============================================================================
52
; USB descriptors. See USB specification for detailed explanations.
53
; First two bytes of every descriptor have the same meaning.
54
struct usb_descr
55
bLength                 db      ?
56
; Size of this descriptor in bytes
57
bDescriptorType         db      ?
58
; One of USB_*_DESCR constants.
59
ends
60
 
61
; USB device descriptor
62
struct usb_device_descr usb_descr
63
bcdUSB                  dw      ?
64
; USB Specification Release number in BCD, e.g. 110h = USB 1.1
65
bDeviceClass            db      ?
66
; USB Device Class Code
67
bDeviceSubClass         db      ?
68
; USB Device Subclass Code
69
bDeviceProtocol         db      ?
70
; USB Device Protocol Code
71
bMaxPacketSize0         db      ?
72
; Maximum packet size for zero endpoint
73
idVendor                dw      ?
74
; Vendor ID
75
idProduct               dw      ?
76
; Product ID
77
bcdDevice               dw      ?
78
; Device release number in BCD
79
iManufacturer           db      ?
80
; Index of string descriptor describing manufacturer
81
iProduct                db      ?
82
; Index of string descriptor describing product
83
iSerialNumber           db      ?
84
; Index of string descriptor describing serial number
85
bNumConfigurations      db      ?
86
; Number of possible configurations
87
ends
88
 
89
; USB configuration descriptor
90
struct usb_config_descr usb_descr
91
wTotalLength            dw      ?
92
; Total length of data returned for this configuration
93
bNumInterfaces          db      ?
94
; Number of interfaces in this configuration
95
bConfigurationValue     db      ?
96
; Value for SET_CONFIGURATION control request
97
iConfiguration          db      ?
98
; Index of string descriptor describing this configuration
99
bmAttributes            db      ?
100
; Bit 6 is SelfPowered, bit 5 is RemoteWakeupSupported,
101
; bit 7 must be 1, other bits must be 0
102
bMaxPower               db      ?
103
; Maximum power consumption from the bus in 2mA units
104
ends
105
 
106
; USB interface descriptor
107
struct usb_interface_descr usb_descr
108
; The following two fields work in pair. Sometimes one interface can work
109
; in different modes; e.g. videostream from web-cameras requires different
110
; bandwidth depending on resolution/quality/compression settings.
111
; Each mode of each interface has its own descriptor with its own endpoints
112
; following; all descriptors for one interface have the same bInterfaceNumber,
113
; and different bAlternateSetting.
114
; By default, any interface operates in mode with bAlternateSetting = 0.
115
; Often this is the only mode. If there are another modes, the active mode
116
; is selected by SET_INTERFACE(bAlternateSetting) control request.
117
bInterfaceNumber        db      ?
118
bAlternateSetting       db      ?
119
bNumEndpoints           db      ?
120
; Number of endpoints used by this interface, excluding zero endpoint
121
bInterfaceClass         db      ?
122
; USB Interface Class Code
123
bInterfaceSubClass      db      ?
124
; USB Interface Subclass Code
125
bInterfaceProtocol      db      ?
126
; USB Interface Protocol Code
127
iInterface              db      ?
128
; Index of string descriptor describing this interface
129
ends
130
 
131
; USB endpoint descriptor
132
struct usb_endpoint_descr usb_descr
133
bEndpointAddress        db      ?
134
; Lower 4 bits form endpoint number,
135
; upper bit is 0 for OUT endpoints and 1 for IN endpoints,
136
; other bits must be zero
137
bmAttributes            db      ?
138
; Lower 2 bits form transfer type, one of *_PIPE,
139
; other bits must be zero for non-isochronous endpoints;
140
; refer to the USB specification for meaning in isochronous case
141
wMaxPacketSize          dw      ?
142
; Lower 11 bits form maximum packet size,
143
; next two bits specify the number of additional transactions per microframe
144
; for high-speed periodic endpoints, other bits must be zero.
145
bInterval               db      ?
146
; Interval for polling endpoint for data transfers.
147
; Isochronous and high-speed interrupt endpoints: poll every 2^(bInterval-1)
148
; (micro)frames
149
; Full/low-speed interrupt endpoints: poll every bInterval frames
150
; High-speed bulk/control OUT endpoints: maximum NAK rate
151
ends
152
 
153
; =============================================================================
154
; =================================== Code ====================================
155
; =============================================================================
156
 
157
; When a new device is ready to be configured, a controller-specific code
158
; calls usb_new_device.
159
; The sequence of further actions:
160
; * open pipe for the zero endpoint (usb_new_device);
161
;   maximum packet size is not known yet, but it must be at least 8 bytes,
162
;   so it is safe to send packets with <= 8 bytes
163
; * issue SET_ADDRESS control request (usb_new_device)
164
; * set the new device address in the pipe (usb_set_address_callback)
165
; * notify a controller-specific code that initialization of other ports
166
;   can be started (usb_set_address_callback)
167
; * issue GET_DESCRIPTOR control request for first 8 bytes of device descriptor
168
;   (usb_after_set_address)
169
; * first 8 bytes of device descriptor contain the true packet size for zero
170
;   endpoint, so set the true packet size (usb_get_descr8_callback)
171
; * first 8 bytes of a descriptor contain the full size of this descriptor,
172
;   issue GET_DESCRIPTOR control request for the full device descriptor
173
;   (usb_after_set_endpoint_size)
174
; * issue GET_DESCRIPTOR control request for first 8 bytes of configuration
175
;   descriptor (usb_get_descr_callback)
176
; * issue GET_DESCRIPTOR control request for full configuration descriptor
177
;   (usb_know_length_callback)
178
; * issue SET_CONFIGURATION control request (usb_set_config_callback)
179
; * parse configuration descriptor, load the corresponding driver(s),
180
;   pass the configuration descriptor to the driver and let the driver do
181
;   the further work (usb_got_config_callback)
182
 
183
; This function is called from controller-specific part
184
; when a new device is ready to be configured.
185
; in: ecx -> pseudo-pipe, part of usb_pipe
186
; in: esi -> usb_controller
187
; in: [esi+usb_controller.ResettingHub] is the pointer to usb_hub for device,
188
;     NULL if the device is connected to the root hub
189
; in: [esi+usb_controller.ResettingPort] is the port for the device, zero-based
190
; in: [esi+usb_controller.ResettingSpeed] is the speed of the device, one of
191
;     USB_SPEED_xx.
192
; out: eax = 0 <=> failed, the caller should disable the port.
193
proc usb_new_device
194
        push    ebx edi         ; save used registers to be stdcall
4547 clevermous 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
210
; 2. Allocate resources. Any device uses the following resources:
3520 clevermous 211
; - device address in the bus
212
; - memory for device data
213
; - pipe for zero endpoint
214
; If some allocation fails, we must undo our actions. Closing the pipe
215
; is a hard task, so we avoid it and open the pipe as the last resource.
216
; The order for other two allocations is quite arbitrary.
4547 clevermous 217
; 2a. Allocate a bus address.
3520 clevermous 218
        push    ecx
219
        call    usb_set_address_request
220
        pop     ecx
4547 clevermous 221
; 2b. If failed, just return zero.
3520 clevermous 222
        test    eax, eax
223
        jz      .nothing
4547 clevermous 224
; 2c. Allocate memory for device data.
3520 clevermous 225
; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR
226
; input and output, see usb_after_set_address. Later we will reallocate it
227
; to actual size needed for descriptors.
4138 clevermous 228
        movi    eax, sizeof.usb_device_data + 8
3520 clevermous 229
        push    ecx
230
        call    malloc
231
        pop     ecx
4547 clevermous 232
; 2d. If failed, free the bus address and return zero.
3520 clevermous 233
        test    eax, eax
234
        jz      .nomemory
4547 clevermous 235
; 2e. Open pipe for endpoint zero.
3520 clevermous 236
; For now, we do not know the actual maximum packet size;
237
; for full-speed devices it can be any of 8, 16, 32, 64 bytes,
238
; low-speed devices must have 8 bytes, high-speed devices must have 64 bytes.
239
; Thus, we must use some fake "maximum packet size" until the actual size
240
; will be known. However, the maximum packet size must be at least 8, and
241
; initial stages of the configuration process involves only packets of <= 8
242
; bytes, they will be transferred correctly as long as
243
; the fake "maximum packet size" is also at least 8.
244
; Thus, any number >= 8 is suitable for actual hardware.
245
; However, software emulation of EHCI in VirtualBox assumes that high-speed
246
; control transfers are those originating from pipes with max packet size = 64,
247
; even on early stages of the configuration process. This is incorrect,
248
; but we have no specific preferences, so let VirtualBox be happy and use 64
249
; as the fake "maximum packet size".
250
        push    eax
251
; We will need many zeroes.
252
; "push edi" is one byte, "push 0" is two bytes; save space, use edi.
253
        xor     edi, edi
254
        stdcall usb_open_pipe, ecx, edi, 64, edi, edi
255
; Put pointer to pipe into ebx. "xchg eax,reg" is one byte, mov is two bytes.
256
        xchg    eax, ebx
257
        pop     eax
4547 clevermous 258
; 2f. If failed, free the memory, the bus address and return zero.
3520 clevermous 259
        test    ebx, ebx
260
        jz      .freememory
4547 clevermous 261
; 3. Store pointer to device data in the pipe structure.
3520 clevermous 262
        mov     [ebx+usb_pipe.DeviceData], eax
4547 clevermous 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
3826 clevermous 266
        mov     [eax+usb_device_data.TTHub], edi
267
        mov     [eax+usb_device_data.TTPort], 0
268
        mov     [eax+usb_device_data.NumInterfaces], edi
269
        mov     [eax+usb_device_data.DeviceDescrSize], 0
270
        mov     dl, [esi+usb_controller.ResettingSpeed]
271
        mov     [eax+usb_device_data.Speed], dl
3520 clevermous 272
        mov     [eax+usb_device_data.NumPipes], 1
3826 clevermous 273
        push    ebx
274
        cmp     dl, USB_SPEED_HS
275
        jz      .nott
276
        mov     ebx, [esi+usb_controller.ResettingHub]
277
        test    ebx, ebx
278
        jz      .nott
279
        mov     cl, [esi+usb_controller.ResettingPort]
280
        mov     edx, [ebx+usb_hub.ConfigPipe]
281
        mov     edx, [edx+usb_pipe.DeviceData]
282
        cmp     [edx+usb_device_data.TTHub], 0
283
        jz      @f
284
        mov     cl, [edx+usb_device_data.TTPort]
285
        mov     ebx, [edx+usb_device_data.TTHub]
286
        jmp     .has_tt
287
@@:
288
        cmp     [edx+usb_device_data.Speed], USB_SPEED_HS
289
        jnz     .nott
290
.has_tt:
291
        mov     [eax+usb_device_data.TTHub], ebx
292
        mov     [eax+usb_device_data.TTPort], cl
293
.nott:
294
        pop     ebx
3520 clevermous 295
        mov     [eax+usb_device_data.ConfigDataSize], edi
296
        mov     [eax+usb_device_data.Interfaces], edi
297
        movzx   ecx, [esi+usb_controller.ResettingPort]
3826 clevermous 298
        mov     [eax+usb_device_data.Port], cl
3520 clevermous 299
        mov     edx, [esi+usb_controller.ResettingHub]
300
        mov     [eax+usb_device_data.Hub], edx
4547 clevermous 301
; 5. Store pointer to the config pipe in the hub data.
3520 clevermous 302
; Config pipe serves as device identifier.
303
; Root hubs use the array inside usb_controller structure,
304
; non-root hubs use the array immediately after usb_hub structure.
305
        test    edx, edx
306
        jz      .roothub
307
        mov     edx, [edx+usb_hub.ConnectedDevicesPtr]
308
        mov     [edx+ecx*4], ebx
309
        jmp     @f
310
.roothub:
311
        mov     [esi+usb_controller.DevicesByPort+ecx*4], ebx
312
@@:
313
        call    usb_reinit_pipe_list
4547 clevermous 314
; 6. Issue SET_ADDRESS control request, using buffer filled in step 2a.
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
327
; 6b. If it succeeded, setup timer to configure wait timeout.
328
        lea     eax, [esi+usb_controller.SetAddressBuffer]
329
        stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
3520 clevermous 330
; Use the return value from usb_control_async as our return value;
331
; if it is zero, then something has failed.
332
.nothing:
4547 clevermous 333
; 7. Return.
3520 clevermous 334
        pop     edi ebx         ; restore used registers to be stdcall
335
        ret
4547 clevermous 336
; Handlers of failures in steps 2b, 2d, 2f.
3520 clevermous 337
.freememory:
338
        call    free
339
        jmp     .freeaddr
340
.nomemory:
341
        dbgstr 'No memory for device data'
342
.freeaddr:
343
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
344
        bts     [esi+usb_controller.ExistingAddresses], ecx
345
        xor     eax, eax
346
        jmp     .nothing
347
endp
348
 
349
; Helper procedure for usb_new_device.
350
; Allocates a new USB address and fills usb_controller.SetAddressBuffer
351
; with data for SET_ADDRESS(allocated_address) request.
352
; out: eax = 0 <=> failed
353
; Destroys edi.
354
proc usb_set_address_request
355
; There are 128 bits, one for each possible address.
356
; Note: only the USB thread works with usb_controller.ExistingAddresses,
357
; so there is no need for synchronization.
358
; We must find a bit set to 1 and clear it.
359
; 1. Find the first dword which has a nonzero bit = which is nonzero.
360
        mov     ecx, 128/32
361
        lea     edi, [esi+usb_controller.ExistingAddresses]
362
        xor     eax, eax
363
        repz scasd
364
; 2. If all dwords are zero, return an error.
365
        jz      .error
366
; 3. The dword at [edi-4] is nonzero. Find the lowest nonzero bit.
367
        bsf     eax, [edi-4]
368
; Now eax = bit number inside the dword at [edi-4].
369
; 4. Clear the bit.
370
        btr     [edi-4], eax
371
; 5. Generate the address by edi = memory address and eax = bit inside dword.
372
; Address = eax + 8 * (edi-4 - (esi+usb_controller.ExistingAddress)).
373
        sub     edi, esi
374
        lea     edi, [eax+(edi-4-usb_controller.ExistingAddresses)*8]
375
; 6. Store the allocated address in SetAddressBuffer and fill remaining fields.
376
; Note that usb_controller is zeroed at allocation, so only command byte needs
377
; to be filled.
378
        mov     byte [esi+usb_controller.SetAddressBuffer+1], USB_SET_ADDRESS
379
        mov     dword [esi+usb_controller.SetAddressBuffer+2], edi
380
; 7. Return non-zero value in eax.
381
        inc     eax
382
.nothing:
383
        ret
384
.error:
385
        dbgstr 'cannot allocate USB address'
386
        xor     eax, eax
387
        jmp     .nothing
388
endp
389
 
390
; This procedure is called by USB stack when SET_ADDRESS request initiated by
391
; usb_new_device is completed, either successfully or unsuccessfully.
392
; Note that USB stack uses esi = pointer to usb_controller.
393
proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
394
        push    ebx     ; save ebx to be stdcall
4547 clevermous 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
3520 clevermous 401
; Load data to registers for further references.
402
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
403
        mov     eax, [esi+usb_controller.HardwareFunc]
4547 clevermous 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
407
        jz      .timeout
3520 clevermous 408
        cmp     [status], 0
409
        jnz     .error
4547 clevermous 410
; 3. Address accepted.
411
; 3a. The controller-specific structure for the control pipe still uses
3520 clevermous 412
; zero address. Call the controller-specific function to change it to
413
; the actual address.
414
; Note that the hardware could cache the controller-specific structure,
415
; so setting the address could take some time until the cache is evicted.
416
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
417
; be safe to continue.
4418 clevermous 418
;        dbgstr 'address set in device'
3520 clevermous 419
        call    [eax+usb_hardware_func.SetDeviceAddress]
4547 clevermous 420
; 3b. If the port is in non-root hub, clear 'reset in progress' flag.
421
; In any case, proceed to 6.
3520 clevermous 422
        mov     eax, [esi+usb_controller.ResettingHub]
423
        test    eax, eax
424
        jz      .return
425
        and     [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
426
.return:
4547 clevermous 427
; 6. Address configuration done, we can proceed with other ports.
3520 clevermous 428
; Call the worker function for that.
429
        call    usb_test_pending_port
4547 clevermous 430
.wakeup:
431
        push    esi edi
432
        call    usb_wakeup
433
        pop     edi esi
3520 clevermous 434
.nothing:
435
        pop     ebx     ; restore ebx to be stdcall
436
        ret
4547 clevermous 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
3520 clevermous 457
.error:
4547 clevermous 458
; 5. Device error: device not responding, disconnect etc.
3520 clevermous 459
        DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
4547 clevermous 460
; 5a. The address has not been accepted. Mark it as free.
3520 clevermous 461
        bts     dword [esi+usb_controller.ExistingAddresses], ecx
4547 clevermous 462
; 5b. Disable the port with bad device.
3520 clevermous 463
; For the root hub, call the controller-specific function and go to 6.
464
; For non-root hubs, let the hub code do its work and return (the request
465
; could take some time, the hub code is responsible for proceeding).
466
        cmp     [esi+usb_controller.ResettingHub], 0
467
        jz      .roothub
468
        mov     eax, [esi+usb_controller.ResettingHub]
469
        call    usb_hub_disable_resetting_port
470
        jmp     .nothing
471
.roothub:
472
        movzx   ecx, [esi+usb_controller.ResettingPort]
473
        call    [eax+usb_hardware_func.PortDisable]
474
        jmp     .return
475
endp
476
 
477
; This procedure is called from usb_subscription_done when the hardware cache
478
; is cleared after request from usb_set_address_callback.
479
; in: ebx -> usb_pipe
480
proc usb_after_set_address
4418 clevermous 481
;        dbgstr 'address set for controller'
3520 clevermous 482
; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
483
; Remember, we still do not know the actual packet size;
484
; 8-bytes-request is safe.
485
; usb_new_device has allocated 8 extra bytes besides sizeof.usb_device_data;
486
; use them for both input and output.
487
        mov     eax, [ebx+usb_pipe.DeviceData]
488
        add     eax, usb_device_data.DeviceDescriptor
489
        mov     dword [eax], \
490
                80h + \         ; device-to-host, standard, device-wide
491
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
492
                (0 shl 16) + \  ; descriptor index: there is only one
493
                (USB_DEVICE_DESCR shl 24)       ; descriptor type
494
        mov     dword [eax+4], 8 shl 16         ; data length
495
        stdcall usb_control_async, ebx, eax, eax, 8, usb_get_descr8_callback, eax, 0
496
        ret
497
endp
498
 
499
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE_DESCR)
500
; request initiated by usb_after_set_address is completed, either successfully
501
; or unsuccessfully.
502
; Note that USB stack uses esi = pointer to usb_controller.
503
proc usb_get_descr8_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
504
;       mov     eax, [buffer]
505
;       DEBUGF 1,'K : descr8: l=%x; %x %x %x %x %x %x %x %x\n',[length],\
506
;               [eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2
507
        push    edi ebx         ; save used registers to be stdcall
508
        mov     ebx, [pipe]
509
; 1. Check whether the operation was successful.
510
; If not, say something to the debug board and stop the initialization.
511
        cmp     [status], 0
512
        jnz     .error
513
; 2. Length of descriptor must be at least sizeof.usb_device_descr bytes.
514
; If not, say something to the debug board and stop the initialization.
515
        mov     eax, [ebx+usb_pipe.DeviceData]
516
        cmp     [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength], sizeof.usb_device_descr
517
        jb      .error
518
; 3. Now first 8 bytes of device descriptor are known;
519
; set DeviceDescrSize accordingly.
520
        mov     [eax+usb_device_data.DeviceDescrSize], 8
521
; 4. The controller-specific structure for the control pipe still uses
522
; the fake "maximum packet size". Call the controller-specific function to
523
; change it to the actual packet size from the device.
524
; Note that the hardware could cache the controller-specific structure,
525
; so changing it could take some time until the cache is evicted.
526
; Thus, the call is asynchronous; meet us in usb_after_set_endpoint_size
527
; when it will be safe to continue.
528
        movzx   ecx, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bMaxPacketSize0]
529
        mov     eax, [esi+usb_controller.HardwareFunc]
530
        call    [eax+usb_hardware_func.SetEndpointPacketSize]
531
.nothing:
532
; 5. Return.
533
        pop     ebx edi         ; restore used registers to be stdcall
534
        ret
535
.error:
536
        dbgstr 'error with USB device descriptor'
537
        jmp     .nothing
538
endp
539
 
540
; This procedure is called from usb_subscription_done when the hardware cache
541
; is cleared after request from usb_get_descr8_callback.
542
; in: ebx -> usb_pipe
543
proc usb_after_set_endpoint_size
544
; 1. Reallocate memory for device data:
545
; add memory for now-known size of device descriptor and extra 8 bytes
546
; for further actions.
547
; 1a. Allocate new memory.
548
        mov     eax, [ebx+usb_pipe.DeviceData]
549
        movzx   eax, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength]
550
; save length for step 2
551
        push    eax
552
        add     eax, sizeof.usb_device_data + 8
553
        call    malloc
554
; 1b. If failed, say something to the debug board and stop the initialization.
555
        test    eax, eax
556
        jz      .nomemory
557
; 1c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
558
        push    eax
559
        push    esi edi
560
        mov     esi, [ebx+usb_pipe.DeviceData]
561
        mov     [ebx+usb_pipe.DeviceData], eax
562
        mov     edi, eax
563
        mov     eax, esi
3826 clevermous 564
        mov     ecx, sizeof.usb_device_data / 4
565
        rep movsd
3520 clevermous 566
        pop     edi esi
567
        call    usb_reinit_pipe_list
568
; 1d. Free the old memory.
569
        call    free
570
        pop     eax
571
; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
572
; restore length saved in step 1a
573
        pop     edx
574
        add     eax, sizeof.usb_device_data
575
        mov     dword [eax], \
576
                80h + \         ; device-to-host, standard, device-wide
577
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
578
                (0 shl 16) + \  ; descriptor index: there is only one
579
                (USB_DEVICE_DESCR shl 24)       ; descriptor type
580
        and     dword [eax+4], 0
581
        mov     [eax+6], dl     ; data length
582
        stdcall usb_control_async, ebx, eax, eax, edx, usb_get_descr_callback, eax, 0
583
; 3. Return.
584
        ret
585
.nomemory:
586
        dbgstr 'No memory for device data'
587
        ret
588
endp
589
 
590
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE)
591
; request initiated by usb_after_set_endpoint_size is completed,
592
; either successfully or unsuccessfully.
593
proc usb_get_descr_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
594
; Note: the prolog is the same as in usb_get_descr8_callback.
595
        push    edi ebx         ; save used registers to be stdcall
596
; 1. Check whether the operation was successful.
597
; If not, say something to the debug board and stop the initialization.
598
        cmp     [status], 0
599
        jnz     usb_get_descr8_callback.error
600
; The full descriptor is known, dump it if specified by compile-time option.
601
if USB_DUMP_DESCRIPTORS
602
        mov     eax, [buffer]
603
        mov     ecx, [length]
604
        sub     ecx, 8
605
        jbe     .skipdebug
606
        DEBUGF 1,'K : device descriptor:'
607
@@:
608
        DEBUGF 1,' %x',[eax]:2
609
        inc     eax
610
        dec     ecx
611
        jnz     @b
612
        DEBUGF 1,'\n'
613
.skipdebug:
614
end if
615
; 2. Check that bLength is the same as was in the previous request.
616
; If not, say something to the debug board and stop the initialization.
617
; It is important, because usb_after_set_endpoint_size has allocated memory
618
; according to the old bLength. Note that [length] for control transfers
619
; includes 8 bytes of setup packet, so data length = [length] - 8.
620
        mov     eax, [buffer]
621
        movzx   ecx, [eax+usb_device_descr.bLength]
622
        add     ecx, 8
623
        cmp     [length], ecx
624
        jnz     usb_get_descr8_callback.error
625
; Amuse the user if she is watching the debug board.
626
        mov     cl, [eax+usb_device_descr.bNumConfigurations]
627
        DEBUGF 1,'K : found USB device with ID %x:%x, %d configuration(s)\n',\
628
                [eax+usb_device_descr.idVendor]:4,\
629
                [eax+usb_device_descr.idProduct]:4,\
630
                cl
631
; 3. If there are no configurations, stop the initialization.
632
        cmp     [eax+usb_device_descr.bNumConfigurations], 0
633
        jz      .nothing
634
; 4. Copy length of device descriptor to device data structure.
635
        movzx   edx, [eax+usb_device_descr.bLength]
636
        mov     [eax+usb_device_data.DeviceDescrSize-usb_device_data.DeviceDescriptor], dl
637
; 5. Issue control transfer GET_DESCRIPTOR(CONFIGURATION). We do not know
638
; the full length of that descriptor, so start with first 8 bytes, they contain
639
; the full length.
640
; usb_after_set_endpoint_size has allocated 8 extra bytes after the
641
; device descriptor, use them for both input and output.
642
        add     eax, edx
643
        mov     dword [eax], \
644
                80h + \         ; device-to-host, standard, device-wide
645
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
646
                (0 shl 16) + \  ; descriptor index: there is only one
647
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
648
        mov     dword [eax+4], 8 shl 16         ; data length
649
        stdcall usb_control_async, [pipe], eax, eax, 8, usb_know_length_callback, eax, 0
650
.nothing:
651
; 6. Return.
652
        pop     ebx edi         ; restore used registers to be stdcall
653
        ret
654
endp
655
 
656
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
657
; request initiated by usb_get_descr_callback is completed,
658
; either successfully or unsuccessfully.
659
proc usb_know_length_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
660
        push    ebx             ; save used registers to be stdcall
661
; 1. Check whether the operation was successful.
662
; If not, say something to the debug board and stop the initialization.
663
        cmp     [status], 0
664
        jnz     .error
665
; 2. Get the total length of data associated with config descriptor and store
666
; it in device data structure. The total length must be at least
667
; sizeof.usb_config_descr bytes; if not, say something to the debug board and
668
; stop the initialization.
669
        mov     eax, [buffer]
670
        mov     edx, [pipe]
671
        movzx   ecx, [eax+usb_config_descr.wTotalLength]
672
        mov     eax, [edx+usb_pipe.DeviceData]
673
        cmp     ecx, sizeof.usb_config_descr
674
        jb      .error
675
        mov     [eax+usb_device_data.ConfigDataSize], ecx
676
; 3. Reallocate memory for device data:
677
; include usb_device_data structure, device descriptor,
678
; config descriptor with all associated data, and extra bytes
679
; sufficient for 8 bytes control packet and for one usb_interface_data struc.
680
; Align extra bytes to dword boundary.
681
if sizeof.usb_interface_data > 8
682
.extra_size = sizeof.usb_interface_data
683
else
684
.extra_size = 8
685
end if
686
; 3a. Allocate new memory.
687
        movzx   edx, [eax+usb_device_data.DeviceDescrSize]
688
        lea     eax, [ecx+edx+sizeof.usb_device_data+.extra_size+3]
689
        and     eax, not 3
690
        push    eax
691
        call    malloc
692
        pop     edx
693
; 3b. If failed, say something to the debug board and stop the initialization.
694
        test    eax, eax
695
        jz      .nomemory
696
; 3c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
697
        push    eax
698
        mov     ebx, [pipe]
699
        push    esi edi
700
        mov     esi, [ebx+usb_pipe.DeviceData]
701
        mov     edi, eax
702
        mov     [ebx+usb_pipe.DeviceData], eax
703
        mov     eax, esi
704
        movzx   ecx, [esi+usb_device_data.DeviceDescrSize]
705
        sub     edx, .extra_size
706
        mov     [esi+usb_device_data.Interfaces], edx
707
        add     ecx, sizeof.usb_device_data + 8
708
        mov     edx, ecx
709
        shr     ecx, 2
710
        and     edx, 3
711
        rep movsd
712
        mov     ecx, edx
713
        rep movsb
714
        pop     edi esi
715
        call    usb_reinit_pipe_list
716
; 3d. Free old memory.
717
        call    free
718
        pop     eax
719
; 4. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
720
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
721
        mov     edx, [eax+usb_device_data.ConfigDataSize]
722
        lea     eax, [eax+ecx+sizeof.usb_device_data]
723
        mov     dword [eax], \
724
                80h + \         ; device-to-host, standard, device-wide
725
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
726
                (0 shl 16) + \  ; descriptor index: there is only one
727
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
728
        and     dword [eax+4], 0
729
        mov     word [eax+6], dx        ; data length
730
        stdcall usb_control_async, [pipe], eax, eax, edx, usb_set_config_callback, eax, 0
731
.nothing:
732
; 5. Return.
733
        pop     ebx             ; restore used registers to be stdcall
734
        ret
735
.error:
736
        dbgstr 'error with USB configuration descriptor'
737
        jmp     .nothing
738
.nomemory:
739
        dbgstr 'No memory for device data'
740
        jmp     .nothing
741
endp
742
 
743
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
744
; request initiated by usb_know_length_callback is completed,
745
; either successfully or unsuccessfully.
746
proc usb_set_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
747
; Note that the prolog is the same as in usb_know_length_callback.
748
        push    ebx             ; save used registers to be stdcall
749
; 1. Check whether the operation was successful.
750
; If not, say something to the debug board and stop the initialization.
751
        xor     ecx, ecx
752
        mov     ebx, [pipe]
753
        cmp     [status], ecx
754
        jnz     usb_know_length_callback.error
755
; The full descriptor is known, dump it if specified by compile-time option.
756
if USB_DUMP_DESCRIPTORS
757
        mov     eax, [buffer]
758
        mov     ecx, [length]
759
        sub     ecx, 8
760
        jbe     .skip_debug
761
        DEBUGF 1,'K : config descriptor:'
762
@@:
763
        DEBUGF 1,' %x',[eax]:2
764
        inc     eax
765
        dec     ecx
766
        jnz     @b
767
        DEBUGF 1,'\n'
768
.skip_debug:
769
        xor     ecx, ecx
770
end if
771
; 2. Issue control transfer SET_CONFIGURATION to activate this configuration.
772
; Usually this is the only configuration.
773
; Use extra bytes allocated by usb_know_length_callback;
774
; offset from device data start is stored in Interfaces.
775
        mov     eax, [ebx+usb_pipe.DeviceData]
776
        mov     edx, [buffer]
777
        add     eax, [eax+usb_device_data.Interfaces]
778
        mov     dl, [edx+usb_config_descr.bConfigurationValue]
779
        mov     dword [eax], USB_SET_CONFIGURATION shl 8
780
        mov     dword [eax+4], ecx
781
        mov     byte [eax+2], dl
782
        stdcall usb_control_async, [pipe], eax, ecx, ecx, usb_got_config_callback, [buffer], ecx
783
        pop     ebx             ; restore used registers to be stdcall
784
        ret
785
endp
786
 
787
; This procedure is called by USB stack when SET_CONFIGURATION
788
; request initiated by usb_set_config_callback is completed,
789
; either successfully or unsuccessfully.
790
; If successfully, the device is configured and ready to work,
791
; pass the device to the corresponding driver(s).
792
proc usb_got_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
793
locals
794
InterfacesData  dd      ?
795
NumInterfaces   dd      ?
796
driver          dd      ?
797
endl
798
; 1. If there was an error, say something to the debug board and stop the
799
; initialization.
800
        cmp     [status], 0
801
        jz      @f
802
        dbgstr 'USB error in SET_CONFIGURATION'
803
        ret
804
@@:
805
        push    ebx edi         ; save used registers to be stdcall
806
; 2. Sanity checks: the total length must be the same as before (because we
807
; have allocated memory assuming the old value), length of config descriptor
808
; must be at least sizeof.usb_config_descr (we use fields from it),
809
; there must be at least one interface.
810
        mov     ebx, [pipe]
811
        mov     ebx, [ebx+usb_pipe.DeviceData]
812
        mov     eax, [calldata]
813
        mov     edx, [ebx+usb_device_data.ConfigDataSize]
814
        cmp     [eax+usb_config_descr.wTotalLength], dx
815
        jnz     .invalid
816
        cmp     [eax+usb_config_descr.bLength], 9
817
        jb      .invalid
818
        movzx   edx, [eax+usb_config_descr.bNumInterfaces]
819
        test    edx, edx
820
        jnz     @f
821
.invalid:
822
        dbgstr 'error: invalid configuration descriptor'
823
        jmp     .nothing
824
@@:
825
; 3. Store the number of interfaces in device data structure.
3826 clevermous 826
        mov     [ebx+usb_device_data.NumInterfaces], edx
3520 clevermous 827
; 4. If there is only one interface (which happens quite often),
828
; the memory allocated in usb_know_length_callback is sufficient.
829
; Otherwise (which also happens quite often), reallocate device data.
830
; 4a. Check whether there is only one interface. If so, skip this step.
831
        cmp     edx, 1
832
        jz      .has_memory
833
; 4b. Allocate new memory.
834
        mov     eax, [ebx+usb_device_data.Interfaces]
835
        lea     eax, [eax+edx*sizeof.usb_interface_data]
836
        call    malloc
837
; 4c. If failed, say something to the debug board and
838
; stop the initialization.
839
        test    eax, eax
840
        jnz     @f
841
        dbgstr 'No memory for device data'
842
        jmp     .nothing
843
@@:
844
; 4d. Copy data from old memory to new memory and switch the pointer in usb_pipe.
845
        push    eax
846
        push    esi
847
        mov     ebx, [pipe]
848
        mov     edi, eax
849
        mov     esi, [ebx+usb_pipe.DeviceData]
850
        mov     [ebx+usb_pipe.DeviceData], eax
851
        mov     eax, esi
852
        mov     ecx, [esi+usb_device_data.Interfaces]
853
        shr     ecx, 2
854
        rep movsd
855
        pop     esi
856
        call    usb_reinit_pipe_list
857
; 4e. Free old memory.
858
        call    free
859
        pop     ebx
860
.has_memory:
861
; 5. Initialize interfaces table: zero all contents.
862
        mov     edi, [ebx+usb_device_data.Interfaces]
863
        add     edi, ebx
864
        mov     [InterfacesData], edi
3826 clevermous 865
        mov     ecx, [ebx+usb_device_data.NumInterfaces]
3520 clevermous 866
if sizeof.usb_interface_data <> 8
867
You have changed sizeof.usb_interface_data? Modify this place too.
868
end if
869
        add     ecx, ecx
870
        xor     eax, eax
871
        rep stosd
872
; No interfaces are found yet.
873
        mov     [NumInterfaces], eax
874
; 6. Get the pointer to config descriptor data.
875
; Note: if there was reallocation, [buffer] is not valid anymore,
876
; so calculate value based on usb_device_data.
877
        movzx   eax, [ebx+usb_device_data.DeviceDescrSize]
878
        lea     eax, [eax+ebx+sizeof.usb_device_data]
879
        mov     [calldata], eax
880
        mov     ecx, [ebx+usb_device_data.ConfigDataSize]
881
; 7. Loop over all descriptors,
882
; scan for interface descriptors with bAlternateSetting = 0,
883
; load the corresponding driver, call its AddDevice function.
884
.descriptor_loop:
885
; While in loop: eax points to the current descriptor,
886
; ecx = number of bytes left, the iteration starts only if ecx is nonzero,
887
; edx = size of the current descriptor.
888
; 7a. The first byte is always accessible; it contains the length of
889
; the current descriptor. Validate that the length is at least 2 bytes,
890
; and the entire descriptor is readable (the length is at most number of
891
; bytes left).
892
        movzx   edx, [eax+usb_descr.bLength]
893
        cmp     edx, sizeof.usb_descr
894
        jb      .invalid
895
        cmp     ecx, edx
896
        jb      .invalid
897
; 7b. Check descriptor type. Ignore all non-INTERFACE descriptor.
898
        cmp     byte [eax+usb_descr.bDescriptorType], USB_INTERFACE_DESCR
899
        jz      .interface
900
.next_descriptor:
901
; 7c. Advance pointer, decrease length left, if there is still something left,
902
; continue the loop.
903
        add     eax, edx
904
        sub     ecx, edx
905
        jnz     .descriptor_loop
906
.done:
907
.nothing:
908
        pop     edi ebx         ; restore used registers to be stdcall
909
        ret
910
.interface:
911
; 7d. Validate the descriptor length.
912
        cmp     edx, sizeof.usb_interface_descr
913
        jb      .next_descriptor
914
; 7e. If bAlternateSetting is nonzero, this descriptor actually describes
915
; another mode of already known interface and belongs to the already loaded
916
; driver; amuse the user and continue to 7c.
917
        cmp     byte [eax+usb_interface_descr.bAlternateSetting], 0
918
        jz      @f
919
        DEBUGF 1,'K : note: alternate setting with %x/%x/%x\n',\
920
                [eax+usb_interface_descr.bInterfaceClass]:2,\
921
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
922
                [eax+usb_interface_descr.bInterfaceProtocol]:2
923
        jmp     .next_descriptor
924
@@:
925
; 7f. Check that the new interface does not overflow allocated table.
926
        mov     edx, [NumInterfaces]
3826 clevermous 927
        inc     edx
928
        cmp     edx, [ebx+usb_device_data.NumInterfaces]
3520 clevermous 929
        ja      .invalid
930
; 7g. We have found a new interface. Advance bookkeeping vars.
931
        mov     [NumInterfaces], edx
932
        add     [InterfacesData], sizeof.usb_interface_data
933
; 7h. Save length left and pointer to the current interface descriptor.
934
        push    ecx eax
935
; Amuse the user if she is watching the debug board.
936
        DEBUGF 1,'K : USB interface class/subclass/protocol = %x/%x/%x\n',\
937
                [eax+usb_interface_descr.bInterfaceClass]:2,\
938
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
939
                [eax+usb_interface_descr.bInterfaceProtocol]:2
940
; 7i. Select the correct driver based on interface class.
941
; For hubs, go to 7j. Otherwise, go to 7k.
942
; Note: this should be rewritten as table-based lookup when more drivers will
943
; be available.
944
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 9
945
        jz      .found_hub
946
        mov     edx, usb_hid_name
947
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 3
948
        jz      .load_driver
949
        mov     edx, usb_print_name
950
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 7
951
        jz      .load_driver
952
        mov     edx, usb_stor_name
953
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 8
954
        jz      .load_driver
955
        mov     edx, usb_other_name
956
        jmp     .load_driver
957
.found_hub:
958
; 7j. Hubs are a part of USB stack, thus, integrated into the kernel.
959
; Use the pointer to hub callbacks and go to 7m.
960
        mov     eax, usb_hub_pseudosrv - USBSRV.usb_func
961
        jmp     .driver_loaded
962
.load_driver:
963
; 7k. Load the corresponding driver.
964
        push    ebx esi edi
965
        stdcall get_service, edx
966
        pop     edi esi ebx
967
; 7l. If failed, say something to the debug board and go to 7p.
968
        test    eax, eax
969
        jnz     .driver_loaded
970
        dbgstr 'failed to load class driver'
971
        jmp     .next_descriptor2
972
.driver_loaded:
973
; 7m. Call AddDevice function of the driver.
974
; Note that top of stack contains a pointer to the current interface,
975
; saved by step 7h.
976
        mov     [driver], eax
977
        mov     eax, [eax+USBSRV.usb_func]
978
        pop     edx
979
        push    edx
980
; Note: usb_hub_init assumes that edx points to usb_interface_descr,
981
; ecx = length rest; if you change the code, modify usb_hub_init also.
982
        stdcall [eax+USBFUNC.add_device], [pipe], [calldata], edx
983
; 7n. If failed, say something to the debug board and go to 7p.
984
        test    eax, eax
985
        jnz     .store_data
986
        dbgstr 'USB device initialization failed'
987
        jmp     .next_descriptor2
988
.store_data:
989
; 7o. Store the returned value and the driver handle to InterfacesData.
990
; Note that step 7g has already advanced InterfacesData.
991
        mov     edx, [InterfacesData]
992
        mov     [edx+usb_interface_data.DriverData-sizeof.usb_interface_data], eax
993
        mov     eax, [driver]
994
        mov     [edx+usb_interface_data.DriverFunc-sizeof.usb_interface_data], eax
995
.next_descriptor2:
996
; 7p. Restore registers saved in step 7h, get the descriptor length and
997
; continue to 7c.
998
        pop     eax ecx
999
        movzx   edx, byte [eax+usb_descr.bLength]
1000
        jmp     .next_descriptor
1001
endp
1002
 
1003
; Driver names, see step 7i of usb_got_config_callback.
1004
iglobal
1005
usb_hid_name    db      'usbhid',0
1006
usb_stor_name   db      'usbstor',0
1007
usb_print_name  db      'usbprint',0
1008
usb_other_name  db      'usbother',0
1009
endg