Subversion Repositories Kolibri OS

Rev

Rev 5051 | Details | Compare with Previous | Last modification | View Log | RSS feed

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