Subversion Repositories Kolibri OS

Rev

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

Rev 4592 Rev 5051
1
; standard driver stuff
1
; standard driver stuff; version of driver model = 5
2
format MS COFF
2
format PE DLL native 0.05
-
 
3
entry START
3
 
4
 
4
DEBUG = 1
5
DEBUG = 1
5
 
6
 
6
; this is for DEBUGF macro from 'fdo.inc'
7
; this is for DEBUGF macro from 'fdo.inc'
7
__DEBUG__ = 1
8
__DEBUG__ = 1
8
__DEBUG_LEVEL__ = 1
9
__DEBUG_LEVEL__ = 1
9
 
-
 
10
include '../proc32.inc'
-
 
11
include '../imports.inc'
-
 
12
include '../fdo.inc'
10
 
13
include '../../struct.inc'
-
 
14
 
-
 
15
public START
-
 
16
public version
11
include '../../struct.inc'
17
 
12
 
18
; Compile-time settings.
13
; Compile-time settings.
19
; If set, the code will dump all descriptors as they are read to the debug board.
14
; If set, the code will dump all descriptors as they are read to the debug board.
20
USB_DUMP_DESCRIPTORS = 1
15
USB_DUMP_DESCRIPTORS = 1
21
; If set, the code will dump any unclaimed input to the debug board.
16
; If set, the code will dump any unclaimed input to the debug board.
22
HID_DUMP_UNCLAIMED = 1
17
HID_DUMP_UNCLAIMED = 1
23
 
18
 
24
; USB constants
19
; USB constants
25
DEVICE_DESCR_TYPE           = 1
20
DEVICE_DESCR_TYPE           = 1
26
CONFIG_DESCR_TYPE           = 2
21
CONFIG_DESCR_TYPE           = 2
27
STRING_DESCR_TYPE           = 3
22
STRING_DESCR_TYPE           = 3
28
INTERFACE_DESCR_TYPE        = 4
23
INTERFACE_DESCR_TYPE        = 4
29
ENDPOINT_DESCR_TYPE         = 5
24
ENDPOINT_DESCR_TYPE         = 5
30
DEVICE_QUALIFIER_DESCR_TYPE = 6
25
DEVICE_QUALIFIER_DESCR_TYPE = 6
31
 
26
 
32
CONTROL_PIPE     = 0
27
CONTROL_PIPE     = 0
33
ISOCHRONOUS_PIPE = 1
28
ISOCHRONOUS_PIPE = 1
34
BULK_PIPE        = 2
29
BULK_PIPE        = 2
35
INTERRUPT_PIPE   = 3
30
INTERRUPT_PIPE   = 3
36
 
31
 
37
; USB HID constants
32
; USB HID constants
38
HID_DESCR_TYPE      = 21h
33
HID_DESCR_TYPE      = 21h
39
REPORT_DESCR_TYPE   = 22h
34
REPORT_DESCR_TYPE   = 22h
40
PHYSICAL_DESCR_TYPE = 23h
35
PHYSICAL_DESCR_TYPE = 23h
41
 
36
 
42
; USB structures
37
; USB structures
43
struct config_descr
38
struct config_descr
44
bLength                 db      ?
39
bLength                 db      ?
45
bDescriptorType         db      ?
40
bDescriptorType         db      ?
46
wTotalLength            dw      ?
41
wTotalLength            dw      ?
47
bNumInterfaces          db      ?
42
bNumInterfaces          db      ?
48
bConfigurationValue     db      ?
43
bConfigurationValue     db      ?
49
iConfiguration          db      ?
44
iConfiguration          db      ?
50
bmAttributes            db      ?
45
bmAttributes            db      ?
51
bMaxPower               db      ?
46
bMaxPower               db      ?
52
ends
47
ends
53
 
48
 
54
struct interface_descr
49
struct interface_descr
55
bLength                 db      ?
50
bLength                 db      ?
56
bDescriptorType         db      ?
51
bDescriptorType         db      ?
57
bInterfaceNumber        db      ?
52
bInterfaceNumber        db      ?
58
bAlternateSetting       db      ?
53
bAlternateSetting       db      ?
59
bNumEndpoints           db      ?
54
bNumEndpoints           db      ?
60
bInterfaceClass         db      ?
55
bInterfaceClass         db      ?
61
bInterfaceSubClass      db      ?
56
bInterfaceSubClass      db      ?
62
bInterfaceProtocol      db      ?
57
bInterfaceProtocol      db      ?
63
iInterface              db      ?
58
iInterface              db      ?
64
ends
59
ends
65
 
60
 
66
struct endpoint_descr
61
struct endpoint_descr
67
bLength                 db      ?
62
bLength                 db      ?
68
bDescriptorType         db      ?
63
bDescriptorType         db      ?
69
bEndpointAddress        db      ?
64
bEndpointAddress        db      ?
70
bmAttributes            db      ?
65
bmAttributes            db      ?
71
wMaxPacketSize          dw      ?
66
wMaxPacketSize          dw      ?
72
bInterval               db      ?
67
bInterval               db      ?
73
ends
68
ends
74
 
69
 
75
; USB HID structures
70
; USB HID structures
76
struct hid_descr
71
struct hid_descr
77
bLength                 db      ?
72
bLength                 db      ?
78
bDescriptorType         db      ?
73
bDescriptorType         db      ?
79
bcdHID                  dw      ?
74
bcdHID                  dw      ?
80
bCountryCode            db      ?
75
bCountryCode            db      ?
81
bNumDescriptors         db      ?
76
bNumDescriptors         db      ?
82
base_sizeof     rb      0
77
base_sizeof     rb      0
83
; now two fields are repeated .bNumDescriptors times:
78
; now two fields are repeated .bNumDescriptors times:
84
subDescriptorType       db      ?
79
subDescriptorType       db      ?
85
subDescriptorLength     dw      ?
80
subDescriptorLength     dw      ?
86
ends
81
ends
87
 
