Subversion Repositories Kolibri OS

Rev

Rev 3681 | Go to most recent revision | Details | 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
; 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
; Note that malloc destroys ebx.
463
        push    ebx
464
        call    malloc
465
        pop     ebx
466
; 1b. If failed, say something to the debug board and stop the initialization.
467
        test    eax, eax
468
        jz      .nomemory
469
; 1c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
470
        push    eax
471
        push    esi edi
472
        mov     esi, [ebx+usb_pipe.DeviceData]
473
        mov     [ebx+usb_pipe.DeviceData], eax
474
        mov     edi, eax
475
        mov     eax, esi
476
repeat sizeof.usb_device_data / 4
477
        movsd
478
end repeat
479
        pop     edi esi
480
        call    usb_reinit_pipe_list
481
; 1d. Free the old memory.
482
; Note that free destroys ebx.
483
        push    ebx
484
        call    free
485
        pop     ebx
486
        pop     eax
487
; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
488
; restore length saved in step 1a
489
        pop     edx
490
        add     eax, sizeof.usb_device_data
491
        mov     dword [eax], \
492
                80h + \         ; device-to-host, standard, device-wide
493
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
494
                (0 shl 16) + \  ; descriptor index: there is only one
495
                (USB_DEVICE_DESCR shl 24)       ; descriptor type
496
        and     dword [eax+4], 0
497
        mov     [eax+6], dl     ; data length
498
        stdcall usb_control_async, ebx, eax, eax, edx, usb_get_descr_callback, eax, 0
499
; 3. Return.
500
        ret
501
.nomemory:
502
        dbgstr 'No memory for device data'
503
        ret
504
endp
505
 
506
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE)
507
; request initiated by usb_after_set_endpoint_size is completed,
508
; either successfully or unsuccessfully.
509
proc usb_get_descr_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
510
; Note: the prolog is the same as in usb_get_descr8_callback.
511
        push    edi ebx         ; save used registers to be stdcall
512
; 1. Check whether the operation was successful.
513
; If not, say something to the debug board and stop the initialization.
514
        cmp     [status], 0
515
        jnz     usb_get_descr8_callback.error
516
; The full descriptor is known, dump it if specified by compile-time option.
517
if USB_DUMP_DESCRIPTORS
518
        mov     eax, [buffer]
519
        mov     ecx, [length]
520
        sub     ecx, 8
521
        jbe     .skipdebug
522
        DEBUGF 1,'K : device descriptor:'
523
@@:
524
        DEBUGF 1,' %x',[eax]:2
525
        inc     eax
526
        dec     ecx
527
        jnz     @b
528
        DEBUGF 1,'\n'
529
.skipdebug:
530
end if
531
; 2. Check that bLength is the same as was in the previous request.
532
; If not, say something to the debug board and stop the initialization.
533
; It is important, because usb_after_set_endpoint_size has allocated memory
534
; according to the old bLength. Note that [length] for control transfers
535
; includes 8 bytes of setup packet, so data length = [length] - 8.
536
        mov     eax, [buffer]
537
        movzx   ecx, [eax+usb_device_descr.bLength]
538
        add     ecx, 8
539
        cmp     [length], ecx
540
        jnz     usb_get_descr8_callback.error
541
; Amuse the user if she is watching the debug board.
542
        mov     cl, [eax+usb_device_descr.bNumConfigurations]
543
        DEBUGF 1,'K : found USB device with ID %x:%x, %d configuration(s)\n',\
544
                [eax+usb_device_descr.idVendor]:4,\
545
                [eax+usb_device_descr.idProduct]:4,\
546
                cl
547
; 3. If there are no configurations, stop the initialization.
548
        cmp     [eax+usb_device_descr.bNumConfigurations], 0
549
        jz      .nothing
550
; 4. Copy length of device descriptor to device data structure.
551
        movzx   edx, [eax+usb_device_descr.bLength]
552
        mov     [eax+usb_device_data.DeviceDescrSize-usb_device_data.DeviceDescriptor], dl
