Subversion Repositories Kolibri OS

Rev

Rev 5051 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5051 Rev 5148
1
; Parser of HID structures: parse HID report descriptor,
1
; Parser of HID structures: parse HID report descriptor,
2
; parse/generate input/output/feature reports.
2
; parse/generate input/output/feature reports.
3
 
3
 
4
; =============================================================================
4
; =============================================================================
5
; ================================= Constants =================================
5
; ================================= Constants =================================
6
; =============================================================================
6
; =============================================================================
7
; Usage codes from HID specification
7
; Usage codes from HID specification
8
; Generic Desktop usage page
8
; Generic Desktop usage page
9
USAGE_GD_POINTER     = 10001h
9
USAGE_GD_POINTER     = 10001h
10
USAGE_GD_MOUSE       = 10002h
10
USAGE_GD_MOUSE       = 10002h
11
USAGE_GD_JOYSTICK    = 10004h
11
USAGE_GD_JOYSTICK    = 10004h
12
USAGE_GD_GAMEPAD     = 10005h
12
USAGE_GD_GAMEPAD     = 10005h
13
USAGE_GD_KEYBOARD    = 10006h
13
USAGE_GD_KEYBOARD    = 10006h
14
USAGE_GD_KEYPAD      = 10007h
14
USAGE_GD_KEYPAD      = 10007h
15
 
15
 
16
USAGE_GD_X           = 10030h
16
USAGE_GD_X           = 10030h
17
USAGE_GD_Y           = 10031h
17
USAGE_GD_Y           = 10031h
18
USAGE_GD_Z           = 10032h
18
USAGE_GD_Z           = 10032h
19
USAGE_GD_RX          = 10033h
19
USAGE_GD_RX          = 10033h
20
USAGE_GD_RY          = 10034h
20
USAGE_GD_RY          = 10034h
21
USAGE_GD_RZ          = 10035h
21
USAGE_GD_RZ          = 10035h
22
USAGE_GD_SLIDER      = 10036h
22
USAGE_GD_SLIDER      = 10036h
23
USAGE_GD_DIAL        = 10037h
23
USAGE_GD_DIAL        = 10037h
24
USAGE_GD_WHEEL       = 10038h
24
USAGE_GD_WHEEL       = 10038h
-
 
25
 
-
 
26
USAGE_GD_CONS_CTRL   = 0C0001h ; Consumer control (media keys)
25
 
27
 
26
; Keyboard/Keypad usage page
28
; Keyboard/Keypad usage page
27
USAGE_KBD_NOEVENT    = 70000h
29
USAGE_KBD_NOEVENT    = 70000h
28
USAGE_KBD_ROLLOVER   = 70001h
30
USAGE_KBD_ROLLOVER   = 70001h
29
USAGE_KBD_POSTFAIL   = 70002h
31
USAGE_KBD_POSTFAIL   = 70002h
30
USAGE_KBD_FIRST_KEY  = 70004h ; this is 'A', actually
32
USAGE_KBD_FIRST_KEY  = 70004h ; this is 'A', actually
31
USAGE_KBD_LCTRL      = 700E0h
33
USAGE_KBD_LCTRL      = 700E0h
32
USAGE_KBD_LSHIFT     = 700E1h
34
USAGE_KBD_LSHIFT     = 700E1h
33
USAGE_KBD_LALT       = 700E2h
35
USAGE_KBD_LALT       = 700E2h
34
USAGE_KBD_LWIN       = 700E3h
36
USAGE_KBD_LWIN       = 700E3h
35
USAGE_KBD_RCTRL      = 700E4h
37
USAGE_KBD_RCTRL      = 700E4h
36
USAGE_KBD_RSHIFT     = 700E5h
38
USAGE_KBD_RSHIFT     = 700E5h
37
USAGE_KBD_RALT       = 700E6h
39
USAGE_KBD_RALT       = 700E6h
38
USAGE_KBD_RWIN       = 700E7h
40
USAGE_KBD_RWIN       = 700E7h
39
 
41
 
40
; LED usage page
42
; LED usage page
41
USAGE_LED_NUMLOCK    = 80001h
43
USAGE_LED_NUMLOCK    = 80001h
42
USAGE_LED_CAPSLOCK   = 80002h
44
USAGE_LED_CAPSLOCK   = 80002h
43
USAGE_LED_SCROLLLOCK = 80003h
45
USAGE_LED_SCROLLLOCK = 80003h
44
 
46
 
45
; Button usage page
47
; Button usage page
46
; First button is USAGE_BUTTON_PAGE+1, second - USAGE_BUTTON_PAGE+2 etc.
48
; First button is USAGE_BUTTON_PAGE+1, second - USAGE_BUTTON_PAGE+2 etc.
47
USAGE_BUTTON_PAGE    = 90000h
49
USAGE_BUTTON_PAGE    = 90000h
-
 
50
 
-
 
51
; Consumer control usage page
-
 
52
USAGE_CONSUMER       = 0C0000h
48
 
53
 
49
; Flags for input/output/feature fields
54
; Flags for input/output/feature fields
50
HID_FIELD_CONSTANT   = 1 ; if not, then Data field
55
HID_FIELD_CONSTANT   = 1 ; if not, then Data field
51
HID_FIELD_VARIABLE   = 2 ; if not, then Array field
56
HID_FIELD_VARIABLE   = 2 ; if not, then Array field
52
HID_FIELD_RELATIVE   = 4 ; if not, then Absolute field
57
HID_FIELD_RELATIVE   = 4 ; if not, then Absolute field
53
HID_FIELD_WRAP       = 8
58
HID_FIELD_WRAP       = 8
54
HID_FIELD_NONLINEAR  = 10h
59
HID_FIELD_NONLINEAR  = 10h
55
HID_FIELD_NOPREFERRED= 20h ; no preferred state
60
HID_FIELD_NOPREFERRED= 20h ; no preferred state
56
HID_FIELD_HASNULL    = 40h ; has null state
61
HID_FIELD_HASNULL    = 40h ; has null state
57
HID_FIELD_VOLATILE   = 80h ; for output/feature fields
62
HID_FIELD_VOLATILE   = 80h ; for output/feature fields
58
HID_FIELD_BUFBYTES   = 100h; buffered bytes
63
HID_FIELD_BUFBYTES   = 100h; buffered bytes
59
 
64
 
60
; Report descriptor can easily describe gigabytes of (meaningless) data.
65
; Report descriptor can easily describe gigabytes of (meaningless) data.
61
; Keep report size reasonable to avoid excessive memory allocations and
66
; Keep report size reasonable to avoid excessive memory allocations and
62
; calculation overflows; 1 Kb is more than enough (typical size is 3-10 bytes).
67
; calculation overflows; 1 Kb is more than enough (typical size is 3-10 bytes).
63
MAX_REPORT_BYTES = 1024
68
MAX_REPORT_BYTES = 1024
64
 
69
 
65
; =============================================================================
70
; =============================================================================
66
; ================================ Structures =================================
71
; ================================ Structures =================================
67
; =============================================================================
72
; =============================================================================
68
; Every meaningful report field group has one or more associated usages.
73
; Every meaningful report field group has one or more associated usages.
69
; Usages can be individual or joined into continuous ranges.
74
; Usages can be individual or joined into continuous ranges.
70
; This structure describes one range or one individual usage in a large array;
75
; This structure describes one range or one individual usage in a large array;
71
; individual usage is equivalent to a range of length 1.
76
; individual usage is equivalent to a range of length 1.
72
struct usage_range
77
struct usage_range
73
offset          dd      ?
78
offset          dd      ?
74
; Sum of range sizes over all previous array items.
79
; Sum of range sizes over all previous array items.
75
; Size of range a equals
80
; Size of range a equals
76
; [a + sizeof.usage_range + usage_range.offset] - [a + usage_range.offset].
81
; [a + sizeof.usage_range + usage_range.offset] - [a + usage_range.offset].
77
; The total sum over all array items immediately follows the array,
82
; The total sum over all array items immediately follows the array,
78
; this field must be the first so that the formula above works for the last item.
83
; this field must be the first so that the formula above works for the last item.
79
first_usage     dd      ?
84
first_usage     dd      ?
80
; Usage code for first item in the range.
85
; Usage code for first item in the range.
81
ends
86
ends
82
 
87
 
83
; This structure describes one group of report fields with identical properties.
88
; This structure describes one group of report fields with identical properties.
84
struct report_field_group
89
struct report_field_group
85
next            dd      ?
90
next            dd      ?
86
; All field groups in one report are organized in a single-linked list.
91
; All field groups in one report are organized in a single-linked list.
87
; This is the next group in the report or 0 for the last group.
92
; This is the next group in the report or 0 for the last group.
88
size            dd      ?
93
size            dd      ?
89
; Size in bits of one field. Cannot be zero or greater than 32.
94
; Size in bits of one field. Cannot be zero or greater than 32.
90
count           dd      ?       ; field count, cannot be zero
95
count           dd      ?       ; field count, cannot be zero
91
offset          dd      ?       ; offset from report start, in bits
96
offset          dd      ?       ; offset from report start, in bits
92
; Following fields are decoded from report descriptor, see HID spec for details.
97
; Following fields are decoded from report descriptor, see HID spec for details.
93
flags           dd      ?
98
flags           dd      ?
94
logical_minimum dd      ?
99
logical_minimum dd      ?
95
logical_maximum dd      ?
100
logical_maximum dd      ?
96
physical_minimum dd     ?
101
physical_minimum dd     ?
97
physical_maximum dd     ?
102
physical_maximum dd     ?
98
unit_exponent   dd      ?
103
unit_exponent   dd      ?
99
unit            dd      ?
104
unit            dd      ?
100
; Following fields are used to speedup extract_field_value.
105
; Following fields are used to speedup extract_field_value.
101
mask            dd      ?
106
mask            dd      ?
102
; Bitmask for all data bits except sign bit:
107
; Bitmask for all data bits except sign bit:
103
; (1 shl .size) - 1 for unsigned fields, (1 shl (.size-1)) - 1 for signed fields
108
; (1 shl .size) - 1 for unsigned fields, (1 shl (.size-1)) - 1 for signed fields
104
sign_mask       dd      ?
109
sign_mask       dd      ?
105
; Zero for unsigned fields. Bitmask with sign bit set for signed fields.
110
; Zero for unsigned fields. Bitmask with sign bit set for signed fields.
106
common_sizeof   rd      0
111
common_sizeof   rd      0
107
; Variable and Array field groups differ significantly.
112
; Variable and Array field groups differ significantly.
108
; Variable field groups are simple. There are .count fields, each field has
113
; Variable field groups are simple. There are .count fields, each field has
109
; predefined Usage, the content of a field is its value. Each field is
114
; predefined Usage, the content of a field is its value. Each field is
110
; always present in the report. For Variable field groups, we just keep
115
; always present in the report. For Variable field groups, we just keep
111
; additional .count dwords with usages for individual fields.
116
; additional .count dwords with usages for individual fields.
112
; Array field groups are complicated. There are .count uniform fields.
117
; Array field groups are complicated. There are .count uniform fields.
113
; The content of a field determines Usage; Usages which are currently presented
118
; The content of a field determines Usage; Usages which are currently presented
114
; in the report have value = 1, other Usages have value = 0. The number of
119
; in the report have value = 1, other Usages have value = 0. The number of
115
; possible Usages is limited only by field .size; 32-bit field could encode any
120
; possible Usages is limited only by field .size; 32-bit field could encode any
116
; Usage, so it is unreasonable to keep all Usages in the plain array, as with
121
; Usage, so it is unreasonable to keep all Usages in the plain array, as with
117
; Variable fields. However, many unrelated Usages in one group are meaningless,
122
; Variable fields. However, many unrelated Usages in one group are meaningless,
118
; so usually possible values are grouped in sequential ranges; number of ranges
123
; so usually possible values are grouped in sequential ranges; number of ranges
119
; is limited by report descriptor size (max 0xFFFF bytes should contain all
124
; is limited by report descriptor size (max 0xFFFF bytes should contain all
120
; information, including usage ranges and field descriptions).
125
; information, including usage ranges and field descriptions).
121
; Also, for Array variables we pass changes in state to drivers, not the state
126
; Also, for Array variables we pass changes in state to drivers, not the state
122
; itself, because sending information about all possible Usages is inpractical;
127
; itself, because sending information about all possible Usages is inpractical;
123
; so we should remember the previous state in addition to the current state.
128
; so we should remember the previous state in addition to the current state.
124
; Thus, for Array variables keep the following information, in this order:
129
; Thus, for Array variables keep the following information, in this order:
125
; * some members listed below; note that they do NOT exist for Variable groups;
130
; * some members listed below; note that they do NOT exist for Variable groups;
126
; * array of usage ranges in form of usage_range structures, including
131
; * array of usage ranges in form of usage_range structures, including
127
;   an additional dword after array described in usage_range structure;
132
;   an additional dword after array described in usage_range structure;
128
; * allocated memory for current values of the report;
133
; * allocated memory for current values of the report;
129
; * values of the previous report.
134
; * values of the previous report.
130
num_values_prev dd      ?       ; number of values in the previous report
135
num_values_prev dd      ?       ; number of values in the previous report
131
num_usage_ranges dd     ?       ; number of usage_range, always nonzero
136
num_usage_ranges dd     ?       ; number of usage_range, always nonzero
132
usages          rd      0
137
usages          rd      0
133
ends
138
ends
134
 
139
 
135
; This structure describes one report.
140
; This structure describes one report.
136
; All reports of one type are organized into a single-linked list.
141
; All reports of one type are organized into a single-linked list.
137
struct report
142
struct report
138
next            dd      ?       ; pointer to next report of the same type, if any
143
next            dd      ?       ; pointer to next report of the same type, if any
139
size            dd      ?       ; total size in bits
144
size            dd      ?       ; total size in bits
140
first_field     dd      ?       ; pointer to first report_field_group for this report
145
first_field     dd      ?       ; pointer to first report_field_group for this report
141
last_field      dd      ?
146
last_field      dd      ?
142
; pointer to last report_field_group for this report, if any;
147
; pointer to last report_field_group for this report, if any;
143
; address of .first_field, if .first_field is 0
148
; address of .first_field, if .first_field is 0
144
id              dd      ?
149
id              dd      ?
145
; Report ID, if assigned. Zero otherwise.
150
; Report ID, if assigned. Zero otherwise.
146
top_level_collection dd ?       ; top-level collection for this report
151
top_level_collection dd ?       ; top-level collection for this report
147
ends
152
ends
148
 
153
 
149
; This structure describes a set of reports of the same type;
154
; This structure describes a set of reports of the same type;
150
; there are 3 sets (possibly empty), input, output and feature.
155
; there are 3 sets (possibly empty), input, output and feature.
151
struct report_set
156
struct report_set
152
data            dd      ?
157
data            dd      ?
153
; If .numbered is zero, this is zero for the empty set and
158
; If .numbered is zero, this is zero for the empty set and
154
; a pointer to the (only) report structure otherwise.
159
; a pointer to the (only) report structure otherwise.
155
; If .numbered is nonzero, this is a pointer to 256-dword array of pointers
160
; If .numbered is nonzero, this is a pointer to 256-dword array of pointers
156
; to reports organized by report ID.
161
; to reports organized by report ID.
157
first_report    dd      ?
162
first_report    dd      ?
158
; Pointer to the first report or 0 for the empty set.
163
; Pointer to the first report or 0 for the empty set.
159
numbered        db      ?
164
numbered        db      ?
160
; If zero, report IDs are not used, there can be at most one report in the set.
165
; If zero, report IDs are not used, there can be at most one report in the set.
161
; If nonzero, first byte of the report is report ID.
166
; If nonzero, first byte of the report is report ID.
162
                rb      3       ; padding
