Subversion Repositories Kolibri OS

Rev

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

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