Subversion Repositories Kolibri OS

Rev

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

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