167
                rb      3       ; padding
163
ends
168
ends
164
 
169
 
165
; This structure describes a range of reports of one type that belong to
170
; This structure describes a range of reports of one type that belong to
166
; some collection.
171
; some collection.
167
struct collection_report_set
172
struct collection_report_set
168
first_report    dd      ?
173
first_report    dd      ?
169
first_field     dd      ?
174
first_field     dd      ?
170
last_report     dd      ?
175
last_report     dd      ?
171
last_field      dd      ?
176
last_field      dd      ?
172
ends
177
ends
173
 
178
 
174
; This structure defines driver callbacks which are used while
179
; This structure defines driver callbacks which are used while
175
; device is active; i.e. all callbacks except add_device.
180
; device is active; i.e. all callbacks except add_device.
176
struct hid_driver_active_callbacks
181
struct hid_driver_active_callbacks
177
disconnect      dd      ?
182
disconnect      dd      ?
178
; Called when an existing HID device is disconnected.
183
; Called when an existing HID device is disconnected.
179
;
184
;
180
; Four following functions are called when a new input packet arrives
185
; Four following functions are called when a new input packet arrives
181
; in the following order: .begin_packet, then .input_field several times
186
; in the following order: .begin_packet, then .input_field several times
182
; for each input field, interleaved with .array_overflow? for array groups,
187
; for each input field, interleaved with .array_overflow? for array groups,
183
; then .end_packet.
188
; then .end_packet.
184
begin_packet    dd      ?
189
begin_packet    dd      ?
185
; edi -> driver data
190
; edi -> driver data
186
array_overflow? dd      ?
191
array_overflow? dd      ?
187
; edi -> driver data
192
; edi -> driver data
188
; out: CF cleared <=> ignore this array
193
; out: CF cleared <=> ignore this array
189
input_field     dd      ?
194
input_field     dd      ?
190
; edi -> driver data, ecx = usage, edx = value
195
; edi -> driver data, ecx = usage, edx = value
191
end_packet      dd      ?
196
end_packet      dd      ?
192
; edi -> driver data
197
; edi -> driver data
193
ends
198
ends
194
 
199
 
195
; This structure describes one collection.
200
; This structure describes one collection.
196
struct collection
201
struct collection
197
next            dd      ?       ; pointer to the next collection in the same level
202
next            dd      ?       ; pointer to the next collection in the same level
198
                                ; must be the first field
203
                                ; must be the first field
199
parent          dd      ?       ; pointer to nesting collection
204
parent          dd      ?       ; pointer to nesting collection
200
first_child     dd      ?       ; pointer to the first nested collection
205
first_child     dd      ?       ; pointer to the first nested collection
201
last_child      dd      ?       ; pointer to the last nested collection
206
last_child      dd      ?       ; pointer to the last nested collection
202
                                ; or to .first_child, if .first_child is zero
207
                                ; or to .first_child, if .first_child is zero
203
type            dd      ?       ; Application, Physical etc
208
type            dd      ?       ; Application, Physical etc
204
usage           dd      ?       ; associated Usage code
209
usage           dd      ?       ; associated Usage code
205
; Next fields are filled only for top-level collections.
210
; Next fields are filled only for top-level collections.
206
callbacks       hid_driver_active_callbacks
211
callbacks       hid_driver_active_callbacks
207
driver_data     dd      ?       ; value to be passed as is to driver callbacks
212
driver_data     dd      ?       ; value to be passed as is to driver callbacks
208
input           collection_report_set
213
input           collection_report_set
209
output          collection_report_set
214
output          collection_report_set
210
feature         collection_report_set
215
feature         collection_report_set
211
ends
216
ends
212
 
217
 
213
; This structure keeps all data used by the HID layer for one device.
218
; This structure keeps all data used by the HID layer for one device.
214
struct hid_data
219
struct hid_data
215
input           report_set
220
input           report_set
216
output          report_set
221
output          report_set
217
feature         report_set
222
feature         report_set
218
first_collection        dd      ?
223
first_collection        dd      ?
219
ends
224
ends
220
 
225
 
221
; This structure defines callbacks required from the driver.
226
; This structure defines callbacks required from the driver.
222
struct hid_driver_callbacks
227
struct hid_driver_callbacks
223
add_device      dd      ?
228
add_device      dd      ?
224
; Called when a new HID device is connected.
229
; Called when a new HID device is connected.
225
active          hid_driver_active_callbacks
230
active          hid_driver_active_callbacks
226
ends
231
ends
227
 
232
 
228
; Two following structures describe temporary data;
233
; Two following structures describe temporary data;
229
; the corresponding objects cease to exist when HID parser completes
234
; the corresponding objects cease to exist when HID parser completes
230
; state of Global items
235
; state of Global items
231
struct global_items
236
struct global_items
232
next                    dd      ?
237
next                    dd      ?
233
usage_page              dd      ?
238
usage_page              dd      ?
234
logical_minimum         dd      ?
239
logical_minimum         dd      ?
235
logical_maximum         dd      ?
240
logical_maximum         dd      ?
236
physical_minimum        dd      ?
241
physical_minimum        dd      ?
237
physical_maximum        dd      ?
242
physical_maximum        dd      ?
238
unit_exponent           dd      ?
243
unit_exponent           dd      ?
239
unit                    dd      ?
244
unit                    dd      ?
240
report_size             dd      ?
245
report_size             dd      ?
241
report_id               dd      ?
246
report_id               dd      ?
242
report_count            dd      ?
247
report_count            dd      ?
243
ends
248
ends
244
 
249
 
245
; one range of Usages
250
; one range of Usages
246
struct usage_list_item
251
struct usage_list_item
247
next                    dd      ?
252
next                    dd      ?
248
first_usage             dd      ?
253
first_usage             dd      ?
249
num_usages              dd      ?
254
num_usages              dd      ?
250
ends
255
ends
251
 
256
 
252
; =============================================================================
257
; =============================================================================
253
; =================================== Code ====================================
258
; =================================== Code ====================================
254
; =============================================================================
259
; =============================================================================
255
 
260
 
256
macro workers_globals
261
macro workers_globals
257
{
262
{
258
        workers_globals
263
        workers_globals
259
; Jump tables for switch'ing in the code.
264
; Jump tables for switch'ing in the code.
260
align 4
265
align 4
261
; jump table for two lower bits which encode size of item data
266
; jump table for two lower bits which encode size of item data
262
parse_descr_label.fetch_jumps:
267
parse_descr_label.fetch_jumps:
263
        dd      parse_descr_label.fetch_none    ; x0, x4, x8, xC
268
        dd      parse_descr_label.fetch_none    ; x0, x4, x8, xC
264
        dd      parse_descr_label.fetch_byte    ; x1, x5, x9, xD
269
        dd      parse_descr_label.fetch_byte    ; x1, x5, x9, xD
265
        dd      parse_descr_label.fetch_word    ; x2, x6, xA, xE
270
        dd      parse_descr_label.fetch_word    ; x2, x6, xA, xE
266
        dd      parse_descr_label.fetch_dword   ; x3, x7, xB, xF
271
        dd      parse_descr_label.fetch_dword   ; x3, x7, xB, xF
267
; jump table for two next bits which encode item type
272
; jump table for two next bits which encode item type
268
parse_descr_label.type_jumps:
273
parse_descr_label.type_jumps:
269
        dd      parse_descr_label.parse_main
274
        dd      parse_descr_label.parse_main
270
        dd      parse_descr_label.parse_global
275
        dd      parse_descr_label.parse_global
271
        dd      parse_descr_label.parse_local
276
        dd      parse_descr_label.parse_local
272
        dd      parse_descr_label.parse_reserved
277
        dd      parse_descr_label.parse_reserved
273
; jump table for 4 upper bits in the case of Main item
278
; jump table for 4 upper bits in the case of Main item
274
parse_descr_label.main_jumps:
279
parse_descr_label.main_jumps:
275
        dd      parse_descr_label.input ; 80...83
280
        dd      parse_descr_label.input ; 80...83
276
        dd      parse_descr_label.output        ; 90...93
281
        dd      parse_descr_label.output        ; 90...93
277
        dd      parse_descr_label.collection    ; A0...A3
282
        dd      parse_descr_label.collection    ; A0...A3
278
        dd      parse_descr_label.feature       ; B0...B3
283
        dd      parse_descr_label.feature       ; B0...B3
279
        dd      parse_descr_label.end_collection ; C0...C3
284
        dd      parse_descr_label.end_collection ; C0...C3
280
parse_descr_label.num_main_items = ($ - parse_descr_label.main_jumps) / 4
285
parse_descr_label.num_main_items = ($ - parse_descr_label.main_jumps) / 4
281
; jump table for 4 upper bits in the case of Global item
286
; jump table for 4 upper bits in the case of Global item
282
parse_descr_label.global_jumps:
287
parse_descr_label.global_jumps:
283
        dd      parse_descr_label.usage_page    ; 04...07
288
        dd      parse_descr_label.usage_page    ; 04...07
284
        dd      parse_descr_label.logical_minimum ; 14...17
289
        dd      parse_descr_label.logical_minimum ; 14...17
285
        dd      parse_descr_label.logical_maximum ; 24...27
290
        dd      parse_descr_label.logical_maximum ; 24...27
286
        dd      parse_descr_label.physical_minimum ; 34...37
291
        dd      parse_descr_label.physical_minimum ; 34...37
287
        dd      parse_descr_label.physical_maximum ; 44...47
292
        dd      parse_descr_label.physical_maximum ; 44...47
288
        dd      parse_descr_label.unit_exponent ; 54...57
293
        dd      parse_descr_label.unit_exponent ; 54...57
289
        dd      parse_descr_label.unit          ; 64...67
294
        dd      parse_descr_label.unit          ; 64...67
290
        dd      parse_descr_label.report_size   ; 74...77
295
        dd      parse_descr_label.report_size   ; 74...77
291
        dd      parse_descr_label.report_id     ; 84...87
296
        dd      parse_descr_label.report_id     ; 84...87
292
        dd      parse_descr_label.report_count  ; 94...97
297
        dd      parse_descr_label.report_count  ; 94...97
293
        dd      parse_descr_label.push          ; A4...A7
298
        dd      parse_descr_label.push          ; A4...A7
294
        dd      parse_descr_label.pop           ; B4...B7
299
        dd      parse_descr_label.pop           ; B4...B7
295
parse_descr_label.num_global_items = ($ - parse_descr_label.global_jumps) / 4
300
parse_descr_label.num_global_items = ($ - parse_descr_label.global_jumps) / 4
296
; jump table for 4 upper bits in the case of Local item
301
; jump table for 4 upper bits in the case of Local item
297
parse_descr_label.local_jumps:
302
parse_descr_label.local_jumps:
298
        dd      parse_descr_label.usage ; 08...0B
303
        dd      parse_descr_label.usage ; 08...0B
299
        dd      parse_descr_label.usage_minimum ; 18...1B
304
        dd      parse_descr_label.usage_minimum ; 18...1B
300
        dd      parse_descr_label.usage_maximum ; 28...2B
305
        dd      parse_descr_label.usage_maximum ; 28...2B
301
        dd      parse_descr_label.item_parsed   ; 38...3B = designator item; ignore
306
        dd      parse_descr_label.item_parsed   ; 38...3B = designator item; ignore
302
        dd      parse_descr_label.item_parsed   ; 48...4B = designator minimum; ignore
307
        dd      parse_descr_label.item_parsed   ; 48...4B = designator minimum; ignore
303
        dd      parse_descr_label.item_parsed   ; 58...5B = designator maximum; ignore
308
        dd      parse_descr_label.item_parsed   ; 58...5B = designator maximum; ignore
304
        dd      parse_descr_label.item_parsed   ; 68...6B not assigned
309
        dd      parse_descr_label.item_parsed   ; 68...6B not assigned
305
        dd      parse_descr_label.item_parsed   ; 78...7B = string index; ignore
310
        dd      parse_descr_label.item_parsed   ; 78...7B = string index; ignore
306
        dd      parse_descr_label.item_parsed   ; 88...8B = string minimum; ignore
311
        dd      parse_descr_label.item_parsed   ; 88...8B = string minimum; ignore
307
        dd      parse_descr_label.item_parsed   ; 98...9B = string maximum; ignore
312
        dd      parse_descr_label.item_parsed   ; 98...9B = string maximum; ignore
308
        dd      parse_descr_label.delimiter     ; A8...AB
313
        dd      parse_descr_label.delimiter     ; A8...AB
309
parse_descr_label.num_local_items = ($ - parse_descr_label.local_jumps) / 4
314
parse_descr_label.num_local_items = ($ - parse_descr_label.local_jumps) / 4
310
}
315
}
311
 
316
 
312
; Local variables for parse_descr.
317
; Local variables for parse_descr.
313
macro parse_descr_locals
318
macro parse_descr_locals
314
{
319
{
315
cur_item_size   dd      ?       ; encoded size of data for current item
320
cur_item_size   dd      ?       ; encoded size of data for current item
316
report_ok       db      ?       ; 0 on error, 1 if everything is ok
321
report_ok       db      ?       ; 0 on error, 1 if everything is ok
317
field_type      db      ?       ; 0/1/2 for input/output/feature fields
322
field_type      db      ?       ; 0/1/2 for input/output/feature fields
318
                rb      2       ; alignment
323
                rb      2       ; alignment
319
field_data      dd      ?       ; data for current item when it describes a field group
324
field_data      dd      ?       ; data for current item when it describes a field group
320
last_reports    rd      3       ; pointers to last input/output/feature records
325
last_reports    rd      3       ; pointers to last input/output/feature records
321
usage_minimum   dd      ?       ; current value of Usage Minimum
326
usage_minimum   dd      ?       ; current value of Usage Minimum
322
usage_list      dd      ?       ; list head of usage_list_item
327
usage_list      dd      ?       ; list head of usage_list_item
323
usage_tail      dd      ?       ; list tail of usage_list_item
328
usage_tail      dd      ?       ; list tail of usage_list_item
324
num_usage_ranges dd     ?       ; number of usage ranges, size of usage_list
329
num_usage_ranges dd     ?       ; number of usage ranges, size of usage_list
325
delimiter_depth dd      ?       ; normally 0; 1 inside of Delimiter();
330
delimiter_depth dd      ?       ; normally 0; 1 inside of Delimiter();
326
                                ; nested Delimiter()s are not allowed
331
                                ; nested Delimiter()s are not allowed
327
usage_variant   dd      ?       ; 0 outside of Delimiter()s and for first Usage inside Delimiter(),
332
usage_variant   dd      ?       ; 0 outside of Delimiter()s and for first Usage inside Delimiter(),
328
                                ; incremented with each new Usage inside Delimiter()
333
                                ; incremented with each new Usage inside Delimiter()
329
cur_collection  dd      ?       ; current collection
334
cur_collection  dd      ?       ; current collection
330
last_collection dd      ?       ; last top-level collection
335
last_collection dd      ?       ; last top-level collection
331
}
336
}
332
 