553
; 5. Issue control transfer GET_DESCRIPTOR(CONFIGURATION). We do not know
554
; the full length of that descriptor, so start with first 8 bytes, they contain
555
; the full length.
556
; usb_after_set_endpoint_size has allocated 8 extra bytes after the
557
; device descriptor, use them for both input and output.
558
        add     eax, edx
559
        mov     dword [eax], \
560
                80h + \         ; device-to-host, standard, device-wide
561
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
562
                (0 shl 16) + \  ; descriptor index: there is only one
563
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
564
        mov     dword [eax+4], 8 shl 16         ; data length
565
        stdcall usb_control_async, [pipe], eax, eax, 8, usb_know_length_callback, eax, 0
566
.nothing:
567
; 6. Return.
568
        pop     ebx edi         ; restore used registers to be stdcall
569
        ret
570
endp
571
 
572
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
573
; request initiated by usb_get_descr_callback is completed,
574
; either successfully or unsuccessfully.
575
proc usb_know_length_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
576
        push    ebx             ; save used registers to be stdcall
577
; 1. Check whether the operation was successful.
578
; If not, say something to the debug board and stop the initialization.
579
        cmp     [status], 0
580
        jnz     .error
581
; 2. Get the total length of data associated with config descriptor and store
582
; it in device data structure. The total length must be at least
583
; sizeof.usb_config_descr bytes; if not, say something to the debug board and
584
; stop the initialization.
585
        mov     eax, [buffer]
586
        mov     edx, [pipe]
587
        movzx   ecx, [eax+usb_config_descr.wTotalLength]
588
        mov     eax, [edx+usb_pipe.DeviceData]
589
        cmp     ecx, sizeof.usb_config_descr
590
        jb      .error
591
        mov     [eax+usb_device_data.ConfigDataSize], ecx
592
; 3. Reallocate memory for device data:
593
; include usb_device_data structure, device descriptor,
594
; config descriptor with all associated data, and extra bytes
595
; sufficient for 8 bytes control packet and for one usb_interface_data struc.
596
; Align extra bytes to dword boundary.
597
if sizeof.usb_interface_data > 8
598
.extra_size = sizeof.usb_interface_data
599
else
600
.extra_size = 8
601
end if
602
; 3a. Allocate new memory.
603
        movzx   edx, [eax+usb_device_data.DeviceDescrSize]
604
        lea     eax, [ecx+edx+sizeof.usb_device_data+.extra_size+3]
605
        and     eax, not 3
606
        push    eax
607
        call    malloc
608
        pop     edx
609
; 3b. If failed, say something to the debug board and stop the initialization.
610
        test    eax, eax
611
        jz      .nomemory
612
; 3c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
613
        push    eax
614
        mov     ebx, [pipe]
615
        push    esi edi
616
        mov     esi, [ebx+usb_pipe.DeviceData]
617
        mov     edi, eax
618
        mov     [ebx+usb_pipe.DeviceData], eax
619
        mov     eax, esi
620
        movzx   ecx, [esi+usb_device_data.DeviceDescrSize]
621
        sub     edx, .extra_size
622
        mov     [esi+usb_device_data.Interfaces], edx
623
        add     ecx, sizeof.usb_device_data + 8
624
        mov     edx, ecx
625
        shr     ecx, 2
626
        and     edx, 3
627
        rep movsd
628
        mov     ecx, edx
629
        rep movsb
630
        pop     edi esi
631
        call    usb_reinit_pipe_list
632
; 3d. Free old memory.
633
        call    free
634
        pop     eax
635
; 4. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
636
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
637
        mov     edx, [eax+usb_device_data.ConfigDataSize]
638
        lea     eax, [eax+ecx+sizeof.usb_device_data]
639
        mov     dword [eax], \
640
                80h + \         ; device-to-host, standard, device-wide
641
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
642
                (0 shl 16) + \  ; descriptor index: there is only one
643
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
644
        and     dword [eax+4], 0
645
        mov     word [eax+6], dx        ; data length
646
        stdcall usb_control_async, [pipe], eax, eax, edx, usb_set_config_callback, eax, 0
647
.nothing:
648
; 5. Return.
649
        pop     ebx             ; restore used registers to be stdcall
650
        ret
