diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-16 19:08:16 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-16 19:08:16 +0000 |
commit | f66aa23286252a911e122349249b2def1d9c5810 (patch) | |
tree | e04f35197a66308d724047934187bbabc1b57457 | |
parent | b7145b509d269f4a5ffcecad9a969c6a0a480f20 (diff) | |
download | nuttx-f66aa23286252a911e122349249b2def1d9c5810.tar.gz nuttx-f66aa23286252a911e122349249b2def1d9c5810.tar.bz2 nuttx-f66aa23286252a911e122349249b2def1d9c5810.zip |
More HID keyboard support
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3255 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-x | nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c | 328 | ||||
-rw-r--r-- | nuttx/drivers/usbhost/usbhost_hidkbd.c | 668 | ||||
-rw-r--r-- | nuttx/drivers/usbhost/usbhost_skeleton.c | 65 | ||||
-rw-r--r-- | nuttx/drivers/usbhost/usbhost_storage.c | 88 | ||||
-rw-r--r-- | nuttx/examples/hidkbd/hidkbd_main.c | 2 |
5 files changed, 848 insertions, 303 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c index 6c056b1dc..78258d25e 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -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. @@ -774,43 +788,314 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv, } /******************************************************************************* + * 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: diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c index 7cdc41b0b..cf07ccc4e 100644 --- a/nuttx/drivers/usbhost/usbhost_hidkbd.c +++ b/nuttx/drivers/usbhost/usbhost_hidkbd.c @@ -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 */ +/* This determines how often the USB keyboard will be polled in units of + * of microseconds. The default is 100MS. + */ -#ifndef CONFIG_SCHED_WORKQUEUE -# error "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)" +#ifndef CONFIG_HIDKBD_POLLUSEC +# define CONFIG_HIDKBD_POLLUSEC (100*1000) #endif -/* This determines how often the USB keyboard will be polled in units of - * of clock ticks. The default is 100MS. - */ +/* Signals must not be disabled as they are needed by usleep */ -#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. - */ +/* Provide some default values for other configuration settings */ -# define CONFIG_HIDKBD_POLLTICKS (CLK_TCK/10) +#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); @@ -529,6 +464,191 @@ static void usbhost_destroy(FAR void *arg) } /**************************************************************************** + * 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 * * Description: @@ -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]; + /* 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). + */ - uvdbg("Register driver\n"); - usbhost_mkdevname(priv, devname); - (void)register_driver(devname, &usbhost_fops, 0666, NULL); - } + uvdbg("user_start: Start poll task\n"); - /* Check if we successfully initialized. We now have to be concerned - * about asynchronous modification of crefs because the driver has - * been registerd. + /* 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). */ - if (ret == OK) + 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. - */ + usbhost_givesem(&g_exclsem); + ret = -ENOMEM; + goto errout; + } - 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 */ + /* Now wait for the poll task to get properly initialized */ - uvdbg("Successfully initialized\n"); - priv->crefs--; - usbhost_givesem(&priv->exclsem); - } - } + usbhost_takesem(&g_syncsem); + usbhost_givesem(&g_exclsem); - /* Disconnect on any errors detected during volume initialization */ + /* Register the driver */ - if (ret != OK) - { - udbg("ERROR! Aborting: %d\n", ret); - usbhost_destroy(priv); - } + 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,62 +1298,135 @@ 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) + (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) { - /* 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. + /* 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. */ - if (up_interrupt_context()) - { - /* Destroy the instance on the worker thread. */ + 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("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy); + uvdbg("Entry\n"); + DEBUGASSERT(filep && filep->f_inode); + inode = filep->f_inode; + priv = inode->i_private; - /* Cancel the period polling thread */ + /* Decrement the reference count on the driver */ - (void)work_cancel(&priv->work); - DEBUGASSERT(priv->work.worker == NULL); + DEBUGASSERT(priv->crefs > 1); + usbhost_takesem(&priv->exclsem); + priv->crefs--; - /* Then schedule the destruction */ + /* Release the semaphore. The following operations when crefs == 1 are + * safe because we know that there is no outstanding open references to + * the driver. + */ - (void)work_queue(&priv->work, usbhost_destroy, priv, 0); - } - else - { - /* Do the work now */ + usbhost_givesem(&priv->exclsem); - usbhost_destroy(priv); - } + /* 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); + irqrestore(flags); return OK; } /**************************************************************************** - * Character driver methods - ****************************************************************************/ -/**************************************************************************** * Name: usbhost_read * * Description: @@ -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); diff --git a/nuttx/drivers/usbhost/usbhost_skeleton.c b/nuttx/drivers/usbhost/usbhost_skeleton.c index fe3d71a28..ae37da02a 100644 --- a/nuttx/drivers/usbhost/usbhost_skeleton.c +++ b/nuttx/drivers/usbhost/usbhost_skeleton.c @@ -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(); diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c index 759d5bd6c..e6fd11047 100644 --- a/nuttx/drivers/usbhost/usbhost_storage.c +++ b/nuttx/drivers/usbhost/usbhost_storage.c @@ -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; diff --git a/nuttx/examples/hidkbd/hidkbd_main.c b/nuttx/examples/hidkbd/hidkbd_main.c index 8a98afd51..47de0fbcf 100644 --- a/nuttx/examples/hidkbd/hidkbd_main.c +++ b/nuttx/examples/hidkbd/hidkbd_main.c @@ -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"); |