Subversion Repositories Kolibri OS

Rev

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