651
.error:
652
        dbgstr 'error with USB configuration descriptor'
653
        jmp     .nothing
654
.nomemory:
655
        dbgstr 'No memory for device data'
656
        jmp     .nothing
657
endp
658
 
659
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
660
; request initiated by usb_know_length_callback is completed,
661
; either successfully or unsuccessfully.
662
proc usb_set_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
663
; Note that the prolog is the same as in usb_know_length_callback.
664
        push    ebx             ; save used registers to be stdcall
665
; 1. Check whether the operation was successful.
666
; If not, say something to the debug board and stop the initialization.
667
        xor     ecx, ecx
668
        mov     ebx, [pipe]
669
        cmp     [status], ecx
670
        jnz     usb_know_length_callback.error
671
; The full descriptor is known, dump it if specified by compile-time option.
672
if USB_DUMP_DESCRIPTORS
673
        mov     eax, [buffer]
674
        mov     ecx, [length]
675
        sub     ecx, 8
676
        jbe     .skip_debug
677
        DEBUGF 1,'K : config descriptor:'
678
@@:
679
        DEBUGF 1,' %x',[eax]:2
680
        inc     eax
681
        dec     ecx
682
        jnz     @b
683
        DEBUGF 1,'\n'
684
.skip_debug:
685
        xor     ecx, ecx
686
end if
687
; 2. Issue control transfer SET_CONFIGURATION to activate this configuration.
688
; Usually this is the only configuration.
689
; Use extra bytes allocated by usb_know_length_callback;
690
; offset from device data start is stored in Interfaces.
691
        mov     eax, [ebx+usb_pipe.DeviceData]
692
        mov     edx, [buffer]
693
        add     eax, [eax+usb_device_data.Interfaces]
694
        mov     dl, [edx+usb_config_descr.bConfigurationValue]
695
        mov     dword [eax], USB_SET_CONFIGURATION shl 8
696
        mov     dword [eax+4], ecx
697
        mov     byte [eax+2], dl
698
        stdcall usb_control_async, [pipe], eax, ecx, ecx, usb_got_config_callback, [buffer], ecx
699
        pop     ebx             ; restore used registers to be stdcall
700
        ret
701
endp
702
 
703
; This procedure is called by USB stack when SET_CONFIGURATION
704
; request initiated by usb_set_config_callback is completed,
705
; either successfully or unsuccessfully.
706
; If successfully, the device is configured and ready to work,
707
; pass the device to the corresponding driver(s).
708
proc usb_got_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
709
locals
710
InterfacesData  dd      ?
711
NumInterfaces   dd      ?
712
driver          dd      ?
713
endl
714
; 1. If there was an error, say something to the debug board and stop the
715
; initialization.
716
        cmp     [status], 0
717
        jz      @f
718
        dbgstr 'USB error in SET_CONFIGURATION'
719
        ret
720
@@:
721
        push    ebx edi         ; save used registers to be stdcall
722
; 2. Sanity checks: the total length must be the same as before (because we
723
; have allocated memory assuming the old value), length of config descriptor
724
; must be at least sizeof.usb_config_descr (we use fields from it),
725
; there must be at least one interface.
726
        mov     ebx, [pipe]
727
        mov     ebx, [ebx+usb_pipe.DeviceData]
728
        mov     eax, [calldata]
729
        mov     edx, [ebx+usb_device_data.ConfigDataSize]
730
        cmp     [eax+usb_config_descr.wTotalLength], dx
731
        jnz     .invalid
732
        cmp     [eax+usb_config_descr.bLength], 9
733
        jb      .invalid
734
        movzx   edx, [eax+usb_config_descr.bNumInterfaces]
735
        test    edx, edx
736
        jnz     @f
737
.invalid:
738
        dbgstr 'error: invalid configuration descriptor'
739
        jmp     .nothing
740
@@:
741
; 3. Store the number of interfaces in device data structure.
742
        mov     [ebx+usb_device_data.NumInterfaces], dl
743
; 4. If there is only one interface (which happens quite often),
744
; the memory allocated in usb_know_length_callback is sufficient.
745
; Otherwise (which also happens quite often), reallocate device data.
746
; 4a. Check whether there is only one interface. If so, skip this step.
747
        cmp     edx, 1