82
 
88
; Include macro for parsing report descriptors/data.
83
; Include macro for parsing report descriptors/data.
89
macro workers_globals
84
macro workers_globals
90
{}
85
{}
91
include 'report.inc'
86
include 'report.inc'
92
 
87
 
93
; Driver data for all devices
88
; Driver data for all devices
94
struct usb_device_data
89
struct usb_device_data
95
hid                     hid_data        ; data of HID layer
90
hid                     hid_data        ; data of HID layer
96
epdescr                 dd      ?       ; endpoint descriptor
91
epdescr                 dd      ?       ; endpoint descriptor
97
hiddescr                dd      ?       ; HID descriptor
92
hiddescr                dd      ?       ; HID descriptor
98
interface_number        dd      ?       ; copy of interface_descr.bInterfaceNumber
93
interface_number        dd      ?       ; copy of interface_descr.bInterfaceNumber
99
configpipe              dd      ?       ; config pipe handle
94
configpipe              dd      ?       ; config pipe handle
100
intpipe                 dd      ?       ; interrupt pipe handle
95
intpipe                 dd      ?       ; interrupt pipe handle
101
input_transfer_size     dd      ?       ; input transfer size
96
input_transfer_size     dd      ?       ; input transfer size
102
input_buffer            dd      ?       ; buffer for input transfers
97
input_buffer            dd      ?       ; buffer for input transfers
103
control                 rb      8       ; control packet to device
98
control                 rb      8       ; control packet to device
104
ends
99
ends
105
 
100
 
-
 
101
section '.flat' code readable writable executable
-
 
102
include '../../macros.inc'
-
 
103
include '../../proc32.inc'
-
 
104
include '../../peimport.inc'
106
section '.flat' code readable align 16
105
include '../../fdo.inc'
107
; The start procedure.
106
; The start procedure.
108
proc START
107
proc START
109
virtual at esp
108
virtual at esp
110
        dd      ?       ; return address
109
        dd      ?       ; return address
111
.reason dd      ?
110
.reason dd      ?
-
 
111
.cmdline dd     ?
112
end virtual
112
end virtual
113
; 1. Test whether the procedure is called with the argument DRV_ENTRY.
113
; 1. Test whether the procedure is called with the argument DRV_ENTRY.
114
; If not, return 0.
114
; If not, return 0.
115
        xor     eax, eax        ; initialize return value
115
        xor     eax, eax        ; initialize return value
116
        cmp     [.reason], 1    ; compare the argument
116
        cmp     [.reason], 1    ; compare the argument
117
        jnz     .nothing
117
        jnz     .nothing
118
; 2. Register self as a USB driver.
118
; 2. Register self as a USB driver.
119
; The name is my_driver = 'usbhid'; IOCTL interface is not supported;
119
; The name is my_driver = 'usbhid'; IOCTL interface is not supported;
120
; usb_functions is an offset of a structure with callback functions.
120
; usb_functions is an offset of a structure with callback functions.
121
        stdcall RegUSBDriver, my_driver, eax, usb_functions
121
        invoke  RegUSBDriver, my_driver, eax, usb_functions
122
; 3. Return the returned value of RegUSBDriver.
122
; 3. Return the returned value of RegUSBDriver.
123
.nothing:
123
.nothing:
124
        ret     4
124
        ret
125
endp
125
endp
126
 
126
 
127
; This procedure is called when new HID device is detected.
127
; This procedure is called when new HID device is detected.
128
; It initializes the device.
128
; It initializes the device.
129
proc AddDevice
129
proc AddDevice
130
        push    ebx esi edi     ; save used registers to be stdcall
130
        push    ebx esi edi     ; save used registers to be stdcall
131
virtual at esp
131
virtual at esp
132
                rd      3       ; saved registers
132
                rd      3       ; saved registers
133
                dd      ?       ; return address
133
                dd      ?       ; return address
134
.config_pipe    dd      ?
134
.config_pipe    dd      ?
135
.config_descr   dd      ?
135
.config_descr   dd      ?
136
.interface      dd      ?
136
.interface      dd      ?
137
end virtual
137
end virtual
138
        DEBUGF 1,'K : USB HID device detected\n'
138
        DEBUGF 1,'K : USB HID device detected\n'
139
; 1. Allocate memory for device data.
139
; 1. Allocate memory for device data.
140
        movi    eax, sizeof.usb_device_data
140
        movi    eax, sizeof.usb_device_data
141
        call    Kmalloc
141
        invoke  Kmalloc
142
        test    eax, eax
142
        test    eax, eax
143
        jnz     @f
143
        jnz     @f
144
        mov     esi, nomemory_msg
144
        mov     esi, nomemory_msg
145
        call    SysMsgBoardStr
145
        invoke  SysMsgBoardStr
146
        jmp     .return0
146
        jmp     .return0
147
@@:
147
@@:
148
; zero-initialize it
148
; zero-initialize it
149
        mov     edi, eax
149
        mov     edi, eax
150
        xchg    eax, ebx
150
        xchg    eax, ebx
151
        xor     eax, eax
151
        xor     eax, eax
152
        movi    ecx, sizeof.usb_device_data / 4
