Subversion Repositories Kolibri OS

Rev

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

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