748
        jz      .has_memory
749
; 4b. Allocate new memory.
750
        mov     eax, [ebx+usb_device_data.Interfaces]
751
        lea     eax, [eax+edx*sizeof.usb_interface_data]
752
        call    malloc
753
; 4c. If failed, say something to the debug board and
754
; stop the initialization.
755
        test    eax, eax
756
        jnz     @f
757
        dbgstr 'No memory for device data'
758
        jmp     .nothing
759
@@:
760
; 4d. Copy data from old memory to new memory and switch the pointer in usb_pipe.
761
        push    eax
762
        push    esi
763
        mov     ebx, [pipe]
764
        mov     edi, eax
765
        mov     esi, [ebx+usb_pipe.DeviceData]
766
        mov     [ebx+usb_pipe.DeviceData], eax
767
        mov     eax, esi
768
        mov     ecx, [esi+usb_device_data.Interfaces]
769
        shr     ecx, 2
770
        rep movsd
771
        pop     esi
772
        call    usb_reinit_pipe_list
773
; 4e. Free old memory.
774
        call    free
775
        pop     ebx
776
.has_memory:
777
; 5. Initialize interfaces table: zero all contents.
778
        mov     edi, [ebx+usb_device_data.Interfaces]
779
        add     edi, ebx
780
        mov     [InterfacesData], edi
781
        movzx   ecx, [ebx+usb_device_data.NumInterfaces]
782
if sizeof.usb_interface_data <> 8
783
You have changed sizeof.usb_interface_data? Modify this place too.
784
end if
785
        add     ecx, ecx
786
        xor     eax, eax
787
        rep stosd
788
; No interfaces are found yet.
789
        mov     [NumInterfaces], eax
790
; 6. Get the pointer to config descriptor data.
791
; Note: if there was reallocation, [buffer] is not valid anymore,
792
; so calculate value based on usb_device_data.
793
        movzx   eax, [ebx+usb_device_data.DeviceDescrSize]
794
        lea     eax, [eax+ebx+sizeof.usb_device_data]
795
        mov     [calldata], eax
796
        mov     ecx, [ebx+usb_device_data.ConfigDataSize]
797
; 7. Loop over all descriptors,
798
; scan for interface descriptors with bAlternateSetting = 0,
799
; load the corresponding driver, call its AddDevice function.
800
.descriptor_loop:
801
; While in loop: eax points to the current descriptor,
802
; ecx = number of bytes left, the iteration starts only if ecx is nonzero,
803
; edx = size of the current descriptor.
804
; 7a. The first byte is always accessible; it contains the length of
805
; the current descriptor. Validate that the length is at least 2 bytes,
806
; and the entire descriptor is readable (the length is at most number of
807
; bytes left).
808
        movzx   edx, [eax+usb_descr.bLength]
809
        cmp     edx, sizeof.usb_descr
810
        jb      .invalid
811
        cmp     ecx, edx
812
        jb      .invalid
813
; 7b. Check descriptor type. Ignore all non-INTERFACE descriptor.
814
        cmp     byte [eax+usb_descr.bDescriptorType], USB_INTERFACE_DESCR
815
        jz      .interface
816
.next_descriptor:
817
; 7c. Advance pointer, decrease length left, if there is still something left,
818
; continue the loop.
819
        add     eax, edx
820
        sub     ecx, edx
821
        jnz     .descriptor_loop
822
.done:
823
.nothing:
824
        pop     edi ebx         ; restore used registers to be stdcall
825
        ret
826
.interface:
827
; 7d. Validate the descriptor length.
828
        cmp     edx, sizeof.usb_interface_descr
829
        jb      .next_descriptor
830
; 7e. If bAlternateSetting is nonzero, this descriptor actually describes
831
; another mode of already known interface and belongs to the already loaded
832
; driver; amuse the user and continue to 7c.
833
        cmp     byte [eax+usb_interface_descr.bAlternateSetting], 0
834
        jz      @f
835
        DEBUGF 1,'K : note: alternate setting with %x/%x/%x\n',\