152
        movi    ecx, sizeof.usb_device_data / 4
153
        rep stosd
153
        rep stosd
154
        mov     edx, [.interface]
154
        mov     edx, [.interface]
155
; HID devices use one IN interrupt endpoint for polling the device
155
; HID devices use one IN interrupt endpoint for polling the device
156
; and an optional OUT interrupt endpoint. We do not use the later,
156
; and an optional OUT interrupt endpoint. We do not use the later,
157
; but must locate the first. Look for the IN interrupt endpoint.
157
; but must locate the first. Look for the IN interrupt endpoint.
158
; Also, look for the HID descriptor; according to HID spec, it must be
158
; Also, look for the HID descriptor; according to HID spec, it must be
159
; located before endpoint descriptors.
159
; located before endpoint descriptors.
160
; 2. Get the upper bound of all descriptors' data.
160
; 2. Get the upper bound of all descriptors' data.
161
        mov     eax, [.config_descr]
161
        mov     eax, [.config_descr]
162
        movzx   ecx, [eax+config_descr.wTotalLength]
162
        movzx   ecx, [eax+config_descr.wTotalLength]
163
        add     eax, ecx
163
        add     eax, ecx
164
; 3. Loop over all descriptors until
164
; 3. Loop over all descriptors until
165
; either end-of-data reached - this is fail
165
; either end-of-data reached - this is fail
166
; or interface descriptor found - this is fail, all further data
166
; or interface descriptor found - this is fail, all further data
167
;    correspond to that interface
167
;    correspond to that interface
168
; or endpoint descriptor for IN endpoint is found
168
; or endpoint descriptor for IN endpoint is found
169
; (HID descriptor must be located before the endpoint descriptor).
169
; (HID descriptor must be located before the endpoint descriptor).
170
; 3a. Loop start: edx points to the interface descriptor.
170
; 3a. Loop start: edx points to the interface descriptor.
171
.lookep:
171
.lookep:
172
; 3b. Get next descriptor.
172
; 3b. Get next descriptor.
173
        movzx   ecx, byte [edx] ; the first byte of all descriptors is length
173
        movzx   ecx, byte [edx] ; the first byte of all descriptors is length
174
        test    ecx, ecx
174
        test    ecx, ecx
175
        jz      .cfgerror
175
        jz      .cfgerror
176
        add     edx, ecx
176
        add     edx, ecx
177
; 3c. Check that at least two bytes are readable. The opposite is an error.
177
; 3c. Check that at least two bytes are readable. The opposite is an error.
178
        inc     edx
178
        inc     edx
179
        cmp     edx, eax
179
        cmp     edx, eax
180
        jae     .cfgerror
180
        jae     .cfgerror
181
        dec     edx
181
        dec     edx