337
 
333
; Parse report descriptor. The caller should provide local variables
338
; Parse report descriptor. The caller should provide local variables
334
; [buffer] = pointer to report descriptor, [length] = length of report descriptor,
339
; [buffer] = pointer to report descriptor, [length] = length of report descriptor,
335
; [calldata] = pointer to hid_data (possibly wrapped in a large structure).
340
; [calldata] = pointer to hid_data (possibly wrapped in a large structure).
336
macro parse_descr
341
macro parse_descr
337
{
342
{
338
parse_descr_label:
343
parse_descr_label:
339
; 1. Initialize.
344
; 1. Initialize.
340
; 1a. Set some variables to initial values.
345
; 1a. Set some variables to initial values.
341
        xor     edi, edi
346
        xor     edi, edi
342
        mov     dword [report_ok], edi
347
        mov     dword [report_ok], edi
343
        mov     [usage_list], edi
348
        mov     [usage_list], edi
344
        mov     [cur_collection], edi
349
        mov     [cur_collection], edi
345
        mov     eax, [calldata]
350
        mov     eax, [calldata]
346
        add     eax, hid_data.input.first_report
351
        add     eax, hid_data.input.first_report
347
        mov     [last_reports+0*4], eax
352
        mov     [last_reports+0*4], eax
348
        add     eax, hid_data.output.first_report - hid_data.input.first_report
353
        add     eax, hid_data.output.first_report - hid_data.input.first_report
349
        mov     [last_reports+1*4], eax
354
        mov     [last_reports+1*4], eax
350
        add     eax, hid_data.feature.first_report - hid_data.output.first_report
355
        add     eax, hid_data.feature.first_report - hid_data.output.first_report
351
        mov     [last_reports+2*4], eax
356
        mov     [last_reports+2*4], eax
352
        add     eax, hid_data.first_collection - hid_data.feature.first_report
357
        add     eax, hid_data.first_collection - hid_data.feature.first_report
353
        mov     [last_collection], eax
358
        mov     [last_collection], eax
354
; 1b. Allocate state of global items.
359
; 1b. Allocate state of global items.
355
        movi    eax, sizeof.global_items
360
        movi    eax, sizeof.global_items
356
        invoke  Kmalloc
361
        invoke  Kmalloc
357
        test    eax, eax
362
        test    eax, eax
358
        jz      .memory_error
363
        jz      .memory_error
359
; 1c. Zero-initialize it and move pointer to edi.
364
; 1c. Zero-initialize it and move pointer to edi.
360
        push    eax
365
        push    eax
361
        xchg    eax, edi
366
        xchg    eax, edi
362
        movi    ecx, sizeof.global_items / 4
367
        movi    ecx, sizeof.global_items / 4
363
        rep stosd
368
        rep stosd
364
        pop     edi
369
        pop     edi
365
; 1d. Load pointer to data into esi and make [length] point to end of data.
370
; 1d. Load pointer to data into esi and make [length] point to end of data.
366
        mov     esi, [buffer]
371
        mov     esi, [buffer]
367
        add     [length], esi
372
        add     [length], esi
368
; 2. Clear all local items.
373
; 2. Clear all local items.
369
; This is needed in the beginning and after processing any Main item.
374
; This is needed in the beginning and after processing any Main item.
370
.zero_local_items:
375
.zero_local_items:
371
        mov     eax, [usage_list]
376
        mov     eax, [usage_list]
372
@@:
377
@@:
373
        test    eax, eax
378
        test    eax, eax
374
        jz      @f
379
        jz      @f
375
        push    [eax+usage_list_item.next]
380
        push    [eax+usage_list_item.next]
376
        invoke  Kfree
381
        invoke  Kfree
377
        pop     eax
382
        pop     eax
378
        jmp     @b
383
        jmp     @b
379
@@:
384
@@:
380
        lea     ecx, [usage_list]
385
        lea     ecx, [usage_list]
381
        mov     [usage_tail], ecx
386
        mov     [usage_tail], ecx
382
        mov     [ecx], eax
387
        mov     [ecx], eax
383
        mov     [delimiter_depth], eax
388
        mov     [delimiter_depth], eax
384
        mov     [usage_variant], eax
389
        mov     [usage_variant], eax
385
        mov     [usage_minimum], eax
390
        mov     [usage_minimum], eax
386
        mov     [num_usage_ranges], eax
391
        mov     [num_usage_ranges], eax
387
; 3. Parse items until end of data found.
392
; 3. Parse items until end of data found.
388
        cmp     esi, [length]
393
        cmp     esi, [length]
389
        jae     .parse_end
394
        jae     .parse_end
390
.fetch_next_item:
395
.fetch_next_item:
391
; --------------------------------- Parse item --------------------------------
396
; --------------------------------- Parse item --------------------------------
392
; 4. Parse one item.
397
; 4. Parse one item.
393
; 4a. Get item data. eax = first item byte = code+type+size (4+2+2 bits),
398
; 4a. Get item data. eax = first item byte = code+type+size (4+2+2 bits),
394
; ebx = item data interpreted as unsigned,
399
; ebx = item data interpreted as unsigned,
395
; ecx = item data interpreted as signed.
400
; ecx = item data interpreted as signed.
396
        movzx   eax, byte [esi]
401
        movzx   eax, byte [esi]
397
        mov     ecx, eax
402
        mov     ecx, eax
398
        and     ecx, 3
403
        and     ecx, 3
399
        mov     [cur_item_size], ecx
404
        mov     [cur_item_size], ecx
400
        jmp     dword [.fetch_jumps+ecx*4]
405
        jmp     dword [.fetch_jumps+ecx*4]
401
.invalid_report:
406
.invalid_report:
402
        mov     esi, invalid_report_msg
407
        mov     esi, invalid_report_msg
403
        jmp     .end_str
408
        jmp     .end_str
404
.fetch_none:
409
.fetch_none:
405
        xor     ebx, ebx
410
        xor     ebx, ebx
406
        xor     ecx, ecx
411
        xor     ecx, ecx
407
        inc     esi
412
        inc     esi
408
        jmp     .fetched
413
        jmp     .fetched
409
.fetch_byte:
414
.fetch_byte:
410
        add     esi, 2
415
        add     esi, 2
411
        cmp     esi, [length]
416
        cmp     esi, [length]
412
        ja      .invalid_report
417
        ja      .invalid_report
413
        movzx   ebx, byte [esi-1]
418
        movzx   ebx, byte [esi-1]
414
        movsx   ecx, bl
419
        movsx   ecx, bl
415
        jmp     .fetched
420
        jmp     .fetched
416
.fetch_word:
421
.fetch_word:
417
        add     esi, 3
422
        add     esi, 3
418
        cmp     esi, [length]
423
        cmp     esi, [length]
419
        ja      .invalid_report
424
        ja      .invalid_report
420
        movzx   ebx, word [esi-2]
425
        movzx   ebx, word [esi-2]
421
        movsx   ecx, bx
426
        movsx   ecx, bx
422
        jmp     .fetched
427
        jmp     .fetched
423
.fetch_dword:
428
.fetch_dword:
424
        add     esi, 5
429
        add     esi, 5
425
        cmp     esi, [length]
430
        cmp     esi, [length]
426
        ja      .invalid_report
431
        ja      .invalid_report
427
        mov     ebx, dword [esi-4]
432
        mov     ebx, dword [esi-4]
428
        mov     ecx, ebx
433
        mov     ecx, ebx
429
.fetched:
434
.fetched:
430
; 4b. Select the branch according to item type.
435
; 4b. Select the branch according to item type.
431
; For every type, select the concrete handler and go there.
436
; For every type, select the concrete handler and go there.
432
        mov     edx, eax
437
        mov     edx, eax
433
        shr     edx, 2
438
        shr     edx, 2
434
        and     edx, 3
439
        and     edx, 3
435
        shr     eax, 4
440
        shr     eax, 4
436
        jmp     dword [.type_jumps+edx*4]
441
        jmp     dword [.type_jumps+edx*4]
437
; -------------------------------- Main items ---------------------------------
442
; -------------------------------- Main items ---------------------------------
438
.parse_main:
443
.parse_main:
439
        sub     eax, 8
444
        sub     eax, 8
440
        cmp     eax, .num_main_items
445
        cmp     eax, .num_main_items
441
        jae     .item_parsed
446
        jae     .item_parsed
442
        jmp     dword [.main_jumps+eax*4]
447
        jmp     dword [.main_jumps+eax*4]
443
; There are 5 Main items.
448
; There are 5 Main items.
444
; Input/Output/Feature items create new field groups in the corresponding report;
449
; Input/Output/Feature items create new field groups in the corresponding report;
445
; Collection item opens a new collection (possibly nested),
450
; Collection item opens a new collection (possibly nested),
446
; End Collection item closes the most nested collection.
451
; End Collection item closes the most nested collection.
447
.output:
452
.output:
448
        mov     [field_type], 1
453
        mov     [field_type], 1
449
        jmp     .new_field
454
        jmp     .new_field
450
.feature:
455
.feature:
451
        mov     [field_type], 2
456
        mov     [field_type], 2
452
        jmp     .new_field
457
        jmp     .new_field
453
.input:
458
.input:
454
        mov     [field_type], 0
459
        mov     [field_type], 0
455
.new_field:
460
.new_field:
456
; Create a new field group.
461
; Create a new field group.
457
        mov     [field_data], ebx
462
        mov     [field_data], ebx
458
        movzx   ebx, [field_type]
463
        movzx   ebx, [field_type]
459
if sizeof.report_set = 12
464
if sizeof.report_set = 12
460
        lea     ebx, [ebx*3]
465
        lea     ebx, [ebx*3]
461
        shl     ebx, 2
466
        shl     ebx, 2
462
else
467
else
463
err Change the code
468
err Change the code
464
end if
469
end if
465
        add     ebx, [calldata]
470
        add     ebx, [calldata]
466
; 5. Sanity checks: field size and fields count must be nonzero,
471
; 5. Sanity checks: field size and fields count must be nonzero,
467
; field size cannot be more than 32 bits,
472
; field size cannot be more than 32 bits,
468
; if field count is more than MAX_REPORT_SIZE * 8, the report would be more than
473
; if field count is more than MAX_REPORT_SIZE * 8, the report would be more than
469
; MAX_REPORT_SIZE bytes, so it is invalid too.
474
; MAX_REPORT_SIZE bytes, so it is invalid too.
470
; More precise check for size occurs later; this check only guarantees that
475
; More precise check for size occurs later; this check only guarantees that
471
; there will be no overflows during subsequent calculations.
476
; there will be no overflows during subsequent calculations.
472
        cmp     [edi+global_items.report_size], 0
477
        cmp     [edi+global_items.report_size], 0
473
        jz      .invalid_report
478
        jz      .invalid_report
474
        cmp     [edi+global_items.report_size], 32
479
        cmp     [edi+global_items.report_size], 32
475
        ja      .invalid_report
480
        ja      .invalid_report
476
; There are devices with Report Count(0) + Input(Constant Variable),
481
; There are devices with Report Count(0) + Input(Constant Variable),
477
; zero-length padding. Thus, do not consider descriptors with Report Count(0)
482
; zero-length padding. Thus, do not consider descriptors with Report Count(0)
478
; as invalid; instead, just ignore fields with Report Count(0).
483
; as invalid; instead, just ignore fields with Report Count(0).
479
        cmp     [edi+global_items.report_count], 0
484
        cmp     [edi+global_items.report_count], 0
480
        jz      .zero_local_items
485
        jz      .zero_local_items
481
        cmp     [edi+global_items.report_count], MAX_REPORT_BYTES * 8
486
        cmp     [edi+global_items.report_count], MAX_REPORT_BYTES * 8
482
        ja      .invalid_report
487
        ja      .invalid_report
483
; 6. Get the pointer to the place for the corresponding report in ebx.
488
; 6. Get the pointer to the place for the corresponding report in ebx.
484
; 6a. If report ID is not assigned, ebx already points to report_set.data,
489
; 6a. If report ID is not assigned, ebx already points to report_set.data,
485
; so go to 7.
490
; so go to 7.
486
        cmp     [edi+global_items.report_id], 0
491
        cmp     [edi+global_items.report_id], 0
487
        jz      .report_ptr_found
492
        jz      .report_ptr_found
488
; 6b. If table for reports was already allocated,
493
; 6b. If table for reports was already allocated,
489
; go to 6d skipping the next substep.
494
; go to 6d skipping the next substep.
490
        cmp     [ebx+report_set.numbered], 0
495
        cmp     [ebx+report_set.numbered], 0
491
        jnz     .report_set_allocated
496
        jnz     .report_set_allocated
492
; 6c. This is the first report with ID;
497
; 6c. This is the first report with ID;
493
; allocate and zero-initialize table for reports.
498
; allocate and zero-initialize table for reports.
494
; Note: it is incorrect but theoretically possible that some fields were
499
; Note: it is incorrect but theoretically possible that some fields were
495
; already allocated in report without ID; if so, abort processing with error.
500
; already allocated in report without ID; if so, abort processing with error.
496
        cmp     [ebx+report_set.data], 0
501
        cmp     [ebx+report_set.data], 0
497
        jnz     .invalid_report
502
        jnz     .invalid_report
498
        mov     eax, 256*4
503
        mov     eax, 256*4
499
        invoke  Kmalloc
504
        invoke  Kmalloc
500
        test    eax, eax
505
        test    eax, eax
501
        jz      .memory_error
506
        jz      .memory_error
502
        mov     [ebx+report_set.data], eax
507
        mov     [ebx+report_set.data], eax
503
        inc     [ebx+report_set.numbered]
508
        inc     [ebx+report_set.numbered]
504
        push    edi
509
        push    edi
505
        mov     edi, eax
510
        mov     edi, eax
506
        mov     ecx, 256
511
        mov     ecx, 256
507
        xor     eax, eax
512
        xor     eax, eax
508
        rep stosd
513
        rep stosd
509
        pop     edi
514
        pop     edi
510
; 6d. Report ID is assigned, report table is allocated,
515
; 6d. Report ID is assigned, report table is allocated,
511
; get the pointer to the corresponding item in the report table.
516
; get the pointer to the corresponding item in the report table.
512
.report_set_allocated:
517
.report_set_allocated:
513
        mov     ebx, [ebx+report_set.data]
518
        mov     ebx, [ebx+report_set.data]
514
        mov     ecx, [edi+global_items.report_id]
519
        mov     ecx, [edi+global_items.report_id]
515
        lea     ebx, [ebx+ecx*4]
520
        lea     ebx, [ebx+ecx*4]
516
; 7. If the field group is the first one in the report,
521
; 7. If the field group is the first one in the report,
517
; allocate and initialize report without fields.
522
; allocate and initialize report without fields.
518
.report_ptr_found:
523
.report_ptr_found:
519
; 7a. Check whether the report has been allocated.
524
; 7a. Check whether the report has been allocated.
520
        cmp     dword [ebx], 0
525
        cmp     dword [ebx], 0
521
        jnz     .report_allocated
526
        jnz     .report_allocated
522
; 7b. Allocate.
527
; 7b. Allocate.
523
        movi    eax, sizeof.report
528
        movi    eax, sizeof.report
524
        invoke  Kmalloc
529
        invoke  Kmalloc
525
        test    eax, eax
530
        test    eax, eax
526
        jz      .memory_error
531
        jz      .memory_error
527
; 7c. Initialize.
532
; 7c. Initialize.
528
        xor     edx, edx
533
        xor     edx, edx
529
        lea     ecx, [eax+report.first_field]
534
        lea     ecx, [eax+report.first_field]
530
        mov     [ebx], eax
535
        mov     [ebx], eax
531
        mov     [eax+report.next], edx
536
        mov     [eax+report.next], edx
532
        mov     [eax+report.size], edx
537
        mov     [eax+report.size], edx
533
        mov     [ecx], edx
538
        mov     [ecx], edx
534
        mov     [eax+report.last_field], ecx
539
        mov     [eax+report.last_field], ecx
535
        mov     [eax+report.top_level_collection], edx
540
        mov     [eax+report.top_level_collection], edx
536
        mov     ecx, [edi+global_items.report_id]
541
        mov     ecx, [edi+global_items.report_id]
537
        mov     [eax+report.id], ecx
542
        mov     [eax+report.id], ecx
538
; 7d. Append to the overall list of reports.
543
; 7d. Append to the overall list of reports.
539
        movzx   edx, [field_type]
544
        movzx   edx, [field_type]
540
        lea     edx, [last_reports+edx*4]
545
        lea     edx, [last_reports+edx*4]
541
        mov     ecx, [edx]
546
        mov     ecx, [edx]
542
        mov     [edx], eax
547
        mov     [edx], eax
543
        mov     [ecx], eax
548
        mov     [ecx], eax
544
.report_allocated:
549
.report_allocated:
545
        mov     ebx, [ebx]
550
        mov     ebx, [ebx]
546
; ebx points to an already existing report; add new field.
551
; ebx points to an already existing report; add new field.
547
; 8. Calculate total size of the group and
552
; 8. Calculate total size of the group and
548
; check that the new group would not overflow the report.
553
; check that the new group would not overflow the report.
549
        mov     eax, [edi+global_items.report_size]
554
        mov     eax, [edi+global_items.report_size]
550
        mul     [edi+global_items.report_count]
555
        mul     [edi+global_items.report_count]
551
        mov     ecx, [ebx+report.size]
556
        mov     ecx, [ebx+report.size]
552
        add     ecx, eax
557
        add     ecx, eax
553
        cmp     ecx, MAX_REPORT_BYTES * 8
558
        cmp     ecx, MAX_REPORT_BYTES * 8
554
        ja      .invalid_report
559
        ja      .invalid_report
555
; 9. If there are no usages for this group, this is padding;
560
; 9. If there are no usages for this group, this is padding;
556
; add it's size to total report size and stop processing.
561
; add it's size to total report size and stop processing.
557
        cmp     [num_usage_ranges], 0
562
        cmp     [num_usage_ranges], 0
558
        jz      .padding
563
        jz      .padding
559
; 10. Allocate memory for the group: this includes field group structure
564
; 10. Allocate memory for the group: this includes field group structure
560
; and additional fields depending on field type.
565
; and additional fields depending on field type.
561
; See comments in report_field_group structure.
566
; See comments in report_field_group structure.
562
        push    eax
567
        push    eax
563
        mov     edx, [edi+global_items.report_count]
568
        mov     edx, [edi+global_items.report_count]
564
        lea     eax, [report_field_group.common_sizeof+edx*4]
569
        lea     eax, [report_field_group.common_sizeof+edx*4]
565
        test    byte [field_data], HID_FIELD_VARIABLE
570
        test    byte [field_data], HID_FIELD_VARIABLE
566
        jnz     @f
571
        jnz     @f
567
        lea     eax, [eax+edx*4]
572
        lea     eax, [eax+edx*4]
568
        mov     edx, [num_usage_ranges]
573
        mov     edx, [num_usage_ranges]
569
        lea     eax, [eax+edx*sizeof.usage_range+4]
574
        lea     eax, [eax+edx*sizeof.usage_range+4]
570
@@:
575
@@:
571
        invoke  Kmalloc
576
        invoke  Kmalloc
572
        pop     edx
577
        pop     edx
573
        test    eax, eax
578
        test    eax, eax
574
        jz      .memory_error
579
        jz      .memory_error
575
; 11. Update report data.
580
; 11. Update report data.
576
; Field offset is the current report size;
581
; Field offset is the current report size;
577
; get the current report size and update report size.
582
; get the current report size and update report size.
578
; Also store the pointer to new field in the previous last field
583
; Also store the pointer to new field in the previous last field
579
; and update the last field.
584
; and update the last field.
580
        mov     ecx, [ebx+report.last_field]
585
        mov     ecx, [ebx+report.last_field]
581
        xadd    [ebx+report.size], edx
586
        xadd    [ebx+report.size], edx
582
        mov     [ebx+report.last_field], eax
587
        mov     [ebx+report.last_field], eax
583
        mov     [ecx], eax
588
        mov     [ecx], eax
584
; 12. Initialize field data: offset was calculated in the previous step,
589
; 12. Initialize field data: offset was calculated in the previous step,
585
; copy other characteristics from global_items data,
590
; copy other characteristics from global_items data,
586
; calculate .mask and .sign_mask.
591
; calculate .mask and .sign_mask.
587
        mov     [eax+report_field_group.offset], edx
592
        mov     [eax+report_field_group.offset], edx
588
        xor     edx, edx
593
        xor     edx, edx
589
        mov     [eax+report_field_group.next], edx
594
        mov     [eax+report_field_group.next], edx
590
        mov     [eax+report_field_group.sign_mask], edx
595
        mov     [eax+report_field_group.sign_mask], edx
591
        inc     edx
596
        inc     edx
592
        mov     ecx, [edi+global_items.report_size]
597
        mov     ecx, [edi+global_items.report_size]
593
        mov     [eax+report_field_group.size], ecx
598
        mov     [eax+report_field_group.size], ecx
594
        shl     edx, cl
599
        shl     edx, cl
595
        cmp     [edi+global_items.logical_minimum], 0
600
        cmp     [edi+global_items.logical_minimum], 0
596
        jge     .unsigned
601
        jge     .unsigned
597
        shr     edx, 1
602
        shr     edx, 1
598
        mov     [eax+report_field_group.sign_mask], edx
603
        mov     [eax+report_field_group.sign_mask], edx
599
.unsigned:
604
.unsigned:
600
        dec     edx
605
        dec     edx
601
        mov     [eax+report_field_group.mask], edx
606
        mov     [eax+report_field_group.mask], edx
602
        mov     ecx, [edi+global_items.report_count]
607
        mov     ecx, [edi+global_items.report_count]
603
        mov     [eax+report_field_group.count], ecx
608
        mov     [eax+report_field_group.count], ecx
604
        mov     ecx, [field_data]
609
        mov     ecx, [field_data]
605
        mov     [eax+report_field_group.flags], ecx
610
        mov     [eax+report_field_group.flags], ecx
606
irps field, logical_minimum logical_maximum physical_minimum physical_maximum unit_exponent unit
611
irps field, logical_minimum logical_maximum physical_minimum physical_maximum unit_exponent unit
607
\{
612
\{
608
        mov     ecx, [edi+global_items.\#field]
613
        mov     ecx, [edi+global_items.\#field]
609
        mov     [eax+report_field_group.\#field], ecx
614
        mov     [eax+report_field_group.\#field], ecx
610
\}
615
\}
611
; 13. Update the current collection; nesting collections will be updated by
616
; 13. Update the current collection; nesting collections will be updated by
612
; end-of-collection handler.
617
; end-of-collection handler.
613
        movzx   edx, [field_type]
618
        movzx   edx, [field_type]
614
if sizeof.collection_report_set = 16
619
if sizeof.collection_report_set = 16
615
        shl     edx, 4
620
        shl     edx, 4
616
else
621
else
617
err Change the code
622
err Change the code
618
end if
623
end if
619
        mov     ecx, [cur_collection]
624
        mov     ecx, [cur_collection]
620
        test    ecx, ecx
625
        test    ecx, ecx
621
        jz      .no_collection
626
        jz      .no_collection
622
        lea     ecx, [ecx+collection.input+edx]
627
        lea     ecx, [ecx+collection.input+edx]
623
        mov     [ecx+collection_report_set.last_report], ebx
628
        mov     [ecx+collection_report_set.last_report], ebx
624
        mov     [ecx+collection_report_set.last_field], eax
629
        mov     [ecx+collection_report_set.last_field], eax
625
        cmp     [ecx+collection_report_set.first_field], 0
630
        cmp     [ecx+collection_report_set.first_field], 0
626
        jnz     .no_collection
631
        jnz     .no_collection
627
        mov     [ecx+collection_report_set.first_report], ebx
632
        mov     [ecx+collection_report_set.first_report], ebx
628
        mov     [ecx+collection_report_set.first_field], eax
633
        mov     [ecx+collection_report_set.first_field], eax
629
.no_collection:
634
.no_collection:
630
; 14. Transform usage ranges. The target format depends on field type.
635
; 14. Transform usage ranges. The target format depends on field type.
631
        test    byte [eax+report_field_group.flags], HID_FIELD_VARIABLE
636
        test    byte [eax+report_field_group.flags], HID_FIELD_VARIABLE
632
        jz      .transform_usages_for_array
637
        jz      .transform_usages_for_array
633
; For Variable field groups, expand all ranges to array with .count Usages.
638
; For Variable field groups, expand all ranges to array with .count Usages.
634
; If total number of Usages in all ranges is too large, ignore excessive.
639
; If total number of Usages in all ranges is too large, ignore excessive.
635
; If total number of Usages in all ranges is too small, duplicate the last
640
; If total number of Usages in all ranges is too small, duplicate the last
636
; Usage up to .count Usages (e.g. group of several indicators can have one usage
641
; Usage up to .count Usages (e.g. group of several indicators can have one usage
637
; "Generic Indicator" assigned to all fields).
642
; "Generic Indicator" assigned to all fields).
638
        mov     ecx, [eax+report_field_group.count]
643
        mov     ecx, [eax+report_field_group.count]
639
        mov     ebx, [usage_list]
644
        mov     ebx, [usage_list]
640
.next_usage_range_for_variable:
645
.next_usage_range_for_variable:
641
        mov     edx, [ebx+usage_list_item.first_usage]
646
        mov     edx, [ebx+usage_list_item.first_usage]
642
        push    [ebx+usage_list_item.num_usages]
647
        push    [ebx+usage_list_item.num_usages]
643
.next_usage_for_variable:
648
.next_usage_for_variable:
644
        mov     [eax+report_field_group.common_sizeof], edx
649
        mov     [eax+report_field_group.common_sizeof], edx
645
        dec     ecx
650
        dec     ecx
646
        jz      @f
651
        jz      @f
647
        add     eax, 4
652
        add     eax, 4
648
        inc     edx
653
        inc     edx
649
        dec     dword [esp]
654
        dec     dword [esp]
650
        jnz     .next_usage_for_variable
655
        jnz     .next_usage_for_variable
651
        dec     edx
656
        dec     edx
652
        inc     dword [esp]
657
        inc     dword [esp]
653
        cmp     [ebx+usage_list_item.next], 0
658
        cmp     [ebx+usage_list_item.next], 0
654
        jz      .next_usage_for_variable
659
        jz      .next_usage_for_variable
655
        pop     edx
660
        pop     edx
656
        mov     ebx, [ebx+usage_list_item.next]
661
        mov     ebx, [ebx+usage_list_item.next]
657
        jmp     .next_usage_range_for_variable
662
        jmp     .next_usage_range_for_variable
658
@@:
663
@@:
659
        pop     ebx
664
        pop     ebx
660
        jmp     .zero_local_items
665
        jmp     .zero_local_items
661
.transform_usages_for_array:
666
.transform_usages_for_array:
662
; For Array field groups, leave ranges unexpanded, but recode in the form
667
; For Array field groups, leave ranges unexpanded, but recode in the form
663
; more convenient to value lookup, see comments in report_field_group structure.
668
; more convenient to value lookup, see comments in report_field_group structure.
664
        mov     ecx, [num_usage_ranges]
669
        mov     ecx, [num_usage_ranges]
665
        mov     [eax+report_field_group.num_usage_ranges], ecx
670
        mov     [eax+report_field_group.num_usage_ranges], ecx
666
        and     [eax+report_field_group.num_values_prev], 0
671
        and     [eax+report_field_group.num_values_prev], 0
667
        mov     ecx, [usage_list]
672
        mov     ecx, [usage_list]
668
        xor     ebx, ebx
673
        xor     ebx, ebx
669
@@:
674
@@:
670
        mov     edx, [ecx+usage_list_item.first_usage]
675
        mov     edx, [ecx+usage_list_item.first_usage]
671
        mov     [eax+report_field_group.usages+usage_range.offset], ebx
676
        mov     [eax+report_field_group.usages+usage_range.offset], ebx
672
        add     ebx, [ecx+usage_list_item.num_usages]
677
        add     ebx, [ecx+usage_list_item.num_usages]
673
        jc      .invalid_report
678
        jc      .invalid_report
674
        mov     [eax+report_field_group.usages+usage_range.first_usage], edx
679
        mov     [eax+report_field_group.usages+usage_range.first_usage], edx
675
        add     eax, sizeof.usage_range
680
        add     eax, sizeof.usage_range
676
        mov     ecx, [ecx+usage_list_item.next]
681
        mov     ecx, [ecx+usage_list_item.next]
677
        test    ecx, ecx
682
        test    ecx, ecx
678
        jnz     @b
683
        jnz     @b
679
        mov     [eax+report_field_group.usages], ebx
684
        mov     [eax+report_field_group.usages], ebx
680
; New field is initialized.
685
; New field is initialized.
681
        jmp     .zero_local_items
686
        jmp     .zero_local_items
682
.padding:
687
.padding:
683
        mov     [ebx+report.size], ecx
688
        mov     [ebx+report.size], ecx
684
        jmp     .zero_local_items
689
        jmp     .zero_local_items
685
; Create a new collection, nested in the current one.
690
; Create a new collection, nested in the current one.
686
.collection:
691
.collection:
687
; Actions are quite straightforward:
692
; Actions are quite straightforward:
688
; allocate, zero-initialize, update parent, if there is one,
693
; allocate, zero-initialize, update parent, if there is one,
689
; make it current.
694
; make it current.
690
        movi    eax, sizeof.collection
695
        movi    eax, sizeof.collection
691
        invoke  Kmalloc
696
        invoke  Kmalloc
692
        test    eax, eax
697
        test    eax, eax
693
        jz      .memory_error
698
        jz      .memory_error
694
        push    eax edi
699
        push    eax edi
695
        movi    ecx, sizeof.collection / 4
700
        movi    ecx, sizeof.collection / 4
696
        xchg    edi, eax
701
        xchg    edi, eax
697
        xor     eax, eax
702
        xor     eax, eax
698
        rep stosd
703
        rep stosd
699
        pop     edi eax
704
        pop     edi eax
700
        mov     edx, [cur_collection]
705
        mov     edx, [cur_collection]
701
        mov     [eax+collection.parent], edx
706
        mov     [eax+collection.parent], edx
702
        lea     ecx, [last_collection]
707
        lea     ecx, [last_collection]
703
        test    edx, edx
708
        test    edx, edx
704
        jz      .no_parent
709
        jz      .no_parent
705
        lea     ecx, [edx+collection.last_child]
710
        lea     ecx, [edx+collection.last_child]
706
.no_parent:
711
.no_parent:
707
        mov     edx, [ecx]
712
        mov     edx, [ecx]
708
        mov     [ecx], eax
713
        mov     [ecx], eax
709
        mov     [edx], eax
714
        mov     [edx], eax
710
        lea     ecx, [eax+collection.first_child]
715
        lea     ecx, [eax+collection.first_child]
711
; In theory, there must be at least one usage.
716
; In theory, there must be at least one usage.
712
; In practice, some nested collections don't have any. Use zero in this case.
717
; In practice, some nested collections don't have any. Use zero in this case.
713
        mov     edx, [usage_list]
718
        mov     edx, [usage_list]
714
        test    edx, edx
719
        test    edx, edx
715
        jz      @f
720
        jz      @f
716
        mov     edx, [edx+usage_list_item.first_usage]
721
        mov     edx, [edx+usage_list_item.first_usage]
717
@@:
722
@@:
718
        mov     [eax+collection.last_child], ecx
723
        mov     [eax+collection.last_child], ecx
719
        mov     [eax+collection.type], ebx
724
        mov     [eax+collection.type], ebx
720
        mov     [eax+collection.usage], edx
725
        mov     [eax+collection.usage], edx
721
        mov     [cur_collection], eax
726
        mov     [cur_collection], eax
722
        jmp     .zero_local_items
727
        jmp     .zero_local_items
723
; Close the current collection.
728
; Close the current collection.
724
.end_collection:
729
.end_collection:
725
; There must be an opened collection.
730
; There must be an opened collection.
726
        mov     eax, [cur_collection]
731
        mov     eax, [cur_collection]
727
        test    eax, eax
732
        test    eax, eax
728
        jz      .invalid_report
733
        jz      .invalid_report
729
; Make parent collection the current one.
734
; Make parent collection the current one.
730
        mov     edx, [eax+collection.parent]
735
        mov     edx, [eax+collection.parent]
731
        mov     [cur_collection], edx
736
        mov     [cur_collection], edx
732
; Add field range of the closing collection to field range for nesting collection,
737
; Add field range of the closing collection to field range for nesting collection,
733
; if there is one.
738
; if there is one.
734
        test    edx, edx
739
        test    edx, edx
735
        jz      .zero_local_items
740
        jz      .zero_local_items
736
        push    3       ; for each type: input, output, feature
741
        push    3       ; for each type: input, output, feature
737
.update_ranges:
742
.update_ranges:
738
        mov     ecx, [eax+collection.input.last_report]
743
        mov     ecx, [eax+collection.input.last_report]
739
        test    ecx, ecx
744
        test    ecx, ecx
740
        jz      .no_fields
745
        jz      .no_fields
741
        mov     [edx+collection.input.last_report], ecx
746
        mov     [edx+collection.input.last_report], ecx
742
        mov     ecx, [eax+collection.input.last_field]
747
        mov     ecx, [eax+collection.input.last_field]
743
        mov     [edx+collection.input.last_field], ecx
748
        mov     [edx+collection.input.last_field], ecx
744
        cmp     [edx+collection.input.first_report], 0
749
        cmp     [edx+collection.input.first_report], 0
745
        jnz     .no_fields
750
        jnz     .no_fields
746
        mov     ecx, [eax+collection.input.first_report]
751
        mov     ecx, [eax+collection.input.first_report]
747
        mov     [edx+collection.input.first_report], ecx
752
        mov     [edx+collection.input.first_report], ecx
748
        mov     ecx, [eax+collection.input.first_field]
753
        mov     ecx, [eax+collection.input.first_field]
749
        mov     [edx+collection.input.first_field], ecx
754
        mov     [edx+collection.input.first_field], ecx
750
.no_fields:
755
.no_fields:
751
        add     eax, sizeof.collection_report_set
756
        add     eax, sizeof.collection_report_set
752
        add     edx, sizeof.collection_report_set
757
        add     edx, sizeof.collection_report_set
753
        dec     dword [esp]
758
        dec     dword [esp]
754
        jnz     .update_ranges
759
        jnz     .update_ranges
755
        pop     eax
760
        pop     eax
756
        jmp     .zero_local_items
761
        jmp     .zero_local_items
757
; ------------------------------- Global items --------------------------------
762
; ------------------------------- Global items --------------------------------
758
.parse_global:
763
.parse_global:
759
        cmp     eax, .num_global_items
764
        cmp     eax, .num_global_items
760
        jae     .item_parsed
765
        jae     .item_parsed
761
        jmp     dword [.global_jumps+eax*4]
766
        jmp     dword [.global_jumps+eax*4]
762
; For most global items, just store the value in the current global_items structure.
767
; For most global items, just store the value in the current global_items structure.
763
; Note 1: Usage Page will be used for upper word of Usage[| Minimum|Maximum], so
768
; Note 1: Usage Page will be used for upper word of Usage[| Minimum|Maximum], so
764
; shift it in advance.
769
; shift it in advance.
765
; Note 2: the HID specification allows both signed and unsigned values for
770
; Note 2: the HID specification allows both signed and unsigned values for
766
; logical and physical minimum/maximum, but does not give a method to distinguish.
771
; logical and physical minimum/maximum, but does not give a method to distinguish.
767
; Thus, hope that minimum comes first, parse the minimum as signed value always,
772
; Thus, hope that minimum comes first, parse the minimum as signed value always,
768
; if it is less than zero, assume signed values, otherwise assume unsigned values.
773
; if it is less than zero, assume signed values, otherwise assume unsigned values.
769
; This covers both common cases Minimum(0)/Maximum(FF) and Minimum(-7F)/Maximum(7F).
774
; This covers both common cases Minimum(0)/Maximum(FF) and Minimum(-7F)/Maximum(7F).
770
; Note 3: zero value for Report ID is forbidden by the HID specification.
775
; Note 3: zero value for Report ID is forbidden by the HID specification.
771
; It is quite convenient, we use report_id == 0 for reports without ID.
776
; It is quite convenient, we use report_id == 0 for reports without ID.
772
.usage_page:
777
.usage_page:
773
        shl     ebx, 16
778
        shl     ebx, 16
774
        mov     [edi+global_items.usage_page], ebx
779
        mov     [edi+global_items.usage_page], ebx
775
        jmp     .item_parsed
780
        jmp     .item_parsed
776
.logical_minimum:
781
.logical_minimum:
777
        mov     [edi+global_items.logical_minimum], ecx
782
        mov     [edi+global_items.logical_minimum], ecx
778
        jmp     .item_parsed
783
        jmp     .item_parsed
779
.logical_maximum:
784
.logical_maximum:
780
        cmp     [edi+global_items.logical_minimum], 0
785
        cmp     [edi+global_items.logical_minimum], 0
781
        jge     @f
786
        jge     @f
782
        mov     ebx, ecx
787
        mov     ebx, ecx
783
@@:
788
@@:
784
        mov     [edi+global_items.logical_maximum], ebx
789
        mov     [edi+global_items.logical_maximum], ebx
785
        jmp     .item_parsed
790
        jmp     .item_parsed
786
.physical_minimum:
791
.physical_minimum:
787
        mov     [edi+global_items.physical_minimum], ecx
792
        mov     [edi+global_items.physical_minimum], ecx
788
        jmp     .item_parsed
793
        jmp     .item_parsed
789
.physical_maximum:
794
.physical_maximum:
790
        cmp     [edi+global_items.physical_maximum], 0
795
        cmp     [edi+global_items.physical_maximum], 0
791
        jge     @f
796
        jge     @f
792
        mov     ebx, ecx
797
        mov     ebx, ecx
793
@@:
798
@@:
794
        mov     [edi+global_items.physical_maximum], ebx
799
        mov     [edi+global_items.physical_maximum], ebx
795
        jmp     .item_parsed
800
        jmp     .item_parsed
796
.unit_exponent:
801
.unit_exponent:
797
        mov     [edi+global_items.unit_exponent], ecx
802
        mov     [edi+global_items.unit_exponent], ecx
798
        jmp     .item_parsed
803
        jmp     .item_parsed
799
.unit:
804
.unit:
800
        mov     [edi+global_items.unit], ebx
805
        mov     [edi+global_items.unit], ebx
801
        jmp     .item_parsed
806
        jmp     .item_parsed
802
.report_size:
807
.report_size:
803
        mov     [edi+global_items.report_size], ebx
808
        mov     [edi+global_items.report_size], ebx
804
        jmp     .item_parsed
809
        jmp     .item_parsed
805
.report_id:
810
.report_id:
806
        test    ebx, ebx
811
        test    ebx, ebx
807
        jz      .invalid_report
812
        jz      .invalid_report
808
        cmp     ebx, 0x100
813
        cmp     ebx, 0x100
809
        jae     .invalid_report
814
        jae     .invalid_report
810
        mov     [edi+global_items.report_id], ebx
815
        mov     [edi+global_items.report_id], ebx
811
        jmp     .item_parsed
816
        jmp     .item_parsed
812
.report_count:
817
.report_count:
813
        mov     [edi+global_items.report_count], ebx
818
        mov     [edi+global_items.report_count], ebx
814
        jmp     .item_parsed
819
        jmp     .item_parsed
815
; Two special global items: Push/Pop.
820
; Two special global items: Push/Pop.
816
.push:
821
.push:
817
; For Push, allocate new global_items structure,
822
; For Push, allocate new global_items structure,
818
; initialize from the current one and make it current.
823
; initialize from the current one and make it current.
819
        movi    eax, sizeof.global_items
824
        movi    eax, sizeof.global_items
820
        invoke  Kmalloc
825
        invoke  Kmalloc
821
        test    eax, eax
826
        test    eax, eax
822
        jz      .memory_error
827
        jz      .memory_error
823
        push    esi eax
828
        push    esi eax
824
        movi    ecx, sizeof.global_items / 4
829
        movi    ecx, sizeof.global_items / 4
825
        mov     esi, edi
830
        mov     esi, edi
826
        xchg    eax, edi
831
        xchg    eax, edi
827
        rep movsd
832
        rep movsd
828
        pop     edi esi
833
        pop     edi esi
829
        mov     [edi+global_items.next], eax
834
        mov     [edi+global_items.next], eax
830
        jmp     .item_parsed
835
        jmp     .item_parsed
831
.pop:
836
.pop:
832
; For Pop, restore the last global_items structure and free the current one.
837
; For Pop, restore the last global_items structure and free the current one.
833
        mov     eax, [edi+global_items.next]
838
        mov     eax, [edi+global_items.next]
834
        test    eax, eax
839
        test    eax, eax
835
        jz      .invalid_report
840
        jz      .invalid_report
836
        push    eax
841
        push    eax
837
        xchg    eax, edi
842
        xchg    eax, edi
838
        invoke  Kfree
843
        invoke  Kfree
839
        pop     edi
844
        pop     edi
840
        jmp     .item_parsed
845
        jmp     .item_parsed
841
; -------------------------------- Local items --------------------------------
846
; -------------------------------- Local items --------------------------------
842
.parse_local:
847
.parse_local:
843
        cmp     eax, .num_local_items
848
        cmp     eax, .num_local_items
844
        jae     .item_parsed
849
        jae     .item_parsed
845
        jmp     dword [.local_jumps+eax*4]
850
        jmp     dword [.local_jumps+eax*4]
846
.usage:
851
.usage:
847
; Usage tag.
852
; Usage tag.
848
; If length is 0, 1, 2 bytes, append the global item Usage Page.
853
; If length is 0, 1, 2 bytes, append the global item Usage Page.
849
        cmp     [cur_item_size], 2
854
        cmp     [cur_item_size], 2
850
        ja      @f
855
        ja      @f
851
        or      ebx, [edi+global_items.usage_page]
856
        or      ebx, [edi+global_items.usage_page]
852
@@:
857
@@:
853
; If inside Delimiter(), ignore everything except the first tag.
858
; If inside Delimiter(), ignore everything except the first tag.
854
        cmp     [delimiter_depth], 0
859
        cmp     [delimiter_depth], 0
855
        jz      .usage.write
860
        jz      .usage.write
856
        inc     [usage_variant]
861
        inc     [usage_variant]
857
        cmp     [usage_variant], 1
862
        cmp     [usage_variant], 1
858
        jnz     .item_parsed
863
        jnz     .item_parsed
859
.usage.write:
864
.usage.write:
860
; Add new range with start = item data and length = 1.
865
; Add new range with start = item data and length = 1.
861
        mov     [usage_minimum], ebx
866
        mov     [usage_minimum], ebx
862
        push    1
867
        push    1
863
.new_usage:
868
.new_usage:
864
        movi    eax, sizeof.usage_list_item
869
        movi    eax, sizeof.usage_list_item
865
        invoke  Kmalloc
870
        invoke  Kmalloc
866
        pop     edx
871
        pop     edx
867
        test    eax, eax
872
        test    eax, eax
868
        jz      .memory_error
873
        jz      .memory_error
869
        inc     [num_usage_ranges]
874
        inc     [num_usage_ranges]
870
        mov     ecx, [usage_minimum]
875
        mov     ecx, [usage_minimum]
871
        and     [eax+usage_list_item.next], 0
876
        and     [eax+usage_list_item.next], 0
872
        mov     [eax+usage_list_item.first_usage], ecx
877
        mov     [eax+usage_list_item.first_usage], ecx
873
        mov     [eax+usage_list_item.num_usages], edx
878
        mov     [eax+usage_list_item.num_usages], edx
874
        mov     ecx, [usage_tail]
879
        mov     ecx, [usage_tail]
875
        mov     [usage_tail], eax
880
        mov     [usage_tail], eax
876
        mov     [ecx], eax
881
        mov     [ecx], eax
877
        jmp     .item_parsed
882
        jmp     .item_parsed
878
.usage_minimum:
883
.usage_minimum:
879
; Usage Minimum tag. Just store in the local var.
884
; Usage Minimum tag. Just store in the local var.
880
; If length is 0, 1, 2 bytes, append the global item Usage Page.
885
; If length is 0, 1, 2 bytes, append the global item Usage Page.
881
        cmp     [cur_item_size], 2
886
        cmp     [cur_item_size], 2
882
        ja      @f
887
        ja      @f
883
        or      ebx, [edi+global_items.usage_page]
888
        or      ebx, [edi+global_items.usage_page]
884
@@:
889
@@:
885
        mov     [usage_minimum], ebx
890
        mov     [usage_minimum], ebx
886
        jmp     .item_parsed
891
        jmp     .item_parsed
887
.usage_maximum:
892
.usage_maximum:
888
; Usage Maximum tag.
893
; Usage Maximum tag.
889
; If length is 0, 1, 2 bytes, append the global item Usage Page.
894
; If length is 0, 1, 2 bytes, append the global item Usage Page.
890
        cmp     [cur_item_size], 2
895
        cmp     [cur_item_size], 2
891
        ja      @f
896
        ja      @f
892
        or      ebx, [edi+global_items.usage_page]
897
        or      ebx, [edi+global_items.usage_page]
893
@@:
898
@@:
894
; Meaningless inside Delimiter().
899
; Meaningless inside Delimiter().
895
        cmp     [delimiter_depth], 0
900
        cmp     [delimiter_depth], 0
896
        jnz     .invalid_report
901
        jnz     .invalid_report
897
; Add new range with start = saved Usage Minimum and
902
; Add new range with start = saved Usage Minimum and
898
; length = Usage Maximum - Usage Minimum + 1.
903
; length = Usage Maximum - Usage Minimum + 1.
899
        sub     ebx, [usage_minimum]
904
        sub     ebx, [usage_minimum]
900
        inc     ebx
905
        inc     ebx
901
        push    ebx
906
        push    ebx
902
        jmp     .new_usage
907
        jmp     .new_usage
903
.delimiter:
908
.delimiter:
904
; Delimiter tag.
909
; Delimiter tag.
905
        test    ebx, ebx
910
        test    ebx, ebx
906
        jz      .delimiter.close
911
        jz      .delimiter.close
907
; Delimiter(Opened).
912
; Delimiter(Opened).
908
; Store that we are inside Delimiter(),
913
; Store that we are inside Delimiter(),
909
; say a warning that only preferred Usage will be used.
914
; say a warning that only preferred Usage will be used.
910
        cmp     [delimiter_depth], 0
915
        cmp     [delimiter_depth], 0
911
        jnz     .invalid_report
916
        jnz     .invalid_report
912
        inc     [delimiter_depth]
917
        inc     [delimiter_depth]
913
        push    esi
918
        push    esi
914
        mov     esi, delimiter_note
919
        mov     esi, delimiter_note
915
        invoke  SysMsgBoardStr
920
        invoke  SysMsgBoardStr
916
        pop     esi
921
        pop     esi
917
        jmp     .item_parsed
922
        jmp     .item_parsed
918
.delimiter.close:
923
.delimiter.close:
919
; Delimiter(Closed).
924
; Delimiter(Closed).
920
; Store that we are not inside Delimiter() anymore.
925
; Store that we are not inside Delimiter() anymore.
921
        dec     [delimiter_depth]
926
        dec     [delimiter_depth]
922
        js      .invalid_report
927
        js      .invalid_report
923
        and     [usage_variant], 0
928
        and     [usage_variant], 0
924
        jmp     .item_parsed
929
        jmp     .item_parsed
925
.parse_reserved:
930
.parse_reserved:
926
; Ignore reserved items, except that tag 0xFE means long item
931
; Ignore reserved items, except that tag 0xFE means long item
927
; with first data byte = length of additional data,
932
; with first data byte = length of additional data,
928
; second data byte = long item tag. No long items are defined yet,
933
; second data byte = long item tag. No long items are defined yet,
929
; so just skip them.
934
; so just skip them.
930
        cmp     eax, 0xF
935
        cmp     eax, 0xF
931
        jnz     .item_parsed
936
        jnz     .item_parsed
932
        cmp     [cur_item_size], 2
937
        cmp     [cur_item_size], 2
933
        jnz     .item_parsed
938
        jnz     .item_parsed
934
        movzx   ecx, bl
939
        movzx   ecx, bl
935
        add     esi, ecx
940
        add     esi, ecx
936
        cmp     esi, [length]
941
        cmp     esi, [length]
937
        ja      .invalid_report
942
        ja      .invalid_report
938
.item_parsed:
943
.item_parsed:
939
        cmp     esi, [length]
944
        cmp     esi, [length]
940
        jb      .fetch_next_item
945
        jb      .fetch_next_item
941
.parse_end:
946
.parse_end:
942
;-------------------------------- End of parsing ------------------------------
947
;-------------------------------- End of parsing ------------------------------
943
; If there are opened collections, it is invalid report.
948
; If there are opened collections, it is invalid report.
944
        cmp     [cur_collection], 0
949
        cmp     [cur_collection], 0
945
        jnz     .invalid_report
950
        jnz     .invalid_report
946
; There must be at least one input field.
951
; There must be at least one input field.
947
        mov     eax, [calldata]
952
        mov     eax, [calldata]
948
        add     eax, hid_data.input.first_report
953
        add     eax, hid_data.input.first_report
949
        cmp     [last_reports+0*4], eax
954
        cmp     [last_reports+0*4], eax
950
        jz      .invalid_report
955
        jz      .invalid_report
951
; Everything is ok.
956
; Everything is ok.
952
        inc     [report_ok]
957
        inc     [report_ok]
953
        jmp     .end
958
        jmp     .end
954
.memory_error:
959
.memory_error:
955
        mov     esi, nomemory_msg
960
        mov     esi, nomemory_msg
956
.end_str:
961
.end_str:
957
        invoke  SysMsgBoardStr
962
        invoke  SysMsgBoardStr
958
.end:
963
.end:
959
; Free all global_items structures.
964
; Free all global_items structures.
960
        test    edi, edi
965
        test    edi, edi
961
        jz      @f
966
        jz      @f
962
        push    [edi+global_items.next]
967
        push    [edi+global_items.next]
963
        xchg    eax, edi
968
        xchg    eax, edi
964
        invoke  Kfree
969
        invoke  Kfree
965
        pop     edi
970
        pop     edi
966
        jmp     .end
971
        jmp     .end
967
@@:
972
@@:
968
; Free the last Usage list, if any.
973
; Free the last Usage list, if any.
969
        mov     eax, [usage_list]
974
        mov     eax, [usage_list]
970
@@:
975
@@:
971
        test    eax, eax
976
        test    eax, eax
972
        jz      @f
977
        jz      @f
973
        push    [eax+usage_list_item.next]
978
        push    [eax+usage_list_item.next]
974
        invoke  Kfree
979
        invoke  Kfree
975
        pop     eax
980
        pop     eax
976
        jmp     @b
981
        jmp     @b
977
@@:
982
@@:
978
}
983
}
979
 
984
 
980
; Assign drivers to top-level HID collections.
985
; Assign drivers to top-level HID collections.
981
; The caller should provide ebx = pointer to hid_data and a local variable
986
; The caller should provide ebx = pointer to hid_data and a local variable
982
; [has_driver], it will be initialized with 0 if no driver is present.
987
; [has_driver], it will be initialized with 0 if no driver is present.
983
macro postprocess_descr
988
macro postprocess_descr
984
{
989
{
985
postprocess_report_label:
990
postprocess_report_label:
986
; Assign drivers to top-level collections.
991
; Assign drivers to top-level collections.
987
; Use mouse driver for Usage(GenericDesktop:Mouse),
992
; Use mouse driver for Usage(GenericDesktop:Mouse),
988
; use keyboard driver for Usage(GenericDesktop:Keyboard)
993
; use keyboard driver for Usage(GenericDesktop:Keyboard)
989
; and Usage(GenericDesktop:Keypad)
994
; and Usage(GenericDesktop:Keypad)
990
; 1. Prepare for the loop: get the pointer to the first collection,
995
; 1. Prepare for the loop: get the pointer to the first collection,
991
; store that no drivers were assigned yet.
996
; store that no drivers were assigned yet.
992
        mov     edi, [ebx+hid_data.first_collection]
997
        mov     edi, [ebx+hid_data.first_collection]
993
if ~HID_DUMP_UNCLAIMED
998
if ~HID_DUMP_UNCLAIMED
994
        mov     [has_driver], 0
999
        mov     [has_driver], 0
995
end if
1000
end if
996
.next_collection:
1001
.next_collection:
997
; 2. Test whether there is a collection to test; if no, break from the loop.
1002
; 2. Test whether there is a collection to test; if no, break from the loop.
998
        test    edi, edi
1003
        test    edi, edi
999
        jz      .postprocess_done
1004
        jz      .postprocess_done
1000
; 3. Get pointer to driver callbacks depending on [collection.usage].
1005
; 3. Get pointer to driver callbacks depending on [collection.usage].
1001
; If [collection.usage] is unknown, use default driver if HID_DUMP_UNCLAIMED
1006
; If [collection.usage] is unknown, use default driver if HID_DUMP_UNCLAIMED
1002
; and do not assign a driver otherwise.
1007
; and do not assign a driver otherwise.
1003
        mov     esi, mouse_driver
1008
        mov     esi, mouse_driver
1004
        cmp     [edi+collection.usage], USAGE_GD_POINTER
1009
        cmp     [edi+collection.usage], USAGE_GD_POINTER
1005
        jz      .has_driver
1010
        jz      .has_driver
1006
        cmp     [edi+collection.usage], USAGE_GD_MOUSE
1011
        cmp     [edi+collection.usage], USAGE_GD_MOUSE
1007
        jz      .has_driver
1012
        jz      .has_driver
1008
        mov     esi, keyboard_driver
1013
        mov     esi, keyboard_driver
1009
        cmp     [edi+collection.usage], USAGE_GD_KEYBOARD
1014
        cmp     [edi+collection.usage], USAGE_GD_KEYBOARD
1010
        jz      .has_driver
1015
        jz      .has_driver
1011
        cmp     [edi+collection.usage], USAGE_GD_KEYPAD
1016
        cmp     [edi+collection.usage], USAGE_GD_KEYPAD
1012
        jz      .has_driver
1017
        jz      .has_driver
-
 
1018
        mov     esi, multimedia_driver
-
 
1019
        cmp     [edi+collection.usage], USAGE_GD_CONS_CTRL
-
 
1020
        jz      .has_driver
1013
if HID_DUMP_UNCLAIMED
1021
if HID_DUMP_UNCLAIMED
1014
        mov     esi, default_driver
1022
        mov     esi, default_driver
1015
else
1023
else
1016
        xor     esi, esi
1024
        xor     esi, esi
1017
end if
1025
end if
1018
; 4. If no driver is assigned (possible only if not HID_DUMP_UNCLAIMED),
1026
; 4. If no driver is assigned (possible only if not HID_DUMP_UNCLAIMED),
1019
; go to 7 with driver data = 0;
1027
; go to 7 with driver data = 0;
1020
; other code uses this as a sign that driver callbacks should not be called.
1028
; other code uses this as a sign that driver callbacks should not be called.
1021
.has_driver:
1029
.has_driver:
1022
        xor     eax, eax
1030
        xor     eax, eax
1023
if ~HID_DUMP_UNCLAIMED
1031
if ~HID_DUMP_UNCLAIMED
1024
        test    esi, esi
1032
        test    esi, esi
1025
        jz      .set_driver
1033
        jz      .set_driver
1026
end if
1034
end if
1027
; 5. Notify the driver about new device.
1035
; 5. Notify the driver about new device.
1028
        call    [esi+hid_driver_callbacks.add_device]
1036
        call    [esi+hid_driver_callbacks.add_device]
1029
; 6. If the driver has returned non-zero driver data,
1037
; 6. If the driver has returned non-zero driver data,
1030
; store that is an assigned driver.
1038
; store that is an assigned driver.
1031
; Otherwise, if HID_DUMP_UNCLAIMED, try to assign the default driver.
1039
; Otherwise, if HID_DUMP_UNCLAIMED, try to assign the default driver.
1032
if HID_DUMP_UNCLAIMED
1040
if HID_DUMP_UNCLAIMED
1033
        test    eax, eax
1041
        test    eax, eax
1034
        jnz     .set_driver
1042
        jnz     .set_driver
1035
        mov     esi, default_driver
1043
        mov     esi, default_driver
1036
        call    [esi+hid_driver_callbacks.add_device]
1044
        call    [esi+hid_driver_callbacks.add_device]
1037
else
1045
else
1038
        test    eax, eax
1046
        test    eax, eax
1039
        jz      @f
1047
        jz      @f
1040
        mov     [has_driver], 1
1048
        mov     [has_driver], 1
1041
        jmp     .set_driver
1049
        jmp     .set_driver
1042
@@:
1050
@@:
1043
        xor     esi, esi
1051
        xor     esi, esi
1044
end if
1052
end if
1045
.set_driver:
1053
.set_driver:
1046
; 7. Store driver data. If a driver is assigned, copy driver callbacks.
1054
; 7. Store driver data. If a driver is assigned, copy driver callbacks.
1047
        mov     [edi+collection.driver_data], eax
1055
        mov     [edi+collection.driver_data], eax
1048
        test    esi, esi
1056
        test    esi, esi
1049
        jz      @f
1057
        jz      @f
1050
        push    edi
1058
        push    edi
1051
        lodsd   ; skip hid_driver_callbacks.add_device
1059
        lodsd   ; skip hid_driver_callbacks.add_device
1052
        add     edi, collection.callbacks
1060
        add     edi, collection.callbacks
1053
repeat sizeof.hid_driver_active_callbacks / 4
1061
repeat sizeof.hid_driver_active_callbacks / 4
1054
        movsd
1062
        movsd
1055
end repeat
1063
end repeat
1056
        pop     edi
1064
        pop     edi
1057
@@:
1065
@@:
1058
; 8. Store pointer to the collection in all input reports belonging to it.
1066
; 8. Store pointer to the collection in all input reports belonging to it.
1059
; Note that the HID spec requires that reports should not cross top-level collections.
1067
; Note that the HID spec requires that reports should not cross top-level collections.
1060
        mov     eax, [edi+collection.input.first_report]
1068
        mov     eax, [edi+collection.input.first_report]
1061
        test    eax, eax
1069
        test    eax, eax
1062
        jz      .reports_processed
1070
        jz      .reports_processed
1063
.next_report:
1071
.next_report:
1064
        mov     [eax+report.top_level_collection], edi
1072
        mov     [eax+report.top_level_collection], edi
1065
        cmp     eax, [edi+collection.input.last_report]
1073
        cmp     eax, [edi+collection.input.last_report]
1066
        mov     eax, [eax+report.next]
1074
        mov     eax, [eax+report.next]
1067
        jnz     .next_report
1075
        jnz     .next_report
1068
.reports_processed:
1076
.reports_processed:
1069
        mov     edi, [edi+collection.next]
1077
        mov     edi, [edi+collection.next]
1070
        jmp     .next_collection
1078
        jmp     .next_collection
1071
.postprocess_done:
1079
.postprocess_done:
1072
}
1080
}
1073
 
1081
 
1074
; Cleanup all resources allocated during parse_descr and postprocess_descr.
1082
; Cleanup all resources allocated during parse_descr and postprocess_descr.
1075
; Called when the corresponding device is disconnected
1083
; Called when the corresponding device is disconnected
1076
; with ebx = pointer to hid_data.
1084
; with ebx = pointer to hid_data.
1077
macro hid_cleanup
1085
macro hid_cleanup
1078
{
1086
{
1079
; 1. Notify all assigned drivers about disconnect.
1087
; 1. Notify all assigned drivers about disconnect.
1080
; Loop over all top-level collections and call callbacks.disconnect,
1088
; Loop over all top-level collections and call callbacks.disconnect,
1081
; if a driver is assigned.
1089
; if a driver is assigned.
1082
        mov     esi, [ebx+hid_data.first_collection]
1090
        mov     esi, [ebx+hid_data.first_collection]
1083
.notify_drivers:
1091
.notify_drivers:
1084
        test    esi, esi
1092
        test    esi, esi
1085
        jz      .notify_drivers_done
1093
        jz      .notify_drivers_done
1086
        mov     edi, [esi+collection.driver_data]
1094
        mov     edi, [esi+collection.driver_data]
1087
        test    edi, edi
1095
        test    edi, edi
1088
        jz      @f
1096
        jz      @f
1089
        call    [esi+collection.callbacks.disconnect]
1097
        call    [esi+collection.callbacks.disconnect]
1090
@@:
1098
@@:
1091
        mov     esi, [esi+collection.next]
1099
        mov     esi, [esi+collection.next]
1092
        jmp     .notify_drivers
1100
        jmp     .notify_drivers
1093
.notify_drivers_done:
1101
.notify_drivers_done:
1094
; 2. Free all collections.
1102
; 2. Free all collections.
1095
        mov     esi, [ebx+hid_data.first_collection]
1103
        mov     esi, [ebx+hid_data.first_collection]
1096
.free_collections:
1104
.free_collections:
1097
        test    esi, esi
1105
        test    esi, esi
1098
        jz      .collections_done
1106
        jz      .collections_done
1099
; If a collection has childen, make it forget about them,
1107
; If a collection has childen, make it forget about them,
1100
; kill all children; after last child is killed, return to
1108
; kill all children; after last child is killed, return to
1101
; the collection as a parent; this time, it will appear
1109
; the collection as a parent; this time, it will appear
1102
; as childless, so it will be killed after children.
1110
; as childless, so it will be killed after children.
1103
        mov     eax, [esi+collection.first_child]
1111
        mov     eax, [esi+collection.first_child]
1104
        test    eax, eax
1112
        test    eax, eax
1105
        jz      .no_children
1113
        jz      .no_children
1106
        and     [esi+collection.first_child], 0
1114
        and     [esi+collection.first_child], 0
1107
        xchg    esi, eax
1115
        xchg    esi, eax
1108
        jmp     .free_collections
1116
        jmp     .free_collections
1109
.no_children:
1117
.no_children:
1110
; If a collection has no children (maybe there were no children at all,
1118
; If a collection has no children (maybe there were no children at all,
1111
; maybe all children were already killed), kill it and proceed either to
1119
; maybe all children were already killed), kill it and proceed either to
1112
; next sibling (if any) or to the parent.
1120
; next sibling (if any) or to the parent.
1113
        mov     eax, [esi+collection.next]
1121
        mov     eax, [esi+collection.next]
1114
        test    eax, eax
1122
        test    eax, eax
1115
        jnz     @f
1123
        jnz     @f
1116
        mov     eax, [esi+collection.parent]
1124
        mov     eax, [esi+collection.parent]
1117
@@:
1125
@@:
1118
        xchg    eax, esi
1126
        xchg    eax, esi
1119
        invoke  Kfree
1127
        invoke  Kfree
1120
        jmp     .free_collections
1128
        jmp     .free_collections
1121
.collections_done:
1129
.collections_done:
1122
; 3. Free all three report sets.
1130
; 3. Free all three report sets.
1123
        push    3
1131
        push    3
1124
        lea     esi, [ebx+hid_data.input]
1132
        lea     esi, [ebx+hid_data.input]
1125
; For every report set, loop over all reports,
1133
; For every report set, loop over all reports,
1126
; for every report free all field groups, then free report itself.
1134
; for every report free all field groups, then free report itself.
1127
; When all reports in one set have been freed, free also report list table,
1135
; When all reports in one set have been freed, free also report list table,
1128
; if there is one (reports are numbered).
1136
; if there is one (reports are numbered).
1129
.report_set_loop:
1137
.report_set_loop:
1130
        mov     edi, [esi+report_set.first_report]
1138
        mov     edi, [esi+report_set.first_report]
1131
.report_loop:
1139
.report_loop:
1132
        test    edi, edi
1140
        test    edi, edi
1133
        jz      .report_done
1141
        jz      .report_done
1134
        mov     eax, [edi+report.first_field]
1142
        mov     eax, [edi+report.first_field]
1135
.field_loop:
1143
.field_loop:
1136
        test    eax, eax
1144
        test    eax, eax
1137
        jz      .field_done
1145
        jz      .field_done
1138
        push    [eax+report_field_group.next]
1146
        push    [eax+report_field_group.next]
1139
        invoke  Kfree
1147
        invoke  Kfree
1140
        pop     eax
1148
        pop     eax
1141
        jmp     .field_loop
1149
        jmp     .field_loop
1142
.field_done:
1150
.field_done:
1143
        mov     eax, [edi+report.next]
1151
        mov     eax, [edi+report.next]
1144
        xchg    eax, edi
1152
        xchg    eax, edi
1145
        invoke  Kfree
1153
        invoke  Kfree
1146
        jmp     .report_loop
1154
        jmp     .report_loop
1147
.report_done:
1155
.report_done:
1148
        cmp     [esi+report_set.numbered], 0
1156
        cmp     [esi+report_set.numbered], 0
1149
        jz      @f
1157
        jz      @f
1150
        mov     eax, [esi+report_set.data]
1158
        mov     eax, [esi+report_set.data]
1151
        invoke  Kfree
1159
        invoke  Kfree
1152
@@:
1160
@@:
1153
        add     esi, sizeof.report_set
1161
        add     esi, sizeof.report_set
1154
        dec     dword [esp]
1162
        dec     dword [esp]
1155
        jnz     .report_set_loop
1163
        jnz     .report_set_loop
1156
        pop     eax
1164
        pop     eax
1157
}
1165
}
1158
 
1166
 
1159
; Helper for parse_input. Extracts value of one field.
1167
; Helper for parse_input. Extracts value of one field.
1160
; in: esi -> report_field_group
1168
; in: esi -> report_field_group
1161
; in: eax = offset in bits from report start
1169
; in: eax = offset in bits from report start
1162
; in: report -> report data
1170
; in: report -> report data
1163
; out: edx = value
1171
; out: edx = value
1164
; Note: it can read one dword past report data.
1172
; Note: it can read one dword past report data.
1165
macro extract_field_value report
1173
macro extract_field_value report
1166
{
1174
{
1167
        mov     ecx, eax
1175
        mov     ecx, eax
1168
        shr     eax, 5
1176
        shr     eax, 5
1169
        shl     eax, 2
1177
        shl     eax, 2
1170
        add     eax, report
1178
        add     eax, report
1171
        and     ecx, 31
1179
        and     ecx, 31
1172
        mov     edx, [eax]
1180
        mov     edx, [eax]
1173
        mov     eax, [eax+4]
1181
        mov     eax, [eax+4]
1174
        shrd    edx, eax, cl
1182
        shrd    edx, eax, cl
1175
        mov     ecx, [esi+report_field_group.sign_mask]
1183
        mov     ecx, [esi+report_field_group.sign_mask]
1176
        and     ecx, edx
1184
        and     ecx, edx
1177
        and     edx, [esi+report_field_group.mask]
1185
        and     edx, [esi+report_field_group.mask]
1178
        sub     edx, ecx
1186
        sub     edx, ecx
1179
}
1187
}
1180
 
1188
 
1181
; Local variables for parse_input.
1189
; Local variables for parse_input.
1182
macro parse_input_locals
1190
macro parse_input_locals
1183
{
1191
{
1184
count_inside_group      dd      ?
1192
count_inside_group      dd      ?
1185
; Number of fields left in the current field.
1193
; Number of fields left in the current field.
1186
field_offset            dd      ?
1194
field_offset            dd      ?
1187
; Offset of the current field from report start, in bits.
1195
; Offset of the current field from report start, in bits.
1188
field_range_size                dd      ?
1196
field_range_size                dd      ?
1189
; Size of range with valid values, Logical Maximum - Logical Minimum + 1.
1197
; Size of range with valid values, Logical Maximum - Logical Minimum + 1.
1190
cur_usage               dd      ?
1198
cur_usage               dd      ?
1191
; Pointer to current usage for Variable field groups.
1199
; Pointer to current usage for Variable field groups.
1192
num_values              dd      ?
1200
num_values              dd      ?
1193
; Number of values in the current instantiation of Array field group.
1201
; Number of values in the current instantiation of Array field group.
1194
values_base             dd      ?
1202
values_base             dd      ?
1195
; Pointer to memory allocated for array with current values.
1203
; Pointer to memory allocated for array with current values.
1196
values_prev             dd      ?
1204
values_prev             dd      ?
1197
; Pointer to memory allocated for array with previous values.
1205
; Pointer to memory allocated for array with previous values.
1198
values_cur_ptr          dd      ?
1206
values_cur_ptr          dd      ?
1199
; Pointer to the next value in [values_base] array.
1207
; Pointer to the next value in [values_base] array.
1200
values_end              dd      ?
1208
values_end              dd      ?
1201
; End of data in array with current values.
1209
; End of data in array with current values.
1202
values_prev_ptr         dd      ?
1210
values_prev_ptr         dd      ?
1203
; Pointer to the next value in [values_prev_ptr] array.
1211
; Pointer to the next value in [values_prev_ptr] array.
1204
values_prev_end         dd      ?
1212
values_prev_end         dd      ?
1205
; End of data in array with previous values.
1213
; End of data in array with previous values.
1206
}
1214
}
1207
 
1215
 
1208
; Parse input report. The caller should provide esi = pointer to report,
1216
; Parse input report. The caller should provide esi = pointer to report,
1209
; local variables parse_input_locals and [buffer] = report data.
1217
; local variables parse_input_locals and [buffer] = report data.
1210
macro parse_input
1218
macro parse_input
1211
{
1219
{
1212
; 1. Ignore the report if there is no driver for it.
1220
; 1. Ignore the report if there is no driver for it.
1213
        mov     ebx, [esi+report.top_level_collection]
1221
        mov     ebx, [esi+report.top_level_collection]
1214
        mov     edi, [ebx+collection.driver_data]
1222
        mov     edi, [ebx+collection.driver_data]
1215
        test    edi, edi
1223
        test    edi, edi
1216
        jz      .done
1224
        jz      .done
1217
; 2. Notify the driver that a new packet arrived.
1225
; 2. Notify the driver that a new packet arrived.
1218
        call    [ebx+collection.callbacks.begin_packet]
1226
        call    [ebx+collection.callbacks.begin_packet]
1219
; Loop over all field groups.
1227
; Loop over all field groups.
1220
; Report without fields is meaningless, but theoretically possible:
1228
; Report without fields is meaningless, but theoretically possible:
1221
; parse_descr does not create reports of zero size, but
1229
; parse_descr does not create reports of zero size, but
1222
; a report can consist of "padding" fields without usages and have
1230
; a report can consist of "padding" fields without usages and have
1223
; no real fields.
1231
; no real fields.
1224
        mov     esi, [esi+report.first_field]
1232
        mov     esi, [esi+report.first_field]
1225
        test    esi, esi
1233
        test    esi, esi
1226
        jz      .packet_processed
1234
        jz      .packet_processed
1227
.field_loop:
1235
.field_loop:
1228
; 3. Prepare for group handling: initialize field offset, fields count
1236
; 3. Prepare for group handling: initialize field offset, fields count
1229
; and size of range for valid values.
1237
; and size of range for valid values.
1230
        mov     eax, [esi+report_field_group.offset]
1238
        mov     eax, [esi+report_field_group.offset]
1231
        mov     [field_offset], eax
1239
        mov     [field_offset], eax
1232
        mov     ecx, [esi+report_field_group.count]
1240
        mov     ecx, [esi+report_field_group.count]
1233
        mov     [count_inside_group], ecx
1241
        mov     [count_inside_group], ecx
1234
        mov     eax, [esi+report_field_group.logical_maximum]
1242
        mov     eax, [esi+report_field_group.logical_maximum]
1235
        inc     eax
1243
        inc     eax
1236
        sub     eax, [esi+report_field_group.logical_minimum]
1244
        sub     eax, [esi+report_field_group.logical_minimum]
1237
        mov     [field_range_size], eax
1245
        mov     [field_range_size], eax
1238
; 4. Select handler. Variable and Array groups are handled entirely differently;
1246
; 4. Select handler. Variable and Array groups are handled entirely differently;
1239
; for Variable groups, advance to 5, for Array groups, go to 6.
1247
; for Variable groups, advance to 5, for Array groups, go to 6.
1240
        test    byte [esi+report_field_group.flags], HID_FIELD_VARIABLE
1248
        test    byte [esi+report_field_group.flags], HID_FIELD_VARIABLE
1241
        jz      .array_field
1249
        jz      .array_field
1242
; 5. Variable groups. They are simple. Loop over all .count fields,
1250
; 5. Variable groups. They are simple. Loop over all .count fields,
1243
; for every field extract the value and get the next usage,
1251
; for every field extract the value and get the next usage,
1244
; if the value is within valid range, call the driver.
1252
; if the value is within valid range, call the driver.
1245
        lea     eax, [esi+report_field_group.common_sizeof]
1253
        lea     eax, [esi+report_field_group.common_sizeof]
1246
        mov     [cur_usage], eax
1254
        mov     [cur_usage], eax
1247
.variable_data_loop:
1255
.variable_data_loop:
1248
        mov     eax, [field_offset]
1256
        mov     eax, [field_offset]
1249
        extract_field_value [buffer]    ; -> edx
1257
        extract_field_value [buffer]    ; -> edx
1250
        mov     ecx, [cur_usage]
1258
        mov     ecx, [cur_usage]
1251
        mov     ecx, [ecx]
1259
        mov     ecx, [ecx]
1252
        call    [ebx+collection.callbacks.input_field]
1260
        call    [ebx+collection.callbacks.input_field]
1253
        add     [cur_usage], 4
1261
        add     [cur_usage], 4
1254
        mov     eax, [esi+report_field_group.size]
1262
        mov     eax, [esi+report_field_group.size]
1255
        add     [field_offset], eax
1263
        add     [field_offset], eax
1256
        dec     [count_inside_group]
1264
        dec     [count_inside_group]
1257
        jnz     .variable_data_loop
1265
        jnz     .variable_data_loop
1258
; Variable group is processed; go to 12.
1266
; Variable group is processed; go to 12.
1259
        jmp     .field_done
1267
        jmp     .field_done
1260
.array_field:
1268
.array_field:
1261
; Array groups. They are complicated.
1269
; Array groups. They are complicated.
1262
; 6. Array group: extract all values in one array.
1270
; 6. Array group: extract all values in one array.
1263
; memory was allocated during group creation, use it
1271
; memory was allocated during group creation, use it
1264
; 6a. Prepare: get data pointer, initialize num_values with zero.
1272
; 6a. Prepare: get data pointer, initialize num_values with zero.
1265
        mov     eax, [esi+report_field_group.num_usage_ranges]
1273
        mov     eax, [esi+report_field_group.num_usage_ranges]
1266
        lea     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+4]
1274
        lea     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+4]
1267
        mov     eax, [esi+report_field_group.count]
1275
        mov     eax, [esi+report_field_group.count]
1268
        mov     [values_cur_ptr], edx
1276
        mov     [values_cur_ptr], edx
1269
        mov     [values_base], edx
1277
        mov     [values_base], edx
1270
        lea     edx, [edx+ecx*4]
1278
        lea     edx, [edx+ecx*4]
1271
        mov     [values_prev], edx
1279
        mov     [values_prev], edx
1272
        mov     [values_prev_ptr], edx
1280
        mov     [values_prev_ptr], edx
1273
        mov     [num_values], 0
1281
        mov     [num_values], 0
1274
; 6b. Start loop for every field. Note that there must be at least one field,
1282
; 6b. Start loop for every field. Note that there must be at least one field,
1275
; parse_descr does not allow .count == 0.
1283
; parse_descr does not allow .count == 0.
1276
.array_getval_loop:
1284
.array_getval_loop:
1277
; 6c. Extract the value of the current field.
1285
; 6c. Extract the value of the current field.
1278
        mov     eax, [field_offset]
1286
        mov     eax, [field_offset]
1279
        extract_field_value [buffer]    ; -> edx
1287
        extract_field_value [buffer]    ; -> edx
1280
; 6d. Transform the value to the usage with binary search in array of
1288
; 6d. Transform the value to the usage with binary search in array of
1281
; usage_ranges. started at [esi+report_field_group.usages]
1289
; usage_ranges. started at [esi+report_field_group.usages]
1282
; having [esi+report_field_group.num_usage_ranges] items.
1290
; having [esi+report_field_group.num_usage_ranges] items.
1283
; Ignore items outside of valid range.
1291
; Ignore items outside of valid range.
1284
        sub     edx, [esi+report_field_group.logical_minimum]
1292
        sub     edx, [esi+report_field_group.logical_minimum]
1285
        cmp     edx, [field_range_size]
1293
        cmp     edx, [field_range_size]
1286
        jae     .array_skip_item
1294
        jae     .array_skip_item
1287
; If there are too few usages, use last of them.
1295
; If there are too few usages, use last of them.
1288
        mov     ecx, [esi+report_field_group.num_usage_ranges]  ; upper bound
1296
        mov     ecx, [esi+report_field_group.num_usage_ranges]  ; upper bound
1289
        xor     eax, eax        ; lower bound
1297
        xor     eax, eax        ; lower bound
1290
        cmp     edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset]
1298
        cmp     edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset]
1291
        jae     .array_last_usage
1299
        jae     .array_last_usage
1292
; loop invariant: usages[eax].offset <= edx < usages[ecx].offset
1300
; loop invariant: usages[eax].offset <= edx < usages[ecx].offset
1293
.array_find_usage:
1301
.array_find_usage:
1294
        lea     edi, [eax+ecx]
1302
        lea     edi, [eax+ecx]
1295
        shr     edi, 1
1303
        shr     edi, 1
1296
        cmp     edi, eax
1304
        cmp     edi, eax
1297
        jz      .array_found_usage_range
1305
        jz      .array_found_usage_range
1298
        cmp     edx, [esi+report_field_group.usages+edi*sizeof.usage_range+usage_range.offset]
1306
        cmp     edx, [esi+report_field_group.usages+edi*sizeof.usage_range+usage_range.offset]
1299
        jae     .update_low
1307
        jae     .update_low
1300
        mov     ecx, edi
1308
        mov     ecx, edi
1301
        jmp     .array_find_usage
1309
        jmp     .array_find_usage
1302
.update_low:
1310
.update_low:
1303
        mov     eax, edi
1311
        mov     eax, edi
1304
        jmp     .array_find_usage
1312
        jmp     .array_find_usage
1305
.array_last_usage:
1313
.array_last_usage:
1306
        lea     eax, [ecx-1]
1314
        lea     eax, [ecx-1]
1307
        mov     edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset]
1315
        mov     edx, [esi+report_field_group.usages+ecx*sizeof.usage_range+usage_range.offset]
1308
        dec     edx
1316
        dec     edx
1309
.array_found_usage_range:
1317
.array_found_usage_range:
1310
        sub     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.offset]
