Subversion Repositories Kolibri OS

Rev

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

  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. }
  1443.