1
0
Fork 0
forked from nuttx/nuttx-update

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:
patacongo 2011-01-16 19:08:16 +00:00
parent 258009c392
commit 2270d885e9
5 changed files with 860 additions and 315 deletions

View file

@ -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:

View file

@ -43,6 +43,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <semaphore.h>
@ -53,7 +54,6 @@
#include <nuttx/fs.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbhost.h>
@ -67,32 +67,32 @@
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
/* Worker thread support is required */
#ifndef CONFIG_SCHED_WORKQUEUE
# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
#endif
/* This determines how often the USB keyboard will be polled in units of
* of clock ticks. The default is 100MS.
* of microseconds. The default is 100MS.
*/
#ifndef CONFIG_HIDKBD_POLLTICKS
/* The value CLK_TCK gives the frequency in HZ of the system timer. This
* is, the number of ticks in one second. So one tenth of this would give
* is the number of ticks required for a 100MS delay between polls.
*/
#ifndef CONFIG_HIDKBD_POLLUSEC
# define CONFIG_HIDKBD_POLLUSEC (100*1000)
#endif
# define CONFIG_HIDKBD_POLLTICKS (CLK_TCK/10)
/* Signals must not be disabled as they are needed by usleep */
/* Provide some default values for other configuration settings */
#ifndef CONFIG_HIDKBD_DEFPRIO
# define CONFIG_HIDKBD_DEFPRIO 50
#endif
#ifndef CONFIG_HIDKBD_STACKSIZE
# define CONFIG_HIDKBD_STACKSIZE 1024
#endif
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/sd[n] device driver path. It
/* 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.
*/
#define DEV_FORMAT "/dev/sd%c"
#define DEV_NAMELEN 10
#define DEV_FORMAT "/dev/kbd%c"
#define DEV_NAMELEN 11
/* Used in usbhost_cfgdesc() */
@ -107,8 +107,8 @@
* Private Types
****************************************************************************/
/* This structure contains the internal, private state of the USB host mass
* storage class.
/* This structure contains the internal, private state of the USB host
* keyboard storage class.
*/
struct usbhost_state_s
@ -121,15 +121,16 @@ struct usbhost_state_s
struct usbhost_driver_s *drvr;
/* The remainder of the fields are provide o the mass storage class */
/* The remainder of the fields are provide o the keyboard class driver */
char sdchar; /* Character identifying the /dev/sd[n] device */
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 */
int16_t crefs; /* Reference count on the driver instance */
sem_t exclsem; /* Used to maintain mutual exclusive access */
struct work_s work; /* For interacting with the worker thread */
FAR uint8_t *tdbuffer; /* The allocated transfer descriptor buffer */
size_t tdbuflen; /* Size of the allocated transfer buffer */
FAR uint8_t *tbuffer; /* The allocated transfer buffer */
size_t tbuflen; /* Size of the allocated transfer buffer */
pid_t pollpid; /* PID of the poll task */
/* Endpoints:
* EP0 (Control):
@ -167,10 +168,10 @@ static int usbhost_allocdevno(FAR struct usbhost_state_s *priv);
static void usbhost_freedevno(FAR struct usbhost_state_s *priv);
static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname);
/* Worker thread actions */
/* Keyboard polling thread */
static void usbhost_kbdpoll(FAR void *arg);
static void usbhost_destroy(FAR void *arg);
static void usbhost_destroy(FAR struct usbhost_state_s *priv);
static int usbhost_kbdpoll(int argc, char *argv[]);
/* Helpers for usbhost_connect() */
@ -205,12 +206,14 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *class);
/* Driver methods. We export the keyboard as a standard character driver */
static ssize_t usbhost_read(FAR struct file *filp,
static int usbhost_open(FAR struct file *filep);
static int usbhost_close(FAR struct file *filep);
static ssize_t usbhost_read(FAR struct file *filep,
FAR char *buffer, size_t len);
static ssize_t usbhost_write(FAR struct file *filp,
static ssize_t usbhost_write(FAR struct file *filep,
FAR const char *buffer, size_t len);
#ifndef CONFIG_DISABLE_POLL
static int usbhost_poll(FAR struct file *filp, FAR struct pollfd *fds,
static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup);
#endif
@ -219,7 +222,7 @@ static int usbhost_poll(FAR struct file *filp, FAR struct pollfd *fds,
****************************************************************************/
/* This structure provides the registry entry ID informatino that will be
* used to associate the USB host mass storage class to a connected USB
* used to associate the USB host keyboard class driver to a connected USB
* device.
*/
@ -244,8 +247,8 @@ static struct usbhost_registry_s g_skeleton =
static const struct file_operations usbhost_fops =
{
0, /* open */
0, /* close */
usbhost_open, /* open */
usbhost_close, /* close */
usbhost_read, /* read */
usbhost_write, /* write */
0, /* seek */
@ -255,10 +258,16 @@ static const struct file_operations usbhost_fops =
#endif
};
/* This is a bitmap that is used to allocate device names /dev/sda-z. */
/* This is a bitmap that is used to allocate device names /dev/kbda-z. */
static uint32_t g_devinuse;
/* The following are used to managed the class creation operation */
static sem_t g_exclsem; /* For mutually exclusive thread creation */
static sem_t g_syncsem; /* Thread data passing interlock */
static struct usbhost_state_s *g_priv; /* Data passed to thread */
/****************************************************************************
* Private Functions
****************************************************************************/
@ -361,7 +370,7 @@ static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
if ((g_devinuse & bitno) == 0)
{
g_devinuse |= bitno;
priv->sdchar = 'a' + devno;
priv->devchar = 'a' + devno;
irqrestore(flags);
return OK;
}
@ -373,7 +382,7 @@ static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
{
int devno = 'a' - priv->sdchar;
int devno = 'a' - priv->devchar;
if (devno >= 0 && devno < 26)
{
@ -385,80 +394,7 @@ static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
{
(void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
}
/****************************************************************************
* Name: usbhost_kbdpoll
*
* Description:
* Periodically check for new keyboard data.
*
* Input Parameters:
* arg - A reference to the class instance to be destroyed.
*
* Returned Values:
* None
*
****************************************************************************/
static void usbhost_kbdpoll(FAR void *arg)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
irqstate_t flags;
#ifdef CONFIG_DEBUG_USB
static unsigned int npolls = 0;
#endif
int ret;
/* Poll the keyboard */
#warning "Missing logic"
/* Setup for the next poll. We have to be careful here because the work
* structure may be used by the interrupt handler if the USB device is
* disconnected.
*/
flags = irqsave();
/* Is the device still connected? If not, we do not reschedule any further
* polling of the device.
*/
if (priv->disconnected)
{
udbg("Keyboard removed, polling halted\n");
}
else
{
/* Otherwise, just setup the next poll. */
ret = work_queue(&priv->work, usbhost_kbdpoll, priv, CONFIG_HIDKBD_POLLTICKS);
if (ret != 0)
{
udbg("ERROR: Failed to re-schedule keyboard poll: %d\n", ret);
}
/* If USB debug is on, then provide some periodic indication that
* polling is still happening.
*/
#ifdef CONFIG_DEBUG_USB
npolls++;
#endif
}
irqrestore(flags);
/* If USB debug is on, then provide some periodic indication that
* polling is still happening.
*/
#ifdef CONFIG_DEBUG_USB
if (!priv->disconnected && (npolls & ~31) == 0)
{
udbg("Still polling: %d\n", npolls);
}
#endif
(void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
}
/****************************************************************************
@ -477,9 +413,8 @@ static void usbhost_kbdpoll(FAR void *arg)
*
****************************************************************************/
static void usbhost_destroy(FAR void *arg)
static void usbhost_destroy(FAR struct usbhost_state_s *priv)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
char devname[DEV_NAMELEN];
DEBUGASSERT(priv != NULL);
@ -528,6 +463,191 @@ static void usbhost_destroy(FAR void *arg)
usbhost_freeclass(priv);
}
/****************************************************************************
* Name: usbhost_dumprpt
*
* Description:
* Dump the interesting context of the keyboard report that we just
* received.
*
* Input Parameters:
* arg - A reference to the class instance to be destroyed.
*
* Returned Values:
* None
*
****************************************************************************/
#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
static inline void usbhost_dumprpt(uint8_t *buffer)
{
struct usbhid_kbdreport_s *rpt = (struct usbhid_kbdreport_s *)buffer;
int i;
for (i = 0; i < 6; i++)
{
if (rpt->key[i])
{
uvdbg("Key %d: %08x modifier: %08x\n", rpt->key[i], rpt->modifier);
}
}
}
#else
# define usbhost_dumprpt(buffer)
#endif
/****************************************************************************
* Name: usbhost_kbdpoll
*
* Description:
* Periodically check for new keyboard data.
*
* Input Parameters:
* arg - A reference to the class instance to be destroyed.
*
* Returned Values:
* None
*
****************************************************************************/
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;
#endif
static unsigned int nerrors;
int ret;
uvdbg("Started\n");
/* Synchronize with the start-up logic. Get the private instance, re-start
* the start-up logic, and wait a bit to make sure that all of the class
* creation logic has a chance to run to completion.
*
* NOTE: that the reference count is incremented here. Therefore, we know
* that the driver data structure will remain stable while this thread is
* running.
*/
priv = g_priv;
DEBUGASSERT(priv != NULL);
priv->polling = true;
priv->crefs++;
usbhost_givesem(&g_syncsem);
sleep(1);
/* Loop here until the device is disconnected */
uvdbg("Entering poll loop\n");
while (!priv->disconnected)
{
/* Make sure that we have exclusive access to the private data
* structure. There may now be other tasks with the character driver
* open and actively trying to interact with the class driver.
*/
usbhost_takesem(&priv->exclsem);
/* Format the hid report request:
*
* bmRequestType 10000001
* bRequest GET_DESCRIPTOR (0x06)
* wValue Descriptor Type and Descriptor Index
* wIndex Interface Number
* wLength Descriptor Length
* Data Descriptor Data
*/
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, 0);
usbhost_putle16(ctrlreq->len, 8);
/* Send the report */
ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer);
usbhost_givesem(&priv->exclsem);
if (ret != OK)
{
nerrors++;
udbg("ERROR: GETDESCRIPTOR/REPORT, DRVR_CTRLIN returned: %d/%d\n",
ret, nerrors);
if (nerrors > 200)
{
udbg("Too man errors... aborting: %d\n", nerrors);
break;
}
}
else
{
/* If debug is enabled, then dump the interesting poarts of the
* report that we just received.
*/
usbhost_dumprpt(priv->tbuffer);
/* Add the newly recevied keystrokes to our internal buffer */
#warning "Missing logic"
}
/* If USB debug is on, then provide some periodic indication that
* polling is still happening.
*/
#ifdef CONFIG_DEBUG_USB
npolls++;
if (!(npolls & ~31) == 0)
{
udbg("Still polling: %d\n", npolls);
}
#endif
/* Wait for the required amount (or until a signal is received). We
* will wake up when either the delay elapses or we are signalled that
* the device has been disconnected.
*/
usleep(CONFIG_HIDKBD_POLLUSEC);
}
/* We get here when the driver is removed.. or when too many errors have
* been encountered.
*
* Make sure that we have exclusive access to the private data structure.
* There may now be other tasks with the character driver open and actively
* trying to interact with the class driver.
*/
usbhost_takesem(&priv->exclsem);
/* Indicate that we are no longer running and decrement the reference
* count help by this thread. If there are no other users of the class,
* we can destroy it now. Otherwise, we have to wait until the all
* of the file descriptors are closed.
*/
udbg("Keyboard removed, polling halted\n");
priv->polling = false;
if (--priv->crefs < 2)
{
/* Destroy the instance (while we hold the semaphore!) */
usbhost_destroy(priv);
}
else
{
/* No, we will destroy the driver instance when it is finally closed */
usbhost_givesem(&priv->exclsem);
}
return 0;
}
/****************************************************************************
* Name: usbhost_cfgdesc
*
@ -769,6 +889,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
static inline int usbhost_devinit(FAR struct usbhost_state_s *priv)
{
char devname[DEV_NAMELEN];
int ret;
/* Set aside a transfer buffer for exclusive use by the keyboard class driver */
@ -787,63 +908,63 @@ static inline int usbhost_devinit(FAR struct usbhost_state_s *priv)
priv->crefs++;
DEBUGASSERT(priv->crefs == 2);
/* Setup a period worker thread event to poll the USB device. */
ret = work_queue(&priv->work, usbhost_kbdpoll, priv, CONFIG_HIDKBD_POLLTICKS);
/* Register the driver */
if (ret == OK)
{
char devname[DEV_NAMELEN];
uvdbg("Register driver\n");
usbhost_mkdevname(priv, devname);
(void)register_driver(devname, &usbhost_fops, 0666, NULL);
}
/* Check if we successfully initialized. We now have to be concerned
* about asynchronous modification of crefs because the driver has
* been registerd.
/* Start a worker task to poll the USB device. It would be nice to used the
* the NuttX worker thread to do this, but this task needs to wait for events
* and activities on the worker thread should not involve significant waiting.
* Having a dedicated thread is more efficient in this sense, but requires more
* memory resources, primarily for the dedicated stack (CONFIG_HIDKBD_STACKSIZE).
*/
if (ret == OK)
uvdbg("user_start: Start poll task\n");
/* The inputs to a task started by task_create() are very awkard for this
* purpose. They are really designed for command line tasks (argc/argv). So
* the following is kludge pass binary data when the keyboard poll task
* is started.
*
* First, make sure we have exclusive access to g_priv (what is the likelihood
* of this being used? About zero, but we protect it anyway).
*/
usbhost_takesem(&g_exclsem);
g_priv = priv;
#ifndef CONFIG_CUSTOM_STACK
priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO,
CONFIG_HIDKBD_STACKSIZE,
(main_t)usbhost_kbdpoll, (const char **)NULL);
#else
priv->pollpid = task_create("usbhost", CONFIG_HIDKBD_DEFPRIO,
(main_t)hidkbd_waiter, (const char **)NULL);
#endif
if (priv->pollpid == ERROR)
{
usbhost_takesem(&priv->exclsem);
DEBUGASSERT(priv->crefs >= 2);
/* Failed to started the poll thread... probably due to memory resources */
/* Handle a corner case where (1) open() has been called so the
* reference count is > 2, but the device has been disconnected.
* In this case, the class instance needs to persist until close()
* is called.
*/
if (priv->crefs <= 2 && priv->disconnected)
{
/* We don't have to give the semaphore because it will be
* destroyed when usb_destroy is called.
*/
ret = -ENODEV;
}
else
{
/* Ready for normal operation as a character device driver */
uvdbg("Successfully initialized\n");
priv->crefs--;
usbhost_givesem(&priv->exclsem);
}
usbhost_givesem(&g_exclsem);
ret = -ENOMEM;
goto errout;
}
/* Disconnect on any errors detected during volume initialization */
/* Now wait for the poll task to get properly initialized */
if (ret != OK)
{
udbg("ERROR! Aborting: %d\n", ret);
usbhost_destroy(priv);
}
usbhost_takesem(&g_syncsem);
usbhost_givesem(&g_exclsem);
/* Register the driver */
uvdbg("Register driver\n");
usbhost_mkdevname(priv, devname);
ret = register_driver(devname, &usbhost_fops, 0666, NULL);
/* We now have to be concerned about asynchronous modification of crefs
* because the driver has been registerd.
*/
errout:
usbhost_takesem(&priv->exclsem);
priv->crefs--;
usbhost_givesem(&priv->exclsem);
return ret;
}
@ -936,7 +1057,7 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
* Name: usbhost_tdalloc
*
* Description:
* Allocate transfer descriptor memory.
* Allocate transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -949,15 +1070,15 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
{
DEBUGASSERT(priv && priv->tdbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tdbuffer, &priv->tdbuflen);
DEBUGASSERT(priv && priv->tbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
}
/****************************************************************************
* Name: usbhost_tdfree
*
* Description:
* Free transfer descriptor memory.
* Free transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -973,12 +1094,12 @@ static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
int result = OK;
DEBUGASSERT(priv);
if (priv->tdbuffer)
if (priv->tbuffer)
{
DEBUGASSERT(priv->drvr);
result = DRVR_FREE(priv->drvr, priv->tdbuffer);
priv->tdbuffer = NULL;
priv->tdbuflen = 0;
result = DRVR_FREE(priv->drvr, priv->tbuffer);
priv->tbuffer = NULL;
priv->tbuflen = 0;
}
return result;
}
@ -1049,9 +1170,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
priv->drvr = drvr;
/* NOTE: We do not yet know the geometry of the USB mass storage device */
/* Return the instance of the USB mass storage class */
/* Return the instance of the USB keyboard class driver */
return &priv->class;
}
@ -1123,6 +1242,34 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
}
}
/* Disconnect on any errors detected during initialization. */
if (ret != OK)
{
priv->disconnected = true;
/* Is the polling task still running? If so, then ask it politely to
* stop and release its reference count.
*/
while (priv->polling)
{
(void)kill(priv->pollpid, SIGALRM);
usleep(500*1000);
}
/* The following operations when crefs == 1 are safe because we know
* that there is no outstanding open references to the driver.
*/
if (priv->crefs <= 1)
{
/* Destroy the class instance */
usbhost_destroy(priv);
}
}
return ret;
}
@ -1151,61 +1298,134 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
static int usbhost_disconnected(struct usbhost_class_s *class)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
irqstate_t flags;
DEBUGASSERT(priv != NULL);
/* Set an indication to any users of the mass storage device that the device
/* Set an indication to any users of the keyboard device that the device
* is no longer available.
*/
flags = irqsave();
priv->disconnected = true;
ullvdbg("Disconnected\n");
/* Now check the number of references on the class instance. If it is one,
* then we can free the class instance now. Otherwise, we will have to
* wait until the holders of the references free them by closing the
* driver.
/* Signal the keyboard polling task. When that task wakes up, it will
* decrement the reference count and, perhaps, destroy the class instance.
*/
ullvdbg("crefs: %d\n", priv->crefs);
if (priv->crefs == 1)
{
/* Destroy the class instance. If we are executing from an interrupt
* handler, then defer the destruction to the worker thread.
* Otherwise, destroy the instance now.
*/
if (up_interrupt_context())
{
/* Destroy the instance on the worker thread. */
uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
/* Cancel the period polling thread */
(void)work_cancel(&priv->work);
DEBUGASSERT(priv->work.worker == NULL);
/* Then schedule the destruction */
(void)work_queue(&priv->work, usbhost_destroy, priv, 0);
}
else
{
/* Do the work now */
usbhost_destroy(priv);
}
}
irqrestore(flags);
(void)kill(priv->pollpid, SIGALRM);
return OK;
}
/****************************************************************************
* Character driver methods
****************************************************************************/
/****************************************************************************
* Name: usbhost_open
*
* Description:
* Standard character driver open method.
*
****************************************************************************/
static int usbhost_open(FAR struct file *filep)
{
FAR struct inode *inode;
FAR struct usbhost_state_s *priv;
irqstate_t flags;
int ret;
uvdbg("Entry\n");
DEBUGASSERT(filep && filep->f_inode);
inode = filep->f_inode;
priv = inode->i_private;
/* Make sure that we have exclusive access to the private data structure */
DEBUGASSERT(priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS);
usbhost_takesem(&priv->exclsem);
/* Check if the keyboard device is still connected. We need to disable
* interrupts 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
* the USB storage device is no longer connected. Refuse any further
* attempts to open the driver.
*/
ret = -ENODEV;
}
else
{
/* Otherwise, just increment the reference count on the driver */
priv->crefs++;
ret = OK;
}
irqrestore(flags);
usbhost_givesem(&priv->exclsem);
return ret;
}
/****************************************************************************
* Name: usbhost_close
*
* Description:
* Standard character driver close method.
*
****************************************************************************/
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);
inode = filep->f_inode;
priv = inode->i_private;
/* Decrement the reference count on the driver */
DEBUGASSERT(priv->crefs > 1);
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.
*/
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)
{
/* Destroy the class instance */
usbhost_destroy(priv);
}
irqrestore(flags);
return OK;
}
/****************************************************************************
* Name: usbhost_read
*
@ -1214,8 +1434,45 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
*
****************************************************************************/
static ssize_t usbhost_read(FAR struct file *filp, FAR char *buffer, size_t len)
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;
uvdbg("Entry\n");
DEBUGASSERT(filep && filep->f_inode && buffer);
inode = filep->f_inode;
priv = inode->i_private;
/* Make sure that we have exclusive access to the private data structure */
DEBUGASSERT(priv && priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS);
usbhost_takesem(&priv->exclsem);
/* Check if the keyboard is still connected. We need to disable interrupts
* 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
* the USB keybaord is no longer connected. Refuse any further attempts
* to access the driver.
*/
ret = -ENODEV;
}
else
{
/* Read data from our internal buffer of received characters */
#warning "Missing logic"
}
irqrestore(flags);
usbhost_givesem(&priv->exclsem);
return 0; /* Return EOF for now */
}
@ -1227,9 +1484,11 @@ static ssize_t usbhost_read(FAR struct file *filp, FAR char *buffer, size_t len)
*
****************************************************************************/
static ssize_t usbhost_write(FAR struct file *filp, FAR const char *buffer, size_t len)
static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer, size_t len)
{
return len; /* Say that everything was written for now */
/* We won't try to write to the keyboard */
return -ENOSYS;
}
/****************************************************************************
@ -1241,7 +1500,7 @@ static ssize_t usbhost_write(FAR struct file *filp, FAR const char *buffer, size
****************************************************************************/
#ifndef CONFIG_DISABLE_POLL
static int usbhost_poll(FAR struct file *filp, FAR struct pollfd *fds,
static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
bool setup)
{
if (setup)
@ -1281,6 +1540,9 @@ int usbhost_kbdinit(void)
{
/* Perform any one-time initialization of the class implementation */
sem_init(&g_exclsem, 0, 1);
sem_init(&g_syncsem, 0, 0);
/* Advertise our availability to support (certain) devices */
return usbhost_registerclass(&g_skeleton);

View file

@ -65,12 +65,12 @@
#endif
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/sd[n] device driver path. It
/* This format is used to construct the /dev/skel[n] device driver path. It
* defined here so that it will be used consistently in all places.
*/
#define DEV_FORMAT "/dev/sd%c"
#define DEV_NAMELEN 10
#define DEV_FORMAT "/dev/skel%c"
#define DEV_NAMELEN 12
/* Used in usbhost_cfgdesc() */
@ -85,8 +85,8 @@
* Private Types
****************************************************************************/
/* This structure contains the internal, private state of the USB host mass
* storage class.
/* This structure contains the internal, private state of the USB host class
* driver.
*/
struct usbhost_state_s
@ -99,15 +99,15 @@ struct usbhost_state_s
struct usbhost_driver_s *drvr;
/* The remainder of the fields are provide o the mass storage class */
/* The remainder of the fields are provide to the class driver */
char sdchar; /* Character identifying the /dev/sd[n] device */
char devchar; /* Character identifying the /dev/skel[n] device */
volatile bool disconnected; /* TRUE: Device has been disconnected */
int16_t crefs; /* Reference count on the driver instance */
sem_t exclsem; /* Used to maintain mutual exclusive access */
struct work_s work; /* For interacting with the worker thread */
FAR uint8_t *tdbuffer; /* The allocated transfer descriptor buffer */
size_t tdbuflen; /* Size of the allocated transfer buffer */
FAR uint8_t *tbuffer; /* The allocated transfer buffer */
size_t tbuflen; /* Size of the allocated transfer buffer */
usbhost_ep_t epin; /* IN endpoint */
usbhost_ep_t epout; /* OUT endpoint */
};
@ -152,8 +152,8 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val);
/* Transfer descriptor memory management */
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv);
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv);
static inline int usbhost_talloc(FAR struct usbhost_state_s *priv);
static inline int usbhost_tfree(FAR struct usbhost_state_s *priv);
/* struct usbhost_registry_s methods */
@ -174,8 +174,7 @@ static int usbhost_disconnected(FAR struct usbhost_class_s *class);
****************************************************************************/
/* This structure provides the registry entry ID informatino that will be
* used to associate the USB host mass storage class to a connected USB
* device.
* used to associate the USB class driver to a connected USB device.
*/
static const const struct usbhost_id_s g_id =
@ -197,7 +196,7 @@ static struct usbhost_registry_s g_skeleton =
&g_id /* id[] */
};
/* This is a bitmap that is used to allocate device names /dev/sda-z. */
/* This is a bitmap that is used to allocate device names /dev/skela-z. */
static uint32_t g_devinuse;
@ -303,7 +302,7 @@ static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
if ((g_devinuse & bitno) == 0)
{
g_devinuse |= bitno;
priv->sdchar = 'a' + devno;
priv->devchar = 'a' + devno;
irqrestore(flags);
return OK;
}
@ -315,7 +314,7 @@ static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
{
int devno = 'a' - priv->sdchar;
int devno = 'a' - priv->devchar;
if (devno >= 0 && devno < 26)
{
@ -327,7 +326,7 @@ static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
{
(void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
(void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
}
/****************************************************************************
@ -761,10 +760,10 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
}
/****************************************************************************
* Name: usbhost_tdalloc
* Name: usbhost_talloc
*
* Description:
* Allocate transfer descriptor memory.
* Allocate transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -775,17 +774,17 @@ static void usbhost_putle32(uint8_t *dest, uint32_t val)
*
****************************************************************************/
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
{
DEBUGASSERT(priv && priv->tdbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tdbuffer, &priv->tdbuflen);
DEBUGASSERT(priv && priv->tbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
}
/****************************************************************************
* Name: usbhost_tdfree
* Name: usbhost_tfree
*
* Description:
* Free transfer descriptor memory.
* Free transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -796,17 +795,17 @@ static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
*
****************************************************************************/
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
{
int result = OK;
DEBUGASSERT(priv);
if (priv->tdbuffer)
if (priv->tbuffer)
{
DEBUGASSERT(priv->drvr);
result = DRVR_FREE(priv->drvr, priv->tdbuffer);
priv->tdbuffer = NULL;
priv->tdbuflen = 0;
result = DRVR_FREE(priv->drvr, priv->tbuffer);
priv->tbuffer = NULL;
priv->tbuflen = 0;
}
return result;
}
@ -877,9 +876,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
priv->drvr = drvr;
/* NOTE: We do not yet know the geometry of the USB mass storage device */
/* Return the instance of the USB mass storage class */
/* Return the instance of the USB class driver */
return &priv->class;
}
@ -983,8 +980,8 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
DEBUGASSERT(priv != NULL);
/* Set an indication to any users of the mass storage device that the device
* is no longer available.
/* Set an indication to any users of the device that the device is no
* longer available.
*/
flags = irqsave();

View file

@ -121,7 +121,7 @@ struct usbhost_state_s
struct usbhost_driver_s *drvr;
/* The remainder of the fields are provide o the mass storage class */
/* The remainder of the fields are provide to the mass storage class */
char sdchar; /* Character identifying the /dev/sd[n] device */
volatile bool disconnected; /* TRUE: Device has been disconnected */
@ -130,8 +130,8 @@ struct usbhost_state_s
uint32_t nblocks; /* Number of blocks on the USB mass storage device */
sem_t exclsem; /* Used to maintain mutual exclusive access */
struct work_s work; /* For interacting with the worker thread */
FAR uint8_t *tdbuffer; /* The allocated transfer descriptor buffer */
size_t tdbuflen; /* Size of the allocated transfer buffer */
FAR uint8_t *tbuffer; /* The allocated transfer buffer */
size_t tbuflen; /* Size of the allocated transfer buffer */
usbhost_ep_t bulkin; /* Bulk IN endpoint */
usbhost_ep_t bulkout; /* Bulk OUT endpoint */
};
@ -210,8 +210,8 @@ static void usbhost_putbe32(uint8_t *dest, uint32_t val);
/* Transfer descriptor memory management */
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv);
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv);
static inline int usbhost_talloc(FAR struct usbhost_state_s *priv);
static inline int usbhost_tfree(FAR struct usbhost_state_s *priv);
static FAR struct usbstrg_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv);
/* struct usbhost_registry_s methods */
@ -665,8 +665,8 @@ usbhost_writecbw(size_t startsector, uint16_t blocksize,
static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
{
FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tdbuffer;
DEBUGASSERT(priv && priv->tdbuffer);
FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tbuffer;
DEBUGASSERT(priv && priv->tbuffer);
/* Request maximum logical unit number. NOTE: On an IN transaction, The
* req and buffer pointers passed to DRVR_CTRLIN may refer to the same
@ -678,7 +678,7 @@ static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
req->type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
req->req = USBSTRG_REQ_GETMAXLUN;
usbhost_putle16(req->len, 1);
return DRVR_CTRLIN(priv->drvr, req, priv->tdbuffer);
return DRVR_CTRLIN(priv->drvr, req, priv->tbuffer);
}
static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
@ -705,10 +705,10 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tdbuffer);
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tbuffer);
}
}
return result;
@ -738,16 +738,16 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv)
/* Receive the sense data response */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
if (result == OK)
{
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tdbuffer);
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tbuffer);
}
}
}
@ -780,22 +780,22 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
/* Receive the read capacity CBW IN response */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
if (result == OK)
{
/* Save the capacity information */
resp = (FAR struct scsiresp_readcapacity10_s *)priv->tdbuffer;
resp = (FAR struct scsiresp_readcapacity10_s *)priv->tbuffer;
priv->nblocks = usbhost_getbe32(resp->lba);
priv->blocksize = usbhost_getbe32(resp->blklen);
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tdbuffer);
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tbuffer);
}
}
}
@ -828,20 +828,20 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
/* Receive the CBW IN response */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_INQUIRY_SIZEOF);
priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF);
if (result == OK)
{
/* TODO: If USB debug is enabled, dump the response data here */
resp = (FAR struct scsiresp_inquiry_s *)priv->tdbuffer;
resp = (FAR struct scsiresp_inquiry_s *)priv->tbuffer;
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tdbuffer);
usbhost_dumpcsw((FAR struct usbstrg_csw_s *)priv->tbuffer);
}
}
}
@ -896,7 +896,7 @@ static void usbhost_destroy(FAR void *arg)
/* Free any transfer buffers */
usbhost_tdfree(priv);
usbhost_tfree(priv);
/* Destroy the semaphores */
@ -1153,7 +1153,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
/* Set aside a transfer buffer for exclusive use by the mass storage driver */
ret = usbhost_tdalloc(priv);
ret = usbhost_talloc(priv);
if (ret != OK)
{
udbg("ERROR: Failed to allocate transfer buffer\n");
@ -1185,7 +1185,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
{
/* Is the unit is ready */
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
csw = (FAR struct usbstrg_csw_s *)priv->tbuffer;
if (csw->status == 0)
{
/* Yes... break out of the loop */
@ -1221,7 +1221,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
{
/* Check the CSW for errors */
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
csw = (FAR struct usbstrg_csw_s *)priv->tbuffer;
if (csw->status != 0)
{
udbg("ERROR: CSW status error: %d\n", csw->status);
@ -1242,7 +1242,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
{
/* Check the CSW for errors */
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
csw = (FAR struct usbstrg_csw_s *)priv->tbuffer;
if (csw->status != 0)
{
udbg("ERROR: CSW status error: %d\n", csw->status);
@ -1478,10 +1478,10 @@ static void usbhost_putbe32(uint8_t *dest, uint32_t val)
}
/****************************************************************************
* Name: usbhost_tdalloc
* Name: usbhost_talloc
*
* Description:
* Allocate transfer descriptor memory.
* Allocate transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -1492,17 +1492,17 @@ static void usbhost_putbe32(uint8_t *dest, uint32_t val)
*
****************************************************************************/
static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
{
DEBUGASSERT(priv && priv->tdbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tdbuffer, &priv->tdbuflen);
DEBUGASSERT(priv && priv->tbuffer == NULL);
return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
}
/****************************************************************************
* Name: usbhost_tdfree
* Name: usbhost_tfree
*
* Description:
* Free transfer descriptor memory.
* Free transfer buffer memory.
*
* Input Parameters:
* priv - A reference to the class instance.
@ -1513,17 +1513,17 @@ static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
*
****************************************************************************/
static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
{
int result = OK;
DEBUGASSERT(priv);
if (priv->tdbuffer)
if (priv->tbuffer)
{
DEBUGASSERT(priv->drvr);
result = DRVR_FREE(priv->drvr, priv->tdbuffer);
priv->tdbuffer = NULL;
priv->tdbuflen = 0;
result = DRVR_FREE(priv->drvr, priv->tbuffer);
priv->tbuffer = NULL;
priv->tbuflen = 0;
}
return result;
}
@ -1547,11 +1547,11 @@ static FAR struct usbstrg_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pr
{
FAR struct usbstrg_cbw_s *cbw = NULL;
DEBUGASSERT(priv->tdbuffer && priv->tdbuflen >= sizeof(struct usbstrg_cbw_s))
DEBUGASSERT(priv->tbuffer && priv->tbuflen >= sizeof(struct usbstrg_cbw_s))
/* Intialize the CBW sructure */
cbw = (FAR struct usbstrg_cbw_s *)priv->tdbuffer;
cbw = (FAR struct usbstrg_cbw_s *)priv->tbuffer;
memset(cbw, 0, sizeof(struct usbstrg_cbw_s));
usbhost_putle32(cbw->signature, USBSTRG_CBW_SIGNATURE);
return cbw;
@ -1943,14 +1943,14 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
FAR struct usbstrg_csw_s *csw;
/* Check the CSW status */
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
csw = (FAR struct usbstrg_csw_s *)priv->tbuffer;
if (csw->status == 0)
{
ret = nsectors;
@ -2035,14 +2035,14 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
/* Receive the CSW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
priv->tbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
FAR struct usbstrg_csw_s *csw;
/* Check the CSW status */
csw = (FAR struct usbstrg_csw_s *)priv->tdbuffer;
csw = (FAR struct usbstrg_csw_s *)priv->tbuffer;
if (csw->status == 0)
{
ret = nsectors;

View file

@ -150,7 +150,7 @@ int user_start(int argc, char *argv[])
/* First, register all of the USB host HID keyboard class driver */
printf("user_start: Register class drivers\n");
ret = usbhost_storageinit();
ret = usbhost_kbdinit();
if (ret != OK)
{
printf("user_start: Failed to register the KBD class\n");