; HID mouse driver, part of USBHID driver. ; Global constants. ; They are assembled in a macro to separate code and data; ; the code is located at the point of "include 'mouse.inc'", ; the data are collected when workers_globals is instantiated. macro workers_globals { ; include global constants from previous workers workers_globals align 4 ; Callbacks for HID layer. mouse_driver: dd mouse_driver_add_device dd mouse_driver_disconnect dd mouse_driver_begin_packet dd mouse_driver_array_overflow? dd mouse_driver_input_field dd mouse_driver_end_packet } ; Data that are specific for one mouse device. struct mouse_device_data buttons dd ? ; buttons that are currently pressed dx dd ? ; current x moving dy dd ? ; current y moving wheel dd ? ; current wheel moving hwheel dd ? ends ; This procedure is called when HID layer detects a new mouse. ; in: ebx -> device_data from USB layer, edi -> collection ; out: eax = device-specific data or NULL on error proc mouse_driver_add_device ; Get screen resolution so we can calculate absolute coordinates. mov eax, 14 int 0x40 mov [screen_y], eax and [screen_y], 0xffff shr eax, 16 mov [screen_x], eax ; Just allocate memory; no initialization needed. movi eax, sizeof.mouse_device_data call Kmalloc ret endp ; This procedure is called when HID layer detects disconnect of a previously ; connected mouse. ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) proc mouse_driver_disconnect ; Free the allocated memory. mov eax, edi call Kfree ret endp ; This procedure is called when HID layer starts processing a new input packet ; from a mouse. ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) proc mouse_driver_begin_packet ; Zero all variables describing the current state. mov [edi+mouse_device_data.buttons], 0 mov [edi+mouse_device_data.dx], 0 mov [edi+mouse_device_data.dy], 0 mov [edi+mouse_device_data.wheel], 0 mov [edi+mouse_device_data.hwheel], 0 ret endp ; This procedure is called when HID layer processes every non-empty array field group. ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) ; in: ecx = fields count (always nonzero), edx = pointer to fields values ; in: esi -> report_field_group ; out: CF set => array is ok, CF cleared => array should be ignored proc mouse_driver_array_overflow? ; no array fields, no overflows stc ret endp ; This procedure is called from HID layer for every field. ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) ; in: ecx = field usage, edx = value, esi -> report_field_group proc mouse_driver_input_field ; 1. Determine the handler. We process x/y moving, wheel and up to 32 buttons. ; Pass other fields to the default handler - default_driver_input_field if ; HID_DUMP_UNCLAIMED is enabled, just ignore otherwise. cmp ecx, USAGE_GD_X jz .x cmp ecx, USAGE_GD_Y jz .y cmp ecx, USAGE_GD_WHEEL jz .wheel cmp ecx, 0xC0238 jz .hwheel sub ecx, USAGE_BUTTON_PAGE + 1 jb .unclaimed cmp ecx, 32 jae .unclaimed ; 2. This is a button. ; If a button is pressed, set the corresponding bit in the state. ; If a button is not pressed, do nothing. test edx, edx jz @f bts [edi+mouse_device_data.buttons], ecx @@: if ~HID_DUMP_UNCLAIMED .unclaimed: end if ret if HID_DUMP_UNCLAIMED .unclaimed: add ecx, USAGE_BUTTON_PAGE + 1 jmp default_driver_input_field end if .x: ; 3. This is x moving. For relative fields, store the value in the state. ; Pass absolute field to the default handler. test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE jz .relative_x mov [edi+mouse_device_data.dx], edx ret .y: ; 4. This is y moving. For relative fields, store the value in the state, ; changing the sign: HID uses "mathematics" scheme with Y axis increasing from ; bottom to top, the kernel expects "programming" PS/2-style with Y axis ; increasing from top to bottom. ; Pass absolute fields to the default handler. test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE jz .relative_y neg edx mov [edi+mouse_device_data.dy], edx ret .wheel: ; 5. This is wheel event. For relative fields, store the value in the state, ; changing the sign. Pass absolute fields to the default handler. test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE jz .unclaimed neg edx mov [edi+mouse_device_data.wheel], edx ret .hwheel: test byte [esi+report_field_group.flags], HID_FIELD_RELATIVE jz .unclaimed mov [edi+mouse_device_data.hwheel], edx ret .relative_x: push ebx mov eax, [screen_x] mul edx mov ebx, 0x8000 div ebx mov [edi+mouse_device_data.dx], eax or [edi+mouse_device_data.buttons], 0x80000000 pop ebx ret .relative_y: push ebx mov eax, [screen_y] mul edx mov ebx, 0x8000 div ebx mov [edi+mouse_device_data.dy], eax or [edi+mouse_device_data.buttons], 0x40000000 pop ebx ret endp ; This procedure is called when HID layer ends processing a new input packet ; from a mouse. ; in: edi -> mouse_device_data (pointer returned from mouse_driver_add_device) proc mouse_driver_end_packet ; Call the kernel, passing collected state. stdcall SetMouseData, \ [edi+mouse_device_data.buttons], \ [edi+mouse_device_data.dx], \ [edi+mouse_device_data.dy], \ [edi+mouse_device_data.wheel], \ [edi+mouse_device_data.hwheel] ret endp