Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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