836
                [eax+usb_interface_descr.bInterfaceClass]:2,\
837
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
838
                [eax+usb_interface_descr.bInterfaceProtocol]:2
839
        jmp     .next_descriptor
840
@@:
841
; 7f. Check that the new interface does not overflow allocated table.
842
        mov     edx, [NumInterfaces]
843
        inc     dl
844
        jz      .invalid
845
        cmp     dl, [ebx+usb_device_data.NumInterfaces]
846
        ja      .invalid
847
; 7g. We have found a new interface. Advance bookkeeping vars.
848
        mov     [NumInterfaces], edx
849
        add     [InterfacesData], sizeof.usb_interface_data
850
; 7h. Save length left and pointer to the current interface descriptor.
851
        push    ecx eax
852
; Amuse the user if she is watching the debug board.
853
        DEBUGF 1,'K : USB interface class/subclass/protocol = %x/%x/%x\n',\
854
                [eax+usb_interface_descr.bInterfaceClass]:2,\
855
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
856
                [eax+usb_interface_descr.bInterfaceProtocol]:2
857
; 7i. Select the correct driver based on interface class.
858
; For hubs, go to 7j. Otherwise, go to 7k.
859
; Note: this should be rewritten as table-based lookup when more drivers will
860
; be available.
861
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 9
862
        jz      .found_hub
863
        mov     edx, usb_hid_name
864
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 3
865
        jz      .load_driver
866
        mov     edx, usb_print_name
867
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 7
868
        jz      .load_driver
869
        mov     edx, usb_stor_name
870
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 8
871
        jz      .load_driver
872
        mov     edx, usb_other_name
873
        jmp     .load_driver
874
.found_hub:
875
; 7j. Hubs are a part of USB stack, thus, integrated into the kernel.
876
; Use the pointer to hub callbacks and go to 7m.
877
        mov     eax, usb_hub_pseudosrv - USBSRV.usb_func
878
        jmp     .driver_loaded
879
.load_driver:
880
; 7k. Load the corresponding driver.
881
        push    ebx esi edi
882
        stdcall get_service, edx
883
        pop     edi esi ebx
884
; 7l. If failed, say something to the debug board and go to 7p.
885
        test    eax, eax
886
        jnz     .driver_loaded
887
        dbgstr 'failed to load class driver'
888
        jmp     .next_descriptor2
889
.driver_loaded:
890
; 7m. Call AddDevice function of the driver.
891
; Note that top of stack contains a pointer to the current interface,
892
; saved by step 7h.
893
        mov     [driver], eax
894
        mov     eax, [eax+USBSRV.usb_func]
895
        pop     edx
896
        push    edx
897
; Note: usb_hub_init assumes that edx points to usb_interface_descr,
898
; ecx = length rest; if you change the code, modify usb_hub_init also.
899
        stdcall [eax+USBFUNC.add_device], [pipe], [calldata], edx
900
; 7n. If failed, say something to the debug board and go to 7p.
901
        test    eax, eax
902
        jnz     .store_data
903
        dbgstr 'USB device initialization failed'
904
        jmp     .next_descriptor2
905
.store_data:
906
; 7o. Store the returned value and the driver handle to InterfacesData.
907
; Note that step 7g has already advanced InterfacesData.
908
        mov     edx, [InterfacesData]
909
        mov     [edx+usb_interface_data.DriverData-sizeof.usb_interface_data], eax
910
        mov     eax, [driver]
911
        mov     [edx+usb_interface_data.DriverFunc-sizeof.usb_interface_data], eax
912
.next_descriptor2:
913
; 7p. Restore registers saved in step 7h, get the descriptor length and
914
; continue to 7c.
915
        pop     eax ecx
916
        movzx   edx, byte [eax+usb_descr.bLength]
917
        jmp     .next_descriptor
918
endp
919
 
920
; Driver names, see step 7i of usb_got_config_callback.
921
iglobal
922
usb_hid_name    db      'usbhid',0
923
usb_stor_name   db      'usbstor',0
924
usb_print_name  db      'usbprint',0
925
usb_other_name  db      'usbother',0
926
endg