1318
        sub     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.offset]
1311
        add     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.first_usage]
1319
        add     edx, [esi+report_field_group.usages+eax*sizeof.usage_range+usage_range.first_usage]
1312
; 6e. Store the usage, advance data pointer, continue loop started at 6b.
1320
; 6e. Store the usage, advance data pointer, continue loop started at 6b.
1313
        mov     eax, [values_cur_ptr]
1321
        mov     eax, [values_cur_ptr]
1314
        mov     [eax], edx
1322
        mov     [eax], edx
1315
        add     [values_cur_ptr], 4
1323
        add     [values_cur_ptr], 4
1316
        inc     [num_values]
1324
        inc     [num_values]
1317
.array_skip_item:
1325
.array_skip_item:
1318
        mov     eax, [esi+report_field_group.size]
1326
        mov     eax, [esi+report_field_group.size]
1319
        add     [field_offset], eax
1327
        add     [field_offset], eax
1320
        dec     [count_inside_group]
1328
        dec     [count_inside_group]
1321
        jnz     .array_getval_loop
1329
        jnz     .array_getval_loop
1322
; 7. Array group: ask driver about array overflow.
1330
; 7. Array group: ask driver about array overflow.
1323
; If driver says that the array is invalid, stop processing this group
1331
; If driver says that the array is invalid, stop processing this group
1324
; (in particular, do not update previous values).
1332
; (in particular, do not update previous values).
1325
        mov     ecx, [num_values]
