Rev 3709 | Rev 4598 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3709 | clevermous | 1 | ; HID keyboard driver, part of USBHID driver. |
2 | |||
3 | ; Global constants. |
||
4 | ; They are assembled in a macro to separate code and data; |
||
5 | ; the code is located at the point of "include 'keyboard.inc'", |
||
6 | ; the data are collected when workers_globals is instantiated. |
||
7 | macro workers_globals |
||
8 | { |
||
9 | ; include global constants from previous workers |
||
3711 | clevermous | 10 | workers_globals |
3709 | clevermous | 11 | align 4 |
12 | ; Callbacks for HID layer. |
||
13 | keyboard_driver: |
||
3711 | clevermous | 14 | dd keyboard_driver_add_device |
15 | dd keyboard_driver_disconnect |
||
16 | dd keyboard_driver_begin_packet |
||
17 | dd keyboard_driver_array_overflow? |
||
18 | dd keyboard_driver_input_field |
||
19 | dd keyboard_driver_end_packet |
||
3709 | clevermous | 20 | ; Callbacks for keyboard layer. |
21 | kbd_functions: |
||
3711 | clevermous | 22 | dd 12 |
23 | dd CloseKeyboard |
||
24 | dd SetKeyboardLights |
||
3709 | clevermous | 25 | ; Kernel keyboard layer takes input in form of PS/2 scancodes. |
26 | ; data for keyboard: correspondence between HID usage keys and PS/2 scancodes. |
||
3711 | clevermous | 27 | EX = 80h ; if set, precede the scancode with special scancode 0xE0 |
3709 | clevermous | 28 | label control_keys byte |
29 | ; Usages 700E0h ... 700E7h: LCtrl, LShift, LAlt, LWin, RCtrl, RShift, RAlt, RWin |
||
30 | db 1Dh, 2Ah, 38h, 5Bh+EX, 1Dh+EX, 36h, 38h+EX, 5Ch+EX |
||
31 | ; Usages 70004h ... 70004h + normal_keys_number - 1 |
||
32 | label normal_keys byte |
||
33 | db 1Eh, 30h, 2Eh, 20h, 12h, 21h, 22h, 23h, 17h, 24h, 25h, 26h, 32h, 31h, 18h, 19h |
||
3711 | clevermous | 34 | db 10h, 13h, 1Fh, 14h, 16h, 2Fh, 11h, 2Dh, 15h, 2Ch, 02h, 03h, 04h, 05h, 06h, 07h |
3709 | clevermous | 35 | db 08h, 09h, 0Ah, 0Bh, 1Ch, 01h, 0Eh, 0Fh, 39h, 0Ch, 0Dh, 1Ah, 1Bh, 2Bh, 0, 27h |
36 | db 28h, 29h, 33h, 34h, 35h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh, 40h, 41h, 42h, 43h, 44h |
||
37 | db 57h, 58h,37h+EX,46h,0,52h+EX,47h+EX,49h+EX,53h+EX,4Fh+EX,51h+EX,4Dh+EX,4Bh+EX,50h+EX,48h+EX,45h |
||
3711 | clevermous | 38 | db 35h+EX,37h,4Ah,4Eh,1Ch+EX,4Fh,50h, 51h, 4Bh, 4Ch, 4Dh, 47h, 48h, 49h, 52h, 53h |
39 | db 0,5Dh+EX,5Eh+EX |
||
3709 | clevermous | 40 | normal_keys_number = $ - normal_keys |
41 | } |
||
42 | |||
43 | ; Data that are specific for one keyboard device. |
||
44 | struct keyboard_device_data |
||
45 | handle dd ? ; keyboard handle from RegKeyboard |
||
46 | timer dd ? ; auto-repeat timer handle |
||
47 | repeatkey db ? ; auto-repeat key code |
||
3711 | clevermous | 48 | rb 3 ; padding |
49 | usbdev dd ? ; pointer to device_data of USB and HID layers |
||
50 | modifiers dd ? ; state of LCtrl ... RWin |
||
51 | led_report dd ? ; output report for LEDs state |
||
52 | numlock_bit dd ? ; position of NumLock bit in LED output report |
||
53 | capslock_bit dd ? |
||
54 | scrolllock_bit dd ? ; guess what |
||
3709 | clevermous | 55 | ends |
56 | |||
57 | ; This procedure is called when HID layer detects a new keyboard. |
||
58 | ; in: ebx -> usb_device_data, edi -> collection |
||
59 | ; out: eax = device-specific data or NULL on error |
||
60 | proc keyboard_driver_add_device |
||
61 | ; 1. Allocate memory for keyboard_device_data. If failed, return NULL. |
||
3711 | clevermous | 62 | movi eax, sizeof.keyboard_device_data |
63 | call Kmalloc |
||
64 | test eax, eax |
||
65 | jz .nothing |
||
3709 | clevermous | 66 | ; 2. Initialize keyboard_device_data: store pointer to USB layer data, |
67 | ; zero some fields, initialize bit positions to -1. |
||
3711 | clevermous | 68 | mov [eax+keyboard_device_data.usbdev], ebx |
69 | xor ecx, ecx |
||
70 | mov [eax+keyboard_device_data.timer], ecx |
||
71 | mov [eax+keyboard_device_data.repeatkey], cl |
||
72 | mov [eax+keyboard_device_data.modifiers], ecx |
||
73 | mov [eax+keyboard_device_data.led_report], ecx |
||
74 | dec ecx |
||
75 | mov [eax+keyboard_device_data.numlock_bit], ecx |
||
76 | mov [eax+keyboard_device_data.capslock_bit], ecx |
||
77 | mov [eax+keyboard_device_data.scrolllock_bit], ecx |
||
3709 | clevermous | 78 | ; 3. Look for LED report and bits corresponding to indicators. |
79 | ; For now, assume that all LEDs are set by the same report. |
||
80 | ; 3a. Save registers. |
||
3711 | clevermous | 81 | push ebx esi |
3709 | clevermous | 82 | ; 3b. Prepare for loop over output reports: get the first output report. |
83 | ; If there are no output records, skip step 3; |
||
84 | ; default values of led_report and *_bit were set in step 2. |
||
3711 | clevermous | 85 | mov edx, [edi+collection.output.first_report] |
86 | test edx, edx |
||
87 | jz .led_report_set |
||
3709 | clevermous | 88 | .scan_led_report: |
89 | ; Process one output report. |
||
90 | ; 3c. Prepare for loop over field groups in the current report: |
||
91 | ; get the first field group. |
||
3711 | clevermous | 92 | mov ecx, [edx+report.first_field] |
3709 | clevermous | 93 | .scan_led_field: |
94 | ; Process one field group. |
||
95 | ; 3d. If there are no more field groups, exit the loop over field groups. |
||
3711 | clevermous | 96 | test ecx, ecx |
97 | jz .next_led_report |
||
3709 | clevermous | 98 | ; For now, assume that all LEDs are plain variable fields, not arrays. |
99 | ; 3e. Ignore array field groups. |
||
3711 | clevermous | 100 | test byte [ecx+report_field_group.flags], HID_FIELD_VARIABLE |
101 | jz .next_led_field |
||
3709 | clevermous | 102 | ; 3f. Loop over all fields in the current group. |
3711 | clevermous | 103 | push [ecx+report_field_group.count] |
3709 | clevermous | 104 | ; esi = pointer to usage of the current field |
3711 | clevermous | 105 | lea esi, [ecx+report_field_group.common_sizeof] |
3709 | clevermous | 106 | ; ebx = bit position of the current field |
3711 | clevermous | 107 | mov ebx, [ecx+report_field_group.offset] |
3709 | clevermous | 108 | ; if report is numbered, add extra byte in the start of report |
3711 | clevermous | 109 | cmp [edx+report.id], 0 |
110 | jz .scan_led_usage |
||
111 | add ebx, 8 |
||
3709 | clevermous | 112 | .scan_led_usage: |
113 | ; for USAGE_LED_*LOCK, store the current bit position in the corresponding field |
||
114 | ; and store the current report as the LED report |
||
3711 | clevermous | 115 | cmp dword [esi], USAGE_LED_NUMLOCK |
116 | jz .numlock |
||
117 | cmp dword [esi], USAGE_LED_CAPSLOCK |
||
118 | jz .capslock |
||
119 | cmp dword [esi], USAGE_LED_SCROLLLOCK |
||
120 | jnz .next_field |
||
3709 | clevermous | 121 | .scrolllock: |
3711 | clevermous | 122 | mov [eax+keyboard_device_data.scrolllock_bit], ebx |
123 | jmp @f |
||
3709 | clevermous | 124 | .capslock: |
3711 | clevermous | 125 | mov [eax+keyboard_device_data.capslock_bit], ebx |
126 | jmp @f |
||
3709 | clevermous | 127 | .numlock: |
3711 | clevermous | 128 | mov [eax+keyboard_device_data.numlock_bit], ebx |
3709 | clevermous | 129 | @@: |
3711 | clevermous | 130 | mov [eax+keyboard_device_data.led_report], edx |
3709 | clevermous | 131 | .next_field: |
3711 | clevermous | 132 | add esi, 4 |
133 | add ebx, [ecx+report_field_group.size] |
||
134 | dec dword [esp] |
||
135 | jnz .scan_led_usage |
||
136 | pop ebx |
||
3709 | clevermous | 137 | .next_led_field: |
138 | ; 3g. Continue loop over field groups: get next field group. |
||
3711 | clevermous | 139 | mov ecx, [ecx+report_field_group.next] |
140 | jmp .scan_led_field |
||
3709 | clevermous | 141 | .next_led_report: |
142 | ; 3h. If the LED report has been set, break from the loop over reports. |
||
143 | ; Otherwise, get the next report and continue if the current report is not |
||
144 | ; the last for this collection. |
||
3711 | clevermous | 145 | cmp [eax+keyboard_device_data.led_report], 0 |
146 | jnz .led_report_set |
||
147 | cmp edx, [edi+collection.output.last_report] |
||
148 | mov edx, [edx+report.next] |
||
149 | jnz .scan_led_report |
||
3709 | clevermous | 150 | .led_report_set: |
151 | ; 3i. Restore registers. |
||
3711 | clevermous | 152 | pop esi ebx |
3709 | clevermous | 153 | ; 4. Register keyboard in the kernel. |
154 | ; store pointer to keyboard_device_data in the stack |
||
3711 | clevermous | 155 | push eax |
3709 | clevermous | 156 | ; call kernel API |
3711 | clevermous | 157 | stdcall RegKeyboard, kbd_functions, eax |
3709 | clevermous | 158 | ; restore pointer to keyboard_device_data from the stack, |
159 | ; putting keyboard handle from API to the stack |
||
3711 | clevermous | 160 | xchg eax, [esp] |
3709 | clevermous | 161 | ; put keyboard handle from API from the stack to keyboard_device_data field |
3711 | clevermous | 162 | pop [eax+keyboard_device_data.handle] |
3709 | clevermous | 163 | ; If failed, free keyboard_device_data and return NULL. |
3711 | clevermous | 164 | cmp [eax+keyboard_device_data.handle], 0 |
165 | jz .fail_free |
||
3709 | clevermous | 166 | ; 5. Return pointer to keyboard_device_data. |
167 | .nothing: |
||
3711 | clevermous | 168 | ret |
3709 | clevermous | 169 | .fail_free: |
3711 | clevermous | 170 | call Kfree |
171 | xor eax, eax |
||
172 | ret |
||
3709 | clevermous | 173 | endp |
174 | |||
175 | ; This procedure is called when HID layer detects disconnect of a previously |
||
176 | ; connected keyboard. |
||
177 | ; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
||
178 | proc keyboard_driver_disconnect |
||
179 | ; 1. If an autorepeat timer is active, stop it. |
||
3711 | clevermous | 180 | cmp [edi+keyboard_device_data.timer], 0 |
181 | jz @f |
||
3709 | clevermous | 182 | stdcall CancelTimerHS, [edi+keyboard_device_data.timer] |
183 | @@: |
||
184 | ; 2. Unregister keyboard in the kernel. |
||
3711 | clevermous | 185 | stdcall DelKeyboard, [edi+keyboard_device_data.handle] |
3709 | clevermous | 186 | ; We should free data in CloseKeyboard, not here. |
3711 | clevermous | 187 | ret |
3709 | clevermous | 188 | endp |
189 | |||
190 | ; This procedure is called when HID layer starts processing a new input packet |
||
191 | ; from a keyboard. |
||
192 | ; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
||
193 | proc keyboard_driver_begin_packet |
||
194 | ; Nothing to do. |
||
3711 | clevermous | 195 | ret |
3709 | clevermous | 196 | endp |
197 | |||
198 | ; This procedure is called when HID layer processes every non-empty array field group. |
||
199 | ; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
||
200 | ; in: ecx = fields count (always nonzero), edx = pointer to fields values |
||
201 | ; in: esi -> report_field_group |
||
202 | ; out: CF set => group is ok, CF cleared => group should be ignored |
||
203 | proc keyboard_driver_array_overflow? |
||
204 | ; The keyboard signals array overflow by filling the entire array with |
||
205 | ; USAGE_KBD_ROLLOVER codes. |
||
3711 | clevermous | 206 | mov eax, [edx] ; eax = first field in the array |
207 | sub eax, USAGE_KBD_ROLLOVER ; eax = 0 if overflow, nonzero otherwise |
||
208 | neg eax ; CF cleared if eax was zero, CF set if eax was nonzero |
||
209 | ret |
||
3709 | clevermous | 210 | endp |
211 | |||
212 | ; This procedure is called from HID layer for every field. |
||
213 | ; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
||
214 | ; in: ecx = field usage, edx = value, esi -> report_field_group |
||
215 | proc keyboard_driver_input_field |
||
216 | if HID_DUMP_UNCLAIMED |
||
217 | .unclaimed = default_driver_input_field |
||
218 | end if |
||
219 | ; 1. Process normal keys: |
||
220 | ; from USAGE_KBD_FIRST_KEY to USAGE_KBD_FIRST_KEY + normal_keys_number - 1, |
||
221 | ; excluding zeroes in [normal_keys]. |
||
222 | ; 1a. Test whether usage is in the range. |
||
3711 | clevermous | 223 | lea eax, [ecx-USAGE_KBD_FIRST_KEY] |
224 | cmp eax, normal_keys_number |
||
225 | jae .not_normal_key |
||
3709 | clevermous | 226 | ; 1b. If the corresponding entry in [normal_keys] is zero, |
227 | ; pass this field to the default handler - if HID_DUMP_UNCLAIMED is enabled, |
||
228 | ; default handler is default_driver_input_field, otherwise just ignore the field. |
||
3711 | clevermous | 229 | cmp [normal_keys + eax], 0 |
230 | jz .unclaimed |
||
3709 | clevermous | 231 | ; 1c. Get the scancode. |
3711 | clevermous | 232 | movzx ecx, [normal_keys + eax] |
3709 | clevermous | 233 | ; 1d. Further actions are slightly different for key press and key release. |
234 | ; Decide what to do. |
||
3711 | clevermous | 235 | test edx, edx |
236 | jz .normal_key_released |
||
3709 | clevermous | 237 | .normal_key_pressed: |
238 | ; The key is pressed. |
||
239 | ; 1e. Store the last pressed key for autorepeat. |
||
3711 | clevermous | 240 | mov [edi+keyboard_device_data.repeatkey], cl |
3709 | clevermous | 241 | ; 1f. Copy bit 7 to CF and send scancode with bit 7 cleared. |
3711 | clevermous | 242 | btr ecx, 7 |
243 | call .send_key |
||
3709 | clevermous | 244 | ; 1g. Stop the previous autorepeat timer, if any. |
3711 | clevermous | 245 | mov eax, [edi+keyboard_device_data.timer] |
246 | test eax, eax |
||
247 | jz @f |
||
248 | stdcall CancelTimerHS, eax |
||
3709 | clevermous | 249 | @@: |
250 | ; 1h. Start the new autorepeat timer with 250 ms initial delay |
||
251 | ; and 50 ms subsequent delays. |
||
3711 | clevermous | 252 | stdcall TimerHS, 25, 5, autorepeat_timer, edi |
253 | mov [edi+keyboard_device_data.timer], eax |
||
3709 | clevermous | 254 | if ~HID_DUMP_UNCLAIMED |
255 | .unclaimed: |
||
256 | end if |
||
3711 | clevermous | 257 | ret |
3709 | clevermous | 258 | .normal_key_released: |
259 | ; The key is released. |
||
260 | ; 1i. Stop the autorepeat timer if it is autorepeating the released key. |
||
3711 | clevermous | 261 | cmp [edi+keyboard_device_data.repeatkey], cl |
262 | jnz .no_stop_timer |
||
263 | push ecx |
||
264 | mov [edi+keyboard_device_data.repeatkey], 0 |
||
265 | mov eax, [edi+keyboard_device_data.timer] |
||
266 | test eax, eax |
||
267 | jz @f |
||
268 | stdcall CancelTimerHS, eax |
||
269 | mov [edi+keyboard_device_data.timer], 0 |
||
3709 | clevermous | 270 | @@: |
3711 | clevermous | 271 | pop ecx |
3709 | clevermous | 272 | .no_stop_timer: |
273 | ; 1j. Copy bit 7 to CF and send scancode with bit 7 set. |
||
3711 | clevermous | 274 | bts ecx, 7 |
275 | call .send_key |
||
276 | ret |
||
3709 | clevermous | 277 | .not_normal_key: |
278 | ; 2. USAGE_KBD_NOEVENT is simply a filler for free array fields, |
||
279 | ; ignore it. |
||
3711 | clevermous | 280 | cmp ecx, USAGE_KBD_NOEVENT |
281 | jz .nothing |
||
3709 | clevermous | 282 | ; 3. Process modifiers: 8 keys starting at USAGE_KBD_LCTRL. |
283 | ; 3a. Test whether usage is in range. |
||
284 | ; If not, we don't know what this field means, so pass it to the default handler. |
||
3711 | clevermous | 285 | lea eax, [ecx-USAGE_KBD_LCTRL] |
286 | cmp eax, 8 |
||
287 | jae .unclaimed |
||
3709 | clevermous | 288 | ; 3b. Further actions are slightly different for modifier press |
289 | ; and modifier release. Decide what to do. |
||
3711 | clevermous | 290 | test edx, edx |
291 | jz .modifier_not_pressed |
||
3709 | clevermous | 292 | .modifier_pressed: |
293 | ; The modifier is pressed. |
||
294 | ; 3c. Set the corresponding status bit. |
||
295 | ; If it was not set, send the corresponding scancode to the kernel |
||
296 | ; with bit 7 cleared. |
||
3711 | clevermous | 297 | bts [edi+keyboard_device_data.modifiers], eax |
298 | jc @f |
||
299 | movzx ecx, [control_keys+eax] |
||
300 | btr ecx, 7 |
||
301 | call .send_key |
||
3709 | clevermous | 302 | @@: |
303 | .nothing: |
||
3711 | clevermous | 304 | ret |
3709 | clevermous | 305 | .modifier_not_pressed: |
306 | ; The modifier is not pressed. |
||
307 | ; 3d. Clear the correspodning status bit. |
||
308 | ; If it was set, send the corresponding scancode to the kernel |
||
309 | ; with bit 7 set. |
||
3711 | clevermous | 310 | btr [edi+keyboard_device_data.modifiers], eax |
311 | jnc @f |
||
312 | movzx ecx, [control_keys+eax] |
||
313 | bts ecx, 7 |
||
314 | call .send_key |
||
3709 | clevermous | 315 | @@: |
3711 | clevermous | 316 | ret |
3709 | clevermous | 317 | |
318 | ; Helper procedure. Sends scancode from cl to the kernel. |
||
319 | ; If CF is set, precede it with special code 0xE0. |
||
320 | .send_key: |
||
3711 | clevermous | 321 | jnc @f |
322 | push ecx |
||
323 | mov ecx, 0xE0 |
||
324 | call SetKeyboardData |
||
325 | pop ecx |
||
3709 | clevermous | 326 | @@: |
3711 | clevermous | 327 | call SetKeyboardData |
328 | ret |
||
3709 | clevermous | 329 | endp |
330 | |||
331 | ; This procedure is called when HID layer ends processing a new input packet |
||
332 | ; from a keyboard. |
||
333 | ; in: edi -> keyboard_device_data (pointer returned from keyboard_driver_add_device) |
||
334 | proc keyboard_driver_end_packet |
||
335 | ; Nothing to do. |
||
3711 | clevermous | 336 | ret |
3709 | clevermous | 337 | endp |
338 | |||
339 | ; Timer callback for SetTimerHS. |
||
340 | proc autorepeat_timer |
||
341 | virtual at esp |
||
3711 | clevermous | 342 | dd ? ; return address |
343 | .data dd ? |
||
3709 | clevermous | 344 | end virtual |
345 | ; Just resend the last pressed key. |
||
3711 | clevermous | 346 | mov eax, [.data] |
347 | movzx ecx, [eax+keyboard_device_data.repeatkey] |
||
3709 | clevermous | 348 | ; Copy bit 7 to CF and send scancode with bit 7 cleared. |
3711 | clevermous | 349 | btr ecx, 7 |
350 | call keyboard_driver_input_field.send_key |
||
351 | ret 4 |
||
3709 | clevermous | 352 | endp |
353 | |||
354 | ; This function is called from the keyboard layer |
||
355 | ; when it is safe to free keyboard data. |
||
356 | proc CloseKeyboard |
||
357 | virtual at esp |
||
3711 | clevermous | 358 | dd ? ; return address |
359 | .device_data dd ? |
||
3709 | clevermous | 360 | end virtual |
3711 | clevermous | 361 | mov eax, [.device_data] |
362 | call Kfree |
||
363 | ret 4 |
||
3709 | clevermous | 364 | endp |
365 | |||
366 | ; This function is called from the keyboard layer |
||
367 | ; to update LED state on the keyboard. |
||
368 | proc SetKeyboardLights stdcall uses ebx esi edi, device_data, led_state |
||
369 | locals |
||
3711 | clevermous | 370 | size dd ? |
3709 | clevermous | 371 | endl |
372 | ; 1. Get the pointer to the LED report. |
||
373 | ; If there is no LED report, exit from the function. |
||
3711 | clevermous | 374 | mov ebx, [device_data] |
375 | mov esi, [ebx+keyboard_device_data.led_report] |
||
376 | test esi, esi |
||
377 | jz .nothing |
||
3709 | clevermous | 378 | ; 2. Get report size in bytes. |
379 | ; report.size is size in bits without possible report ID; |
||
380 | ; if an ID is assigned, the size is one byte greater. |
||
3711 | clevermous | 381 | mov eax, [esi+report.size] |
382 | add eax, 7 |
||
383 | shr eax, 3 |
||
384 | cmp [esi+report.id], 0 |
||
385 | jz @f |
||
386 | inc eax |
||
3709 | clevermous | 387 | @@: |
3711 | clevermous | 388 | mov [size], eax |
3709 | clevermous | 389 | ; 3. Allocate memory for report + 8 bytes for setup packet. |
390 | ; Dword-align size for subsequent rep stosd and bts. |
||
391 | ; If failed, exit from the function. |
||
3711 | clevermous | 392 | add eax, 8 + 3 |
393 | and eax, not 3 |
||
394 | push eax |
||
395 | call Kmalloc |
||
396 | pop ecx |
||
397 | test eax, eax |
||
398 | jz .nothing |
||
3709 | clevermous | 399 | ; 4. Zero-initialize output report. |
3711 | clevermous | 400 | push eax |
401 | mov edi, eax |
||
402 | shr ecx, 2 |
||
403 | xor eax, eax |
||
404 | rep stosd |
||
405 | pop edi |
||
406 | add edi, 8 |
||
3709 | clevermous | 407 | ; 5. Store report ID, if assigned. If not assigned, that would just write zero |
408 | ; over zeroes. |
||
3711 | clevermous | 409 | mov edx, [esi+report.id] |
410 | mov [edi], edx |
||
3709 | clevermous | 411 | ; 6. Set report bits corresponding to active indicators. |
3711 | clevermous | 412 | mov eax, [led_state] |
413 | test al, 1 ; PS/2 Scroll Lock |
||
414 | jz @f |
||
415 | mov ecx, [ebx+keyboard_device_data.scrolllock_bit] |
||
416 | test ecx, ecx |
||
417 | js @f |
||
418 | bts [edi], ecx |
||
3709 | clevermous | 419 | @@: |
3711 | clevermous | 420 | test al, 2 ; PS/2 Num Lock |
421 | jz @f |
||
422 | mov ecx, [ebx+keyboard_device_data.numlock_bit] |
||
423 | test ecx, ecx |
||
424 | js @f |
||
425 | bts [edi], ecx |
||
3709 | clevermous | 426 | @@: |
3711 | clevermous | 427 | test al, 4 ; PS/2 Caps Lock |
428 | jz @f |
||
429 | mov ecx, [ebx+keyboard_device_data.capslock_bit] |
||
430 | test ecx, ecx |
||
431 | js @f |
||
432 | bts [edi], ecx |
||
3709 | clevermous | 433 | @@: |
434 | ; 7. Fill setup packet. |
||
3711 | clevermous | 435 | shl edx, 16 ; move Report ID to byte 2 |
436 | or edx, 21h + \ ; Class-specific request to Interface |
||
437 | (9 shl 8) + \ ; SET_REPORT |
||
438 | (2 shl 24) ; Report Type = Output |
||
439 | lea eax, [edi-8] |
||
440 | mov ebx, [ebx+keyboard_device_data.usbdev] |
||
441 | mov dword [eax], edx |
||
442 | mov edx, [size] |
||
443 | shl edx, 16 ; move Size to last word |
||
444 | or edx, [ebx+usb_device_data.interface_number] |
||
445 | mov [eax+4], edx |
||
3709 | clevermous | 446 | ; 8. Submit output control request. |
3711 | clevermous | 447 | stdcall USBControlTransferAsync, [ebx+usb_device_data.configpipe], \ |
448 | eax, edi, [size], after_set_keyboard_lights, ebx, 0 |
||
3709 | clevermous | 449 | ; If failed, free the buffer now. |
450 | ; If succeeded, the callback will free the buffer. |
||
3711 | clevermous | 451 | test eax, eax |
452 | jnz .nothing |
||
453 | lea eax, [edi-8] |
||
454 | call Kfree |
||
3709 | clevermous | 455 | .nothing: |
3711 | clevermous | 456 | ret |
3709 | clevermous | 457 | endp |
458 | |||
459 | ; This procedure is called from the USB subsystem when the request initiated by |
||
460 | ; SetKeyboardLights is completed, either successfully or unsuccessfully. |
||
461 | proc after_set_keyboard_lights |
||
462 | virtual at esp |
||
3711 | clevermous | 463 | dd ? ; return address |
464 | .pipe dd ? |
||
465 | .status dd ? |
||
466 | .buffer dd ? |
||
467 | .length dd ? |
||
468 | .calldata dd ? |
||
3709 | clevermous | 469 | end virtual |
470 | ; Ignore status, just free the buffer allocated by SetKeyboardLights. |
||
3711 | clevermous | 471 | mov eax, [.buffer] |
472 | sub eax, 8 |
||
473 | call Kfree |
||
474 | ret 20 |
||
3709 | clevermous | 475 | endp |