Subversion Repositories Kolibri OS

Rev

Rev 5177 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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