1333
        mov     ecx, [num_values]
1326
        test    ecx, ecx
1334
        test    ecx, ecx
1327
        jz      .duplicates_removed
1335
        jz      .duplicates_removed
1328
        mov     edx, [values_base]
1336
        mov     edx, [values_base]
1329
        mov     edi, [ebx+collection.driver_data]
1337
        mov     edi, [ebx+collection.driver_data]
1330
        call    [ebx+collection.callbacks.array_overflow?]
1338
        call    [ebx+collection.callbacks.array_overflow?]
1331
        jnc     .field_done
1339
        jnc     .field_done
1332
; 8. Array group: sort the array with current values.
1340
; 8. Array group: sort the array with current values.
1333
        push    esi
1341
        push    esi
1334
        mov     ecx, [num_values]
1342
        mov     ecx, [num_values]
1335
        mov     edx, [values_base]
1343
        mov     edx, [values_base]
1336
        call    sort
1344
        call    sort
1337
        pop     esi
1345
        pop     esi
1338
; 9. Array group: remove duplicates.
1346
; 9. Array group: remove duplicates.
1339
        cmp     [num_values], 1
1347
        cmp     [num_values], 1
1340
        jbe     .duplicates_removed
1348
        jbe     .duplicates_removed
1341
        mov     eax, [values_base]
