Subversion Repositories Kolibri OS

Rev

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

  1. ; standard driver stuff
  2. format MS COFF
  3.  
  4. DEBUG = 1
  5.  
  6. ; this is for DEBUGF macro from 'fdo.inc'
  7. __DEBUG__ = 1
  8. __DEBUG_LEVEL__ = 1
  9.  
  10. include 'proc32.inc'
  11. include 'imports.inc'
  12. include 'fdo.inc'
  13.  
  14. public START
  15. public version
  16.  
  17. ; USB constants
  18. DEVICE_DESCR_TYPE = 1
  19. CONFIG_DESCR_TYPE = 2
  20. STRING_DESCR_TYPE = 3
  21. INTERFACE_DESCR_TYPE = 4
  22. ENDPOINT_DESCR_TYPE = 5
  23. DEVICE_QUALIFIER_DESCR_TYPE = 6
  24.  
  25. CONTROL_PIPE = 0
  26. ISOCHRONOUS_PIPE = 1
  27. BULK_PIPE = 2
  28. INTERRUPT_PIPE = 3
  29.  
  30. ; USB structures
  31. virtual at 0
  32. config_descr:
  33. .bLength                db      ?
  34. .bDescriptorType        db      ?
  35. .wTotalLength           dw      ?
  36. .bNumInterfaces         db      ?
  37. .bConfigurationValue    db      ?
  38. .iConfiguration         db      ?
  39. .bmAttributes           db      ?
  40. .bMaxPower              db      ?
  41. .sizeof:
  42. end virtual
  43.  
  44. virtual at 0
  45. interface_descr:
  46. .bLength                db      ?
  47. .bDescriptorType        db      ?
  48. .bInterfaceNumber       db      ?
  49. .bAlternateSetting      db      ?
  50. .bNumEndpoints          db      ?
  51. .bInterfaceClass        db      ?
  52. .bInterfaceSubClass     db      ?
  53. .bInterfaceProtocol     db      ?
  54. .iInterface             db      ?
  55. .sizeof:
  56. end virtual
  57.  
  58. virtual at 0
  59. endpoint_descr:
  60. .bLength                db      ?
  61. .bDescriptorType        db      ?
  62. .bEndpointAddress       db      ?
  63. .bmAttributes           db      ?
  64. .wMaxPacketSize         dw      ?
  65. .bInterval              db      ?
  66. .sizeof:
  67. end virtual
  68.  
  69. ; Driver data for all devices
  70. virtual at 0
  71. device_data:
  72. .type           dd      ?       ; 1 = keyboard, 2 = mouse
  73. .intpipe        dd      ?       ; interrupt pipe handle
  74. .packetsize     dd      ?
  75. .packet         rb      8       ; packet with data from device
  76. .control        rb      8       ; control packet to device
  77. .sizeof:
  78. end virtual
  79.  
  80. ; Driver data for mouse
  81. virtual at device_data.sizeof
  82. mouse_data:
  83. ; no additional data
  84. .sizeof:
  85. end virtual
  86.  
  87. ; Driver data for keyboard
  88. virtual at device_data.sizeof
  89. keyboard_data:
  90. .handle         dd      ?       ; keyboard handle from RegKeyboard
  91. .configpipe     dd      ?       ; config pipe handle
  92. .prevpacket     rb      8       ; previous packet with data from device
  93. .timer          dd      ?       ; auto-repeat timer handle
  94. .repeatkey      db      ?       ; auto-repeat key code
  95. .ledstate       db      ?       ; state of LEDs
  96.                 align 4
  97. .sizeof:
  98. end virtual
  99.  
  100. section '.flat' code readable align 16
  101. ; The start procedure.
  102. START:
  103. ; 1. Test whether the procedure is called with the argument DRV_ENTRY.
  104. ; If not, return 0.
  105.         xor     eax, eax        ; initialize return value
  106.         cmp     dword [esp+4], 1        ; compare the argument
  107.         jnz     .nothing
  108. ; 2. Register self as a USB driver.
  109. ; The name is my_driver = 'usbhid'; IOCTL interface is not supported;
  110. ; usb_functions is an offset of a structure with callback functions.
  111.         stdcall RegUSBDriver, my_driver, eax, usb_functions
  112. ; 3. Return the returned value of RegUSBDriver.
  113. .nothing:
  114.         ret     4
  115.  
  116. ; This procedure is called when new HID device is detected.
  117. ; It initializes the device.
  118. AddDevice:
  119. ; Arguments are addressed through esp. In this point of the function,
  120. ; [esp+4] = a handle of the config pipe, [esp+8] points to config_descr
  121. ; structure, [esp+12] points to interface_descr structure.
  122. ; 1. Check device type. Currently only mice and keyboards with
  123. ; boot protocol are supported.
  124. ; 1a. Get the subclass and the protocol. Since bInterfaceSubClass and
  125. ; bInterfaceProtocol are subsequent in interface_descr, just one
  126. ; memory reference is used for both.
  127.         mov     edx, [esp+12]
  128.         push    ebx     ; save used register to be stdcall
  129.         mov     cx, word [edx+interface_descr.bInterfaceSubClass]
  130. ; 1b. For boot protocol, subclass must be 1 and protocol must be either 1 for
  131. ; a keyboard or 2 for a mouse. Check.
  132.         cmp     cx, 0x0101
  133.         jz      .keyboard
  134.         cmp     cx, 0x0201
  135.         jz      .mouse
  136. ; 1c. If the device is neither a keyboard nor a mouse, print a message and
  137. ; go to 6c.
  138.         DEBUGF 1,'K : unknown HID device\n'
  139.         jmp     .nothing
  140. ; 1d. If the device is a keyboard or a mouse, print a message and continue
  141. ; configuring.
  142. .keyboard:
  143.         DEBUGF 1,'K : USB keyboard detected\n'
  144.         push    keyboard_data.sizeof
  145.         jmp     .common
  146. .mouse:
  147.         DEBUGF 1,'K : USB mouse detected\n'
  148.         push    mouse_data.sizeof
  149. .common:
  150. ; 2. Allocate memory for device data.
  151.         pop     eax     ; get size of device data
  152. ; 2a. Call the kernel, saving and restoring register edx.
  153.         push    edx
  154.         call    Kmalloc
  155.         pop     edx
  156. ; 2b. Check result. If failed, say a message and go to 6c.
  157.         test    eax, eax
  158.         jnz     @f
  159.         DEBUGF 1,'K : no memory\n'
  160.         jmp     .nothing
  161. @@:
  162.         xchg    eax, ebx
  163. ; HID devices use one IN interrupt endpoint for polling the device
  164. ; and an optional OUT interrupt endpoint. We do not use the later,
  165. ; but must locate the first. Look for the IN interrupt endpoint.
  166. ; 3. Get the upper bound of all descriptors' data.
  167.         mov     eax, [esp+8+4]  ; configuration descriptor
  168.         movzx   ecx, [eax+config_descr.wTotalLength]
  169.         add     eax, ecx
  170. ; 4. Loop over all descriptors until
  171. ; either end-of-data reached - this is fail
  172. ; or interface descriptor found - this is fail, all further data
  173. ;    correspond to that interface
  174. ; or endpoint descriptor found.
  175. ; 4a. Loop start: eax points to the interface descriptor.
  176. .lookep:
  177. ; 4b. Get next descriptor.
  178.         movzx   ecx, byte [edx] ; the first byte of all descriptors is length
  179.         add     edx, ecx
  180. ; 4c. Check that at least two bytes are readable. The opposite is an error.
  181.         inc     edx
  182.         cmp     edx, eax
  183.         jae     .errorep
  184.         dec     edx
  185. ; 4d. Check that this descriptor is not interface descriptor. The opposite is
  186. ; an error.
  187.         cmp     byte [edx+endpoint_descr.bDescriptorType], INTERFACE_DESCR_TYPE
  188.         jz      .errorep
  189. ; 4e. Test whether this descriptor is an endpoint descriptor. If not, continue
  190. ; the loop.
  191.         cmp     byte [edx+endpoint_descr.bDescriptorType], ENDPOINT_DESCR_TYPE
  192.         jnz     .lookep
  193. ; 5. Check that the descriptor contains all required data and all data are
  194. ; readable. If so, proceed to 7.
  195.         cmp     byte [edx+endpoint_descr.bLength], endpoint_descr.sizeof
  196.         jb      .errorep
  197.         sub     eax, endpoint_descr.sizeof
  198.         cmp     edx, eax
  199.         jbe     @f
  200. ; 6. An error occured during processing endpoint descriptor.
  201. .errorep:
  202. ; 6a. Print a message.
  203.         DEBUGF 1,'K : error: invalid endpoint descriptor\n'
  204. ; 6b. Free memory allocated for device data.
  205. .free:
  206.         xchg    eax, ebx
  207.         call    Kfree
  208. .nothing:
  209. ; 6c. Return an error.
  210.         xor     eax, eax
  211.         pop     ebx
  212.         ret     12
  213. @@:
  214. ; 7. Check that the endpoint is IN interrupt endpoint. If not, go to 6.
  215.         test    [edx+endpoint_descr.bEndpointAddress], 80h
  216.         jz      .errorep
  217.         mov     cl, [edx+endpoint_descr.bmAttributes]
  218.         and     cl, 3
  219.         cmp     cl, INTERRUPT_PIPE
  220.         jnz     .errorep
  221. ; 8. Open pipe for the endpoint.
  222. ; 8a. Load parameters from the descriptor.
  223.         movzx   ecx, [edx+endpoint_descr.bEndpointAddress]
  224.         movzx   eax, [edx+endpoint_descr.bInterval]
  225.         movzx   edx, [edx+endpoint_descr.wMaxPacketSize]
  226. ; 8b. Call the kernel, saving and restoring edx.
  227.         push    edx
  228.         stdcall USBOpenPipe, [esp+4+24], ecx, edx, INTERRUPT_PIPE, eax
  229.         pop     edx
  230. ; 8c. Check result. If failed, go to 6b.
  231.         test    eax, eax
  232.         jz      .free
  233. ; We use 12 bytes for device type, interrupt pipe and interrupt packet size,
  234. ; 8 bytes for a packet and 8 bytes for previous packet, used by a keyboard.
  235. ; 9. Initialize device data.
  236.         mov     [ebx+device_data.intpipe], eax
  237.         movi    ecx, 8
  238.         cmp     edx, ecx
  239.         jb      @f
  240.         mov     edx, ecx
  241. @@:
  242.         xor     eax, eax
  243.         mov     [ebx+device_data.packetsize], edx
  244.         mov     dword [ebx+device_data.packet], eax
  245.         mov     dword [ebx+device_data.packet+4], eax
  246.         mov     edx, [esp+12+4] ; interface descriptor
  247.         movzx   ecx, [edx+interface_descr.bInterfaceProtocol]
  248.         mov     [ebx+device_data.type], ecx
  249.         cmp     ecx, 1
  250.         jnz     @f
  251.         mov     [ebx+keyboard_data.handle], eax
  252.         mov     [ebx+keyboard_data.timer], eax
  253.         mov     [ebx+keyboard_data.repeatkey], al
  254.         mov     dword [ebx+keyboard_data.prevpacket], eax
  255.         mov     dword [ebx+keyboard_data.prevpacket+4], eax
  256.         mov     eax, [esp+4+4]
  257.         mov     [ebx+keyboard_data.configpipe], eax
  258. @@:
  259. ; 10. Send the control packet SET_PROTOCOL(Boot Protocol) to the interface.
  260.         lea     eax, [ebx+device_data.control]
  261.         mov     dword [eax], 21h + (0Bh shl 8) + (0 shl 16)     ; class request to interface + SET_PROTOCOL + Boot protocol
  262.         and     dword [eax+4], 0
  263.         mov     dl, [edx+interface_descr.bInterfaceNumber]
  264.         mov     [eax+4], dl
  265. ; Callback function is mouse_configured for mice and keyboard_configured1 for keyboards.
  266.         mov     edx, keyboard_configured1
  267.         cmp     ecx, 1
  268.         jz      @f
  269.         mov     edx, mouse_configured
  270. @@:
  271.         stdcall USBControlTransferAsync, [esp+4+28], eax, 0, 0, edx, ebx, 0
  272. ; 11. Return with pointer to device data as returned value.
  273.         xchg    eax, ebx
  274.         pop     ebx
  275.         ret     12
  276.  
  277. ; This function is called when SET_PROTOCOL command for keyboard is done,
  278. ; either successful or unsuccessful.
  279. keyboard_configured1:
  280.         xor     edx, edx
  281. ; 1. Check the status of the transfer.
  282. ; If the transfer was failed, go to the common error handler.
  283.         cmp     dword [esp+8], edx      ; status is zero?
  284.         jnz     keyboard_data_ready.error
  285. ; 2. Send the control packet SET_IDLE(infinity). HID auto-repeat is not useful.
  286.         mov     eax, [esp+20]
  287.         push    edx     ; flags for USBControlTransferAsync
  288.         push    eax     ; userdata for USBControlTransferAsync
  289.         add     eax, device_data.control
  290.         mov     dword [eax], 21h + (0Ah shl 8) + (0 shl 24)     ; class request to interface + SET_IDLE + no autorepeat
  291.         stdcall USBControlTransferAsync, dword [eax+keyboard_data.configpipe-device_data.control], \
  292.                 eax, edx, edx, keyboard_configured2; , <userdata>, <flags>
  293. ; 3. Return.
  294.         ret     20
  295.  
  296. ; This function is called when SET_IDLE command for keyboard is done,
  297. ; either successful or unsuccessful.
  298. keyboard_configured2:
  299. ; Check the status of the transfer and go to the corresponding label
  300. ; in the main handler.
  301.         cmp     dword [esp+8], 0
  302.         jnz     keyboard_data_ready.error
  303.         mov     edx, [esp+20]
  304.         push    edx
  305.         stdcall RegKeyboard, usbkbd_functions, edx
  306.         pop     edx
  307.         mov     [edx+keyboard_data.handle], eax
  308.         jmp     keyboard_data_ready.next
  309.  
  310. ; This function is called when another interrupt packet arrives,
  311. ; processed either successfully or unsuccessfully.
  312. ; It should parse the packet and initiate another transfer with
  313. ; the same callback function.
  314. keyboard_data_ready:
  315. ; 1. Check the status of the transfer.
  316.         mov     eax, [esp+8]
  317.         test    eax, eax
  318.         jnz     .error
  319. ; Parse the packet, comparing with the previous packet.
  320. ; For boot protocol, USB keyboard packet consists of the first byte
  321. ; with status keys that are currently pressed. The second byte should
  322. ; be ignored, and other 5 bytes denote keys that are currently pressed.
  323.         push    esi ebx         ; save used registers to be stdcall
  324. ; 2. Process control keys.
  325. ; 2a. Initialize before loop for control keys. edx = mask for control bits
  326. ; that were changed.
  327.         mov     ebx, [esp+20+8]
  328.         movzx   edx, byte [ebx+device_data.packet]      ; get state of control keys
  329.         xor     dl, byte [ebx+keyboard_data.prevpacket] ; compare with previous state
  330. ; 2b. If state of control keys has not changed, advance to 3.
  331.         jz      .nocontrol
  332. ; 2c. Otherwise, loop over control keys; esi = bit number.
  333.         xor     esi, esi
  334. .controlloop:
  335. ; 2d. Skip bits that have not changed.
  336.         bt      edx, esi
  337.         jnc     .controlnext
  338.         push    edx     ; save register which is possibly modified by API
  339. ; The state of the current control key has changed.
  340. ; 2e. For extended control keys, send the prefix 0xE0.
  341.         mov     al, [control_keys+esi]
  342.         test    al, al
  343.         jns     @f
  344.         push    eax
  345.         mov     ecx, 0xE0
  346.         call    SetKeyboardData
  347.         pop     eax
  348.         and     al, 0x7F
  349. @@:
  350. ; 2f. If the current state of the control key is "pressed", send normal
  351. ; scancode. Otherwise, the key is released, so set the high bit in scancode.
  352.         movzx   ecx, al
  353.         bt      dword [ebx+device_data.packet], esi
  354.         jc      @f
  355.         or      cl, 0x80
  356. @@:
  357.         call    SetKeyboardData
  358.         pop     edx     ; restore register which was possibly modified by API
  359. .controlnext:
  360. ; 2g. We have 8 control keys.
  361.         inc     esi
  362.         cmp     esi, 8
  363.         jb      .controlloop
  364. .nocontrol:
  365. ; 3. Initialize before loop for normal keys. esi = index.
  366.         movi    esi, 2
  367. .normalloop:
  368. ; 4. Process one key which was pressed in the previous packet.
  369. ; 4a. Get the next pressed key from the previous packet.
  370.         movzx   eax, byte [ebx+esi+keyboard_data.prevpacket]
  371. ; 4b. Ignore special codes.
  372.         cmp     al, 3
  373.         jbe     .normalnext1
  374. ; 4c. Ignore keys that are still pressed in the current packet.
  375.         lea     ecx, [ebx+device_data.packet]
  376.         call    haskey
  377.         jz      .normalnext1
  378. ; 4d. Say warning about keys with strange codes.
  379.         cmp     eax, normal_keys_number
  380.         jae     .badkey1
  381.         movzx   ecx, [normal_keys+eax]
  382.         jecxz   .badkey1
  383. ; 4e. For extended keys, send the prefix 0xE0.
  384.         push    ecx     ; save keycode
  385.         test    cl, cl
  386.         jns     @f
  387.         push    ecx
  388.         mov     ecx, 0xE0
  389.         call    SetKeyboardData
  390.         pop     ecx
  391. @@:
  392. ; 4f. Send the release event.
  393.         or      cl, 0x80
  394.         call    SetKeyboardData
  395. ; 4g. If this key is autorepeating, stop the timer.
  396.         pop     ecx     ; restore keycode
  397.         cmp     cl, [ebx+keyboard_data.repeatkey]
  398.         jnz     .normalnext1
  399.         mov     eax, [ebx+keyboard_data.timer]
  400.         test    eax, eax
  401.         jz      .normalnext1
  402.         stdcall CancelTimerHS, eax
  403.         and     [ebx+keyboard_data.timer], 0
  404.         jmp     .normalnext1
  405. .badkey1:
  406.         DEBUGF 1,'K : unknown keycode: %x\n',al
  407. .normalnext1:
  408. ; 5. Process one key which is pressed in the current packet.
  409. ; 5a. Get the next pressed key from the current packet.
  410.         movzx   eax, byte [ebx+esi+device_data.packet]
  411. ; 5b. Ignore special codes.
  412.         cmp     al, 3
  413.         jbe     .normalnext2
  414. ; 5c. Ignore keys that were already pressed in the previous packet.
  415.         lea     ecx, [ebx+keyboard_data.prevpacket]
  416.         call    haskey
  417.         jz      .normalnext2
  418. ; 5d. Say warning about keys with strange codes.
  419.         cmp     eax, normal_keys_number
  420.         jae     .badkey2
  421.         movzx   ecx, [normal_keys+eax]
  422.         jecxz   .badkey2
  423. ; 5e. For extended keys, send the prefix 0xE0.
  424.         push    ecx     ; save keycode
  425.         test    cl, cl
  426.         jns     @f
  427.         push    ecx
  428.         mov     ecx, 0xE0
  429.         call    SetKeyboardData
  430.         pop     ecx
  431. @@:
  432. ; 5f. Send the press event.
  433.         and     cl, not 0x80
  434.         call    SetKeyboardData
  435. ; 5g. Stop the current auto-repeat timer, if present.
  436.         mov     eax, [ebx+keyboard_data.timer]
  437.         test    eax, eax
  438.         jz      @f
  439.         stdcall CancelTimerHS, eax
  440. @@:
  441. ; 5h. Start the auto-repeat timer.
  442.         pop     ecx     ; restore keycode
  443.         mov     [ebx+keyboard_data.repeatkey], cl
  444.         stdcall TimerHS, 25, 5, autorepeat_timer, ebx
  445.         mov     [ebx+keyboard_data.timer], eax
  446.         jmp     .normalnext2
  447. .badkey2:
  448.         DEBUGF 1,'K : unknown keycode: %x\n',al
  449. .normalnext2:
  450. ; 6. Advance to next key.
  451.         inc     esi
  452.         cmp     esi, 8
  453.         jb      .normalloop
  454. ; 7. Save the packet data for future reference.
  455.         mov     eax, dword [ebx+device_data.packet]
  456.         mov     dword [ebx+keyboard_data.prevpacket], eax
  457.         mov     eax, dword [ebx+device_data.packet+4]
  458.         mov     dword [ebx+keyboard_data.prevpacket+4], eax
  459.         pop     ebx esi ; restore registers to be stdcall
  460. .next:
  461. ; 8. Initiate transfer on the interrupt pipe.
  462.         mov     eax, [esp+20]
  463.         push    1       ; flags for USBNormalTransferAsync
  464.         push    eax     ; userdata for USBNormalTransferAsync
  465.         add     eax, device_data.packet
  466.         stdcall USBNormalTransferAsync, dword [eax+device_data.intpipe-device_data.packet], \
  467.                 eax, dword [eax+device_data.packetsize-device_data.packet], \
  468.                 keyboard_data_ready;, <userdata>, <flags>
  469. ; 9. Return.
  470. .nothing:
  471.         ret     20
  472. .error:
  473. ; An error has occured.
  474. ; 10. If an error is caused by the disconnect, do nothing, it is handled
  475. ; in DeviceDisconnected. Otherwise, say a message.
  476.         cmp     eax, 16
  477.         jz      @f
  478.         push    esi
  479.         mov     esi, errormsgkbd
  480.         call    SysMsgBoardStr
  481.         pop     esi
  482. @@:
  483.         ret     20
  484.  
  485. ; Auxiliary procedure for keyboard_data_ready.
  486. haskey:
  487.         movi    edx, 2
  488. @@:
  489.         cmp     byte [ecx+edx], al
  490.         jz      @f
  491.         inc     edx
  492.         cmp     edx, 7
  493.         jbe     @b
  494. @@:
  495.         ret
  496.  
  497. ; Timer function for auto-repeat.
  498. autorepeat_timer:
  499.         mov     eax, [esp+4]
  500.         movzx   ecx, [eax+keyboard_data.repeatkey]
  501.         test    cl, cl
  502.         jns     @f
  503.         push    ecx
  504.         mov     ecx, 0xE0
  505.         call    SetKeyboardData
  506.         pop     ecx
  507.         and     cl, not 0x80
  508. @@:
  509.         call    SetKeyboardData
  510.         ret     4
  511.  
  512. ; This function is called to update LED state on the keyboard.
  513. SetKeyboardLights:
  514.         mov     eax, [esp+4]
  515.         add     eax, device_data.control
  516.         mov     dword [eax], 21h + (9 shl 8) + (2 shl 24)
  517.                 ; class request to interface + SET_REPORT + Output zero report
  518.         mov     byte [eax+6], 1
  519.         mov     edx, [esp+8]
  520.         shr     dl, 1
  521.         jnc     @f
  522.         or      dl, 4
  523. @@:
  524.         lea     ecx, [eax+keyboard_data.ledstate-device_data.control]
  525.         mov     [ecx], dl
  526.         stdcall USBControlTransferAsync, dword [eax+keyboard_data.configpipe-device_data.control], \
  527.                 eax, ecx, 1, keyboard_data_ready.nothing, 0, 0
  528.         ret     8
  529.  
  530. ; This function is called when it is safe to free keyboard data.
  531. CloseKeyboard:
  532.         mov     eax, [esp+4]
  533.         push    ebx
  534.         call    Kfree
  535.         pop     ebx
  536.         ret     4
  537.  
  538. ; This function is called when SET_PROTOCOL command for mouse is done,
  539. ; either successful or unsuccessful.
  540. mouse_configured:
  541. ; Check the status of the transfer and go to the corresponding label
  542. ; in the main handler.
  543.         cmp     dword [esp+8], 0
  544.         jnz     mouse_data_ready.error
  545.         mov     eax, [esp+20]
  546.         add     eax, device_data.packet
  547.         jmp     mouse_data_ready.next
  548.  
  549. ; This function is called when another interrupt packet arrives,
  550. ; processed either successfully or unsuccessfully.
  551. ; It should parse the packet and initiate another transfer with
  552. ; the same callback function.
  553. mouse_data_ready:
  554. ; 1. Check the status of the transfer.
  555.         mov     eax, [esp+8]
  556.         test    eax, eax
  557.         jnz     .error
  558.         mov     edx, [esp+16]
  559. ; 2. Parse the packet.
  560. ; For boot protocol, USB mouse packet consists of at least 3 bytes.
  561. ; The first byte is state of mouse buttons, the next two bytes are
  562. ; x and y movements.
  563. ; Normal mice do not distinguish between boot protocol and report protocol;
  564. ; in this case, scroll data are also present. Advanced mice, however,
  565. ; support two different protocols, boot protocol is used for compatibility
  566. ; and does not contain extended buttons or scroll data.
  567.         mov     eax, [esp+12]   ; buffer
  568.         push    eax
  569.         xor     ecx, ecx
  570.         cmp     edx, 4
  571.         jbe     @f
  572.         movsx   ecx, byte [eax+4]
  573. @@:
  574.         push    ecx
  575.         xor     ecx, ecx
  576.         cmp     edx, 3
  577.         jbe     @f
  578.         movsx   ecx, byte [eax+3]
  579.         neg     ecx
  580. @@:
  581.         push    ecx
  582.         xor     ecx, ecx
  583.         cmp     edx, 2
  584.         jbe     @f
  585.         movsx   ecx, byte [eax+2]
  586.         neg     ecx
  587. @@:
  588.         push    ecx
  589.         movsx   ecx, byte [eax+1]
  590.         push    ecx
  591.         movzx   ecx, byte [eax]
  592.         push    ecx
  593.         call    SetMouseData
  594.         pop     eax
  595. .next:
  596. ; 3. Initiate transfer on the interrupt pipe.
  597.         stdcall USBNormalTransferAsync, dword [eax+device_data.intpipe-device_data.packet], \
  598.                 eax, dword [eax+device_data.packetsize-device_data.packet], mouse_data_ready, eax, 1
  599. ; 4. Return.
  600.         ret     20
  601. .error:
  602. ; An error has occured.
  603. ; 5. If an error is caused by the disconnect, do nothing, it is handled
  604. ; in DeviceDisconnected. Otherwise, say a message.
  605.         cmp     eax, 16
  606.         jz      @f
  607.         push    esi
  608.         mov     esi, errormsgmouse
  609.         call    SysMsgBoardStr
  610.         pop     esi
  611. @@:
  612.         ret     20
  613.  
  614. ; This function is called when the device is disconnected.
  615. DeviceDisconnected:
  616.         push    ebx     ; save used register to be stdcall
  617. ; 1. Say a message. Use different messages for keyboards and mice.
  618.         mov     ebx, [esp+4+4]
  619.         push    esi
  620.         mov     esi, disconnectmsgk
  621.         cmp     byte [ebx+device_data.type], 1
  622.         jz      @f
  623.         mov     esi, disconnectmsgm
  624. @@:
  625.         stdcall SysMsgBoardStr
  626.         pop     esi
  627. ; 2. If device is keyboard, then we must unregister it as a keyboard and
  628. ; possibly stop the auto-repeat timer.
  629.         cmp     byte [ebx+device_data.type], 1
  630.         jnz     .nokbd
  631.         mov     eax, [ebx+keyboard_data.timer]
  632.         test    eax, eax
  633.         jz      @f
  634.         stdcall CancelTimerHS, eax
  635. @@:
  636.         mov     ecx, [ebx+keyboard_data.handle]
  637.         jecxz   .nokbd
  638.         stdcall DelKeyboard, ecx
  639. ; If keyboard is registered, then we should free data in CloseKeyboard, not here.
  640.         jmp     .nothing
  641. .nokbd:
  642. ; 3. Free the device data.
  643.         xchg    eax, ebx
  644.         call    Kfree
  645. ; 4. Return.
  646. .nothing:
  647.         pop     ebx     ; restore used register to be stdcall
  648.         ret     4       ; purge one dword argument to be stdcall
  649.  
  650. ; strings
  651. my_driver       db      'usbhid',0
  652. errormsgmouse   db      'K : USB transfer error, disabling mouse',10,0
  653. errormsgkbd     db      'K : USB transfer error, disabling keyboard',10,0
  654. disconnectmsgm  db      'K : USB mouse disconnected',10,0
  655. disconnectmsgk  db      'K : USB keyboard disconnected',10,0
  656.  
  657. ; data for keyboard: correspondence between HID usage keys and PS/2 scancodes.
  658. EX = 80h
  659. label control_keys byte
  660.         db      1Dh, 2Ah, 38h, 5Bh+EX, 1Dh+EX, 36h, 38h+EX, 5Ch+EX
  661. label normal_keys byte
  662.         db      00h, 00h, 00h, 00h, 1Eh, 30h, 2Eh, 20h, 12h, 21h, 22h, 23h, 17h, 24h, 25h, 26h  ; 0x
  663.         db      32h, 31h, 18h, 19h, 10h, 13h, 1Fh, 14h, 16h, 2Fh, 11h, 2Dh, 15h, 2Ch, 02h, 03h  ; 1x
  664.         db      04h, 05h, 06h, 07h, 08h, 09h, 0Ah, 0Bh, 1Ch, 01h, 0Eh, 0Fh, 39h, 0Ch, 0Dh, 1Ah  ; 2x
  665.         db      1Bh, 2Bh, 2Bh, 27h, 28h, 29h, 33h, 34h, 35h, 3Ah, 3Bh, 3Ch, 3Dh, 3Eh, 3Fh, 40h  ; 3x
  666.         db      41h, 42h, 43h, 44h, 57h, 58h,37h+EX,46h,0,52h+EX,47h+EX,49h+EX,53h+EX,4Fh+EX,51h+EX,4Dh+EX      ; 4x
  667.         db      4Bh+EX,50h+EX,48h+EX,45h,35h+EX,37h,4Ah,4Eh,1Ch+EX,4Fh,50h,51h,4Bh,4Ch,4Dh,47h  ; 5x
  668.         db      48h, 49h, 52h, 53h, 56h,5Dh+EX,5Eh+EX,59h,64h,65h,66h, 67h, 68h, 69h, 6Ah, 6Bh  ; 6x
  669.         db      6Ch, 6Dh, 6Eh, 76h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h  ; 7x
  670.         db      00h, 00h, 00h, 00h, 00h, 7Eh, 00h, 73h, 70h, 7Dh, 79h, 7Bh, 5Ch, 00h, 00h, 00h  ; 8x
  671.         db      0F2h,0F1h,78h, 77h, 76h
  672. normal_keys_number = $ - normal_keys
  673.  
  674. ; Exported variable: kernel API version.
  675. align 4
  676. version dd      50005h
  677. ; Structure with callback functions.
  678. usb_functions:
  679.         dd      12
  680.         dd      AddDevice
  681.         dd      DeviceDisconnected
  682.  
  683. ; Structure with callback functions for keyboards.
  684. usbkbd_functions:
  685.         dd      12
  686.         dd      CloseKeyboard
  687.         dd      SetKeyboardLights
  688.  
  689. ; for DEBUGF macro
  690. include_debug_strings
  691.  
  692. ; for uninitialized data
  693. section '.data' data readable writable align 16
  694.