182
; 3d. Check that this descriptor is not interface descriptor. The opposite is
182
; 3d. Check that this descriptor is not interface descriptor. The opposite is
183
; an error.
183
; an error.
184
        cmp     [edx+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE
184
        cmp     [edx+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE
185
        jz      .cfgerror
185
        jz      .cfgerror
186
; 3e. For HID descriptor, proceed to 4.
186
; 3e. For HID descriptor, proceed to 4.
187
; For endpoint descriptor, go to 5.
187
; For endpoint descriptor, go to 5.
188
; For other descriptors, continue the loop.
188
; For other descriptors, continue the loop.
189
; Note: bDescriptorType is in the same place in all descriptors.
189
; Note: bDescriptorType is in the same place in all descriptors.
190
        cmp     [edx+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
190
        cmp     [edx+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
191
        jz      .foundep
191
        jz      .foundep
192
        cmp     [edx+endpoint_descr.bDescriptorType], HID_DESCR_TYPE
192
        cmp     [edx+endpoint_descr.bDescriptorType], HID_DESCR_TYPE
193
        jnz     .lookep
193
        jnz     .lookep
194
; 4a. Check that the descriptor contains all required data and all data are
194
; 4a. Check that the descriptor contains all required data and all data are
195
; readable. The opposite is an error.
195
; readable. The opposite is an error.
196
        movzx   ecx, [edx+hid_descr.bLength]
196
        movzx   ecx, [edx+hid_descr.bLength]
197
        cmp     ecx, hid_descr.base_sizeof + 3
197
        cmp     ecx, hid_descr.base_sizeof + 3
198
        jb      .cfgerror
198
        jb      .cfgerror
199
        add     ecx, edx
199
        add     ecx, edx
200
        cmp     ecx, eax
200
        cmp     ecx, eax
201
        ja      .cfgerror
201
        ja      .cfgerror
202
; 4b. Store the pointer in usb_device_data structure for further references.
202
; 4b. Store the pointer in usb_device_data structure for further references.
203
        mov     [ebx+usb_device_data.hiddescr], edx
203
        mov     [ebx+usb_device_data.hiddescr], edx
204
; 4c. Continue the loop.
204
; 4c. Continue the loop.
205
        jmp     .lookep
205
        jmp     .lookep
206
.foundep:
206
.foundep:
207
; 5a. Check that the descriptor contains all required data and all data are
207
; 5a. Check that the descriptor contains all required data and all data are
208
; readable. The opposite is an error.
208
; readable. The opposite is an error.
209
        cmp     byte [edx+endpoint_descr.bLength], sizeof.endpoint_descr
209
        cmp     byte [edx+endpoint_descr.bLength], sizeof.endpoint_descr
210
        jb      .cfgerror
210
        jb      .cfgerror
211
        lea     ecx, [edx+sizeof.endpoint_descr]
211
        lea     ecx, [edx+sizeof.endpoint_descr]
212
        cmp     ecx, eax
212
        cmp     ecx, eax
213
        jbe     @f
213
        jbe     @f
214
; 6. An error occured during processing endpoint descriptor.
214
; 6. An error occured during processing endpoint descriptor.
215
.cfgerror:
215
.cfgerror:
216
; 6a. Print a message.
216
; 6a. Print a message.
217
        mov     esi, invalid_config_descr_msg
217
        mov     esi, invalid_config_descr_msg
218
        call    SysMsgBoardStr
218
        invoke  SysMsgBoardStr
219
; 6b. Free memory allocated for device data.
219
; 6b. Free memory allocated for device data.
220
.free:
220
.free:
221
        xchg    eax, ebx
221
        xchg    eax, ebx
222
        call    Kfree
222
        invoke  Kfree
223
.return0:
223
.return0:
224
; 6c. Return an error.
224
; 6c. Return an error.
225
        xor     eax, eax
225
        xor     eax, eax
226
.nothing:
226
.nothing:
227
        pop     edi esi ebx     ; restore used registers to be stdcall
227
        pop     edi esi ebx     ; restore used registers to be stdcall
228
        ret     12
228
        ret     12
229
@@:
229
@@:
230
; 5b. If this is not IN interrupt endpoint, ignore it and continue the loop.
230
; 5b. If this is not IN interrupt endpoint, ignore it and continue the loop.
231
        test    [edx+endpoint_descr.bEndpointAddress], 80h
231
        test    [edx+endpoint_descr.bEndpointAddress], 80h
232
        jz      .lookep
232
        jz      .lookep
233
        mov     cl, [edx+endpoint_descr.bmAttributes]
233
        mov     cl, [edx+endpoint_descr.bmAttributes]
234
        and     cl, 3
234
        and     cl, 3
235
        cmp     cl, INTERRUPT_PIPE
235
        cmp     cl, INTERRUPT_PIPE
236
        jnz     .lookep
236
        jnz     .lookep
237
; 5c. Store the pointer in usb_device_data structure for futher references.
237
; 5c. Store the pointer in usb_device_data structure for futher references.
238
        mov     [ebx+usb_device_data.epdescr], edx
238
        mov     [ebx+usb_device_data.epdescr], edx
239
; 5d. Check that HID descriptor was found. If not, go to 6.
239
; 5d. Check that HID descriptor was found. If not, go to 6.
240
        cmp     [ebx+usb_device_data.hiddescr], 0
240
        cmp     [ebx+usb_device_data.hiddescr], 0
241
        jz      .cfgerror
241
        jz      .cfgerror
242
.descriptors_found:
242
.descriptors_found:
243
; 6. Configuration descriptor seems to be ok.
243
; 6. Configuration descriptor seems to be ok.
244
; Send SET_IDLE command disabling auto-repeat feature (it is quite useless)
244
; Send SET_IDLE command disabling auto-repeat feature (it is quite useless)
245
; and continue configuring in SET_IDLE callback.
245
; and continue configuring in SET_IDLE callback.
246
        lea     edx, [ebx+usb_device_data.control]
246
        lea     edx, [ebx+usb_device_data.control]
247
        mov     eax, [.interface]
247
        mov     eax, [.interface]
248
        mov     dword [edx], 21h + \    ; Class-specific request to Interface
248
        mov     dword [edx], 21h + \    ; Class-specific request to Interface
249
                (0Ah shl 8) + \         ; SET_IDLE
249
                (0Ah shl 8) + \         ; SET_IDLE
250
                (0 shl 16) + \          ; apply to all input reports
250
                (0 shl 16) + \          ; apply to all input reports
251
                (0 shl 24)              ; disable auto-repeat
251
                (0 shl 24)              ; disable auto-repeat
252
        movzx   eax, [eax+interface_descr.bInterfaceNumber]
252
        movzx   eax, [eax+interface_descr.bInterfaceNumber]
253
        mov     [ebx+usb_device_data.interface_number], eax
253
        mov     [ebx+usb_device_data.interface_number], eax
254
        mov     [edx+4], eax            ; set interface number, zero length
254
        mov     [edx+4], eax            ; set interface number, zero length
255
        mov     eax, [.config_pipe]
255
        mov     eax, [.config_pipe]
256
        mov     [ebx+usb_device_data.configpipe], eax
256
        mov     [ebx+usb_device_data.configpipe], eax
257
        xor     ecx, ecx
257
        xor     ecx, ecx
258
        stdcall USBControlTransferAsync, eax, edx, ecx, ecx, idle_set, ebx, ecx
258
        invoke  USBControlTransferAsync, eax, edx, ecx, ecx, idle_set, ebx, ecx
259
; 7. Return pointer to usb_device_data.
259
; 7. Return pointer to usb_device_data.
260
        xchg    eax, ebx
260
        xchg    eax, ebx
261
        jmp     .nothing
261
        jmp     .nothing
262
endp
262
endp
263
 
263
 
264
; This procedure is called by USB stack when SET_IDLE request initiated by
264
; This procedure is called by USB stack when SET_IDLE request initiated by
265
; AddDevice is completed, either successfully or unsuccessfully.
265
; AddDevice is completed, either successfully or unsuccessfully.
266
proc idle_set
266
proc idle_set
267
        push    ebx esi         ; save used registers to be stdcall
267
        push    ebx esi         ; save used registers to be stdcall
268
virtual at esp
268
virtual at esp
269
                rd      2       ; saved registers
269
                rd      2       ; saved registers
270
                dd      ?       ; return address
270
                dd      ?       ; return address
271
.pipe           dd      ?
271
.pipe           dd      ?
272
.status         dd      ?
272
.status         dd      ?
273
.buffer         dd      ?
273
.buffer         dd      ?
274
.length         dd      ?
274
.length         dd      ?
275
.calldata       dd      ?
275
.calldata       dd      ?
276
end virtual
276
end virtual
277
; Ignore status. Support for SET_IDLE is optional, so the device is free to
277
; Ignore status. Support for SET_IDLE is optional, so the device is free to
278
; STALL the request; config pipe should remain functional without explicit cleanup.
278
; STALL the request; config pipe should remain functional without explicit cleanup.
279
        mov     ebx, [.calldata]
279
        mov     ebx, [.calldata]
280
; 1. HID descriptor contains length of Report descriptor. Parse it.
280
; 1. HID descriptor contains length of Report descriptor. Parse it.
281
        mov     esi, [ebx+usb_device_data.hiddescr]
281
        mov     esi, [ebx+usb_device_data.hiddescr]
282
        movzx   ecx, [esi+hid_descr.bNumDescriptors]
282
        movzx   ecx, [esi+hid_descr.bNumDescriptors]
283
        lea     eax, [hid_descr.base_sizeof+ecx*3]
283
        lea     eax, [hid_descr.base_sizeof+ecx*3]
284
        cmp     eax, 100h
284
        cmp     eax, 100h
285
        jae     .cfgerror
285
        jae     .cfgerror
286
        cmp     al, [esi+hid_descr.bLength]
286
        cmp     al, [esi+hid_descr.bLength]
287
        jb      .cfgerror
287
        jb      .cfgerror
288
.look_report:
288
.look_report:
289
        dec     ecx
289
        dec     ecx
290
        js      .cfgerror
290
        js      .cfgerror
291
        cmp     [esi+hid_descr.subDescriptorType], REPORT_DESCR_TYPE
291
        cmp     [esi+hid_descr.subDescriptorType], REPORT_DESCR_TYPE
292
        jz      .found_report
292
        jz      .found_report
293
        add     esi, 3
293
        add     esi, 3
294
        jmp     .look_report
294
        jmp     .look_report
295
.cfgerror:
295
.cfgerror:
296
        mov     esi, invalid_config_descr_msg
296
        mov     esi, invalid_config_descr_msg
297
.abort_with_msg:
297
.abort_with_msg:
298
        call    SysMsgBoardStr
298
        invoke  SysMsgBoardStr
299
        jmp     .nothing
299
        jmp     .nothing
300
.found_report:
300
.found_report:
301
; 2. Send request for the Report descriptor.
301
; 2. Send request for the Report descriptor.
302
; 2a. Allocate memory.
302
; 2a. Allocate memory.
303
        movzx   eax, [esi+hid_descr.subDescriptorLength]
303
        movzx   eax, [esi+hid_descr.subDescriptorLength]
304
        test    eax, eax
304
        test    eax, eax
305
        jz      .cfgerror
305
        jz      .cfgerror
306
        push    eax
306
        push    eax
307
        call    Kmalloc
307
        invoke  Kmalloc
308
        pop     ecx
308
        pop     ecx
309
; If failed, say a message and stop initialization.
309
; If failed, say a message and stop initialization.
310
        mov     esi, nomemory_msg
310
        mov     esi, nomemory_msg
311
        test    eax, eax
311
        test    eax, eax
312
        jz      .abort_with_msg
312
        jz      .abort_with_msg
313
; 2b. Submit the request.
313
; 2b. Submit the request.
314
        xchg    eax, esi
314
        xchg    eax, esi
315
        lea     edx, [ebx+usb_device_data.control]
315
        lea     edx, [ebx+usb_device_data.control]
316
        mov     eax, [ebx+usb_device_data.interface_number]
316
        mov     eax, [ebx+usb_device_data.interface_number]
317
        mov     dword [edx], 81h + \    ; Standard request to Interface
317
        mov     dword [edx], 81h + \    ; Standard request to Interface
318
                (6 shl 8) + \           ; GET_DESCRIPTOR
318
                (6 shl 8) + \           ; GET_DESCRIPTOR
319
                (0 shl 16) + \          ; descriptor index: there is only one report descriptor
319
                (0 shl 16) + \          ; descriptor index: there is only one report descriptor
320
                (REPORT_DESCR_TYPE shl 24); descriptor type
320
                (REPORT_DESCR_TYPE shl 24); descriptor type
321
        mov     [edx+4], ax             ; Interface number
321
        mov     [edx+4], ax             ; Interface number
322
        mov     [edx+6], cx             ; descriptor length
322
        mov     [edx+6], cx             ; descriptor length
323
        stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \
323
        invoke  USBControlTransferAsync, [ebx+usb_device_data.configpipe], \
324
                edx, esi, ecx, got_report, ebx, 0
324
                edx, esi, ecx, got_report, ebx, 0
325
; 2c. If failed, free the buffer and stop initialization.
325
; 2c. If failed, free the buffer and stop initialization.
326
        test    eax, eax
326
        test    eax, eax
327
        jnz     .nothing
327
        jnz     .nothing
328
        xchg    eax, esi
328
        xchg    eax, esi
329
        call    Kfree
329
        invoke  Kfree
330
.nothing:
330
.nothing:
331
        pop     esi ebx         ; restore used registers to be stdcall
331
        pop     esi ebx         ; restore used registers to be stdcall
332
        ret     20
332
        ret     20
333
endp
333
endp
334
 
334
 
335
; This procedure is called by USB stack when the report descriptor queried
335
; This procedure is called by USB stack when the report descriptor queried
336
; by idle_set is completed, either successfully or unsuccessfully.
336
; by idle_set is completed, either successfully or unsuccessfully.
337
proc got_report stdcall uses ebx esi edi, pipe, status, buffer, length, calldata
337
proc got_report stdcall uses ebx esi edi, pipe, status, buffer, length, calldata
338
locals
338
locals
339
parse_descr_locals
339
parse_descr_locals
340
if ~HID_DUMP_UNCLAIMED
340
if ~HID_DUMP_UNCLAIMED
341
has_driver      db      ?
341
has_driver      db      ?
342
                rb      3
342
                rb      3
343
end if
343
end if
344
endl
344
endl
345
; 1. Check the status; if the request has failed, say something to the debug board
345
; 1. Check the status; if the request has failed, say something to the debug board
346
; and stop initialization.
346
; and stop initialization.
347
        cmp     [status], 0
347
        cmp     [status], 0
348
        jnz     .generic_fail
348
        jnz     .generic_fail
349
; 2. Subtract size of setup packet from the total length;
349
; 2. Subtract size of setup packet from the total length;
350
; the rest is length of the descriptor, and it must be nonzero.
350
; the rest is length of the descriptor, and it must be nonzero.
351
        sub     [length], 8
351
        sub     [length], 8
352
        ja      .has_something
352
        ja      .has_something
353
.generic_fail:
353
.generic_fail:
354
        push    esi
354
        push    esi
355
        mov     esi, reportfail
355
        mov     esi, reportfail
356
        call    SysMsgBoardStr
356
        invoke  SysMsgBoardStr
357
        pop     esi
357
        pop     esi
358
        jmp     .exit
358
        jmp     .exit
359
.has_something:
359
.has_something:
360
; 3. Process descriptor.
360
; 3. Process descriptor.
361
; 3a. Dump it to the debug board, if enabled in compile-time setting.
361
; 3a. Dump it to the debug board, if enabled in compile-time setting.
362
if USB_DUMP_DESCRIPTORS
362
if USB_DUMP_DESCRIPTORS
363
        mov     eax, [buffer]
363
        mov     eax, [buffer]
364
        mov     ecx, [length]
364
        mov     ecx, [length]
365
        DEBUGF 1,'K : report descriptor:'
365
        DEBUGF 1,'K : report descriptor:'
366
@@:
366
@@:
367
        DEBUGF 1,' %x',[eax]:2
367
        DEBUGF 1,' %x',[eax]:2
368
        inc     eax
368
        inc     eax
369
        dec     ecx
369
        dec     ecx
370
        jnz     @b
370
        jnz     @b
371
        DEBUGF 1,'\n'
371
        DEBUGF 1,'\n'
372
end if
372
end if
373
; 3b. Call the HID layer.
373
; 3b. Call the HID layer.
374
        parse_descr
374
        parse_descr
375
        cmp     [report_ok], 0
375
        cmp     [report_ok], 0
376
        jz      got_report.exit
376
        jz      got_report.exit
377
        mov     ebx, [calldata]
377
        mov     ebx, [calldata]
378
        postprocess_descr
378
        postprocess_descr
379
; 4. Stop initialization if no driver is assigned.
379
; 4. Stop initialization if no driver is assigned.
380
if ~HID_DUMP_UNCLAIMED
380
if ~HID_DUMP_UNCLAIMED
381
        cmp     [has_driver], 0
381
        cmp     [has_driver], 0
382
        jz      got_report.exit
382
        jz      got_report.exit
383
end if
383
end if
384
; 5. Open interrupt IN pipe. If failed, stop initialization.
384
; 5. Open interrupt IN pipe. If failed, stop initialization.
385
        mov     edx, [ebx+usb_device_data.epdescr]
385
        mov     edx, [ebx+usb_device_data.epdescr]
386
        movzx   ecx, [edx+endpoint_descr.bEndpointAddress]
386
        movzx   ecx, [edx+endpoint_descr.bEndpointAddress]
387
        movzx   eax, [edx+endpoint_descr.bInterval]
387
        movzx   eax, [edx+endpoint_descr.bInterval]
388
        movzx   edx, [edx+endpoint_descr.wMaxPacketSize]
388
        movzx   edx, [edx+endpoint_descr.wMaxPacketSize]
389
        stdcall USBOpenPipe, [ebx+usb_device_data.configpipe], ecx, edx, INTERRUPT_PIPE, eax
389
        invoke  USBOpenPipe, [ebx+usb_device_data.configpipe], ecx, edx, INTERRUPT_PIPE, eax
390
        test    eax, eax
390
        test    eax, eax
391
        jz      got_report.exit
391
        jz      got_report.exit
392
        mov     [ebx+usb_device_data.intpipe], eax
392
        mov     [ebx+usb_device_data.intpipe], eax
393
; 6. Initialize buffer for input packet.
393
; 6. Initialize buffer for input packet.
394
; 6a. Find the length of input packet.
394
; 6a. Find the length of input packet.
395
; This is the maximal length of all input reports.
395
; This is the maximal length of all input reports.
396
        mov     edx, [ebx+usb_device_data.hid.input.first_report]
396
        mov     edx, [ebx+usb_device_data.hid.input.first_report]
397
        xor     eax, eax
397
        xor     eax, eax
398
.find_input_size:
398
.find_input_size:
399
        test    edx, edx
399
        test    edx, edx
400
        jz      .found_input_size
400
        jz      .found_input_size
401
        cmp     eax, [edx+report.size]
401
        cmp     eax, [edx+report.size]
402
        jae     @f
402
        jae     @f
403
        mov     eax, [edx+report.size]
403
        mov     eax, [edx+report.size]
404
@@:
404
@@:
405
        mov     edx, [edx+report.next]
405
        mov     edx, [edx+report.next]
406
        jmp     .find_input_size
406
        jmp     .find_input_size
407
.found_input_size:
407
.found_input_size:
408
; report.size is in bits, transform it to bytes
408
; report.size is in bits, transform it to bytes
409
        add     eax, 7
409
        add     eax, 7
410
        shr     eax, 3
410
        shr     eax, 3
411
; if reports are numbered, the first byte is report ID, include it
411
; if reports are numbered, the first byte is report ID, include it
412
        cmp     [ebx+usb_device_data.hid.input.numbered], 0
412
        cmp     [ebx+usb_device_data.hid.input.numbered], 0
413
        jz      @f
413
        jz      @f
414
        inc     eax
414
        inc     eax
415
@@:
415
@@:
416
        mov     [ebx+usb_device_data.input_transfer_size], eax
416
        mov     [ebx+usb_device_data.input_transfer_size], eax
417
; 6b. Allocate memory for input packet: dword-align and add additional dword
417
; 6b. Allocate memory for input packet: dword-align and add additional dword
418
; for extract_field_value.
418
; for extract_field_value.
419
        add     eax, 4+3
419
        add     eax, 4+3
420
        and     eax, not 3
420
        and     eax, not 3
421
        call    Kmalloc
421
        invoke  Kmalloc
422
        test    eax, eax
422
        test    eax, eax
423
        jnz     @f
423
        jnz     @f
424
        mov     esi, nomemory_msg
424
        mov     esi, nomemory_msg
425
        call    SysMsgBoardStr
425
        invoke  SysMsgBoardStr
426
        jmp     got_report.exit
426
        jmp     got_report.exit
427
@@:
427
@@:
428
        mov     [ebx+usb_device_data.input_buffer], eax
428
        mov     [ebx+usb_device_data.input_buffer], eax
429
; 7. Submit a request for input packet and wait for input.
429
; 7. Submit a request for input packet and wait for input.
430
        call    ask_for_input
430
        call    ask_for_input
431
got_report.exit:
431
got_report.exit:
432
        mov     eax, [buffer]
432
        mov     eax, [buffer]
433
        call    Kfree
433
        invoke  Kfree
434
        ret
434
        ret
435
endp
435
endp
436
 
436
 
437
; Helper procedure for got_report and got_input.
437
; Helper procedure for got_report and got_input.
438
; Submits a request for the next input packet.
438
; Submits a request for the next input packet.
439
proc ask_for_input
439
proc ask_for_input
440
; just call USBNormalTransferAsync with correct parameters,
440
; just call USBNormalTransferAsync with correct parameters,
441
; allow short packets
441
; allow short packets
442
        stdcall USBNormalTransferAsync, \
442
        invoke  USBNormalTransferAsync, \
443
                [ebx+usb_device_data.intpipe], \
443
                [ebx+usb_device_data.intpipe], \
444
                [ebx+usb_device_data.input_buffer], \
444
                [ebx+usb_device_data.input_buffer], \
445
                [ebx+usb_device_data.input_transfer_size], \
445
                [ebx+usb_device_data.input_transfer_size], \
446
                got_input, ebx, \
446
                got_input, ebx, \
447
                1
447
                1
448
        ret
448
        ret
449
endp
449
endp
450
 
450
 
451
; This procedure is called by USB stack when a HID device responds with input
451
; This procedure is called by USB stack when a HID device responds with input
452
; data packet.
452
; data packet.
453
proc got_input stdcall uses ebx esi edi, pipe, status, buffer, length, calldata
453
proc got_input stdcall uses ebx esi edi, pipe, status, buffer, length, calldata
454
locals
454
locals
455
parse_input_locals
455
parse_input_locals
456
endl
456
endl
457
; 1. Validate parameters: fail on error, ignore zero-length transfers.
457
; 1. Validate parameters: fail on error, ignore zero-length transfers.
458
        mov     ebx, [calldata]
458
        mov     ebx, [calldata]
459
        cmp     [status], 0
459
        cmp     [status], 0
460
        jnz     .fail
460
        jnz     .fail
461
        cmp     [length], 0
461
        cmp     [length], 0
462
        jz      .done
462
        jz      .done
463
; 2. Get pointer to report in esi.
463
; 2. Get pointer to report in esi.
464
; 2a. If there are no report IDs, use hid.input.data.
464
; 2a. If there are no report IDs, use hid.input.data.
465
        mov     eax, [buffer]
465
        mov     eax, [buffer]
466
        mov     esi, [ebx+usb_device_data.hid.input.data]
466
        mov     esi, [ebx+usb_device_data.hid.input.data]
467
        cmp     [ebx+usb_device_data.hid.input.numbered], 0
467
        cmp     [ebx+usb_device_data.hid.input.numbered], 0
468
        jz      .report_found
468
        jz      .report_found
469
; 2b. Otherwise, the first byte of report is report ID;
469
; 2b. Otherwise, the first byte of report is report ID;
470
; locate the report by its ID, advance buffer+length to one byte.
470
; locate the report by its ID, advance buffer+length to one byte.
471
        movzx   eax, byte [eax]
471
        movzx   eax, byte [eax]
472
        mov     esi, [esi+eax*4]
472
        mov     esi, [esi+eax*4]
473
        inc     [buffer]
473
        inc     [buffer]
474
        dec     [length]
474
        dec     [length]
475
.report_found:
475
.report_found:
476
; 3. Validate: ignore transfers with unregistered report IDs
476
; 3. Validate: ignore transfers with unregistered report IDs
477
; and transfers which are too short for the corresponding report.
477
; and transfers which are too short for the corresponding report.
478
        test    esi, esi
478
        test    esi, esi
479
        jz      .done
479
        jz      .done
480
        mov     eax, [esi+report.size]
480
        mov     eax, [esi+report.size]
481
        add     eax, 7
481
        add     eax, 7
482
        shr     eax, 3
482
        shr     eax, 3
483
        cmp     eax, [length]
483
        cmp     eax, [length]
484
        ja      .done
484
        ja      .done
485
; 4. Pass everything to HID layer.
485
; 4. Pass everything to HID layer.
486
        parse_input
486
        parse_input
487
.done:
487
.done:
488
; 5. Query the next input.
488
; 5. Query the next input.
489
        mov     ebx, [calldata]
489
        mov     ebx, [calldata]
490
        call    ask_for_input
490
        call    ask_for_input
491
.nothing:
491
.nothing:
492
        ret
492
        ret
493
.fail:
493
.fail:
494
        mov     esi, transfer_error_msg
494
        mov     esi, transfer_error_msg
495
        call    SysMsgBoardStr
495
        invoke  SysMsgBoardStr
496
        jmp     .nothing
496
        jmp     .nothing
497
endp
497
endp
498
 
498
 
499
; This function is called by the USB subsystem when a device is disconnected.
499
; This function is called by the USB subsystem when a device is disconnected.
500
proc DeviceDisconnected
500
proc DeviceDisconnected
501
        push    ebx esi edi     ; save used registers to be stdcall
501
        push    ebx esi edi     ; save used registers to be stdcall
502
virtual at esp
502
virtual at esp
503
                rd      3       ; saved registers
503
                rd      3       ; saved registers
504
                dd      ?       ; return address
504
                dd      ?       ; return address
505
.device_data    dd      ?
505
.device_data    dd      ?
506
end virtual
506
end virtual
507
; 1. Say a message.
507
; 1. Say a message.
508
        mov     ebx, [.device_data]
508
        mov     ebx, [.device_data]
509
        mov     esi, disconnectmsg
509
        mov     esi, disconnectmsg
510
        stdcall SysMsgBoardStr
510
        invoke  SysMsgBoardStr
511
; 2. Ask HID layer to release all HID-related resources.
511
; 2. Ask HID layer to release all HID-related resources.
512
        hid_cleanup
512
        hid_cleanup
513
; 3. Free the device data.
513
; 3. Free the device data.
514
        xchg    eax, ebx
514
        xchg    eax, ebx
515
        call    Kfree
515
        invoke  Kfree
516
; 4. Return.
516
; 4. Return.
517
.nothing:
517
.nothing:
518
        pop     edi esi ebx     ; restore used registers to be stdcall
518
        pop     edi esi ebx     ; restore used registers to be stdcall
519
        ret     4       ; purge one dword argument to be stdcall
519
        ret     4       ; purge one dword argument to be stdcall
520
endp
520
endp
521
 
521
 
522
include 'sort.inc'
522
include 'sort.inc'
523
include 'unclaimed.inc'
523
include 'unclaimed.inc'
524
include 'mouse.inc'
524
include 'mouse.inc'
525
include 'keyboard.inc'
525
include 'keyboard.inc'
526
 
526
 
527
; strings
527
; strings
528
my_driver       db      'usbhid',0
528
my_driver       db      'usbhid',0
529
nomemory_msg    db      'K : no memory',13,10,0
529
nomemory_msg    db      'K : no memory',13,10,0
530
invalid_config_descr_msg db 'K : invalid config descriptor',13,10,0
530
invalid_config_descr_msg db 'K : invalid config descriptor',13,10,0
531
reportfail      db      'K : failed to read report descriptor',13,10,0
531
reportfail      db      'K : failed to read report descriptor',13,10,0
532
transfer_error_msg db   'K : USB transfer error, disabling HID device',13,10,0
532
transfer_error_msg db   'K : USB transfer error, disabling HID device',13,10,0
533
disconnectmsg   db      'K : USB HID device disconnected',13,10,0
533
disconnectmsg   db      'K : USB HID device disconnected',13,10,0
534
invalid_report_msg db   'K : report descriptor is invalid',13,10,0
534
invalid_report_msg db   'K : report descriptor is invalid',13,10,0
535
delimiter_note  db      'K : note: alternate usage ignored',13,10,0
535
delimiter_note  db      'K : note: alternate usage ignored',13,10,0
536
 
-
 
537
; Exported variable: kernel API version.
536
 
538
align 4
-
 
539
version dd      50005h
537
align 4
540
; Structure with callback functions.
538
; Structure with callback functions.
541
usb_functions:
539
usb_functions:
542
        dd      12
540
        dd      12
543
        dd      AddDevice
541
        dd      AddDevice
544
        dd      DeviceDisconnected
542
        dd      DeviceDisconnected
545
 
543
 
546
; for DEBUGF macro
544
; for DEBUGF macro
547
include_debug_strings
545
include_debug_strings
548
 
546
 
549
; Workers data
547
; Workers data
550
workers_globals
548
workers_globals
-
 
549
 
551
 
550
align 4
552
; for uninitialized data
551
data fixups
553
;section '.data' data readable writable align 16
552
end data