1349
        mov     eax, [values_base]
1342
        mov     edx, [eax]
1350
        mov     edx, [eax]
1343
        add     eax, 4
1351
        add     eax, 4
1344
        mov     ecx, eax
1352
        mov     ecx, eax
1345
.duplicates_loop:
1353
.duplicates_loop:
1346
        cmp     edx, [eax]
1354
        cmp     edx, [eax]
1347
        jz      @f
1355
        jz      @f
1348
        mov     edx, [eax]
1356
        mov     edx, [eax]
1349
        mov     [ecx], edx
1357
        mov     [ecx], edx
1350
        add     ecx, 4
1358
        add     ecx, 4
1351
@@:
1359
@@:
1352
        add     eax, 4
1360
        add     eax, 4
1353
        cmp     eax, [values_cur_ptr]
1361
        cmp     eax, [values_cur_ptr]
1354
        jb      .duplicates_loop
1362
        jb      .duplicates_loop
1355
        mov     [values_cur_ptr], ecx
1363
        mov     [values_cur_ptr], ecx
1356
        sub     ecx, [values_base]
1364
        sub     ecx, [values_base]
1357
        shr     ecx, 2
1365
        shr     ecx, 2
1358
        mov     [num_values], ecx
1366
        mov     [num_values], ecx
