usbKeyboardLib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:60k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* usbKeyboardLib.c - USB keyboard class drive with vxWorks SIO interface */
  2. /* Copyright 2000-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01g,08may02,wef  Add ioctl to set keyboard mode to return raw scan codes - 
  7.  SPR #70988. 
  8. 01f,29oct01,wef  Remove automatic buffer creations and repalce with OSS_MALLOC.
  9. 01e,18sep01,wef  merge from wrs.tor2_0.usb1_1-f for veloce
  10. 01d,03jul01,jsv  Re-wrote key tracking logic to fix issue with extra chars
  11.                  when shift is released before the desired shifted key.
  12.                  Made typematic setting globals so they can be modified.
  13.                  Fixed typematic task, not calling callback after queueing
  14.                  chars.
  15.                  Added support of extended keycodes.
  16.                  Fixed shifted key operation when CAPSLOCK is on.
  17. 01c,22jan01,wef  fix tab stops.
  18. 01b,20mar00,rcb  Re-write code to fetch maxPacketSize from endpoint descriptor
  19.    on machines which don't support non-aligned word access.
  20.    Allocate "report" structure separately from SIO_CHAN in order
  21.    to avoid cache problems on MIPS platform.
  22. 01a,27jul99,rcb  written.
  23. */
  24. /*
  25. DESCRIPTION
  26. This module implements the USB keyboard class driver for the vxWorks operating
  27. system.  This module presents an interface which is a superset of the vxWorks
  28. SIO (serial IO) driver model.  That is, this driver presents the external APIs
  29. which would be expected of a standard "multi-mode serial (SIO) driver" and
  30. adds certain extensions which are needed to address adequately the requirements
  31. of the hot-plugging USB environment.
  32. USB keyboards are described as part of the USB "human interface device" class
  33. specification and related documents.  This driver concerns itself only with USB
  34. devices which claim to be keyboards as set forth in the USB HID specification
  35. and ignores other types of human interface devices (i.e., mouse).  USB
  36. keyboards can operate according to either a "boot protocol" or to a "report
  37. protocol".  This driver enables keyboards for operation using the boot
  38. protocol.
  39. As the SIO driver model presents a fairly limited, byte-stream oriented view of
  40. a serial device, this driver maps USB keyboard scan codes into appropriate
  41. ASCII codes.  Scan codes and combinations of scan codes which do not map to the
  42. ASCII character set are suppressed.
  43. Unlike most SIO drivers, the number of channels supported by this driver is not
  44. fixed. Rather, USB keyboards may be added or removed from the system at any
  45. time.  This creates a situation in which the number of channels is dynamic, and
  46. clients of usbKeyboardLib.c need to be made aware of the appearance and 
  47. disappearance of channels.  Therefore, this driver adds an additional set of
  48. functions which allows clients to register for notification upon the insertion
  49. and removal of USB keyboards, and hence the creation and deletion of channels.
  50. This module itself is a client of the Universal Serial Bus Driver (USBD).  All
  51. interaction with the USB buses and devices is handled through the USBD.
  52. INITIALIZATION
  53. As with standard SIO drivers, this driver must be initialized by calling
  54. usbKeyboardDevInit().  usbKeyboardDevInit() in turn initializes its 
  55. connection to the USBD and other internal resources needed for operation.  
  56. Unlike some SIO drivers, there are no usbKeyboardLib.c data structures which need 
  57. to be initialized prior to calling usbKeyboardDevInit().
  58. Prior to calling usbKeyboardDevInit(), the caller must ensure that the USBD
  59. has been properly initialized by calling - at a minimum - usbdInitialize().
  60. It is also the caller's responsibility to ensure that at least one USB HCD
  61. (USB Host Controller Driver) is attached to the USBD - using the USBD function
  62. usbdHcdAttach() - before keyboard operation can begin. However, it is not 
  63. necessary for usbdHcdAttach() to be alled prior to initializating usbKeyboardLib.c.
  64. usbKeyboardLib.c uses the USBD dynamic attach services and is capable of 
  65. recognizing USB keboard attachment and removal on the fly.  Therefore, it is 
  66. possible for USB HCDs to be attached to or detached from the USBD at run time
  67. - as may be required, for example, in systems supporting hot swapping of
  68. hardware.
  69. usbKeyboardLib.c does not export entry points for transmit, receive, and error
  70. interrupt entry points like traditional SIO drivers.  All "interrupt" driven
  71. behavior is managed by the underlying USBD and USB HCD(s), so there is no
  72. need for a caller (or BSP) to connect interrupts on behalf of usbKeyboardLib.c.
  73. For the same reason, there is no post-interrupt-connect initialization code
  74. and usbKeboardLib.c therefore also omits the "devInit2" entry point.
  75. OTHER FUNCTIONS
  76. usbKeyboardLib.c also supports the SIO ioctl interface.  However, attempts to
  77. set parameters like baud rates and start/stop bits have no meaning in the USB
  78. environment and will be treated as no-ops.  
  79. DATA FLOW
  80. For each USB keyboard connected to the system, usbKeyboardLib.c sets up a
  81. USB pipe to monitor input from the keyboard.  Input, in the form of scan codes,
  82. is translated to ASCII codes and placed in an input queue.  If SIO callbacks
  83. have been installed and usbKeyboardLib.c has been placed in the SIO "interrupt" 
  84. mode of operation, then usbKeyboardLib.c will invoke the "character received"
  85. callback for each character in the queue.  When usbKeyboardLib.c has been placed
  86. in the "polled" mode of operation, callbacks will not be invoked and the 
  87. caller will be responsible for fetching keyboard input using the driver's
  88. pollInput() function.
  89. usbKeyboardLib.c does not support output to the keyboard.  Therefore, calls to
  90. the txStartup() and pollOutput() functions will fail.  The only "output" 
  91. supported is the control of the keyboard LEDs, and this is handled internally
  92. by usbKeyboardLib.c.
  93. The caller needs to be aware that usbKeyboardLib.c is not capable of operating
  94. in a true "polled mode" as the underlying USBD and USB HCD always operate in
  95. an interrupt mode.  
  96. TYPEMATIC REPEAT
  97. USB keyboards do not implement typematic repeat, and it is the responsibility
  98. of the host software to implement this feature.  For this purpose, this module
  99. creates a task called typematicThread() which monitors all open channels and
  100. injects repeated characters into input queues as appropriate.
  101. INCLUDE FILES:
  102. sioLib.h usbKeyboardLib.h
  103. */
  104. /* includes */
  105. #include "vxWorks.h"
  106. #include "string.h"
  107. #include "sioLib.h"
  108. #include "errno.h"
  109. #include "ctype.h"
  110. #include "usb/usbPlatform.h"
  111. #include "usb/ossLib.h"  /* operations system srvcs */
  112. #include "usb/usb.h" /* general USB definitions */
  113. #include "usb/usbListLib.h" /* linked list functions */
  114. #include "usb/usbdLib.h" /* USBD interface */
  115. #include "usb/usbLib.h"  /* USB utility functions */
  116. #include "usb/usbHid.h"  /* USB HID definitions */
  117. #include "drv/usb/usbKeyboardLib.h" /* our API */
  118. /* defines */
  119. #define KBD_CLIENT_NAME "usbKeyboardLib"    /* our USBD client name */
  120. #define KBD_Q_DEPTH 8     /* Max characters in keyboard queue */
  121. #define ISEXTENDEDKEYCODE(keyCode)          (keyCode & 0xFF00)
  122. #define ISALPHASCANCODE(scanCode)           ( (scanCode >= 0x04) && (scanCode <= 0x1D) )
  123. #define ISNUMERICSCANCODE(scanCode)         ( (scanCode >= 0x1E) && (scanCode <= 0x27) )
  124. #define ISKEYPADSCANCODE(scanCode)          ( (scanCode >= 0x53) && (scanCode <= 0x63) )
  125. #define ISKEYPADEXTSCANCODE(scanCode)       ( (scanCode >= 0x59) && (scanCode <= 0x63) )
  126. #define ISFUNCTIONSCANCODE(scanCode)        ( (scanCode >= 0x3A) && (scanCode <= 0x45) )
  127. #define ISOTHEREXTENDEDSCANCODE(scanCode)   ( (scanCode >= 0x49) && (scanCode <= 0x52) )
  128. #define ISEXTENDEDSCANCODE(scanCode, modifiers)                                 
  129.                 ( (modifiers & MOD_KEY_ALT) && ISALPHASCANCODE(scanCode) )      
  130.                 || ISFUNCTIONSCANCODE(scanCode)                                 
  131.                 || ISOTHEREXTENDEDSCANCODE(scanCode)
  132. /* If your hardware platform has problems sharing cache lines, then define
  133.  * CACHE_LINE_SIZE below so that critical buffers can be allocated within
  134.  * their own cache lines.
  135.  */
  136. #define CACHE_LINE_SIZE     16
  137. /* typematic definitions */
  138. #define TYPEMATIC_NAME     "tUsbKbd"
  139. /* typedefs */
  140. /*
  141.  * ATTACH_REQUEST
  142.  */
  143. typedef struct attach_request
  144.     {
  145.     LINK reqLink;     /* linked list of requests */
  146.     USB_KBD_ATTACH_CALLBACK callback; /* client callback routine */
  147.     pVOID callbackArg; /* client callback argument */
  148.     } ATTACH_REQUEST, *pATTACH_REQUEST;
  149. /* USB_KBD_SIO_CHAN is the internal data structure we use to track each USB
  150.  * keyboard.
  151.  */
  152. typedef struct usb_kbd_sio_chan
  153.     {
  154.     SIO_CHAN sioChan; /* must be first field */
  155.     LINK sioLink;         /* linked list of keyboard structs */
  156.     UINT16 lockCount; /* Count of times structure locked */
  157.     USBD_NODE_ID nodeId; /* keyboard node Id */
  158.     UINT16 configuration; /* configuration/interface reported as */
  159.     UINT16 interface; /* a keyboard by this device */
  160.     BOOL connected;         /* TRUE if keyboard currently connected */
  161.     USBD_PIPE_HANDLE pipeHandle;/* USBD pipe handle for interrupt pipe */
  162.     USB_IRP irp;         /* IRP to monitor interrupt pipe */
  163.     BOOL irpInUse;         /* TRUE while IRP is outstanding */
  164.     pHID_KBD_BOOT_REPORT pBootReport;/* Keyboard boot report fetched thru pipe */
  165.     char inQueue [KBD_Q_DEPTH]; /* Circular queue for keyboard input */
  166.     UINT16 inQueueCount; /* count of characters in input queue */
  167.     UINT16 inQueueIn; /* next location in queue */
  168.     UINT16 inQueueOut; /* next character to fetch */
  169.     UINT32 typematicTime; /* time current typematic period started */
  170.     UINT32 typematicCount; /* count of keys injected */
  171.     UINT16 typematicChar;  /* current character to repeat */
  172.     int mode;         /* SIO_MODE_INT or SIO_MODE_POLL */
  173.     STATUS (*getTxCharCallback) (); /* tx callback */
  174.     void *getTxCharArg;  /* tx callback argument */
  175.     STATUS (*putRxCharCallback) (); /* rx callback */
  176.     void *putRxCharArg;  /* rx callback argument */
  177.     /* Following variables used to emulate certain ioctl functions. */
  178.     int baudRate;         /* has no meaning in USB */
  179.     /* Following variables maintain keyboard state */
  180.     BOOL capsLock;         /* TRUE if CAPLOCK in effect */
  181.     BOOL scrLock;         /* TRUE if SCRLOCK in effect */
  182.     BOOL numLock;         /* TRUE if NUMLOCK in effect */
  183.     UINT16 activeScanCodes [BOOT_RPT_KEYCOUNT];
  184.     int scanMode; /* raw or ascii */
  185.     } USB_KBD_SIO_CHAN, *pUSB_KBD_SIO_CHAN;
  186. /* forward static declarations */
  187. LOCAL int usbKeyboardTxStartup (SIO_CHAN * pSioChan);
  188. LOCAL int usbKeyboardCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
  189.     STATUS (*callback)(), void *callbackArg);
  190. LOCAL int usbKeyboardPollOutput (SIO_CHAN *pSioChan, char   outChar);
  191. LOCAL int usbKeyboardPollInput (SIO_CHAN *pSioChan, char *thisChar);
  192. LOCAL int usbKeyboardIoctl (SIO_CHAN *pSioChan, int request, void *arg);
  193. LOCAL VOID usbKeyboardIrpCallback (pVOID p);
  194. /* locals */
  195. LOCAL UINT16 initCount = 0; /* Count of init nesting */
  196. LOCAL MUTEX_HANDLE kbdMutex;    /* mutex used to protect internal structs */
  197. LOCAL LIST_HEAD sioList; /* linked list of USB_KBD_SIO_CHAN */
  198. LOCAL LIST_HEAD reqList; /* Attach callback request list */
  199. LOCAL USBD_CLIENT_HANDLE usbdHandle; /* our USBD client handle */
  200. LOCAL THREAD_HANDLE typematicHandle;/* task used to generate typematic repeat */
  201. LOCAL BOOL killTypematic; /* TRUE when typematic thread should exit */
  202. LOCAL BOOL typematicExit; /* TRUE when typematic thread exits */
  203. /* Channel function table. */
  204. LOCAL SIO_DRV_FUNCS usbKeyboardSioDrvFuncs =
  205.     {
  206.     usbKeyboardIoctl,
  207.     usbKeyboardTxStartup,
  208.     usbKeyboardCallbackInstall,
  209.     usbKeyboardPollInput,
  210.     usbKeyboardPollOutput
  211.     };
  212. /* ASCI definitions */
  213. #define SHIFT_CASE_OFFSET   ('a' - 'A')
  214. #define CTRL_CASE_OFFSET    64 /* diff between 'A' and CTRL-A */
  215. #define BS     8 /* backspace, CTRL-H */
  216. #define DEL     BS /* delete key */
  217. #define TAB     9 /* tab, CTRL-I */
  218. #define CR     13 /* carriage return, CTRL-M */
  219. #define ESC     27 /* escape */
  220. /* Scan code lookup table and related constants. */
  221. #define ASCII_MIN         0x0000
  222. #define ASCII_MAX         0x007f
  223. #define CAPLOCK          0x39
  224. #define CAPLOCK_LOCKING      0x82
  225. #define NUMLOCK          0x53
  226. #define NUMLOCK_LOCKING  0x83
  227. #define SCRLOCK          0x47
  228. #define SCRLOCK_LOCKING  0x84
  229. #define NOTKEY         0
  230. #define isAscii(a)  ((a) <= ASCII_MAX)
  231. /* NOTE: The following scan code tables are populated only so far as is useful
  232.  * in order to map the ASCI character set.  Also, the following two tables must
  233.  * remain exactly the same length.
  234.  */
  235. LOCAL UINT16 scanCodes [] =
  236.     {
  237.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, 'a',    'b',    'c',    'd',    /* 0 - 7 */
  238.     'e',    'f',    'g',    'h',    'i',    'j',    'k',    'l',    /* 8 - 15 */
  239.     'm',    'n',    'o',    'p',    'q',    'r',    's',    't',    /* 16 - 23 */
  240.     'u',    'v',    'w',    'x',    'y',    'z',    '1',    '2',    /* 24 - 31 */
  241.     '3',    '4',    '5',    '6',    '7',    '8',    '9',    '0',    /* 32 - 39 */
  242.     CR,     ESC,    DEL,    TAB,    ' ',    '-',    '=',    '[',    /* 40 - 47 */
  243.     ']',    '\',   '#',    ';',    ''',   '`',    ',',    '.',    /* 48 - 55 */
  244.     '/',    NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 56 - 63 */
  245.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 64 - 71 */
  246.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, DEL,    NOTKEY, NOTKEY, NOTKEY, /* 72 - 79 */
  247.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, '/',    '*',    '-',    '+',    /* 80 - 87 */
  248.     CR,     '1',    '2',    '3',    '4',    '5',    '6',    '7',    /* 88 - 95 */
  249.     '8',    '9',    '0',    '.',    '|',    NOTKEY, NOTKEY, '=',    /* 96 - 103 */
  250.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 104 - 111 */
  251.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 112 - 119 */
  252.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 120 - 127 */
  253.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, ',',    '=',  NOTKEY, /* 128 - 135 */
  254.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 136 - 143 */
  255.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 144 - 151 */
  256.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 152 - 159 */
  257.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 160 - 167 */
  258.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 168 - 175 */
  259.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 176 - 183 */
  260.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 184 - 191 */
  261.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 192 - 199 */
  262.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 200 - 207 */
  263.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 208 - 215 */
  264.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 216 - 223 */
  265.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 224 - 231 */
  266.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 232 - 239 */
  267.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 240 - 247 */
  268.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY  /* 248 - 255 */
  269.     };
  270. LOCAL UINT16 scanCodesShift [] =
  271.     {
  272.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, 'A',    'B',    'C',    'D',    /* 0 - 7 */
  273.     'E',    'F',    'G',    'H',    'I',    'J',    'K',    'L',    /* 8 - 15 */
  274.     'M',    'N',    'O',    'P',    'Q',    'R',    'S',    'T',    /* 16 - 23 */
  275.     'U',    'V',    'W',    'X',    'Y',    'Z',    '!',    '@',    /* 24 - 31 */
  276.     '#',    '$',    '%',    '^',    '&',    '*',    '(',    ')',    /* 32 - 39 */
  277.     CR,     ESC,    DEL,    TAB,    ' ',    '_',    '+',    '{',    /* 40 - 47 */
  278.     '}',    '|',    '~',    ':',    '"',    '~',    '<',    '>',    /* 48 - 55 */
  279.     '?',    NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 56 - 63 */
  280.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 64 - 71 */
  281.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, DEL,    NOTKEY, NOTKEY, NOTKEY, /* 72 - 79 */
  282.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, '/',    '*',    '-',    '+',    /* 80 - 87 */
  283.     CR,     '1',    '2',    '3',    '4',    '5',    '6',    '7',    /* 88 - 95 */
  284.     '8',    '9',    '0',    '.',    '|',    NOTKEY, NOTKEY, '=',    /* 96 - 103 */
  285.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 104 - 111 */
  286.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 112 - 119 */
  287.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 120 - 127 */
  288.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, ',',    '=',  NOTKEY, /* 128 - 135 */
  289.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 136 - 143 */
  290.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 144 - 151 */
  291.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 152 - 159 */
  292.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 160 - 167 */
  293.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 168 - 175 */
  294.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 176 - 183 */
  295.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 184 - 191 */
  296.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 192 - 199 */
  297.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 200 - 207 */
  298.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 208 - 215 */
  299.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 216 - 223 */
  300.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 224 - 231 */
  301.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 232 - 239 */
  302.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, /* 240 - 247 */
  303.     NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY, NOTKEY  /* 248 - 255 */
  304.     };
  305. #define SCAN_CODE_TBL_LEN   (sizeof (scanCodes) / sizeof (UINT16))
  306. /*  IBM Extended keycodes.
  307.     Char.     Hex Pair       Char.    Hex Pair
  308.     ALT-A     (0x00,0x1e)    ALT-B    (0x00,0x30)
  309.     ALT-C     (0x00,0x2e)    ALT-D    (0x00,0x20)
  310.     ALT-E     (0x00,0x12)    ALT-F    (0x00,0x21)
  311.     ALT-G     (0x00,0x22)    ALT-H    (0x00,0x23)
  312.     ALT-I     (0x00,0x17)    ALT-J    (0x00,0x24)
  313.     ALT-K     (0x00,0x25)    ALT-L    (0x00,0x26)
  314.     ALT-M     (0x00,0x32)    ALT-N    (0x00,0x31)
  315.     ALT-O     (0x00,0x18)    ALT-P    (0x00,0x19)
  316.     ALT-Q     (0x00,0x10)    ALT-R    (0x00,0x13)
  317.     ALT-S     (0x00,0x1a)    ALT-T    (0x00,0x14)
  318.     ALT-U     (0x00,0x16)    ALT-V    (0x00,0x2f)
  319.     ALT-W     (0x00,0x11)    ALT-X    (0x00,0x2d)
  320.     ALT-Y     (0x00,0x15)    ALT-Z    (0x00,0x2c)
  321.     PgUp      (0x00,0x49)    PgDn     (0x00,0x51)
  322.     Home      (0x00,0x47)    End      (0x00,0x4f)
  323.     UpArrw    (0x00,0x48)    DnArrw   (0x00,0x50)
  324.     LftArrw   (0x00,0x4b)    RtArrw   (0x00,0x4d)
  325.     F1        (0x00,0x3b)    F2       (0x00,0x3c)
  326.     F3        (0x00,0x3d)    F4       (0x00,0x3e)
  327.     F5        (0x00,0x3f)    F6       (0x00,0x40)
  328.     F7        (0x00,0x41)    F8       (0x00,0x42)
  329.     F9        (0x00,0x43)    F10      (0x00,0x44)
  330.     F11       (0x00,0x85)    F12      (0x00,0x86)
  331.     ALT-F1    (0x00,0x68)    ALT-F2   (0x00,0x69)
  332.     ALT-F3    (0x00,0x6a)    ALT-F4   (0x00,0x6b)
  333.     ALT-F5    (0x00,0x6c)    ALT-F6   (0x00,0x6d)
  334.     ALT-F7    (0x00,0x6e)    ALT-F8   (0x00,0x6f)
  335.     ALT-F9    (0x00,0x70)    ALT-F10  (0x00,0x71)
  336.     ALT-F11   (0x00,0x8b)    ALT-F12  (0x00,0x8c)
  337. */
  338. LOCAL UINT16 extendedAlphaKeyCodes [] =
  339.     {
  340.         0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23,
  341.         0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, 0x19,
  342.         0x10, 0x13, 0x1a, 0x14, 0x16, 0x2f, 0x11, 0x2d,
  343.         0x15, 0x2c
  344.     };
  345. LOCAL UINT16 extendedOtherKeyCodes [] =
  346.     {
  347.         0x52, 0x47, 0x49, 0x53, 0x4f, 0x51, 0x4d ,0x4b, 0x50,
  348.         0x48,
  349.     };
  350. LOCAL UINT16 extendedFunctionKeyCodes [] =
  351.     {
  352.         0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42,
  353.         0x43, 0x44, 0x85, 0x86
  354.     };
  355. LOCAL UINT16 extendedAltFunctionKeyCodes [] =
  356.     {
  357.         0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  358.         0x70, 0x71, 0x8b, 0x8c
  359.     };
  360. LOCAL UINT16 extendedKeypadKeyCodes [] =
  361.     {
  362.         0x4F, 0x50, 0x51, 0x4B, 0x00, 0x4D, 0x47, 0x48,
  363.         0x49, 0x52, 0x53
  364.     };
  365. /* globals */
  366. unsigned int TYPEMATIC_DELAY  = 500;    /* 500 msec delay */
  367. unsigned int TYPEMATIC_PERIOD = 66;     /* 66 msec = approx 15 char/sec */
  368. /***************************************************************************
  369. *
  370. * cvtScanCodeToKeyCode - converts scan code to key code if possible
  371. *
  372. * <scanCode> is the scan code to be interpreted and <modifiers> is the 
  373. * current state of the keyboard modifies (e.g., SHIFT).  
  374.     *
  375. * RETURNS: ASCII code if mapping exists, CAPLOCK, SCRLOCK, NUMLOCK, or
  376. *      NOTKEY if no mapping.
  377. */
  378. LOCAL UINT16 cvtScanCodeToKeyCode
  379.     (
  380.     pUSB_KBD_SIO_CHAN pSioChan,
  381.     UINT16 scanCode,
  382.     UINT16 modifiers
  383.     )
  384.     {
  385.     /* Translate keypad keys. */
  386.     if( ISKEYPADSCANCODE(scanCode) )
  387. {
  388.         if( !!(modifiers & MOD_KEY_SHIFT) ^ !!(pSioChan->numLock) )
  389.             return( scanCodes [scanCode] );
  390.         if( ISKEYPADEXTSCANCODE(scanCode) )
  391.     {
  392.             /* If the table contains 0 (like entry for keypad '5') 
  393.      * return NOTKEY. 
  394.      */
  395.             if(extendedKeypadKeyCodes[scanCode-0x59] == 0) 
  396. return(NOTKEY);
  397.             return(0xFF00 | extendedKeypadKeyCodes[scanCode-0x59]);
  398.     }
  399.         return( scanCodes [scanCode] );
  400. }
  401.     /* Translate extended keys. */
  402.     if( ISALPHASCANCODE(scanCode) && (modifiers & MOD_KEY_ALT) )
  403.         return(0xFF00 | extendedAlphaKeyCodes[scanCode-0x04]);
  404.     if( ISOTHEREXTENDEDSCANCODE(scanCode) )
  405.         return(0xFF00 | extendedOtherKeyCodes[scanCode-0x49]);
  406.     if( ISFUNCTIONSCANCODE(scanCode) && (modifiers & MOD_KEY_ALT) )
  407.         return(0xFF00 | extendedAltFunctionKeyCodes[scanCode-0x3A]);
  408.     if( ISFUNCTIONSCANCODE(scanCode))
  409.         return(0xFF00 | extendedFunctionKeyCodes[scanCode-0x3A]);
  410.     /* Translate the scan code into a preliminary ASCII code */
  411.     if (scanCode < SCAN_CODE_TBL_LEN)
  412. {
  413.         /* Translate alpha keys */
  414.         if( ISALPHASCANCODE(scanCode) )
  415.     {
  416.             if( modifiers & MOD_KEY_CTRL )
  417.                 return( scanCodesShift [scanCode] - CTRL_CASE_OFFSET);
  418.             if( !!(modifiers & MOD_KEY_SHIFT) ^ !!(pSioChan->capsLock) )
  419.                 return( scanCodesShift [scanCode] );
  420.             else
  421.                 return( scanCodes [scanCode] );
  422.     }
  423.         /* Translate non-alpha keys */
  424.         if ((modifiers & (MOD_KEY_SHIFT | MOD_KEY_CTRL)) != 0)
  425.          return( scanCodesShift [scanCode] );
  426.         else
  427.         return( scanCodes [scanCode] );
  428. }
  429.     return(NOTKEY);
  430.     }
  431. /***************************************************************************
  432. *
  433. * isKeyPresent - determines if a key is present in an array of keys
  434. *
  435. * RETURNS: TRUE if <key> is present in the <keyArray> passed by the
  436. * caller, else returns FALSE.
  437. */
  438. LOCAL BOOL isKeyPresent
  439.     (
  440.     pUINT16 pKeyArray,
  441.     UINT16 key
  442.     )
  443.     {
  444.     UINT16 i;
  445.     for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  446. if (key == pKeyArray [i])
  447.     return TRUE;
  448.     return FALSE;
  449.     }
  450. /***************************************************************************
  451. *
  452. * setLedReport - Issues a SET_REPORT to change a keyboard's LEDs
  453. *
  454. * RETURNS: N/A
  455. */
  456. LOCAL VOID setLedReport
  457.     (
  458.     pUSB_KBD_SIO_CHAN pSioChan,
  459.     UINT8 ledReport
  460.     )
  461.     {
  462.     UINT8 * pLedReport = OSS_CALLOC (sizeof (UINT8));
  463.     if (pLedReport == NULL)
  464. return;
  465.     *pLedReport = ledReport;
  466.     usbHidReportSet (usbdHandle, 
  467.      pSioChan->nodeId, 
  468.      pSioChan->interface, 
  469.      USB_HID_RPT_TYPE_OUTPUT,      
  470.      0, 
  471.      pLedReport, 
  472.      sizeof (ledReport));
  473.     OSS_FREE (pLedReport);
  474.     }
  475. /***************************************************************************
  476. *
  477. * changeKeyState - changes keyboard state
  478. *
  479. * <key> is CAPLOCK, SCRLOCK, or NUMLOCK.  If <key> is not already 
  480. * active, then, toggle the current keyboard state for the corresponding item.
  481. *
  482. * RETURNS: N/A
  483. */
  484. LOCAL VOID changeKbdState
  485.     (
  486.     pUSB_KBD_SIO_CHAN pSioChan,
  487.     UINT16 scanCode,  /* not used */
  488.     pBOOL pKeyState
  489.     )
  490.     {
  491.     UINT8 ledReport;
  492.     /* The scancode is newly active, toggle the corresponding keyboard state. */
  493.     *pKeyState = !(*pKeyState);
  494.     /* Update the keyboard LEDs */
  495.     ledReport = (pSioChan->capsLock) ? RPT_LED_CAPS_LOCK : 0;
  496.     ledReport |= (pSioChan->scrLock) ? RPT_LED_SCROLL_LOCK : 0;
  497.     ledReport |= (pSioChan->numLock) ? RPT_LED_NUM_LOCK : 0;
  498.     setLedReport (pSioChan, ledReport);
  499.     }
  500. /***************************************************************************
  501. *
  502. * interpScanCode - interprets keyboard scan code
  503. *
  504. * Interprets the <scanCode> according to the <modifiers>.  This function
  505. * handles any special requirements, such as turning an LED ON or OFF in
  506. * response to a keypress.
  507. *
  508. * RETURNS: N/A.
  509. */
  510. LOCAL void interpScanCode
  511.     (
  512.     pUSB_KBD_SIO_CHAN pSioChan,
  513.     UINT16 scanCode,
  514.     UINT16 modifiers
  515.     )
  516.     {
  517.     /* If the key is already active, ignore it. */
  518.     if (isKeyPresent (pSioChan->activeScanCodes, scanCode))
  519.         return;
  520.     /* Determine if special handling is required for the key */
  521.     switch (scanCode)
  522. {
  523.         case CAPLOCK:   /* key is CAPLOCK */
  524.         case CAPLOCK_LOCKING:   /* key is CAPLOCK */
  525.         changeKbdState (pSioChan, scanCode, &pSioChan->capsLock);
  526.         break;
  527.         case SCRLOCK:   /* key is SCRLOCK */
  528.         case SCRLOCK_LOCKING:   /* key is SCRLOCK */
  529.         changeKbdState (pSioChan, scanCode, &pSioChan->scrLock);
  530.         break;
  531.         case NUMLOCK:   /* key is NUMLOCK */
  532.         case NUMLOCK_LOCKING:   /* key is NUMLOCK */
  533.         changeKbdState (pSioChan, scanCode, &pSioChan->numLock);
  534.         break;
  535.         case NOTKEY:    /* no valid scan code mapping */
  536.         default: /* an ASCII character */
  537.     break;
  538. }
  539.     }
  540. /***************************************************************************
  541. *
  542. * putInChar - puts a character into channel's input queue
  543. *
  544. * RETURNS: N/A
  545. */
  546. LOCAL VOID putInChar
  547.     (
  548.     pUSB_KBD_SIO_CHAN pSioChan,
  549.     char putChar
  550.     )
  551.     {
  552.     if (pSioChan->inQueueCount < KBD_Q_DEPTH)
  553. {
  554. pSioChan->inQueue [pSioChan->inQueueIn] = putChar;
  555. if (++pSioChan->inQueueIn == KBD_Q_DEPTH)
  556.     pSioChan->inQueueIn = 0;
  557. pSioChan->inQueueCount++;
  558. }
  559.     }
  560. /***************************************************************************
  561. *
  562. * nextInChar - returns next character from input queue
  563. *
  564. * Returns the next character from the channel's input queue and updates
  565. * the queue pointers.  The caller must ensure that at least one character
  566. * is in the queue prior to calling this function.
  567. *
  568. * RETURNS: next char in queue
  569. */
  570. LOCAL char nextInChar
  571.     (
  572.     pUSB_KBD_SIO_CHAN pSioChan
  573.     )
  574.     {
  575.     char inChar = pSioChan->inQueue [pSioChan->inQueueOut];
  576.     if (++pSioChan->inQueueOut == KBD_Q_DEPTH)
  577. pSioChan->inQueueOut = 0;
  578.     pSioChan->inQueueCount--;
  579.     return inChar;
  580.     }
  581. /***************************************************************************
  582. *
  583. * updateTypematic - generates typematic characters for channel if appropriate
  584. *
  585. * RETURNS: N/A
  586. */
  587. LOCAL VOID updateTypematic
  588.     (
  589.     pUSB_KBD_SIO_CHAN pSioChan
  590.     )
  591.     {
  592.     UINT32 diffTime;
  593.     UINT32 repeatCount;
  594.     /* If the given channel is active and a typematic character is
  595.      * indicated, then update the typematic state.
  596.      */
  597.     if (pSioChan->connected && pSioChan->typematicChar != 0)
  598. {
  599.         diffTime = OSS_TIME () - pSioChan->typematicTime;
  600.         /* If the typematic delay has passed, then it is time to start
  601.          * injecting characters into the queue.
  602.          */
  603.         if (diffTime >= TYPEMATIC_DELAY)
  604.     {
  605.     diffTime -= TYPEMATIC_DELAY;
  606.     repeatCount = diffTime / TYPEMATIC_PERIOD + 1;
  607.     /* Inject characters into the queue.  If the queue is
  608.      * full, putInChar() dumps the character, but we increment
  609.      * the typematicCount anyway.  This keeps the queue from
  610.      * getting too far ahead of the user. 
  611.      */
  612.     while (repeatCount > pSioChan->typematicCount)
  613. {
  614. if( ISEXTENDEDKEYCODE(pSioChan->typematicChar) )
  615.     {
  616.     if(pSioChan->inQueueCount < KBD_Q_DEPTH-1)
  617. {
  618. putInChar (pSioChan, (char) 0);
  619. putInChar (pSioChan, 
  620.    (char) pSioChan->typematicChar & 0xFF);
  621. }
  622.     }
  623. else
  624.     {
  625.     putInChar (pSioChan, pSioChan->typematicChar);
  626.     }
  627. pSioChan->typematicCount++;
  628. }
  629.     /* invoke receive callback */
  630.     while (pSioChan->inQueueCount > 0 &&
  631.     pSioChan->putRxCharCallback != NULL &&
  632.     pSioChan->mode == SIO_MODE_INT)
  633. {
  634.                 (*pSioChan->putRxCharCallback) (pSioChan->putRxCharArg, 
  635. nextInChar (pSioChan));
  636. }
  637.     }
  638. }
  639.     }
  640. /***************************************************************************
  641. *
  642. * interpKbdReport - interprets USB keyboard BOOT report
  643. *
  644. * Interprets a keyboard boot report and updates channel state as
  645. * appropriate.  Operates in one of two modes: ASCII or RAW.  In ASCII mode
  646. * it inserts the ascii character into the character buffer and implements
  647. * typematic repeat.  In RAW mode it always inserts the modifier byte
  648. * regardless of change, it inserts any keypresses that are currently active
  649. * and it inserts a terminating byte of 0xff into the charater buffer.
  650. *
  651. * RETURNS: N/A
  652. */
  653. LOCAL VOID interpKbdReport
  654.     (
  655.     pUSB_KBD_SIO_CHAN pSioChan
  656.     )
  657.     {
  658.     pHID_KBD_BOOT_REPORT pReport = pSioChan->pBootReport;
  659.     UINT16 keyCode;
  660.     UINT16 newTypematicChar;
  661.     UINT16 activeCount;
  662.     UINT16 i;
  663.     /* 
  664.      * interpret each key position in a keyboard boot report 
  665.      * (handles CAPS/SCROLL/NUM lock). 
  666.      */
  667.     for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  668.         interpScanCode (pSioChan, pReport->scanCodes [i], pReport->modifiers);
  669.     /* Raw mode has been set, handle accordingly */
  670.     if (pSioChan->scanMode == SIO_KYBD_MODE_RAW)
  671. {
  672. /* The first byte is any modifier keys, CTRL, SHIFT, ALT, GUI */
  673. putInChar (pSioChan, pReport->modifiers);
  674. for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  675.     if (pReport->scanCodes [i])
  676.     /* Any depressed keys */
  677.     putInChar (pSioChan, pReport->scanCodes [i]);
  678. /* trailing byte */
  679. putInChar (pSioChan, 0xff);
  680.      }
  681.     /* then pSioChan->scanMode must = SIO_KYBD_MODE_ASCII */
  682.     else 
  683. {
  684. /* insert newly activated keys into the input queue for the keyboard */
  685. newTypematicChar = 0;
  686. activeCount = 0;
  687. for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  688.     {
  689.     if (pReport->scanCodes [i])
  690. {
  691. keyCode = cvtScanCodeToKeyCode (pSioChan, 
  692. pReport->scanCodes [i], 
  693. pReport->modifiers);
  694. if (!isKeyPresent (pSioChan->activeScanCodes, 
  695.    pReport->scanCodes [i]))
  696.     {
  697.     /* If there is room in the input queue, enqueue the key,
  698.      * else discard it.
  699.      * For extended keyCodes, make sure there is room for two 
  700.      * chars - the 0 and the ext key. 
  701.      */
  702.     if( ISEXTENDEDKEYCODE(keyCode) )
  703. {
  704. if(pSioChan->inQueueCount < KBD_Q_DEPTH-1)
  705.     {
  706.     putInChar (pSioChan, (char) 0);
  707.     putInChar (pSioChan, (char) keyCode & 0xFF);
  708.     }
  709. }
  710.     else
  711. {
  712. if(keyCode)
  713.     putInChar (pSioChan, (char) keyCode & 0xFF);
  714. }
  715.     }
  716. newTypematicChar = keyCode;
  717. activeCount++;
  718. }
  719.     }
  720.     /* 
  721.      * If newTypematicChar is 0, then no keys were received in 
  722.      * this report - so no keys are being held down.  If 
  723.      * newTypematicChar matches the previous typematic char, 
  724.      * then allow the typematic timer to continue.  If 
  725.      * newTypematicChar is different (but non-zero), then start 
  726.      * a new timer.  In all cases, only one key may be active 
  727.      * for typematic repeat to be enabled. 
  728.      */
  729.     if (activeCount != 1)
  730. newTypematicChar = 0;
  731.     if (newTypematicChar != pSioChan->typematicChar)
  732. {
  733. pSioChan->typematicChar = newTypematicChar;
  734. if (newTypematicChar != 0)
  735.     {
  736.     pSioChan->typematicTime = OSS_TIME ();
  737.     pSioChan->typematicCount = 0;
  738.     }
  739. }
  740.     updateTypematic (pSioChan);
  741. }
  742.     /* invoke receive callback */
  743.     while (pSioChan->inQueueCount > 0 &&
  744.            pSioChan->putRxCharCallback != NULL &&
  745.            pSioChan->mode == SIO_MODE_INT)
  746. {
  747.         (*pSioChan->putRxCharCallback) (pSioChan->putRxCharArg, 
  748. nextInChar (pSioChan));
  749. }
  750.     /* 
  751.      * Copy the current list of active keys to the channel 
  752.      * structure, overwriting the previous list.
  753.      */
  754.     for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  755. pSioChan->activeScanCodes [i] = pReport->scanCodes [i];
  756.     }
  757. /***************************************************************************
  758. *
  759. * usbKeyboardIoctl - special device control
  760. *
  761. * This routine is largely a no-op for the usbKeyboardLib.  The only ioctls
  762. * which are used by this module are the SIO_AVAIL_MODES_GET and SIO_MODE_SET.
  763. *
  764. * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed
  765. * request.
  766. */
  767. LOCAL int usbKeyboardIoctl
  768.     (
  769.     SIO_CHAN *pChan,     /* device to control */
  770.     int request, /* request code */
  771.     void *someArg /* some argument */
  772.     )
  773.     {
  774.     pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan;
  775.     int arg = (int) someArg;
  776.     switch (request)
  777. {
  778. case SIO_BAUD_SET:
  779.     /* baud rate has no meaning for USB.  We store the desired 
  780.      * baud rate value and return OK.
  781.      */
  782.     pSioChan->baudRate = arg;
  783.     return OK;
  784. case SIO_BAUD_GET:
  785.     /* Return baud rate to caller */
  786.     *((int *) arg) = pSioChan->baudRate;
  787.     return OK;
  788. case SIO_MODE_SET:
  789.     /* Set driver operating mode: interrupt or polled */
  790.     if (arg != SIO_MODE_POLL && arg != SIO_MODE_INT)
  791. return EIO;
  792.     pSioChan->mode = arg;
  793.     return OK;
  794. case SIO_MODE_GET:
  795.     /* Return current driver operating mode for channel */
  796.     *((int *) arg) = pSioChan->mode;
  797.     return OK;
  798. case SIO_AVAIL_MODES_GET:
  799.     /* Return modes supported by driver. */
  800.     *((int *) arg) = SIO_MODE_INT | SIO_MODE_POLL;
  801.     return OK;
  802. case SIO_OPEN:
  803.     /* Channel is always open. */
  804.     return OK;
  805.          case SIO_KYBD_MODE_SET:
  806.              switch (arg)
  807.                  {
  808.                  case SIO_KYBD_MODE_RAW:
  809.                  case SIO_KYBD_MODE_ASCII:
  810.                      break;
  811.                  case SIO_KYBD_MODE_UNICODE:
  812.                      return ENOSYS; /* usb doesn't support unicode */
  813.                  }
  814.              pSioChan->scanMode = arg;
  815.              return OK;
  816.          case SIO_KYBD_MODE_GET:
  817.              *(int *)someArg = pSioChan->scanMode;
  818.              return OK;
  819.          case SIO_KYBD_LED_SET:
  820.     {
  821.     UINT8 ledReport;
  822.  
  823.     /*  update the channel's information about the LED state */
  824.     pSioChan->numLock = (arg & SIO_KYBD_LED_NUM) ? SIO_KYBD_LED_NUM : 0;
  825.     pSioChan->capsLock = (arg & SIO_KYBD_LED_CAP) ? 
  826. SIO_KYBD_LED_CAP : 0;
  827.     pSioChan->scrLock = (arg & SIO_KYBD_LED_SCR) ? 
  828. SIO_KYBD_LED_SCR : 0;
  829.     /* 
  830.      * We are relying on the SIO_KYBD_LED_X macros matching the USB
  831.      * LED equivelants.
  832.      */
  833.     ledReport = arg;
  834.     /* set the LED's */
  835.     setLedReport (pSioChan, ledReport);
  836.      
  837.     return OK;
  838.     }
  839.          case SIO_KYBD_LED_GET:
  840.      {
  841.      int tempArg;
  842.           tempArg = (pSioChan->capsLock) ? SIO_KYBD_LED_CAP : 0;
  843.           tempArg |= (pSioChan->scrLock) ? SIO_KYBD_LED_SCR : 0;
  844.           tempArg |= (pSioChan->numLock) ? SIO_KYBD_LED_NUM : 0;
  845.      *(int *) someArg = tempArg;
  846.              return OK;
  847.      }
  848. case SIO_HW_OPTS_SET:   /* optional, not supported */
  849. case SIO_HW_OPTS_GET:   /* optional, not supported */
  850. case SIO_HUP: /* hang up is not supported */
  851. default:     /* unknown/unsupported command. */
  852.     return ENOSYS;
  853. }
  854.     }
  855. /***************************************************************************
  856. *
  857. * usbKeyboardTxStartup - start the interrupt transmitter
  858. *
  859. * The USB keyboard SIO driver does not support output to the keyboard.
  860. *
  861. * RETURNS: EIO
  862. */
  863. LOCAL int usbKeyboardTxStartup
  864.     (
  865.     SIO_CHAN *pChan /* channel to start */
  866.     )
  867.     {
  868.     return EIO;
  869.     }
  870. /***************************************************************************
  871. *
  872. * usbKeyboardCallbackInstall - install ISR callbacks to get/put chars
  873. *
  874. * This driver allows interrupt callbacks for transmitting characters
  875. * and receiving characters.=
  876. *
  877. * RETURNS: OK on success, or ENOSYS for an unsupported callback type.
  878. */ 
  879. LOCAL int usbKeyboardCallbackInstall
  880.     (
  881.     SIO_CHAN *pChan,     /* channel */
  882.     int callbackType,     /* type of callback */
  883.     STATUS (*callback) (),  /* callback */
  884.     void *callbackArg     /* parameter to callback */
  885.     )
  886.     {
  887.     pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan;
  888.     switch (callbackType)
  889. {
  890. case SIO_CALLBACK_GET_TX_CHAR:
  891.     pSioChan->getTxCharCallback = callback;
  892.     pSioChan->getTxCharArg = callbackArg;
  893.     return OK;
  894. case SIO_CALLBACK_PUT_RCV_CHAR:
  895.     pSioChan->putRxCharCallback = callback;
  896.     pSioChan->putRxCharArg = callbackArg;
  897.     return OK;
  898. default:
  899.     return ENOSYS;
  900. }
  901.     }
  902. /***************************************************************************
  903. *
  904. * usbKeyboardPollOutput - output a character in polled mode
  905. *
  906. * The USB keyboard SIO driver does not support output to the keyboard.
  907. *
  908. * RETURNS: EIO
  909. */
  910. LOCAL int usbKeyboardPollOutput
  911.     (
  912.     SIO_CHAN *pChan,
  913.     char outChar
  914.     )
  915.     {
  916.     return EIO;
  917.     }
  918. /***************************************************************************
  919. *
  920. * usbKeyboardPollInput - poll the device for input
  921. *
  922. * RETURNS: OK if a character arrived, EIO on device error, EAGAIN
  923. * if the input buffer if empty, ENOSYS if the device is interrupt-only.
  924. */
  925. LOCAL int usbKeyboardPollInput
  926.     (
  927.     SIO_CHAN *pChan,
  928.     char *thisChar
  929.     )
  930.     {
  931.     pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan;
  932.     int status = OK;
  933.     /* validate parameters */
  934.     if (thisChar == NULL)
  935.         return EIO;
  936.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  937.     /* Check if the input queue is empty. */
  938.     if (pSioChan->inQueueCount == 0)
  939.         status = EAGAIN;
  940.     else
  941. {
  942. /* Return a character from the input queue. */
  943. *thisChar = nextInChar (pSioChan);
  944. }
  945.     OSS_MUTEX_RELEASE (kbdMutex);
  946.     return status;
  947.     }
  948. /***************************************************************************
  949. *
  950. * initKbdIrp - Initialize IRP to listen for input on interrupt pipe
  951. *
  952. * RETURNS: TRUE if able to submit IRP successfully, else FALSE
  953. */
  954. LOCAL BOOL initKbdIrp
  955.     (
  956.     pUSB_KBD_SIO_CHAN pSioChan
  957.     )
  958.     {
  959.     pUSB_IRP pIrp = &pSioChan->irp;
  960.     /* Initialize IRP */
  961.     memset (pIrp, 0, sizeof (*pIrp));
  962.     pIrp->userPtr = pSioChan;
  963.     pIrp->irpLen = sizeof (*pIrp);
  964.     pIrp->userCallback = usbKeyboardIrpCallback;
  965.     pIrp->timeout = USB_TIMEOUT_NONE;
  966.     pIrp->transferLen = sizeof (HID_KBD_BOOT_REPORT);
  967.     pIrp->bfrCount = 1;
  968.     pIrp->bfrList [0].pid = USB_PID_IN;
  969.     pIrp->bfrList [0].pBfr = (pUINT8) pSioChan->pBootReport;
  970.     pIrp->bfrList [0].bfrLen = sizeof (HID_KBD_BOOT_REPORT);
  971.     /* Submit IRP */
  972.     if (usbdTransfer (usbdHandle, pSioChan->pipeHandle, pIrp) != OK)
  973. return FALSE;
  974.     pSioChan->irpInUse = TRUE;
  975.     return TRUE;
  976.     }
  977. /***************************************************************************
  978. *
  979. * usbKeyboardIrpCallback - Invoked upon IRP completion/cancellation
  980. *
  981. * Examines the cause of the IRP completion.  If completion was successful,
  982. * interprets the USB keyboard's boot report and re-submits the IRP.
  983. *
  984. * RETURNS: N/A
  985. */
  986. LOCAL VOID usbKeyboardIrpCallback
  987.     (
  988.     pVOID p     /* completed IRP */
  989.     )
  990.     {
  991.     pUSB_IRP pIrp = (pUSB_IRP) p;
  992.     pUSB_KBD_SIO_CHAN pSioChan = pIrp->userPtr;
  993.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  994.     /* Was the IRP successful? */
  995.     if (pIrp->result == OK)
  996. {
  997. /* Interpret the keyboard report */
  998. interpKbdReport (pSioChan);
  999. }
  1000.     /* Re-submit the IRP unless it was canceled - which would happen only
  1001.      * during pipe shutdown (e.g., the disappearance of the device).
  1002.      */
  1003.     pSioChan->irpInUse = FALSE;
  1004.     if (pIrp->result != S_usbHcdLib_IRP_CANCELED)
  1005. initKbdIrp (pSioChan);
  1006.     OSS_MUTEX_RELEASE (kbdMutex);
  1007.     }
  1008. /***************************************************************************
  1009. *
  1010. * typematicThread - Updates typematic state for each active channel
  1011. *
  1012. * RETURNS: N/A
  1013. */
  1014. LOCAL VOID typematicThread
  1015.     (
  1016.     pVOID param  /* param not used by this thread */
  1017.     )
  1018.     {
  1019.     pUSB_KBD_SIO_CHAN pSioChan;
  1020.     while (!killTypematic)
  1021. {
  1022.         OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  1023.         /* Walk the list of open channels and update the typematic
  1024.          * state for each.
  1025.          */
  1026.         pSioChan = usbListFirst (&sioList);
  1027.         while (pSioChan != NULL)
  1028.     {
  1029.     updateTypematic (pSioChan);
  1030.     pSioChan = usbListNext (&pSioChan->sioLink);
  1031.     }
  1032.         OSS_MUTEX_RELEASE (kbdMutex);
  1033.         OSS_THREAD_SLEEP (TYPEMATIC_PERIOD);
  1034. }
  1035.     typematicExit = TRUE;
  1036.     }
  1037. /***************************************************************************
  1038. *
  1039. * configureSioChan - configure USB keyboard for operation
  1040. *
  1041. * Selects the configuration/interface specified in the <pSioChan>
  1042. * structure.  These values come from the USBD dynamic attach callback,
  1043. * which in turn retrieved them from the configuration/interface
  1044. * descriptors which reported the device to be a keyboard.
  1045. *
  1046. * RETURNS: TRUE if successful, else FALSE if failed to configure channel
  1047. */
  1048. LOCAL BOOL configureSioChan
  1049.     (
  1050.     pUSB_KBD_SIO_CHAN pSioChan
  1051.     )
  1052.     {
  1053.     pUSB_CONFIG_DESCR pCfgDescr;
  1054.     pUSB_INTERFACE_DESCR pIfDescr;
  1055.     pUSB_ENDPOINT_DESCR pEpDescr;
  1056.     UINT8 * pBfr;
  1057.     UINT8 * pScratchBfr;
  1058.     UINT16 actLen;
  1059.     UINT16 ifNo;
  1060.     UINT16 maxPacketSize;
  1061.     if ((pBfr = OSS_MALLOC (USB_MAX_DESCR_LEN)) == NULL)
  1062. return FALSE;
  1063.     /* Read the configuration descriptor to get the configuration selection
  1064.      * value and to determine the device's power requirements.
  1065.      */
  1066.     if (usbdDescriptorGet (usbdHandle, 
  1067.    pSioChan->nodeId,
  1068.    USB_RT_STANDARD | USB_RT_DEVICE, 
  1069.    USB_DESCR_CONFIGURATION, 
  1070.    0, 
  1071.    0,
  1072.    USB_MAX_DESCR_LEN, 
  1073.    pBfr, 
  1074.    &actLen) 
  1075.  != OK)
  1076. {
  1077. OSS_FREE (pBfr);
  1078. return FALSE;
  1079. }
  1080.     if ((pCfgDescr = usbDescrParse (pBfr, 
  1081.     actLen, 
  1082.     USB_DESCR_CONFIGURATION)) 
  1083. == NULL)
  1084.         {
  1085.         OSS_FREE (pBfr);
  1086. return FALSE;
  1087. }
  1088.     /* Look for the interface indicated in the pSioChan structure. */
  1089.     ifNo = 0;
  1090.     /* 
  1091.      * usbDescrParseSkip() modifies the value of the pointer it recieves
  1092.      * so we pass it a copy of our buffer pointer
  1093.      */
  1094.     pScratchBfr = pBfr;
  1095.     while ((pIfDescr = usbDescrParseSkip (&pScratchBfr,
  1096.   &actLen,
  1097.   USB_DESCR_INTERFACE)) 
  1098.     != NULL)
  1099. {
  1100. if (ifNo == pSioChan->interface)
  1101.     break;
  1102. ifNo++;
  1103. }
  1104.     if (pIfDescr == NULL)
  1105.         {
  1106.         OSS_FREE (pBfr);
  1107. return FALSE;
  1108. }
  1109.     /* Retrieve the endpoint descriptor following the identified interface
  1110.      * descriptor.
  1111.      */
  1112.     if ((pEpDescr = usbDescrParseSkip (&pScratchBfr, 
  1113.        &actLen, 
  1114.        USB_DESCR_ENDPOINT))
  1115.   == NULL)
  1116. {
  1117. OSS_FREE (pBfr);
  1118. return FALSE;
  1119. }
  1120.     /* Select the configuration. */
  1121.     if (usbdConfigurationSet (usbdHandle, 
  1122.       pSioChan->nodeId,
  1123.       pCfgDescr->configurationValue, 
  1124.       pCfgDescr->maxPower * USB_POWER_MA_PER_UNIT) 
  1125.     != OK)
  1126.         {
  1127.         OSS_FREE (pBfr);
  1128.         return FALSE;
  1129.         }
  1130.     /* Select interface 
  1131.      * 
  1132.      * NOTE: Some devices may reject this command, and this does not represent
  1133.      * a fatal error.  Therefore, we ignore the return status.
  1134.      */
  1135.     usbdInterfaceSet (usbdHandle, 
  1136.       pSioChan->nodeId, 
  1137.       pSioChan->interface, 
  1138.       pIfDescr->alternateSetting);
  1139.     /* Select the keyboard boot protocol. */
  1140.     if (usbHidProtocolSet (usbdHandle, 
  1141.    pSioChan->nodeId,
  1142.    pSioChan->interface, 
  1143.    USB_HID_PROTOCOL_BOOT) 
  1144.  != OK)
  1145.         {
  1146.         OSS_FREE (pBfr);
  1147.         return FALSE;
  1148.         }
  1149.     /* Set the keyboard idle time to infinite. */
  1150.     if (usbHidIdleSet (usbdHandle, 
  1151.        pSioChan->nodeId,
  1152.        pSioChan->interface, 
  1153.        0 /* no report ID */, 
  1154.        0 /* infinite */) 
  1155.     != OK)
  1156.         {
  1157.         OSS_FREE (pBfr);
  1158.         return FALSE;
  1159.         }
  1160.     /* Turn off LEDs. */
  1161.     setLedReport (pSioChan, 0);
  1162.     /* Create a pipe to monitor input reports from the keyboard. */
  1163.     maxPacketSize = *((pUINT8) &pEpDescr->maxPacketSize) |
  1164.     (*(((pUINT8) &pEpDescr->maxPacketSize) + 1) << 8);
  1165.     if (usbdPipeCreate (usbdHandle, 
  1166. pSioChan->nodeId,     
  1167. pEpDescr->endpointAddress, 
  1168. pCfgDescr->configurationValue,    
  1169. pSioChan->interface, 
  1170. USB_XFRTYPE_INTERRUPT, 
  1171. USB_DIR_IN,    
  1172. maxPacketSize, 
  1173. sizeof (HID_KBD_BOOT_REPORT), 
  1174. pEpDescr->interval, 
  1175. &pSioChan->pipeHandle) 
  1176.      != OK)
  1177.         {
  1178.         OSS_FREE (pBfr);
  1179.         return FALSE;
  1180.         }
  1181.     /* Initiate IRP to listen for input on interrupt pipe */
  1182.     if (!initKbdIrp (pSioChan))
  1183.         {
  1184.         OSS_FREE (pBfr);
  1185.         return FALSE;
  1186.         }
  1187.     OSS_FREE (pBfr);
  1188.     return TRUE;
  1189.     }
  1190. /***************************************************************************
  1191. *
  1192. * destroyAttachRequest - disposes of an ATTACH_REQUEST structure
  1193. *
  1194. * RETURNS: N/A
  1195. */
  1196. LOCAL VOID destroyAttachRequest
  1197.     (
  1198.     pATTACH_REQUEST pRequest
  1199.     )
  1200.     {
  1201.     /* Unlink request */
  1202.     usbListUnlink (&pRequest->reqLink);
  1203.     /* Dispose of structure */
  1204.     OSS_FREE (pRequest);
  1205.     }
  1206. /***************************************************************************
  1207. *
  1208. * destroySioChan - disposes of a USB_KBD_SIO_CHAN structure
  1209. *
  1210. * Unlinks the indicated USB_KBD_SIO_CHAN structure and de-allocates
  1211. * resources associated with the channel.
  1212. *
  1213. * RETURNS: N/A
  1214. */
  1215. LOCAL VOID destroySioChan
  1216.     (
  1217.     pUSB_KBD_SIO_CHAN pSioChan
  1218.     )
  1219.     {
  1220.     /* Unlink the structure. */
  1221.     usbListUnlink (&pSioChan->sioLink);
  1222.     /* Release pipe if one has been allocated. Wait for the IRP to be
  1223.      * cancelled if necessary.
  1224.      */
  1225.     if (pSioChan->pipeHandle != NULL)
  1226. usbdPipeDestroy (usbdHandle, pSioChan->pipeHandle);
  1227.     while (pSioChan->irpInUse)
  1228. OSS_THREAD_SLEEP (1);
  1229.     /* Release structure. */
  1230.     if (pSioChan->pBootReport != NULL)
  1231. OSS_FREE (pSioChan->pBootReport);
  1232.     OSS_FREE (pSioChan);
  1233.     }
  1234. /***************************************************************************
  1235. *
  1236. * createSioChan - creates a new USB_KBD_SIO_CHAN structure
  1237. *
  1238. * Creates a new USB_KBD_SIO_CHAN structure for the indicated <nodeId>.
  1239. * If successful, the new structure is linked into the sioList upon 
  1240. * return.
  1241. *
  1242. * <configuration> and <interface> identify the configuration/interface
  1243. * that first reported itself as a keyboard for this device.
  1244. *
  1245. * RETURNS: pointer to newly created structure, or NULL if failure
  1246. */
  1247. LOCAL pUSB_KBD_SIO_CHAN createSioChan
  1248.     (
  1249.     USBD_NODE_ID nodeId,
  1250.     UINT16 configuration,
  1251.     UINT16 interface
  1252.     )
  1253.     {
  1254.     pUSB_KBD_SIO_CHAN pSioChan;
  1255.     UINT16 i;
  1256.     /* Try to allocate space for a new keyboard struct */
  1257.     if ((pSioChan = OSS_CALLOC (sizeof (*pSioChan))) == NULL)
  1258.      return NULL;
  1259.     if ((pSioChan->pBootReport = OSS_CALLOC (sizeof (*pSioChan->pBootReport)))
  1260.       == NULL)
  1261. {
  1262. OSS_FREE (pSioChan);
  1263. return NULL;
  1264. }
  1265.     pSioChan->sioChan.pDrvFuncs = &usbKeyboardSioDrvFuncs;
  1266.     pSioChan->nodeId = nodeId;
  1267.     pSioChan->connected = TRUE;
  1268.     pSioChan->mode = SIO_MODE_POLL;
  1269.     pSioChan->scanMode = SIO_KYBD_MODE_ASCII;
  1270.     pSioChan->configuration = configuration;
  1271.     pSioChan->interface = interface;
  1272.     for (i = 0; i < BOOT_RPT_KEYCOUNT; i++)
  1273. pSioChan->activeScanCodes [i] = NOTKEY;
  1274.     /* Try to configure the keyboard. */
  1275.     if (!configureSioChan (pSioChan))
  1276. {
  1277. destroySioChan (pSioChan);
  1278. return NULL;
  1279. }
  1280.     /* Link the newly created structure. */
  1281.     usbListLink (&sioList, pSioChan, &pSioChan->sioLink, LINK_TAIL);
  1282.     return pSioChan;
  1283.     }
  1284. /***************************************************************************
  1285. *
  1286. * findSioChan - Searches for a USB_KBD_SIO_CHAN for indicated node ID
  1287. *
  1288. * RETURNS: pointer to matching USB_KBD_SIO_CHAN or NULL if not found
  1289. */
  1290. LOCAL pUSB_KBD_SIO_CHAN findSioChan
  1291.     (
  1292.     USBD_NODE_ID nodeId
  1293.     )
  1294.     {
  1295.     pUSB_KBD_SIO_CHAN pSioChan = usbListFirst (&sioList);
  1296.     while (pSioChan != NULL)
  1297. {
  1298. if (pSioChan->nodeId == nodeId)
  1299.     break;
  1300. pSioChan = usbListNext (&pSioChan->sioLink);
  1301. }
  1302.     return pSioChan;
  1303.     }
  1304. /***************************************************************************
  1305. *
  1306. * notifyAttach - Notifies registered callers of attachment/removal
  1307. *
  1308. * RETURNS: N/A
  1309. */
  1310. LOCAL VOID notifyAttach
  1311.     (
  1312.     pUSB_KBD_SIO_CHAN pSioChan,
  1313.     UINT16 attachCode
  1314.     )
  1315.     {
  1316.     pATTACH_REQUEST pRequest = usbListFirst (&reqList);
  1317.     while (pRequest != NULL)
  1318. {
  1319. (*pRequest->callback) (pRequest->callbackArg, 
  1320.        (SIO_CHAN *) pSioChan, 
  1321.        attachCode);
  1322. pRequest = usbListNext (&pRequest->reqLink);
  1323. }
  1324.     }
  1325. /***************************************************************************
  1326. *
  1327. * usbKeyboardAttachCallback - called by USBD when keyboard attached/removed
  1328. *
  1329. * The USBD will invoke this callback when a USB keyboard is attached to or
  1330. * removed from the system.  <nodeId> is the USBD_NODE_ID of the node being
  1331. * attached or removed. <attachAction> is USBD_DYNA_ATTACH or USBD_DYNA_REMOVE.
  1332. * Keyboards generally report their class information at the interface level,
  1333. * so <configuration> and <interface> will indicate the configuratin/interface
  1334. * that reports itself as a keyboard.  Finally, <deviceClass>, <deviceSubClass>,
  1335. * and <deviceProtocol> will identify a HID/BOOT/KEYBOARD device.
  1336. *
  1337. * NOTE: The USBD will invoke this function once for each configuration/
  1338. * interface which reports itself as a keyboard.  So, it is possible that
  1339. * a single device insertion/removal may trigger multiple callbacks.  We
  1340. * ignore all callbacks except the first for a given device.
  1341. *
  1342. * RETURNS: N/A
  1343. */
  1344. LOCAL VOID usbKeyboardAttachCallback
  1345.     (
  1346.     USBD_NODE_ID nodeId, 
  1347.     UINT16 attachAction, 
  1348.     UINT16 configuration,
  1349.     UINT16 interface,
  1350.     UINT16 deviceClass, 
  1351.     UINT16 deviceSubClass, 
  1352.     UINT16 deviceProtocol
  1353.     )
  1354.     {
  1355.     pUSB_KBD_SIO_CHAN pSioChan;
  1356.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  1357.     /* Depending on the attach code, add a new keyboard or disabled one
  1358.      * that's already been created.
  1359.      */
  1360.     switch (attachAction)
  1361. {
  1362. case USBD_DYNA_ATTACH:
  1363.     /* A new device is being attached.  Check if we already 
  1364.      * have a structure for this device.
  1365.      */
  1366.     if (findSioChan (nodeId) != NULL)
  1367. break;
  1368.     /* Create a new structure to manage this device.  If there's
  1369.      * an error, there's nothing we can do about it, so skip the
  1370.      * device and return immediately. 
  1371.      */
  1372.     if ((pSioChan = createSioChan (nodeId, configuration, interface)) == NULL)
  1373. break;
  1374.     /* Notify registered callers that a new keyboard has been
  1375.      * added and a new channel created.
  1376.      */
  1377.     notifyAttach (pSioChan, USB_KBD_ATTACH);
  1378.     break;
  1379. case USBD_DYNA_REMOVE:
  1380.     /* A device is being detached. Check if we have any
  1381.      * structures to manage this device.
  1382.      */
  1383.     if ((pSioChan = findSioChan (nodeId)) == NULL)
  1384. break;
  1385.     /* The device has been disconnected. */
  1386.     pSioChan->connected = FALSE;
  1387.     /* Notify registered callers that the keyboard has been
  1388.      * removed and the channel disabled. 
  1389.      *
  1390.      * NOTE: We temporarily increment the channel's lock count
  1391.      * to prevent usbKeyboardSioChanUnlock() from destroying the
  1392.      * structure while we're still using it.
  1393.      */
  1394.     pSioChan->lockCount++;
  1395.     notifyAttach (pSioChan, USB_KBD_REMOVE);
  1396.     pSioChan->lockCount--;
  1397.     /* If no callers have the channel structure locked, destroy
  1398.      * it now.  If it is locked, it will be destroyed later during
  1399.      * a call to usbKeyboardUnlock().
  1400.      */
  1401.     if (pSioChan->lockCount == 0)
  1402. destroySioChan (pSioChan);
  1403.     break;
  1404. }
  1405.     OSS_MUTEX_RELEASE (kbdMutex);
  1406.     }
  1407. /***************************************************************************
  1408. *
  1409. * doShutdown - shuts down USB keyboard SIO driver
  1410. *
  1411. * <errCode> should be OK or S_usbKeyboardLib_xxxx.  This value will be
  1412. * passed to ossStatus() and the return value from ossStatus() is the
  1413. * return value of this function.
  1414. *
  1415. * RETURNS: OK, or ERROR per value of <errCode> passed by caller
  1416. */
  1417. LOCAL STATUS doShutdown
  1418.     (
  1419.     int errCode
  1420.     )
  1421.     {
  1422.     pATTACH_REQUEST pRequest;
  1423.     pUSB_KBD_SIO_CHAN pSioChan;
  1424.     /* Kill typematic thread */
  1425.     if (typematicThread != NULL)
  1426. {
  1427. killTypematic = TRUE;
  1428. while (!typematicExit)
  1429.     OSS_THREAD_SLEEP (1);
  1430. OSS_THREAD_DESTROY (typematicHandle);
  1431. }
  1432.     /* Dispose of any outstanding notification requests */
  1433.     while ((pRequest = usbListFirst (&reqList)) != NULL)
  1434. destroyAttachRequest (pRequest);
  1435.     /* Dispose of any open keyboard connections. */
  1436.     while ((pSioChan = usbListFirst (&sioList)) != NULL)
  1437. destroySioChan (pSioChan);
  1438.     
  1439.     /* Release our connection to the USBD.  The USBD automatically 
  1440.      * releases any outstanding dynamic attach requests when a client
  1441.      * unregisters.
  1442.      */
  1443.     if (usbdHandle != NULL)
  1444. {
  1445. usbdClientUnregister (usbdHandle);
  1446. usbdHandle = NULL;
  1447. }
  1448.     /* Release resources. */
  1449.     if (kbdMutex != NULL)
  1450. {
  1451. OSS_MUTEX_DESTROY (kbdMutex);
  1452. kbdMutex = NULL;
  1453. }
  1454.     return ossStatus (errCode);
  1455.     }
  1456. /***************************************************************************
  1457. *
  1458. * usbKeyboardDevInit - initialize USB keyboard SIO driver
  1459. *
  1460. * Initializes the USB keyboard SIO driver.  The USB keyboard SIO driver
  1461. * maintains an initialization count, so calls to this function may be
  1462. * nested.
  1463. *
  1464. * RETURNS: OK, or ERROR if unable to initialize.
  1465. *
  1466. * ERRNO:
  1467. *
  1468. *   S_usbKeyboardLib_OUT_OF_RESOURCES
  1469. *   S_usbKeyboardLib_USBD_FAULT
  1470. */
  1471. STATUS usbKeyboardDevInit (void)
  1472.     {
  1473.     /* If not already initialized, then initialize internal structures
  1474.      * and connection to USBD.
  1475.      */
  1476.     if (initCount == 0)
  1477. {
  1478. /* Initialize lists, structures, resources. */
  1479. memset (&sioList, 0, sizeof (sioList));
  1480. memset (&reqList, 0, sizeof (reqList));
  1481. kbdMutex = NULL;
  1482. usbdHandle = NULL;
  1483. typematicHandle = NULL;
  1484. killTypematic = FALSE;
  1485. typematicExit = FALSE;
  1486. if (OSS_MUTEX_CREATE (&kbdMutex) != OK)
  1487.     return doShutdown (S_usbKeyboardLib_OUT_OF_RESOURCES);
  1488. /* Initialize typematic repeat thread */
  1489. if (OSS_THREAD_CREATE (typematicThread, 
  1490.        NULL, 
  1491.        OSS_PRIORITY_LOW,
  1492.        TYPEMATIC_NAME, 
  1493.        &typematicHandle) 
  1494.      != OK)
  1495.     return doShutdown (S_usbKeyboardLib_OUT_OF_RESOURCES);
  1496. /* Establish connection to USBD */
  1497. if (usbdClientRegister (KBD_CLIENT_NAME, &usbdHandle) != OK ||
  1498.     usbdDynamicAttachRegister (usbdHandle, 
  1499.        USB_CLASS_HID,
  1500.        USB_SUBCLASS_HID_BOOT, 
  1501.        USB_PROTOCOL_HID_BOOT_KEYBOARD,
  1502.        usbKeyboardAttachCallback) 
  1503.      != OK)
  1504. {
  1505. return doShutdown (S_usbKeyboardLib_USBD_FAULT);
  1506. }
  1507. }
  1508.     initCount++;
  1509.     return OK;
  1510.     }
  1511. /***************************************************************************
  1512. *
  1513. * usbKeyboardDevShutdown - shuts down keyboard SIO driver
  1514. *
  1515. * RETURNS: OK, or ERROR if unable to shutdown.
  1516. *
  1517. * ERRNO:
  1518. *   S_usbKeyboardLib_NOT_INITIALIZED
  1519. */
  1520. STATUS usbKeyboardDevShutdown (void)
  1521.     {
  1522.     /* Shut down the USB keyboard SIO driver if the initCount goes to 0. */
  1523.     if (initCount == 0)
  1524. return ossStatus (S_usbKeyboardLib_NOT_INITIALIZED);
  1525.     if (--initCount == 0)
  1526. return doShutdown (OK);
  1527.     return OK;
  1528.     }
  1529. /***************************************************************************
  1530. *
  1531. * usbKeyboardDynamicAttachRegister - Register keyboard attach callback
  1532. *
  1533. * <callback> is a caller-supplied function of the form:
  1534. *
  1535. * .CS
  1536. * typedef (*USB_KBD_ATTACH_CALLBACK) 
  1537. *     (
  1538. *     pVOID arg,
  1539. *     SIO_CHAN *pSioChan,
  1540. *     UINT16 attachCode
  1541. *     );
  1542. * .CE
  1543. *
  1544. * usbKeyboardLib will invoke <callback> each time a USB keyboard
  1545. * is attached to or removed from the system.  <arg> is a caller-defined
  1546. * parameter which will be passed to the <callback> each time it is
  1547. * invoked.  The <callback> will also be passed a pointer to the 
  1548. * SIO_CHAN structure for the channel being created/destroyed and
  1549. * an attach code of USB_KBD_ATTACH or USB_KBD_REMOVE.
  1550. *
  1551. * RETURNS: OK, or ERROR if unable to register callback
  1552. *
  1553. * ERRNO:
  1554. *   S_usbKeyboardLib_BAD_PARAM
  1555. *   S_usbKeyboardLib_OUT_OF_MEMORY
  1556. */
  1557. STATUS usbKeyboardDynamicAttachRegister
  1558.     (
  1559.     USB_KBD_ATTACH_CALLBACK callback, /* new callback to be registered */
  1560.     pVOID arg     /* user-defined arg to callback */
  1561.     )
  1562.     {
  1563.     pATTACH_REQUEST pRequest;
  1564.     pUSB_KBD_SIO_CHAN pSioChan;
  1565.     int status = OK;
  1566.     /* Validate parameters */
  1567.     if (callback == NULL)
  1568. return ossStatus (S_usbKeyboardLib_BAD_PARAM);
  1569.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  1570.     /* Create a new request structure to track this callback request. */
  1571.     if ((pRequest = OSS_CALLOC (sizeof (*pRequest))) == NULL)
  1572. status = S_usbKeyboardLib_OUT_OF_MEMORY;
  1573.     else
  1574. {
  1575. pRequest->callback = callback;
  1576. pRequest->callbackArg = arg;
  1577. usbListLink (&reqList, pRequest, &pRequest->reqLink, LINK_TAIL);
  1578. /* Perform an initial notification of all currrently attached
  1579.  * keyboard devices.
  1580.  */
  1581. pSioChan = usbListFirst (&sioList);
  1582. while (pSioChan != NULL)
  1583.     {
  1584.     if (pSioChan->connected)
  1585. (*callback) (arg, (SIO_CHAN *) pSioChan, USB_KBD_ATTACH);
  1586.     pSioChan = usbListNext (&pSioChan->sioLink);
  1587.     }
  1588. }
  1589.     OSS_MUTEX_RELEASE (kbdMutex);
  1590.     return ossStatus (status);
  1591.     }
  1592. /***************************************************************************
  1593. *
  1594. * usbKeyboardDynamicAttachUnregister - Unregisters keyboard attach callback
  1595. *
  1596. * This function cancels a previous request to be dynamically notified for
  1597. * keyboard attachment and removal.  The <callback> and <arg> paramters must
  1598. * exactly match those passed in a previous call to 
  1599. * usbKeyboardDynamicAttachRegister().
  1600. *
  1601. * RETURNS: OK, or ERROR if unable to unregister callback
  1602. *
  1603. * ERRNO:
  1604. *   S_usbKeyboardLib_NOT_REGISTERED
  1605. */
  1606. STATUS usbKeyboardDynamicAttachUnRegister
  1607.     (
  1608.     USB_KBD_ATTACH_CALLBACK callback, /* callback to be unregistered */
  1609.     pVOID arg     /* user-defined arg to callback */
  1610.     )
  1611.     {
  1612.     pATTACH_REQUEST pRequest;
  1613.     int status = S_usbKeyboardLib_NOT_REGISTERED;
  1614.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  1615.     pRequest = usbListFirst (&reqList);
  1616.     while (pRequest != NULL)
  1617. {
  1618. if (callback == pRequest->callback && arg == pRequest->callbackArg)
  1619.     {
  1620.     /* We found a matching notification request. */
  1621.     destroyAttachRequest (pRequest);
  1622.     status = OK;
  1623.     break;
  1624.     }
  1625. pRequest = usbListNext (&pRequest->reqLink);
  1626. }
  1627.     OSS_MUTEX_RELEASE (kbdMutex);
  1628.     return ossStatus (status);
  1629.     }
  1630. /***************************************************************************
  1631. *
  1632. * usbKeyboardSioChanLock - Marks SIO_CHAN structure as in use
  1633. *
  1634. * A caller uses usbKeyboardSioChanLock() to notify usbKeyboardLib that
  1635. * it is using the indicated SIO_CHAN structure.  usbKeyboardLib maintains
  1636. * a count of callers using a particular SIO_CHAN structure so that it 
  1637. * knows when it is safe to dispose of a structure when the underlying
  1638. * USB keyboard is removed from the system.  So long as the "lock count"
  1639. * is greater than zero, usbKeyboardLib will not dispose of an SIO_CHAN
  1640. * structure.
  1641. *
  1642. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure in use.
  1643. */
  1644. STATUS usbKeyboardSioChanLock
  1645.     (
  1646.     SIO_CHAN *pChan /* SIO_CHAN to be marked as in use */
  1647.     )
  1648.     {
  1649.     pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan;
  1650.     pSioChan->lockCount++;
  1651.     return OK;
  1652.     }
  1653. /***************************************************************************
  1654. *
  1655. * usbKeyboardSioChanUnlock - Marks SIO_CHAN structure as unused
  1656. *
  1657. * This function releases a lock placed on an SIO_CHAN structure.  When a
  1658. * caller no longer needs an SIO_CHAN structure for which it has previously
  1659. * called usbKeyboardSioChanLock(), then it should call this function to
  1660. * release the lock.
  1661. *
  1662. * NOTE: If the underlying USB keyboard device has already been removed
  1663. * from the system, then this function will automatically dispose of the
  1664. * SIO_CHAN structure if this call removes the last lock on the structure.
  1665. * Therefore, a caller must not reference the SIO_CHAN again structure after
  1666. * making this call.
  1667. *
  1668. * RETURNS: OK, or ERROR if unable to mark SIO_CHAN structure unused
  1669. *
  1670. * ERRNO:
  1671. *   S_usbKeyboardLib_NOT_LOCKED
  1672. */
  1673. STATUS usbKeyboardSioChanUnlock
  1674.     (
  1675.     SIO_CHAN *pChan /* SIO_CHAN to be marked as unused */
  1676.     )
  1677.     {
  1678.     pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan;
  1679.     int status = OK;
  1680.     OSS_MUTEX_TAKE (kbdMutex, OSS_BLOCK);
  1681.     if (pSioChan->lockCount == 0)
  1682. status = S_usbKeyboardLib_NOT_LOCKED;
  1683.     else
  1684. {
  1685. /* If this is the last lock and the underlying USB keyboard is
  1686.  * no longer connected, then dispose of the keyboard.
  1687.  */
  1688. if (--pSioChan->lockCount == 0 && !pSioChan->connected)
  1689.     destroySioChan (pSioChan);
  1690. }
  1691.     OSS_MUTEX_RELEASE (kbdMutex);
  1692.     return ossStatus (status);
  1693.     }