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