1359
.duplicates_removed:
1367
.duplicates_removed:
1360
; 10. Array group: compare current and previous values,
1368
; 10. Array group: compare current and previous values,
1361
; call driver for differences.
1369
; call driver for differences.
1362
        mov     edi, [ebx+collection.driver_data]
1370
        mov     edi, [ebx+collection.driver_data]
1363
        mov     eax, [values_cur_ptr]
1371
        mov     eax, [values_cur_ptr]
1364
        mov     [values_end], eax
1372
        mov     [values_end], eax
1365
        mov     eax, [values_base]
1373
        mov     eax, [values_base]
1366
        mov     [values_cur_ptr], eax
1374
        mov     [values_cur_ptr], eax
1367
        mov     eax, [esi+report_field_group.num_values_prev]
1375
        mov     eax, [esi+report_field_group.num_values_prev]
1368
        shl     eax, 2
1376
        shl     eax, 2
1369
        add     eax, [values_prev]
1377
        add     eax, [values_prev]
1370
        mov     [values_prev_end], eax
1378
        mov     [values_prev_end], eax
1371
.find_common:
1379
.find_common:
1372
        mov     eax, [values_cur_ptr]
1380
        mov     eax, [values_cur_ptr]
1373
        cmp     eax, [values_end]
1381
        cmp     eax, [values_end]
