Add logic to map keyboard scancodes

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3257 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-01-18 02:17:49 +00:00
parent f0f2c61a53
commit 57ca7d1157
3 changed files with 288 additions and 70 deletions

View File

@ -952,7 +952,7 @@ static inline int lpc17_addinted(struct lpc17_usbhost_s *priv,
/* Re-enabled periodic list processing */
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval &= ~OHCI_CTRL_PLE;
regval |= OHCI_CTRL_PLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
return OK;
#else
@ -1089,7 +1089,7 @@ static inline int lpc17_reminted(struct lpc17_usbhost_s *priv,
if (head != NULL)
{
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval &= ~OHCI_CTRL_PLE;
regval |= OHCI_CTRL_PLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
}

View File

@ -91,10 +91,25 @@
#ifndef CONFIG_HIDKBD_DEFPRIO
# define CONFIG_HIDKBD_DEFPRIO 50
#endif
#ifndef CONFIG_HIDKBD_STACKSIZE
# define CONFIG_HIDKBD_STACKSIZE 1024
#endif
#ifndef CONFIG_USBHID_BUFSIZE
# define CONFIG_USBHID_BUFSIZE 64
#endif
/* The default is to support 104 key keyboard. CONFIG_USBHID_ALLSCANCODES
* will enable all scancodes.
*/
#ifdef CONFIG_USBHID_ALLSCANCODES
# define USBHID_NUMSCANCODES (USBHID_KBDUSE_MAX+1)
#else
# define USBHID_NUMSCANCODES 104
#endif
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/kbd[n] device driver path. It
* defined here so that it will be used consistently in all places.
@ -136,6 +151,7 @@ struct usbhost_state_s
char devchar; /* Character identifying the /dev/kbd[n] device */
volatile bool disconnected; /* TRUE: Device has been disconnected */
volatile bool polling; /* TRUE: Poll thread is running */
bool open; /* TRUE: The keyboard device is open */
uint8_t ifno; /* Interface number */
int16_t crefs; /* Reference count on the driver instance */
sem_t exclsem; /* Used to maintain mutual exclusive access */
@ -158,6 +174,12 @@ struct usbhost_state_s
usbhost_ep_t epin; /* Interrupt IN endpoint */
usbhost_ep_t epout; /* Optional interrupt OUT endpoint */
/* Buffer used to collect and buffer incoming keyboard characters */
uint16_t headndx; /* Buffer head index */
uint16_t tailndx; /* Buffer tail index */
uint8_t buffer[CONFIG_USBHID_BUFSIZE];
};
/****************************************************************************
@ -183,6 +205,7 @@ static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *dev
/* Keyboard polling thread */
static void usbhost_destroy(FAR void *arg);
static uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier);
static int usbhost_kbdpoll(int argc, char *argv[]);
/* Helpers for usbhost_connect() */
@ -280,6 +303,81 @@ static sem_t g_exclsem; /* For mutually exclusive thread creat
static sem_t g_syncsem; /* Thread data passing interlock */
static struct usbhost_state_s *g_priv; /* Data passed to thread */
/* The following tables map keyboard scan codes to printable ASIC
* characters. There is no support here for function keys or cursor
* controls.
*/
static const uint8_t ucmap[USBHID_NUMSCANCODES] =
{
0, 0, 0, 0, 'A', 'B', 'C', 'D', /* 0x00-0x07: Reserved, errors, A-D */
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 0x08-0x0f: E-L */
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 0x10-0x17: M-T */
'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', /* 0x18-0x1f: U-Z,!,@ */
'#', '$', '%', '^', '&', '*', '(', ')', /* 0x20-0x27: #,$,%,^,&,*,(,) */
'\n', '\033', '\177', 0, ' ', '_', '+', '{', /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */
'}', '|', 0, ':', '"', 0, '<', '>', /* 0x30-0x37: },|,Non-US tilde,:,",grave tidle,<,> */
'?', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,sScrollLock */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
'\n', '1', '2', '3', '4', '4', '6', '7', /* 0x58-0x5f: Enter,1-7 */
'8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
#ifdef CONFIG_USBHID_ALLSCANCODES
0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Ease,SysReq,Cancel,Clear,Prior,Return,Separator */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
'{', '}', '\t', \177, 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
#endif
};
static const uint8_t lcmap[USBHID_NUMSCANCODES] =
{
0, 0, 0, 0, 'a', 'b', 'c', 'd', /* 0x00-0x07: Reserved, errors, a-d */
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', /* 0x08-0x0f: e-l */
'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 0x10-0x17: m-t */
'u', 'v', 'w', 'x', 'y', 'z', '1', '2', /* 0x18-0x1f: u-z,1-2 */
'3', '4', '5', '6', '7', '8', '9', '0', /* 0x20-0x27: 3-9,0 */
'\n', '\033', '\177', '\t', ' ', '-', '=', '[', /* 0x28-0x2f: Enter,escape,del,tab,space,-,=,[ */
']', '\\', '\234', ';', '\'', 0, ',', '.', /* 0x30-0x37: ],\,Non-US pound,;,',grave accent,,,. */
'/', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
'\n', '1', '2', '3', '4', '4', '6', '7', /* 0x58-0x5f: Enter,1-7 */
'8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
#ifdef CONFIG_USBHID_ALLSCANCODES
0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Ease,SysReq,Cancel,Clear,Prior,Return,Separator */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
'{', '}', '\t', '\177', 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
#endif
};
/****************************************************************************
* Private Functions
****************************************************************************/
@ -477,36 +575,42 @@ static void usbhost_destroy(FAR void *arg)
}
/****************************************************************************
* Name: usbhost_dumprpt
* Name: usbhost_mapscancode
*
* Description:
* Dump the interesting context of the keyboard report that we just
* received.
* Map a keyboard scancode to a printable ASCII character. There is no
* support here for function keys or cursor controls in this version of
* the driver.
*
* Input Parameters:
* arg - A reference to the class instance to be destroyed.
* scancode - Scan code to be mapped.
* modifier - Ctrl,Alt,Shift,GUI modifier bits
*
* Returned Values:
* None
*
****************************************************************************/
#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
static inline void usbhost_dumprpt(uint8_t *buffer)
static uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier)
{
struct usbhid_kbdreport_s *rpt = (struct usbhid_kbdreport_s *)buffer;
int i;
for (i = 0; i < 6; i++)
/* Range check */
if (scancode >= USBHID_NUMSCANCODES)
{
if (rpt->key[i])
{
uvdbg("Key %d: %08x modifier: %08x\n", rpt->key[i], rpt->modifier);
}
return 0;
}
/* Is either shift key pressed? */
if ((modifier & (USBHID_MODIFER_LSHIFT|USBHID_MODIFER_RSHIFT)) != 0)
{
return ucmap[scancode];
}
else
{
return lcmap[scancode];
}
}
#else
# define usbhost_dumprpt(buffer)
#endif
/****************************************************************************
* Name: usbhost_kbdpoll
@ -527,9 +631,9 @@ static int usbhost_kbdpoll(int argc, char *argv[])
FAR struct usbhost_state_s *priv;
FAR struct usb_ctrlreq_s *ctrlreq;
#ifdef CONFIG_DEBUG_USB
static unsigned int npolls = 0;
unsigned int npolls = 0;
#endif
static unsigned int nerrors;
unsigned int nerrors;
int ret;
uvdbg("Started\n");
@ -563,7 +667,7 @@ static int usbhost_kbdpoll(int argc, char *argv[])
usbhost_takesem(&priv->exclsem);
/* Format the hid report request:
/* Format the HID report request:
*
* bmRequestType 10000001
* bRequest GET_DESCRIPTOR (0x06)
@ -574,39 +678,119 @@ static int usbhost_kbdpoll(int argc, char *argv[])
*/
ctrlreq = (struct usb_ctrlreq_s *)priv->tbuffer;
ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_INTERFACE;
ctrlreq->req = USB_REQ_GETDESCRIPTOR;
usbhost_putle16(ctrlreq->value, (USBHID_DESCTYPE_REPORT << 8));
usbhost_putle16(ctrlreq->index, priv->ifno);
usbhost_putle16(ctrlreq->len, 8);
ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
ctrlreq->req = USBHID_REQUEST_GETREPORT;
/* Send the report */
usbhost_putle16(ctrlreq->value, (USBHID_REPORTTYPE_INPUT << 8));
usbhost_putle16(ctrlreq->index, priv->ifno);
usbhost_putle16(ctrlreq->len, sizeof(struct usbhid_kbdreport_s));
/* Send HID report request */
ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer);
usbhost_givesem(&priv->exclsem);
/* Check for errors -- Bail if an excessive number of errors
* are encountered.
*/
if (ret != OK)
{
nerrors++;
udbg("ERROR: GETDESCRIPTOR/REPORT, DRVR_CTRLIN returned: %d/%d\n",
udbg("ERROR: GETREPORT/INPUT, DRVR_CTRLIN returned: %d/%d\n",
ret, nerrors);
if (nerrors > 200)
{
udbg("Too man errors... aborting: %d\n", nerrors);
udbg("Too many errors... aborting: %d\n", nerrors);
break;
}
}
else
/* The report was received correctly. But ignore the keystrokes if no
* task has opened the driver.
*/
else if (priv->open)
{
/* If debug is enabled, then dump the interesting poarts of the
* report that we just received.
*/
struct usbhid_kbdreport_s *rpt = (struct usbhid_kbdreport_s *)priv->buffer;
unsigned int head;
unsigned int tail;
uint8_t ascii;
int i;
usbhost_dumprpt(priv->tbuffer);
/* Add the newly received keystrokes to our internal buffer */
/* Add the newly recevied keystrokes to our internal buffer */
#warning "Missing logic"
usbhost_takesem(&priv->exclsem);
head = priv->headndx;
tail = priv->tailndx;
for (i = 0; i < 6; i++)
{
/* Is this key pressed? */
if (rpt->key[i] == USBHID_KBDUSE_NONE)
{
/* Yes.. Add it to the buffer. */
/* Map the keyboard scancode to a printable ASCII
* character. There is no support here for function keys
* or cursor controls in this version of the driver.
*/
ascii = usbhost_mapscancode(rpt->key[i], rpt->modifier);
uvdbg("Key %d: %02x ASCII:%c modifier: %02x\n",
i, rpt->key[i], ascii ? ascii : ' ', rpt->modifier);
/* Zero at this point means that the key does not map to a
* printable character.
*/
if (ascii != 0)
{
/* Handle control characters. Zero after this means
* a valid, NUL character.
*/
if ((rpt->modifier & (USBHID_MODIFER_LSHIFT|USBHID_MODIFER_RSHIFT)) != 0)
{
ascii &= 0x1f;
}
/* Copy the next keyboard character into the user
* buffer.
*/
priv->buffer[head] = ascii;
/* Increment the head index */
if (++head >= CONFIG_USBHID_BUFSIZE)
{
head = 0;
}
/* If the buffer is full, then increment the tail
* index to make space. Is it better to lose old
* keystrokes or new?
*/
if (tail == head)
{
if (++tail >= CONFIG_USBHID_BUFSIZE)
{
tail = 0;
}
}
}
}
}
/* Update the head/tail indices */
priv->headndx = head;
priv->tailndx = tail;
usbhost_givesem(&priv->exclsem);
}
/* If USB debug is on, then provide some periodic indication that
@ -1411,7 +1595,8 @@ static int usbhost_open(FAR struct file *filep)
/* Otherwise, just increment the reference count on the driver */
priv->crefs++;
ret = OK;
priv->open = true;
ret = OK;
}
irqrestore(flags);
@ -1431,7 +1616,6 @@ static int usbhost_close(FAR struct file *filep)
{
FAR struct inode *inode;
FAR struct usbhost_state_s *priv;
irqstate_t flags;
uvdbg("Entry\n");
DEBUGASSERT(filep && filep->f_inode);
@ -1444,32 +1628,45 @@ static int usbhost_close(FAR struct file *filep)
usbhost_takesem(&priv->exclsem);
priv->crefs--;
/* Release the semaphore. The following operations when crefs == 1 are
* safe because we know that there is no outstanding open references to
* the driver.
/* Is this the last reference (other than the one held by the USB host
* controller driver)
*/
usbhost_givesem(&priv->exclsem);
/* We need to disable interrupts momentarily to assure that there are
* no asynchronous disconnect events.
*/
flags = irqsave();
/* Check if the USB keyboard device is still connected. If the device is
* not connected and the reference count just decremented to one, then
* unregister then free the driver class instance.
*/
if (priv->crefs <= 1 && priv->disconnected)
if (priv->crefs <= 1)
{
/* Destroy the class instance */
irqstate_t flags;
usbhost_destroy(priv);
/* Yes.. then the driver is no longer open */
priv->open = false;
priv->headndx = 0;
priv->tailndx = 0;
/* We need to disable interrupts momentarily to assure that there are
* no asynchronous disconnect events.
*/
flags = irqsave();
/* Check if the USB keyboard device is still connected. If the device is
* no longer connected, then unregister the driver and free the driver
* class instance.
*/
if (priv->disconnected)
{
/* Destroy the class instance (we can't use priv after this; we can't
* 'give' the semapore)
*/
usbhost_destroy(priv);
irqrestore(flags);
return OK;
}
irqrestore(flags);
}
irqrestore(flags);
usbhost_givesem(&priv->exclsem);
return OK;
}
@ -1485,8 +1682,9 @@ static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, size_t len
{
FAR struct inode *inode;
FAR struct usbhost_state_s *priv;
irqstate_t flags;
int ret;
size_t remaining;
unsigned int tail;
int ret;
uvdbg("Entry\n");
DEBUGASSERT(filep && filep->f_inode && buffer);
@ -1502,7 +1700,6 @@ static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, size_t len
* momentarily to assure that there are no asynchronous disconnect events.
*/
flags = irqsave();
if (priv->disconnected)
{
/* No... the driver is no longer bound to the class. That means that
@ -1515,9 +1712,28 @@ static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer, size_t len
else
{
/* Read data from our internal buffer of received characters */
#warning "Missing logic"
for (tail = priv->tailndx;
tail != priv->headndx && remaining > 0;
tail++, remaining--)
{
/* Handle wrap-around of the tail index */
if (tail >= CONFIG_USBHID_BUFSIZE)
{
tail = 0;
}
/* Copy the next keyboard character into the user buffer */
*buffer += priv->buffer[tail];
remaining--;
}
/* Update the tail index (pehaps marking the buffer empty) */
priv->tailndx = tail;
}
irqrestore(flags);
usbhost_givesem(&priv->exclsem);
return 0; /* Return EOF for now */

View File

@ -115,10 +115,10 @@
#define USBHID_REQUEST_GETREPORT 0x01
#define USBHID_REQUEST_GETIDLE 0x02
#define USBHID_REQUEST_GET_PROTOCOL 0x03
#define USBHID_REQUEST_SET_REPORT 0x09
#define USBHID_REQUEST_SET_IDLE 0x0a
#define USBHID_REQUEST_SET_PROTOCOL 0x0b
#define USBHID_REQUEST_GETPROTOCOL 0x03
#define USBHID_REQUEST_SETREPORT 0x09
#define USBHID_REQUEST_SETIDLE 0x0a
#define USBHID_REQUEST_SETPROTOCOL 0x0b
/* Report Type (MS byte of wValue for GET_REPORT) (HID 7.2.1) */
@ -414,7 +414,7 @@
#define USBHID_KBDUSE_CLEAR 0x9c /* Keyboard Clear */
#define USBHID_KBDUSE_PRIOR 0x9d /* Keyboard Prior */
#define USBHID_KBDUSE_RETURN 0x9e /* Keyboard Return */
#define USBHID_KBDUSE_SEPARATRO 0x9f /* Keyboard Separator */
#define USBHID_KBDUSE_SEPARATOR 0x9f /* Keyboard Separator */
#define USBHID_KBDUSE_OUT 0xa0 /* Keyboard Out */
#define USBHID_KBDUSE_OPER 0xa1 /* Keyboard Oper */
#define USBHID_KBDUSE_CLEARAGAIN 0xa2 /* Keyboard Clear/Again */
@ -470,6 +470,8 @@
#define USBHID_KBDUSE_RALT 0xe6 /* Keyboard RightAlt */
#define USBHID_KBDUSE_RGUI 0xe7 /* Keyboard Right GUI*/
#define USBHID_KBDUSE_MAX 0xe7
/* Mouse input report (HID B.2) */
#define USBHID_MOUSEIN_BUTTON1 (1 << 0)