More HID keyboard support
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3255 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
e7207f8788
commit
39c428afc2
@ -85,10 +85,11 @@
|
||||
/* OHCI Setup ******************************************************************/
|
||||
/* Frame Interval / Periodic Start */
|
||||
|
||||
#define FI (12000-1) /* 12000 bits per frame (-1) */
|
||||
#define FSMPS ((6 * (FI - 210)) / 7)
|
||||
#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI)
|
||||
#define DEFAULT_PERSTART ((9 * FI) / 10)
|
||||
#define BITS_PER_FRAME 12000
|
||||
#define FI (BITS_PER_FRAME-1)
|
||||
#define FSMPS ((6 * (FI - 210)) / 7)
|
||||
#define DEFAULT_FMINTERVAL ((FSMPS << OHCI_FMINT_FSMPS_SHIFT) | FI)
|
||||
#define DEFAULT_PERSTART (((9 * BITS_PER_FRAME) / 10) - 1)
|
||||
|
||||
/* CLKCTRL enable bits */
|
||||
|
||||
@ -152,11 +153,15 @@ struct lpc17_usbhost_s
|
||||
|
||||
/* Driver status */
|
||||
|
||||
volatile bool connected; /* Connected to device */
|
||||
volatile bool lowspeed; /* Low speed device attached. */
|
||||
volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t rhssem; /* Semaphore to wait Writeback Done Head event */
|
||||
volatile bool connected; /* Connected to device */
|
||||
volatile bool lowspeed; /* Low speed device attached. */
|
||||
volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
uint8_t ininterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
uint8_t outinterval; /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
#endif
|
||||
sem_t exclsem; /* Support mutually exclusive access */
|
||||
sem_t rhssem; /* Semaphore to wait Writeback Done Head event */
|
||||
};
|
||||
|
||||
/* The OCHI expects the size of an endpoint descriptor to be 16 bytes.
|
||||
@ -174,7 +179,7 @@ struct lpc17_ed_s
|
||||
/* Software specific fields */
|
||||
|
||||
uint8_t xfrtype; /* Transfer type. See SB_EP_ATTR_XFER_* in usb.h */
|
||||
uint8_t period; /* Periodic EP polling frequency 1, 2, 4, 6, 16, or 32 */
|
||||
uint8_t interval; /* Periodic EP polling interval: 2, 4, 6, 16, or 32 */
|
||||
volatile uint8_t tdstatus; /* TD control status bits from last Writeback Done Head event */
|
||||
volatile bool wdhwait; /* TRUE: Thread is waiting for WDH interrupt */
|
||||
sem_t wdhsem; /* Semaphore used to wait for Writeback Done Head event */
|
||||
@ -251,11 +256,20 @@ static inline int lpc17_addbulked(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed);
|
||||
static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed);
|
||||
|
||||
#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
|
||||
static unsigned int lpc17_getinterval(uint8_t interval);
|
||||
static void lpc17_setinttab(uint32_t value, unsigned int interval, unsigned int offset);
|
||||
#endif
|
||||
|
||||
static inline int lpc17_addinted(struct lpc17_usbhost_s *priv,
|
||||
const FAR struct usbhost_epdesc_s *epdesc,
|
||||
struct lpc17_ed_s *ed);
|
||||
static inline int lpc17_reminted(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed);
|
||||
|
||||
static inline int lpc17_addisoced(struct lpc17_usbhost_s *priv,
|
||||
const FAR struct usbhost_epdesc_s *epdesc,
|
||||
struct lpc17_ed_s *ed);
|
||||
static inline int lpc17_remisoced(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed);
|
||||
@ -722,9 +736,9 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed)
|
||||
{
|
||||
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
||||
struct lpc17_ed_s *curr = NULL;
|
||||
struct lpc17_ed_s *prev = NULL;
|
||||
uint32_t regval;
|
||||
struct lpc17_ed_s *curr;
|
||||
struct lpc17_ed_s *prev;
|
||||
uint32_t regval;
|
||||
|
||||
/* Find the ED in the bulk list. NOTE: We really should never be mucking
|
||||
* with the bulk list while BLE is set.
|
||||
@ -773,44 +787,315 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_getinterval
|
||||
*
|
||||
* Description:
|
||||
* Convert the endpoint polling interval into a HCCA table increment
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
|
||||
static unsigned int lpc17_getinterval(uint8_t interval)
|
||||
{
|
||||
/* The bInterval field of the endpoint descriptor contains the polling interval
|
||||
* for interrupt and isochronous endpoints. For other types of endpoint, this
|
||||
* value should be ignored. bInterval is provided in units of 1MS frames.
|
||||
*/
|
||||
|
||||
if (interval < 3)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
else if (interval < 7)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else if (interval < 15)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
else if (interval < 31)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_setinttab
|
||||
*
|
||||
* Description:
|
||||
* Set the interrupt table to the selected value using the provided interval
|
||||
* and offset.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE)
|
||||
static void lpc17_setinttab(uint32_t value, unsigned int interval, unsigned int offset)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = offset; i < HCCA_INTTBL_WSIZE; i += interval)
|
||||
{
|
||||
HCCA->inttbl[i] = value;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_addinted
|
||||
*
|
||||
* Description:
|
||||
* Helper function to add an ED to the HCCA interrupt table.
|
||||
*
|
||||
* To avoid reshuffling the table so much and to keep life simple in general,
|
||||
* the following rules are applied:
|
||||
*
|
||||
* 1. IN EDs get the even entries, OUT EDs get the odd entries.
|
||||
* 2. Add IN/OUT EDs are scheduled together at the minimum interval of all
|
||||
* IN/OUT EDs.
|
||||
*
|
||||
* This has the following consequences:
|
||||
*
|
||||
* 1. The minimum support polling rate is 2MS, and
|
||||
* 2. Some devices may get polled at a much higher rate than they request.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static inline int lpc17_addinted(struct lpc17_usbhost_s *priv,
|
||||
const FAR struct usbhost_epdesc_s *epdesc,
|
||||
struct lpc17_ed_s *ed)
|
||||
{
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
# warning "Interrupt endpoints not yet supported"
|
||||
unsigned int interval;
|
||||
unsigned int offset;
|
||||
uint32_t head;
|
||||
uint32_t regval;
|
||||
|
||||
/* Disable periodic list processing. Does this take effect immediately? Or
|
||||
* at the next SOF... need to check.
|
||||
*/
|
||||
|
||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||
regval &= ~OHCI_CTRL_PLE;
|
||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||
|
||||
/* Get the quanitized interval value associated with this ED and save it
|
||||
* in the ED.
|
||||
*/
|
||||
|
||||
interval = lpc17_getinterval(epdesc->interval);
|
||||
ed->interval = interval;
|
||||
uvdbg("interval: %d->%d\n", epdesc->interval, interval);
|
||||
|
||||
/* Get the offset associated with the ED direction. IN EDs get the even
|
||||
* entries, OUT EDs get the odd entries.
|
||||
*
|
||||
* Get the new, minimum interval. Add IN/OUT EDs are scheduled together
|
||||
* at the minimum interval of all IN/OUT EDs.
|
||||
*/
|
||||
|
||||
if (epdesc->in)
|
||||
{
|
||||
offset = 0;
|
||||
if (priv->ininterval > interval)
|
||||
{
|
||||
priv->ininterval = interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
interval = priv->ininterval;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 1;
|
||||
if (priv->outinterval > interval)
|
||||
{
|
||||
priv->outinterval = interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
interval = priv->outinterval;
|
||||
}
|
||||
}
|
||||
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
||||
|
||||
/* Get the head of the first of the duplicated entries. The first offset
|
||||
* entry is always guaranteed to contain the common ED list head.
|
||||
*/
|
||||
|
||||
head = HCCA->inttbl[offset];
|
||||
|
||||
/* Clear all current entries in the interrupt table for this direction */
|
||||
|
||||
lpc17_setinttab(0, 2, offset);
|
||||
|
||||
/* Add the new ED before the old head of the periodic ED list and set the
|
||||
* new ED as the head ED in all of the appropriate entries of the HCCA
|
||||
* interrupt table.
|
||||
*/
|
||||
|
||||
ed->hw.nexted = head;
|
||||
lpc17_setinttab((uint32_t)ed, interval, offset);
|
||||
uvdbg("head: %08x next: %08x\n", ed, head);
|
||||
|
||||
/* Re-enabled periodic list processing */
|
||||
|
||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||
regval &= ~OHCI_CTRL_PLE;
|
||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||
return OK;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_addbulked
|
||||
* Name: lpc17_reminted
|
||||
*
|
||||
* Description:
|
||||
* Helper function to remove an ED from the HCCA interrupt table.
|
||||
*
|
||||
* To avoid reshuffling the table so much and to keep life simple in general,
|
||||
* the following rules are applied:
|
||||
*
|
||||
* 1. IN EDs get the even entries, OUT EDs get the odd entries.
|
||||
* 2. Add IN/OUT EDs are scheduled together at the minimum interval of all
|
||||
* IN/OUT EDs.
|
||||
*
|
||||
* This has the following consequences:
|
||||
*
|
||||
* 1. The minimum support polling rate is 2MS, and
|
||||
* 2. Some devices may get polled at a much higher rate than they request.
|
||||
*
|
||||
*******************************************************************************/
|
||||
|
||||
static inline int lpc17_reminted(struct lpc17_usbhost_s *priv,
|
||||
struct lpc17_ed_s *ed)
|
||||
{
|
||||
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||
# warning "Interrupt endpoints not yet supported"
|
||||
struct lpc17_ed_s *head;
|
||||
struct lpc17_ed_s *curr;
|
||||
struct lpc17_ed_s *prev;
|
||||
unsigned int interval;
|
||||
unsigned int offset;
|
||||
uint32_t regval;
|
||||
|
||||
/* Disable periodic list processing. Does this take effect immediately? Or
|
||||
* at the next SOF... need to check.
|
||||
*/
|
||||
|
||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||
regval &= ~OHCI_CTRL_PLE;
|
||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||
|
||||
/* Get the offset associated with the ED direction. IN EDs get the even
|
||||
* entries, OUT EDs get the odd entries.
|
||||
*/
|
||||
|
||||
if ((ed->hw.ctrl && ED_CONTROL_D_MASK) == ED_CONTROL_D_IN)
|
||||
{
|
||||
offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
/* Get the head of the first of the duplicated entries. The first offset
|
||||
* entry is always guaranteed to contain the common ED list head.
|
||||
*/
|
||||
|
||||
head = (struct lpc17_ed_s *)HCCA->inttbl[offset];
|
||||
uvdbg("ed: %08x head: %08x next: %08x offset: %d\n",
|
||||
ed, head, head ? head->hw.nexted : 0, offset);
|
||||
|
||||
/* Find the ED to be removed in the ED list */
|
||||
|
||||
for (curr = head, prev = NULL;
|
||||
curr && curr != ed;
|
||||
prev = curr, curr = (struct lpc17_ed_s *)curr->hw.nexted);
|
||||
|
||||
/* Hmmm.. It would be a bug if we do not find the ED in the bulk list. */
|
||||
|
||||
DEBUGASSERT(curr != NULL);
|
||||
if (curr != NULL)
|
||||
{
|
||||
/* Clear all current entries in the interrupt table for this direction */
|
||||
|
||||
lpc17_setinttab(0, 2, offset);
|
||||
|
||||
/* Remove the ED from the list.. Is this ED the first on in the list? */
|
||||
|
||||
if (prev == NULL)
|
||||
{
|
||||
/* Yes... set the head of the bulk list to skip over this ED */
|
||||
|
||||
head = (struct lpc17_ed_s *)ed->hw.nexted;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. set the forward link of the previous ED in the list
|
||||
* skip over this ED.
|
||||
*/
|
||||
|
||||
prev->hw.nexted = ed->hw.nexted;
|
||||
}
|
||||
uvdbg("ed: %08x head: %08x next: %08x\n",
|
||||
ed, head, head ? head->hw.nexted : 0);
|
||||
|
||||
/* Calculate the new minimum interval for this list */
|
||||
|
||||
interval = 32;
|
||||
for (curr = head; curr; curr = (struct lpc17_ed_s *)curr->hw.nexted)
|
||||
{
|
||||
if (curr->interval < interval)
|
||||
{
|
||||
interval = curr->interval;
|
||||
}
|
||||
}
|
||||
uvdbg("min interval: %d offset: %d\n", interval, offset);
|
||||
|
||||
/* Save the new minimum interval */
|
||||
|
||||
if ((ed->hw.ctrl && ED_CONTROL_D_MASK) == ED_CONTROL_D_IN)
|
||||
{
|
||||
priv->ininterval = interval;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->outinterval = interval;
|
||||
}
|
||||
|
||||
/* Set the head ED in all of the appropriate entries of the HCCA interrupt
|
||||
* table (head might be NULL).
|
||||
*/
|
||||
|
||||
lpc17_setinttab((uint32_t)head, interval, offset);
|
||||
}
|
||||
|
||||
/* Re-enabled periodic list processing */
|
||||
|
||||
if (head != NULL)
|
||||
{
|
||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||
regval &= ~OHCI_CTRL_PLE;
|
||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||
}
|
||||
|
||||
return OK;
|
||||
#else
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_addbulked
|
||||
* Name: lpc17_addisoced
|
||||
*
|
||||
* Description:
|
||||
* Helper functions to add an ED to the periodic table.
|
||||
@ -818,6 +1103,7 @@ static inline int lpc17_reminted(struct lpc17_usbhost_s *priv,
|
||||
*******************************************************************************/
|
||||
|
||||
static inline int lpc17_addisoced(struct lpc17_usbhost_s *priv,
|
||||
const FAR struct usbhost_epdesc_s *epdesc,
|
||||
struct lpc17_ed_s *ed)
|
||||
{
|
||||
#ifndef CONFIG_USBHOST_ISOC_DISABLE
|
||||
@ -828,7 +1114,7 @@ static inline int lpc17_addisoced(struct lpc17_usbhost_s *priv,
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Name: lpc17_addbulked
|
||||
* Name: lpc17_remisoced
|
||||
*
|
||||
* Description:
|
||||
* Helper functions to remove an ED from the periodic table.
|
||||
@ -1441,7 +1727,7 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
|
||||
|
||||
/* Get the direction of the endpoint */
|
||||
|
||||
if (epdesc->in != 0)
|
||||
if (epdesc->in)
|
||||
{
|
||||
ed->hw.ctrl |= ED_CONTROL_D_IN;
|
||||
}
|
||||
@ -1491,11 +1777,11 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
|
||||
break;
|
||||
|
||||
case USB_EP_ATTR_XFER_INT:
|
||||
ret = lpc17_addinted(priv, ed);
|
||||
ret = lpc17_addinted(priv, epdesc, ed);
|
||||
break;
|
||||
|
||||
case USB_EP_ATTR_XFER_ISOC:
|
||||
ret = lpc17_addisoced(priv, ed);
|
||||
ret = lpc17_addisoced(priv, epdesc, ed);
|
||||
break;
|
||||
|
||||
case USB_EP_ATTR_XFER_CONTROL:
|
||||
|
Loading…
Reference in New Issue
Block a user