1374
        jae     .cur_done
1382
        jae     .cur_done
1375
        mov     ecx, [eax]
1383
        mov     ecx, [eax]
1376
        mov     eax, [values_prev_ptr]
1384
        mov     eax, [values_prev_ptr]
1377
        cmp     eax, [values_prev_end]
1385
        cmp     eax, [values_prev_end]
1378
        jae     .prev_done
1386
        jae     .prev_done
1379
        mov     edx, [eax]
1387
        mov     edx, [eax]
1380
        cmp     ecx, edx
1388
        cmp     ecx, edx
1381
        jb      .advance_cur
1389
        jb      .advance_cur
1382
        ja      .advance_prev
1390
        ja      .advance_prev
1383
; common item in both arrays; ignore
1391
; common item in both arrays; ignore
1384
        add     [values_cur_ptr], 4
1392
        add     [values_cur_ptr], 4
1385
        add     [values_prev_ptr], 4
1393
        add     [values_prev_ptr], 4
1386
        jmp     .find_common
1394
        jmp     .find_common
1387
.advance_cur:
1395
.advance_cur:
1388
; item is present in current array but not in previous;
1396
; item is present in current array but not in previous;
1389
; call the driver with value = 1
1397
; call the driver with value = 1
1390
        add     [values_cur_ptr], 4
1398
        add     [values_cur_ptr], 4
1391
        mov     edx, 1
1399
        mov     edx, 1
1392
        call    [ebx+collection.callbacks.input_field]
1400
        call    [ebx+collection.callbacks.input_field]
1393
        jmp     .find_common
1401
        jmp     .find_common
1394
.advance_prev:
1402
.advance_prev:
1395
; item is present in previous array but not in current;
1403
; item is present in previous array but not in current;
1396
; call the driver with value = 0
1404
; call the driver with value = 0
1397
        add     [values_prev_ptr], 4
1405
        add     [values_prev_ptr], 4
1398
        mov     ecx, edx
1406
        mov     ecx, edx
1399
        xor     edx, edx
1407
        xor     edx, edx
1400
        call    [ebx+collection.callbacks.input_field]
1408
        call    [ebx+collection.callbacks.input_field]
1401
        jmp     .find_common
1409
        jmp     .find_common
1402
.prev_done:
1410
.prev_done:
1403
; for all items which are left in current array
1411
; for all items which are left in current array
1404
; call the driver with value = 1
1412
; call the driver with value = 1
1405
        mov     eax, [values_cur_ptr]
1413
        mov     eax, [values_cur_ptr]
1406
@@:
1414
@@:
1407
        add     [values_cur_ptr], 4
1415
        add     [values_cur_ptr], 4
1408
        mov     ecx, [eax]
1416
        mov     ecx, [eax]
1409
        mov     edx, 1
1417
        mov     edx, 1
1410
        call    [ebx+collection.callbacks.input_field]
1418
        call    [ebx+collection.callbacks.input_field]
1411
        mov     eax, [values_cur_ptr]
1419
        mov     eax, [values_cur_ptr]
1412
        cmp     eax, [values_end]
1420
        cmp     eax, [values_end]
1413
        jb      @b
1421
        jb      @b
1414
        jmp     .copy_array
1422
        jmp     .copy_array
1415
.cur_done:
1423
.cur_done:
1416
; for all items which are left in previous array
1424
; for all items which are left in previous array
1417
; call the driver with value = 0
1425
; call the driver with value = 0
1418
        mov     eax, [values_prev_ptr]
1426
        mov     eax, [values_prev_ptr]
1419
        add     [values_prev_ptr], 4
1427
        add     [values_prev_ptr], 4
1420
        cmp     eax, [values_prev_end]
1428
        cmp     eax, [values_prev_end]
1421
        jae     @f
1429
        jae     @f
1422
        mov     ecx, [eax]
1430
        mov     ecx, [eax]
1423
        xor     edx, edx
1431
        xor     edx, edx
1424
        call    [ebx+collection.callbacks.input_field]
1432
        call    [ebx+collection.callbacks.input_field]
1425
        jmp     .cur_done
1433
        jmp     .cur_done
1426
@@:
1434
@@:
1427
.copy_array:
1435
.copy_array:
1428
; 11. Array group: copy current values to previous values.
1436
; 11. Array group: copy current values to previous values.
1429
        push    esi edi
1437
        push    esi edi
1430
        mov     ecx, [num_values]
1438
        mov     ecx, [num_values]
1431
        mov     [esi+report_field_group.num_values_prev], ecx
1439
        mov     [esi+report_field_group.num_values_prev], ecx
1432
        mov     esi, [values_base]
1440
        mov     esi, [values_base]
1433
        mov     edi, [values_prev]
1441
        mov     edi, [values_prev]
1434
        rep movsd
1442
        rep movsd
1435
        pop     edi esi
1443
        pop     edi esi
1436
; 12. Field group is processed. Repeat with the next group, if any.
1444
; 12. Field group is processed. Repeat with the next group, if any.
1437
.field_done:
1445
.field_done:
1438
        mov     esi, [esi+report_field_group.next]
1446
        mov     esi, [esi+report_field_group.next]
1439
        test    esi, esi
1447
        test    esi, esi
1440
        jnz     .field_loop
1448
        jnz     .field_loop
1441
.packet_processed:
1449
.packet_processed:
1442
; 13. Packet is processed, notify the driver.
1450
; 13. Packet is processed, notify the driver.
1443
        call    [ebx+collection.callbacks.end_packet]
1451
        call    [ebx+collection.callbacks.end_packet]
1444
}
1452
}