Subversion Repositories Kolibri OS

Rev

Rev 4265 | Rev 5201 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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