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:
parent
258009c392
commit
2270d885e9
5 changed files with 860 additions and 315 deletions
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue