Subversion Repositories Kolibri OS

Rev

Rev 3725 | Rev 4265 | 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.
3908 Serge 242
        mov     [eax+usb_device_data.TTHub], edi
243
        mov     [eax+usb_device_data.TTPort], 0
244
        mov     [eax+usb_device_data.NumInterfaces], edi
245
        mov     [eax+usb_device_data.DeviceDescrSize], 0
246
        mov     dl, [esi+usb_controller.ResettingSpeed]
247
        mov     [eax+usb_device_data.Speed], dl
3555 Serge 248
        mov     [eax+usb_device_data.NumPipes], 1
3908 Serge 249
        push    ebx
250
        cmp     dl, USB_SPEED_HS
251
        jz      .nott
252
        mov     ebx, [esi+usb_controller.ResettingHub]
253
        test    ebx, ebx
254
        jz      .nott
255
        mov     cl, [esi+usb_controller.ResettingPort]
256
        mov     edx, [ebx+usb_hub.ConfigPipe]
257
        mov     edx, [edx+usb_pipe.DeviceData]
258
        cmp     [edx+usb_device_data.TTHub], 0
259
        jz      @f
260
        mov     cl, [edx+usb_device_data.TTPort]
261
        mov     ebx, [edx+usb_device_data.TTHub]
262
        jmp     .has_tt
263
@@:
264
        cmp     [edx+usb_device_data.Speed], USB_SPEED_HS
265
        jnz     .nott
266
.has_tt:
267
        mov     [eax+usb_device_data.TTHub], ebx
268
        mov     [eax+usb_device_data.TTPort], cl
269
.nott:
270
        pop     ebx
3555 Serge 271
        mov     [eax+usb_device_data.ConfigDataSize], edi
272
        mov     [eax+usb_device_data.Interfaces], edi
273
        movzx   ecx, [esi+usb_controller.ResettingPort]
3908 Serge 274
        mov     [eax+usb_device_data.Port], cl
3555 Serge 275
        mov     edx, [esi+usb_controller.ResettingHub]
276
        mov     [eax+usb_device_data.Hub], edx
277
; 4. Store pointer to the config pipe in the hub data.
278
; Config pipe serves as device identifier.
279
; Root hubs use the array inside usb_controller structure,
280
; non-root hubs use the array immediately after usb_hub structure.
281
        test    edx, edx
282
        jz      .roothub
283
        mov     edx, [edx+usb_hub.ConnectedDevicesPtr]
284
        mov     [edx+ecx*4], ebx
285
        jmp     @f
286
.roothub:
287
        mov     [esi+usb_controller.DevicesByPort+ecx*4], ebx
288
@@:
289
        call    usb_reinit_pipe_list
290
; 5. Issue SET_ADDRESS control request, using buffer filled in step 1a.
291
; Use the return value from usb_control_async as our return value;
292
; if it is zero, then something has failed.
293
        lea     eax, [esi+usb_controller.SetAddressBuffer]
294
        stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
295
.nothing:
296
; 6. Return.
297
        pop     edi ebx         ; restore used registers to be stdcall
298
        ret
299
; Handlers of failures in steps 1b, 1d, 1f.
300
.freememory:
301
        call    free
302
        jmp     .freeaddr
303
.nomemory:
304
        dbgstr 'No memory for device data'
305
.freeaddr:
306
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
307
        bts     [esi+usb_controller.ExistingAddresses], ecx
308
        xor     eax, eax
309
        jmp     .nothing
310
endp
311
 
312
; Helper procedure for usb_new_device.
313
; Allocates a new USB address and fills usb_controller.SetAddressBuffer
314
; with data for SET_ADDRESS(allocated_address) request.
315
; out: eax = 0 <=> failed
316
; Destroys edi.
317
proc usb_set_address_request
318
; There are 128 bits, one for each possible address.
319
; Note: only the USB thread works with usb_controller.ExistingAddresses,
320
; so there is no need for synchronization.
321
; We must find a bit set to 1 and clear it.
322
; 1. Find the first dword which has a nonzero bit = which is nonzero.
323
        mov     ecx, 128/32
324
        lea     edi, [esi+usb_controller.ExistingAddresses]
325
        xor     eax, eax
326
        repz scasd
327
; 2. If all dwords are zero, return an error.
328
        jz      .error
329
; 3. The dword at [edi-4] is nonzero. Find the lowest nonzero bit.
330
        bsf     eax, [edi-4]
331
; Now eax = bit number inside the dword at [edi-4].
332
; 4. Clear the bit.
333
        btr     [edi-4], eax
334
; 5. Generate the address by edi = memory address and eax = bit inside dword.
335
; Address = eax + 8 * (edi-4 - (esi+usb_controller.ExistingAddress)).
336
        sub     edi, esi
337
        lea     edi, [eax+(edi-4-usb_controller.ExistingAddresses)*8]
338
; 6. Store the allocated address in SetAddressBuffer and fill remaining fields.
339
; Note that usb_controller is zeroed at allocation, so only command byte needs
340
; to be filled.
341
        mov     byte [esi+usb_controller.SetAddressBuffer+1], USB_SET_ADDRESS
342
        mov     dword [esi+usb_controller.SetAddressBuffer+2], edi
343
; 7. Return non-zero value in eax.
344
        inc     eax
345
.nothing:
346
        ret
347
.error:
348
        dbgstr 'cannot allocate USB address'
349
        xor     eax, eax
350
        jmp     .nothing
351
endp
352
 
353
; This procedure is called by USB stack when SET_ADDRESS request initiated by
354
; usb_new_device is completed, either successfully or unsuccessfully.
355
; Note that USB stack uses esi = pointer to usb_controller.
356
proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
357
        push    ebx     ; save ebx to be stdcall
358
; Load data to registers for further references.
359
        mov     ebx, [pipe]
360
        mov     ecx, dword [esi+usb_controller.SetAddressBuffer+2]
361
        mov     eax, [esi+usb_controller.HardwareFunc]
362
; 1. Check whether the device has accepted new address. If so, proceed to 2.
363
; Otherwise, go to 3.
364
        cmp     [status], 0
365
        jnz     .error
366
; 2. Address accepted.
367
; 2a. The controller-specific structure for the control pipe still uses
368
; zero address. Call the controller-specific function to change it to
369
; the actual address.
370
; Note that the hardware could cache the controller-specific structure,
371
; so setting the address could take some time until the cache is evicted.
372
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
373
; be safe to continue.
374
        dbgstr 'address set in device'
375
        call    [eax+usb_hardware_func.SetDeviceAddress]
376
; 2b. If the port is in non-root hub, clear 'reset in progress' flag.
377
; In any case, proceed to 4.
378
        mov     eax, [esi+usb_controller.ResettingHub]
379
        test    eax, eax
380
        jz      .return
381
        and     [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
382
.return:
383
; 4. Address configuration done, we can proceed with other ports.
384
; Call the worker function for that.
385
        call    usb_test_pending_port
386
.nothing:
387
        pop     ebx     ; restore ebx to be stdcall
388
        ret
389
.error:
390
; 3. Device error: device not responding, disconnect etc.
391
        DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
392
; 3a. The address has not been accepted. Mark it as free.
393
        bts     dword [esi+usb_controller.ExistingAddresses], ecx
394
; 3b. Disable the port with bad device.
395
; For the root hub, call the controller-specific function and go to 6.
396
; For non-root hubs, let the hub code do its work and return (the request
397
; could take some time, the hub code is responsible for proceeding).
398
        cmp     [esi+usb_controller.ResettingHub], 0
399
        jz      .roothub
400
        mov     eax, [esi+usb_controller.ResettingHub]
401
        call    usb_hub_disable_resetting_port
402
        jmp     .nothing
403
.roothub:
404
        movzx   ecx, [esi+usb_controller.ResettingPort]
405
        call    [eax+usb_hardware_func.PortDisable]
406
        jmp     .return
407
endp
408
 
409
; This procedure is called from usb_subscription_done when the hardware cache
410
; is cleared after request from usb_set_address_callback.
411
; in: ebx -> usb_pipe
412
proc usb_after_set_address
413
        dbgstr 'address set for controller'
414
; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
415
; Remember, we still do not know the actual packet size;
416
; 8-bytes-request is safe.
417
; usb_new_device has allocated 8 extra bytes besides sizeof.usb_device_data;
418
; use them for both input and output.
419
        mov     eax, [ebx+usb_pipe.DeviceData]
420
        add     eax, usb_device_data.DeviceDescriptor
421
        mov     dword [eax], \
422
                80h + \         ; device-to-host, standard, device-wide
423
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
424
                (0 shl 16) + \  ; descriptor index: there is only one
425
                (USB_DEVICE_DESCR shl 24)       ; descriptor type
426
        mov     dword [eax+4], 8 shl 16         ; data length
427
        stdcall usb_control_async, ebx, eax, eax, 8, usb_get_descr8_callback, eax, 0
428
        ret
429
endp
430
 
431
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE_DESCR)
432
; request initiated by usb_after_set_address is completed, either successfully
433
; or unsuccessfully.
434
; Note that USB stack uses esi = pointer to usb_controller.
435
proc usb_get_descr8_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
436
;       mov     eax, [buffer]
437
;       DEBUGF 1,'K : descr8: l=%x; %x %x %x %x %x %x %x %x\n',[length],\
438
;               [eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2
439
        push    edi ebx         ; save used registers to be stdcall
440
        mov     ebx, [pipe]
441
; 1. Check whether the operation was successful.
442
; If not, say something to the debug board and stop the initialization.
443
        cmp     [status], 0
444
        jnz     .error
445
; 2. Length of descriptor must be at least sizeof.usb_device_descr bytes.
446
; If not, say something to the debug board and stop the initialization.
447
        mov     eax, [ebx+usb_pipe.DeviceData]
448
        cmp     [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength], sizeof.usb_device_descr
449
        jb      .error
450
; 3. Now first 8 bytes of device descriptor are known;
451
; set DeviceDescrSize accordingly.
452
        mov     [eax+usb_device_data.DeviceDescrSize], 8
453
; 4. The controller-specific structure for the control pipe still uses
454
; the fake "maximum packet size". Call the controller-specific function to
455
; change it to the actual packet size from the device.
456
; Note that the hardware could cache the controller-specific structure,
457
; so changing it could take some time until the cache is evicted.
458
; Thus, the call is asynchronous; meet us in usb_after_set_endpoint_size
459
; when it will be safe to continue.
460
        movzx   ecx, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bMaxPacketSize0]
461
        mov     eax, [esi+usb_controller.HardwareFunc]
462
        call    [eax+usb_hardware_func.SetEndpointPacketSize]
463
.nothing:
464
; 5. Return.
465
        pop     ebx edi         ; restore used registers to be stdcall
466
        ret
467
.error:
468
        dbgstr 'error with USB device descriptor'
469
        jmp     .nothing
470
endp
471
 
472
; This procedure is called from usb_subscription_done when the hardware cache
473
; is cleared after request from usb_get_descr8_callback.
474
; in: ebx -> usb_pipe
475
proc usb_after_set_endpoint_size
476
; 1. Reallocate memory for device data:
477
; add memory for now-known size of device descriptor and extra 8 bytes
478
; for further actions.
479
; 1a. Allocate new memory.
480
        mov     eax, [ebx+usb_pipe.DeviceData]
481
        movzx   eax, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength]
482
; save length for step 2
483
        push    eax
484
        add     eax, sizeof.usb_device_data + 8
485
        call    malloc
486
; 1b. If failed, say something to the debug board and stop the initialization.
487
        test    eax, eax
488
        jz      .nomemory
489
; 1c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
490
        push    eax
491
        push    esi edi
492
        mov     esi, [ebx+usb_pipe.DeviceData]
493
        mov     [ebx+usb_pipe.DeviceData], eax
494
        mov     edi, eax
495
        mov     eax, esi
3908 Serge 496
        mov     ecx, sizeof.usb_device_data / 4
497
        rep movsd
3555 Serge 498
        pop     edi esi
499
        call    usb_reinit_pipe_list
500
; 1d. Free the old memory.
501
; Note that free destroys ebx.
502
        push    ebx
503
        call    free
504
        pop     ebx
505
        pop     eax
506
; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
507
; restore length saved in step 1a
508
        pop     edx
509
        add     eax, sizeof.usb_device_data
510
        mov     dword [eax], \
511
                80h + \         ; device-to-host, standard, device-wide
512
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
513
                (0 shl 16) + \  ; descriptor index: there is only one
514
                (USB_DEVICE_DESCR shl 24)       ; descriptor type
515
        and     dword [eax+4], 0
516
        mov     [eax+6], dl     ; data length
517
        stdcall usb_control_async, ebx, eax, eax, edx, usb_get_descr_callback, eax, 0
518
; 3. Return.
519
        ret
520
.nomemory:
521
        dbgstr 'No memory for device data'
522
        ret
523
endp
524
 
525
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE)
526
; request initiated by usb_after_set_endpoint_size is completed,
527
; either successfully or unsuccessfully.
528
proc usb_get_descr_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
529
; Note: the prolog is the same as in usb_get_descr8_callback.
530
        push    edi ebx         ; save used registers to be stdcall
531
; 1. Check whether the operation was successful.
532
; If not, say something to the debug board and stop the initialization.
533
        cmp     [status], 0
534
        jnz     usb_get_descr8_callback.error
535
; The full descriptor is known, dump it if specified by compile-time option.
536
if USB_DUMP_DESCRIPTORS
537
        mov     eax, [buffer]
538
        mov     ecx, [length]
539
        sub     ecx, 8
540
        jbe     .skipdebug
541
        DEBUGF 1,'K : device descriptor:'
542
@@:
543
        DEBUGF 1,' %x',[eax]:2
544
        inc     eax
545
        dec     ecx
546
        jnz     @b
547
        DEBUGF 1,'\n'
548
.skipdebug:
549
end if
550
; 2. Check that bLength is the same as was in the previous request.
551
; If not, say something to the debug board and stop the initialization.
552
; It is important, because usb_after_set_endpoint_size has allocated memory
553
; according to the old bLength. Note that [length] for control transfers
554
; includes 8 bytes of setup packet, so data length = [length] - 8.
555
        mov     eax, [buffer]
556
        movzx   ecx, [eax+usb_device_descr.bLength]
557
        add     ecx, 8
558
        cmp     [length], ecx
559
        jnz     usb_get_descr8_callback.error
560
; Amuse the user if she is watching the debug board.
561
        mov     cl, [eax+usb_device_descr.bNumConfigurations]
562
        DEBUGF 1,'K : found USB device with ID %x:%x, %d configuration(s)\n',\
563
                [eax+usb_device_descr.idVendor]:4,\
564
                [eax+usb_device_descr.idProduct]:4,\
565
                cl
566
; 3. If there are no configurations, stop the initialization.
567
        cmp     [eax+usb_device_descr.bNumConfigurations], 0
568
        jz      .nothing
569
; 4. Copy length of device descriptor to device data structure.
570
        movzx   edx, [eax+usb_device_descr.bLength]
571
        mov     [eax+usb_device_data.DeviceDescrSize-usb_device_data.DeviceDescriptor], dl
572
; 5. Issue control transfer GET_DESCRIPTOR(CONFIGURATION). We do not know
573
; the full length of that descriptor, so start with first 8 bytes, they contain
574
; the full length.
575
; usb_after_set_endpoint_size has allocated 8 extra bytes after the
576
; device descriptor, use them for both input and output.
577
        add     eax, edx
578
        mov     dword [eax], \
579
                80h + \         ; device-to-host, standard, device-wide
580
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
581
                (0 shl 16) + \  ; descriptor index: there is only one
582
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
583
        mov     dword [eax+4], 8 shl 16         ; data length
584
        stdcall usb_control_async, [pipe], eax, eax, 8, usb_know_length_callback, eax, 0
585
.nothing:
586
; 6. Return.
587
        pop     ebx edi         ; restore used registers to be stdcall
588
        ret
589
endp
590
 
591
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
592
; request initiated by usb_get_descr_callback is completed,
593
; either successfully or unsuccessfully.
594
proc usb_know_length_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
595
        push    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     .error
600
; 2. Get the total length of data associated with config descriptor and store
601
; it in device data structure. The total length must be at least
602
; sizeof.usb_config_descr bytes; if not, say something to the debug board and
603
; stop the initialization.
604
        mov     eax, [buffer]
605
        mov     edx, [pipe]
606
        movzx   ecx, [eax+usb_config_descr.wTotalLength]
607
        mov     eax, [edx+usb_pipe.DeviceData]
608
        cmp     ecx, sizeof.usb_config_descr
609
        jb      .error
610
        mov     [eax+usb_device_data.ConfigDataSize], ecx
611
; 3. Reallocate memory for device data:
612
; include usb_device_data structure, device descriptor,
613
; config descriptor with all associated data, and extra bytes
614
; sufficient for 8 bytes control packet and for one usb_interface_data struc.
615
; Align extra bytes to dword boundary.
616
if sizeof.usb_interface_data > 8
617
.extra_size = sizeof.usb_interface_data
618
else
619
.extra_size = 8
620
end if
621
; 3a. Allocate new memory.
622
        movzx   edx, [eax+usb_device_data.DeviceDescrSize]
623
        lea     eax, [ecx+edx+sizeof.usb_device_data+.extra_size+3]
624
        and     eax, not 3
625
        push    eax
626
        call    malloc
627
        pop     edx
628
; 3b. If failed, say something to the debug board and stop the initialization.
629
        test    eax, eax
630
        jz      .nomemory
631
; 3c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
632
        push    eax
633
        mov     ebx, [pipe]
634
        push    esi edi
635
        mov     esi, [ebx+usb_pipe.DeviceData]
636
        mov     edi, eax
637
        mov     [ebx+usb_pipe.DeviceData], eax
638
        mov     eax, esi
639
        movzx   ecx, [esi+usb_device_data.DeviceDescrSize]
640
        sub     edx, .extra_size
641
        mov     [esi+usb_device_data.Interfaces], edx
642
        add     ecx, sizeof.usb_device_data + 8
643
        mov     edx, ecx
644
        shr     ecx, 2
645
        and     edx, 3
646
        rep movsd
647
        mov     ecx, edx
648
        rep movsb
649
        pop     edi esi
650
        call    usb_reinit_pipe_list
651
; 3d. Free old memory.
652
        call    free
653
        pop     eax
654
; 4. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
655
        movzx   ecx, [eax+usb_device_data.DeviceDescrSize]
656
        mov     edx, [eax+usb_device_data.ConfigDataSize]
657
        lea     eax, [eax+ecx+sizeof.usb_device_data]
658
        mov     dword [eax], \
659
                80h + \         ; device-to-host, standard, device-wide
660
                (USB_GET_DESCRIPTOR shl 8) + \  ; request
661
                (0 shl 16) + \  ; descriptor index: there is only one
662
                (USB_CONFIG_DESCR shl 24)       ; descriptor type
663
        and     dword [eax+4], 0
664
        mov     word [eax+6], dx        ; data length
665
        stdcall usb_control_async, [pipe], eax, eax, edx, usb_set_config_callback, eax, 0
666
.nothing:
667
; 5. Return.
668
        pop     ebx             ; restore used registers to be stdcall
669
        ret
670
.error:
671
        dbgstr 'error with USB configuration descriptor'
672
        jmp     .nothing
673
.nomemory:
674
        dbgstr 'No memory for device data'
675
        jmp     .nothing
676
endp
677
 
678
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
679
; request initiated by usb_know_length_callback is completed,
680
; either successfully or unsuccessfully.
681
proc usb_set_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
682
; Note that the prolog is the same as in usb_know_length_callback.
683
        push    ebx             ; save used registers to be stdcall
684
; 1. Check whether the operation was successful.
685
; If not, say something to the debug board and stop the initialization.
686
        xor     ecx, ecx
687
        mov     ebx, [pipe]
688
        cmp     [status], ecx
689
        jnz     usb_know_length_callback.error
690
; The full descriptor is known, dump it if specified by compile-time option.
691
if USB_DUMP_DESCRIPTORS
692
        mov     eax, [buffer]
693
        mov     ecx, [length]
694
        sub     ecx, 8
695
        jbe     .skip_debug
696
        DEBUGF 1,'K : config descriptor:'
697
@@:
698
        DEBUGF 1,' %x',[eax]:2
699
        inc     eax
700
        dec     ecx
701
        jnz     @b
702
        DEBUGF 1,'\n'
703
.skip_debug:
704
        xor     ecx, ecx
705
end if
706
; 2. Issue control transfer SET_CONFIGURATION to activate this configuration.
707
; Usually this is the only configuration.
708
; Use extra bytes allocated by usb_know_length_callback;
709
; offset from device data start is stored in Interfaces.
710
        mov     eax, [ebx+usb_pipe.DeviceData]
711
        mov     edx, [buffer]
712
        add     eax, [eax+usb_device_data.Interfaces]
713
        mov     dl, [edx+usb_config_descr.bConfigurationValue]
714
        mov     dword [eax], USB_SET_CONFIGURATION shl 8
715
        mov     dword [eax+4], ecx
716
        mov     byte [eax+2], dl
717
        stdcall usb_control_async, [pipe], eax, ecx, ecx, usb_got_config_callback, [buffer], ecx
718
        pop     ebx             ; restore used registers to be stdcall
719
        ret
720
endp
721
 
722
; This procedure is called by USB stack when SET_CONFIGURATION
723
; request initiated by usb_set_config_callback is completed,
724
; either successfully or unsuccessfully.
725
; If successfully, the device is configured and ready to work,
726
; pass the device to the corresponding driver(s).
727
proc usb_got_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
728
locals
729
InterfacesData  dd      ?
730
NumInterfaces   dd      ?
731
driver          dd      ?
732
endl
733
; 1. If there was an error, say something to the debug board and stop the
734
; initialization.
735
        cmp     [status], 0
736
        jz      @f
737
        dbgstr 'USB error in SET_CONFIGURATION'
738
        ret
739
@@:
740
        push    ebx edi         ; save used registers to be stdcall
741
; 2. Sanity checks: the total length must be the same as before (because we
742
; have allocated memory assuming the old value), length of config descriptor
743
; must be at least sizeof.usb_config_descr (we use fields from it),
744
; there must be at least one interface.
745
        mov     ebx, [pipe]
746
        mov     ebx, [ebx+usb_pipe.DeviceData]
747
        mov     eax, [calldata]
748
        mov     edx, [ebx+usb_device_data.ConfigDataSize]
749
        cmp     [eax+usb_config_descr.wTotalLength], dx
750
        jnz     .invalid
751
        cmp     [eax+usb_config_descr.bLength], 9
752
        jb      .invalid
753
        movzx   edx, [eax+usb_config_descr.bNumInterfaces]
754
        test    edx, edx
755
        jnz     @f
756
.invalid:
757
        dbgstr 'error: invalid configuration descriptor'
758
        jmp     .nothing
759
@@:
760
; 3. Store the number of interfaces in device data structure.
3908 Serge 761
        mov     [ebx+usb_device_data.NumInterfaces], edx
3555 Serge 762
; 4. If there is only one interface (which happens quite often),
763
; the memory allocated in usb_know_length_callback is sufficient.
764
; Otherwise (which also happens quite often), reallocate device data.
765
; 4a. Check whether there is only one interface. If so, skip this step.
766
        cmp     edx, 1
767
        jz      .has_memory
768
; 4b. Allocate new memory.
769
        mov     eax, [ebx+usb_device_data.Interfaces]
770
        lea     eax, [eax+edx*sizeof.usb_interface_data]
771
        call    malloc
772
; 4c. If failed, say something to the debug board and
773
; stop the initialization.
774
        test    eax, eax
775
        jnz     @f
776
        dbgstr 'No memory for device data'
777
        jmp     .nothing
778
@@:
779
; 4d. Copy data from old memory to new memory and switch the pointer in usb_pipe.
780
        push    eax
781
        push    esi
782
        mov     ebx, [pipe]
783
        mov     edi, eax
784
        mov     esi, [ebx+usb_pipe.DeviceData]
785
        mov     [ebx+usb_pipe.DeviceData], eax
786
        mov     eax, esi
787
        mov     ecx, [esi+usb_device_data.Interfaces]
788
        shr     ecx, 2
789
        rep movsd
790
        pop     esi
791
        call    usb_reinit_pipe_list
792
; 4e. Free old memory.
793
        call    free
794
        pop     ebx
795
.has_memory:
796
; 5. Initialize interfaces table: zero all contents.
797
        mov     edi, [ebx+usb_device_data.Interfaces]
798
        add     edi, ebx
799
        mov     [InterfacesData], edi
3908 Serge 800
        mov     ecx, [ebx+usb_device_data.NumInterfaces]
3555 Serge 801
if sizeof.usb_interface_data <> 8
802
You have changed sizeof.usb_interface_data? Modify this place too.
803
end if
804
        add     ecx, ecx
805
        xor     eax, eax
806
        rep stosd
807
; No interfaces are found yet.
808
        mov     [NumInterfaces], eax
809
; 6. Get the pointer to config descriptor data.
810
; Note: if there was reallocation, [buffer] is not valid anymore,
811
; so calculate value based on usb_device_data.
812
        movzx   eax, [ebx+usb_device_data.DeviceDescrSize]
813
        lea     eax, [eax+ebx+sizeof.usb_device_data]
814
        mov     [calldata], eax
815
        mov     ecx, [ebx+usb_device_data.ConfigDataSize]
816
; 7. Loop over all descriptors,
817
; scan for interface descriptors with bAlternateSetting = 0,
818
; load the corresponding driver, call its AddDevice function.
819
.descriptor_loop:
820
; While in loop: eax points to the current descriptor,
821
; ecx = number of bytes left, the iteration starts only if ecx is nonzero,
822
; edx = size of the current descriptor.
823
; 7a. The first byte is always accessible; it contains the length of
824
; the current descriptor. Validate that the length is at least 2 bytes,
825
; and the entire descriptor is readable (the length is at most number of
826
; bytes left).
827
        movzx   edx, [eax+usb_descr.bLength]
828
        cmp     edx, sizeof.usb_descr
829
        jb      .invalid
830
        cmp     ecx, edx
831
        jb      .invalid
832
; 7b. Check descriptor type. Ignore all non-INTERFACE descriptor.
833
        cmp     byte [eax+usb_descr.bDescriptorType], USB_INTERFACE_DESCR
834
        jz      .interface
835
.next_descriptor:
836
; 7c. Advance pointer, decrease length left, if there is still something left,
837
; continue the loop.
838
        add     eax, edx
839
        sub     ecx, edx
840
        jnz     .descriptor_loop
841
.done:
842
.nothing:
843
        pop     edi ebx         ; restore used registers to be stdcall
844
        ret
845
.interface:
846
; 7d. Validate the descriptor length.
847
        cmp     edx, sizeof.usb_interface_descr
848
        jb      .next_descriptor
849
; 7e. If bAlternateSetting is nonzero, this descriptor actually describes
850
; another mode of already known interface and belongs to the already loaded
851
; driver; amuse the user and continue to 7c.
852
        cmp     byte [eax+usb_interface_descr.bAlternateSetting], 0
853
        jz      @f
854
        DEBUGF 1,'K : note: alternate setting with %x/%x/%x\n',\
855
                [eax+usb_interface_descr.bInterfaceClass]:2,\
856
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
857
                [eax+usb_interface_descr.bInterfaceProtocol]:2
858
        jmp     .next_descriptor
859
@@:
860
; 7f. Check that the new interface does not overflow allocated table.
861
        mov     edx, [NumInterfaces]
3908 Serge 862
        inc     edx
863
        cmp     edx, [ebx+usb_device_data.NumInterfaces]
3555 Serge 864
        ja      .invalid
865
; 7g. We have found a new interface. Advance bookkeeping vars.
866
        mov     [NumInterfaces], edx
867
        add     [InterfacesData], sizeof.usb_interface_data
868
; 7h. Save length left and pointer to the current interface descriptor.
869
        push    ecx eax
870
; Amuse the user if she is watching the debug board.
871
        DEBUGF 1,'K : USB interface class/subclass/protocol = %x/%x/%x\n',\
872
                [eax+usb_interface_descr.bInterfaceClass]:2,\
873
                [eax+usb_interface_descr.bInterfaceSubClass]:2,\
874
                [eax+usb_interface_descr.bInterfaceProtocol]:2
875
; 7i. Select the correct driver based on interface class.
876
; For hubs, go to 7j. Otherwise, go to 7k.
877
; Note: this should be rewritten as table-based lookup when more drivers will
878
; be available.
879
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 9
880
        jz      .found_hub
881
        mov     edx, usb_hid_name
882
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 3
883
        jz      .load_driver
884
        mov     edx, usb_print_name
885
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 7
886
        jz      .load_driver
887
        mov     edx, usb_stor_name
888
        cmp     byte [eax+usb_interface_descr.bInterfaceClass], 8
889
        jz      .load_driver
890
        mov     edx, usb_other_name
891
        jmp     .load_driver
892
.found_hub:
893
; 7j. Hubs are a part of USB stack, thus, integrated into the kernel.
894
; Use the pointer to hub callbacks and go to 7m.
895
        mov     eax, usb_hub_pseudosrv - USBSRV.usb_func
896
        jmp     .driver_loaded
897
.load_driver:
898
; 7k. Load the corresponding driver.
899
        push    ebx esi edi
900
        stdcall get_service, edx
901
        pop     edi esi ebx
902
; 7l. If failed, say something to the debug board and go to 7p.
903
        test    eax, eax
904
        jnz     .driver_loaded
905
        dbgstr 'failed to load class driver'
906
        jmp     .next_descriptor2
907
.driver_loaded:
908
; 7m. Call AddDevice function of the driver.
909
; Note that top of stack contains a pointer to the current interface,
910
; saved by step 7h.
911
        mov     [driver], eax
912
        mov     eax, [eax+USBSRV.usb_func]
913
        pop     edx
914
        push    edx
915
; Note: usb_hub_init assumes that edx points to usb_interface_descr,
916
; ecx = length rest; if you change the code, modify usb_hub_init also.
917
        stdcall [eax+USBFUNC.add_device], [pipe], [calldata], edx
918
; 7n. If failed, say something to the debug board and go to 7p.
919
        test    eax, eax
920
        jnz     .store_data
921
        dbgstr 'USB device initialization failed'
922
        jmp     .next_descriptor2
923
.store_data:
924
; 7o. Store the returned value and the driver handle to InterfacesData.
925
; Note that step 7g has already advanced InterfacesData.
926
        mov     edx, [InterfacesData]
927
        mov     [edx+usb_interface_data.DriverData-sizeof.usb_interface_data], eax
928
        mov     eax, [driver]
929
        mov     [edx+usb_interface_data.DriverFunc-sizeof.usb_interface_data], eax
930
.next_descriptor2:
931
; 7p. Restore registers saved in step 7h, get the descriptor length and
932
; continue to 7c.
933
        pop     eax ecx
934
        movzx   edx, byte [eax+usb_descr.bLength]
935
        jmp     .next_descriptor
936
endp
937
 
938
; Driver names, see step 7i of usb_got_config_callback.
939
iglobal
940
usb_hid_name    db      'usbhid',0
941
usb_stor_name   db      'usbstor',0
942
usb_print_name  db      'usbprint',0
943
usb_other_name  db      'usbother',0
944
endg