aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/usbhost
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/usbhost')
-rw-r--r--nuttx/drivers/usbhost/Kconfig114
-rw-r--r--nuttx/drivers/usbhost/Make.defs57
-rw-r--r--nuttx/drivers/usbhost/hid_parser.c529
-rw-r--r--nuttx/drivers/usbhost/usbhost_enumerate.c518
-rw-r--r--nuttx/drivers/usbhost/usbhost_findclass.c199
-rw-r--r--nuttx/drivers/usbhost/usbhost_hidkbd.c2353
-rw-r--r--nuttx/drivers/usbhost/usbhost_registerclass.c117
-rw-r--r--nuttx/drivers/usbhost/usbhost_registry.c80
-rw-r--r--nuttx/drivers/usbhost/usbhost_registry.h87
-rw-r--r--nuttx/drivers/usbhost/usbhost_skeleton.c1060
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c2244
11 files changed, 0 insertions, 7358 deletions
diff --git a/nuttx/drivers/usbhost/Kconfig b/nuttx/drivers/usbhost/Kconfig
deleted file mode 100644
index 531e94442..000000000
--- a/nuttx/drivers/usbhost/Kconfig
+++ /dev/null
@@ -1,114 +0,0 @@
-#
-# For a description of the syntax of this configuration file,
-# see misc/tools/kconfig-language.txt.
-#
-
-config USBHOST_NPREALLOC
- int "Number of pre-allocated class instances"
- default 4
- ---help---
- Number of pre-allocated class instances
-
-config USBHOST_BULK_DISABLE
- bool "Disable bulk endpoint support"
- default n
- ---help---
- On some architectures, selecting this setting will reduce driver size
- by disabling bulk endpoint support
-
-config USBHOST_INT_DISABLE
- bool "Disable interrupt endpoint support"
- default n
- ---help---
- On some architectures, selecting this setting will reduce driver size
- by disabling interrupt endpoint support
-
-config USBHOST_ISOC_DISABLE
- bool "Disable isochronous endpoint support"
- default n
- ---help---
- On some architectures, selecting this setting will reduce driver size
- by disabling isochronous endpoint support
-
-config USBHOST_MSC
- bool "Mass Storage Class Support"
- default n
- depends on !BULK_DISABLE
- ---help---
- Enable support for the keyboard class driver. This also depends on
- NFILE_DESCRIPTORS > 0 && SCHED_WORKQUEUE=y
-
-config USBHOST_HIDKBD
- bool "HID Keyboard Class Support"
- default n
- depends on !INT_DISABLE
- ---help---
- Enable support for the keyboard class driver. This also depends on
- SCHED_WORKQUEUE && !DISABLE_SIGNALS
-
-if USBHOST_HIDKBD
-config HIDKBD_POLLUSEC
- int "Keyboard Poll Rate (MSEC)"
- default 100000
- ---help---
- Device poll rate in microseconds. Default: 100,000 microseconds.
-
-config HIDKBD_DEFPRIO
- int "Polling Thread Priority"
- default 50
- ---help---
- Priority of the polling thread. Default: 50.
-
-config HIDKBD_STACKSIZE
- int "Polling thread stack size"
- default 1024
- ---help---
- Stack size for polling thread. Default: 1024
-
-config HIDKBD_BUFSIZE
- int "Scancode Buffer Size"
- default 64
- ---help---
- Scancode buffer size. Default: 64.
-
-config HIDKBD_NPOLLWAITERS
- int "Max Number of Waiters for Poll Event"
- default 2
- depends on !DISABLE_POLL
- ---help---
- If the poll() method is enabled, this defines the maximum number
- of threads that can be waiting for keyboard events. Default: 2.
-
-config HIDKBD_RAWSCANCODES
- bool "Use Raw Scan Codes"
- default n
- ---help---
- If set to y no conversions will be made on the raw keyboard scan
- codes. This option is useful during testing. Default: ASCII conversion.
-
-config HIDKBD_ENCODED
- bool "Enocode Special Keys"
- default n
- depends on !HIDKBD_RAWSCANCODES && LIB_KBDCODEC
- ---help---
- Encode special key press events in the user buffer. In this case,
- the user end must decode the encoded special key values using the
- interfaces defined in include/nuttx/input/kbd_codec.h. These
- special keys include such things as up/down arrows, home and end
- keys, etc. If this not defined, only 7-bit print-able and control
- ASCII characters will be provided to the user.
-
-config HIDKBD_ALLSCANCODES
- bool "Use All Scancodes"
- default n
- ---help---
- If set to y all 231 possible scancodes will be converted to
- something. Default: 104 key US keyboard.
-
-config HIDKBD_NODEBOUNCE
- bool "Disable Debounce"
- default n
- ---help---
- If set to y normal debouncing is disabled. Default:
- Debounce enabled (No repeat keys).
-endif
diff --git a/nuttx/drivers/usbhost/Make.defs b/nuttx/drivers/usbhost/Make.defs
deleted file mode 100644
index ebb522695..000000000
--- a/nuttx/drivers/usbhost/Make.defs
+++ /dev/null
@@ -1,57 +0,0 @@
-############################################################################
-# drivers/usbhost/Make.defs
-#
-# Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
-# Author: Gregory Nutt <gnutt@nuttx.org>
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# 3. Neither the name NuttX nor the names of its contributors may be
-# used to endorse or promote products derived from this software
-# without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
-# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
-# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-############################################################################
-
-CSRCS += hid_parser.c
-
-ifeq ($(CONFIG_USBHOST),y)
-
-# Include built-in USB host driver logic
-
-CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c
-CSRCS += usbhost_enumerate.c usbhost_storage.c usbhost_hidkbd.c
-
-# Include add-on USB host driver logic (see misc/drivers)
-
-ifeq ($(CONFIG_NET),y)
- RTL8187_CSRC := ${shell if [ -f usbhost$(DELIM)rtl8187x.c ]; then echo "rtl8187x.c"; fi}
- CSRCS += $(RTL8187_CSRC)
-endif
-endif
-
-# Include USB host driver build logic
-
-DEPPATH += --dep-path usbhost
-VPATH += :usbhost
-CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)usbhost}
diff --git a/nuttx/drivers/usbhost/hid_parser.c b/nuttx/drivers/usbhost/hid_parser.c
deleted file mode 100644
index a0ca6066b..000000000
--- a/nuttx/drivers/usbhost/hid_parser.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/hid_parser.c
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- *
- * Adapted from the LUFA Library:
- *
- * Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com)
- * dean [at] fourwalledcubicle [dot] com, www.lufa-lib.org
- *
- * Permission to use, copy, modify, distribute, and sell this
- * software and its documentation for any purpose is hereby granted
- * without fee, provided that the above copyright notice appear in
- * all copies and that both that the copyright notice and this
- * permission notice and warranty disclaimer appear in supporting
- * documentation, and that the name of the author not be used in
- * advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission.
- *
- * The author disclaim all warranties with regard to this
- * software, including all implied warranties of merchantability
- * and fitness. In no event shall the author be liable for any
- * special, indirect or consequential damages or any damages
- * whatsoever resulting from loss of use, data or profits, whether
- * in an action of contract, negligence or other tortious action,
- * arising out of or in connection with the use or performance of
- * this software.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/usb/hid.h>
-#include <nuttx/usb/hid_parser.h>
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct hid_state_s
-{
- struct hid_rptitem_attributes_s attrib;
- uint8_t rptcount;
- uint8_t id;
-};
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: hid_parsereport
- *
- * Description:
- * Function to process a given HID report returned from an attached device,
- * and store it into a given struct hid_rptinfo_s structure.
- *
- * Input Parameters:
- * report Buffer containing the device's HID report table.
- * rptlen Size in bytes of the HID report table.
- * filter Callback function to decide if an item should be retained
- * rptinfo Pointer to a struct hid_rptinfo_s instance for the parser output.
- *
- * Returned Value:
- * Zero on success, otherwise a negated errno value.
- ****************************************************************************/
-
-int hid_parsereport(FAR const uint8_t *report, int rptlen,
- hid_rptfilter_t filter, FAR struct hid_rptinfo_s *rptinfo)
-{
- struct hid_state_s state[CONFIG_HID_STATEDEPTH];
- struct hid_state_s *currstate = &state[0];
- struct hid_collectionpath_s *collectionpath = NULL;
- struct hid_rptsizeinfo_s *rptidinfo = &rptinfo->rptsize[0];
- uint16_t usage[CONFIG_HID_USAGEDEPTH];
- uint8_t nusage = 0;
- struct hid_range_s usage_range = { 0, 0 };
- int i;
-
- DEBUGASSERT(report && filter && rptinfo);
-
- memset(rptinfo, 0x00, sizeof(struct hid_rptinfo_s));
- memset(currstate, 0x00, sizeof(struct hid_state_s));
- memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s));
-
- rptinfo->nreports = 1;
-
- while (rptlen > 0)
- {
- uint8_t item = *report;
- uint32_t data = 0;
-
- report++;
- rptlen--;
-
- switch (item & USBHID_RPTITEM_SIZE_MASK)
- {
- case USBHID_RPTITEM_SIZE_4: /* 4 bytes of little endian data follow */
- data = (uint32_t)(*report++);
- data |= (uint32_t)(*report++) << 8;
- data |= (uint32_t)(*report++) << 16;
- data |= (uint32_t)(*report++) << 24;
- rptlen -= 4;
- break;
-
- case USBHID_RPTITEM_SIZE_2: /* 2 bytes of little endian data follow */
- data = (uint32_t)(*report++);
- data |= (uint32_t)(*report++) << 8;
- rptlen -= 2;
- break;
-
- case USBHID_RPTITEM_SIZE_1: /* 1 byte of data follows */
- data = (uint32_t)(*report++);
- rptlen -= 1;
- break;
-
- case USBHID_RPTITEM_SIZE_0: /* No data follows */
- default:
- break;
- }
-
- switch (item & ~USBHID_RPTITEM_SIZE_MASK)
- {
- case USBHID_GLOBAL_PUSH_PREFIX:
- if (currstate == &state[CONFIG_HID_STATEDEPTH - 1])
- {
- return -E2BIG;
- }
-
- memcpy((currstate + 1),
- currstate, sizeof(struct hid_rptitem_s));
-
- currstate++;
- break;
-
- case USBHID_GLOBAL_POP_PREFIX:
- if (currstate == &state[0])
- {
- return -EINVAL; /* Pop without push? */
- }
-
- currstate--;
- break;
-
- case USBHID_GLOBAL_USAGEPAGE_PREFIX:
- if ((item & USBHID_RPTITEM_SIZE_MASK) == USBHID_RPTITEM_SIZE_4)
- {
- currstate->attrib.usage.page = (data >> 16);
- }
-
- currstate->attrib.usage.page = data;
- break;
-
- case USBHID_GLOBAL_LOGICALMIN_PREFIX:
- currstate->attrib.logical.min = data;
- break;
-
- case USBHID_GLOBAL_LOGICALMAX_PREFIX:
- currstate->attrib.logical.max = data;
- break;
-
- case USBHID_GLOBAL_PHYSICALMIN_PREFIX:
- currstate->attrib.physical.min = data;
- break;
-
- case USBHID_GLOBAL_PHYSMICALAX_PREFIX:
- currstate->attrib.physical.max = data;
- break;
-
- case USBHID_GLOBAL_UNITEXP_PREFIX:
- currstate->attrib.unit.exponent = data;
- break;
-
- case USBHID_GLOBAL_UNIT_PREFIX:
- currstate->attrib.unit.type = data;
- break;
-
- case USBHID_GLOBAL_REPORTSIZE_PREFIX:
- currstate->attrib.bitsize = data;
- break;
-
- case USBHID_GLOBAL_REPORTCOUNT_PREFIX:
- currstate->rptcount = data;
- break;
-
- case USBHID_GLOBAL_REPORTID_PREFIX:
- currstate->id = data;
-
- if (rptinfo->haverptid)
- {
- rptidinfo = NULL;
-
- for (i = 0; i < rptinfo->nreports; i++)
- {
- if (rptinfo->rptsize[i].id == currstate->id)
- {
- rptidinfo = &rptinfo->rptsize[i];
- break;
- }
- }
-
- if (rptidinfo == NULL)
- {
- if (rptinfo->nreports == CONFIG_HID_MAXIDS)
- {
- return -EINVAL;
- }
-
- rptidinfo = &rptinfo->rptsize[rptinfo->nreports++];
- memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s));
- }
- }
-
- rptinfo->haverptid = true;
-
- rptidinfo->id = currstate->id;
- break;
-
- case USBHID_LOCAL_USAGE_PREFIX:
- if (nusage == CONFIG_HID_USAGEDEPTH)
- {
- return -E2BIG;
- }
-
- usage[nusage++] = data;
- break;
-
- case USBHID_LOCAL_USAGEMIN_PREFIX:
- usage_range.min = data;
- break;
-
- case USBHID_LOCAL_USAGEMAX_PREFIX:
- usage_range.max = data;
- break;
-
- case USBHID_MAIN_COLLECTION_PREFIX:
- if (collectionpath == NULL)
- {
- collectionpath = &rptinfo->collectionpaths[0];
- }
- else
- {
- struct hid_collectionpath_s *ParentCollectionPath = collectionpath;
-
- collectionpath = &rptinfo->collectionpaths[1];
-
- while (collectionpath->parent != NULL)
- {
- if (collectionpath == &rptinfo->collectionpaths[CONFIG_HID_MAXCOLLECTIONS - 1])
- {
- return -EINVAL;
- }
-
- collectionpath++;
- }
-
- collectionpath->parent = ParentCollectionPath;
- }
-
- collectionpath->type = data;
- collectionpath->usage.page = currstate->attrib.usage.page;
-
- if (nusage)
- {
- collectionpath->usage.usage = usage[0];
-
- for (i = 0; i < nusage; i++)
- usage[i] = usage[i + 1];
-
- nusage--;
- }
- else if (usage_range.min <= usage_range.max)
- {
- collectionpath->usage.usage = usage_range.min++;
- }
-
- break;
-
- case USBHID_MAIN_ENDCOLLECTION_PREFIX:
- if (collectionpath == NULL)
- {
- return -EINVAL;
- }
-
- collectionpath = collectionpath->parent;
- break;
-
- case USBHID_MAIN_INPUT_PREFIX:
- case USBHID_MAIN_OUTPUT_PREFIX:
- case USBHID_MAIN_FEATURE_PREFIX:
- {
- int itemno;
- for (itemno = 0; itemno < currstate->rptcount; itemno++)
- {
- struct hid_rptitem_s newitem;
- uint8_t tag;
-
- memcpy(&newitem.attrib, &currstate->attrib,
- sizeof(struct hid_rptitem_attributes_s));
-
- newitem.flags = data;
- newitem.collectionpath = collectionpath;
- newitem.id = currstate->id;
-
- if (nusage)
- {
- newitem.attrib.usage.usage = usage[0];
-
- for (i = 0; i < nusage; i++)
- {
- usage[i] = usage[i + 1];
- }
- nusage--;
- }
- else if (usage_range.min <= usage_range.max)
- {
- newitem.attrib.usage.usage = usage_range.min++;
- }
-
- tag = (item & ~USBHID_RPTITEM_SIZE_MASK);
- if (tag == USBHID_MAIN_INPUT_PREFIX)
- {
- newitem.type = HID_REPORT_ITEM_IN;
- }
- else if (tag == USBHID_MAIN_OUTPUT_PREFIX)
- {
- newitem.type = HID_REPORT_ITEM_OUT;
- }
- else
- {
- newitem.type = HID_REPORT_ITEM_FEATURE;
- }
-
- newitem.bitoffset = rptidinfo->size[newitem.type];
- rptidinfo->size[newitem.type] += currstate->attrib.bitsize;
-
- /* Accumulate the maximum report size */
-
- if (rptinfo->maxrptsize < newitem.bitoffset)
- {
- rptinfo->maxrptsize = newitem.bitoffset;
- }
-
- if ((data & USBHID_MAIN_CONSTANT) == 0 && filter(&newitem))
- {
- if (rptinfo->nitems == CONFIG_HID_MAXITEMS)
- {
- return -EINVAL;
- }
-
- memcpy(&rptinfo->items[rptinfo->nitems],
- &newitem, sizeof(struct hid_rptitem_s));
-
- rptinfo->nitems++;
- }
- }
- }
- break;
- }
-
- if ((item & USBHID_RPTITEM_TYPE_MASK) == USBHID_RPTITEM_TYPE_MAIN)
- {
- usage_range.min = 0;
- usage_range.max = 0;
- nusage = 0;
- }
- }
-
- if (!(rptinfo->nitems))
- {
- return -ENOENT;
- }
-
- return OK;
-}
-
-/****************************************************************************
- * Name: hid_getitem
- *
- * Description:
- * Extracts the given report item's value out of the given HID report and
- * places it into the value member of the report item's struct hid_rptitem_s
- * structure.
- *
- * When called on a report with an item that exists in that report, this
- * copies the report item's Value to it's previous element for easy
- * checking to see if an item's value has changed before processing a
- * report. If the given item does not exist in the report, the function
- * does not modify the report item's data.
- *
- * Input Parameters
- * report Buffer containing an IN or FEATURE report from an attached
- * device.
- * item Pointer to the report item of interest in a struct hid_rptinfo_s
- * item array.
- *
- * Returned Value:
- * Zero on success, otherwise a negated errno value.
- *
- ****************************************************************************/
-
-int hid_getitem(FAR const uint8_t *report, FAR struct hid_rptitem_s *item)
-{
- uint16_t remaining = item->attrib.bitsize;
- uint16_t offset = item->bitoffset;
- uint32_t mask = (1 << 0);
-
- if (item->id)
- {
- if (item->id != report[0])
- {
- return -ENOENT;
- }
-
- report++;
- }
-
- item->previous = item->value;
- item->value = 0;
-
- while (remaining--)
- {
- if (report[offset >> 3] & (1 << (offset & 7)))
- {
- item->value |= mask;
- }
-
- offset++;
- mask <<= 1;
- }
-
- return OK;
-}
-
-/****************************************************************************
- * Name: hid_putitem
- *
- * Desription:
- * Retrieves the given report item's value out of the Value member of the
- * report item's struct hid_rptitem_s structure and places it into the correct
- * position in the HID report buffer. The report buffer is assumed to have
- * the appropriate bits cleared before calling this function (i.e., the
- * buffer should be explicitly cleared before report values are added).
- *
- * When called, this copies the report item's Value element to it's
- * previous element for easy checking to see if an item's value has
- * changed before sending a report.
- *
- * If the device has multiple HID reports, the first byte in the report is
- * set to the report ID of the given item.
- *
- * Input Parameters:
- * report Buffer holding the current OUT or FEATURE report data.
- * item Pointer to the report item of interest in a struct hid_rptinfo_s
- * item array.
- *
- ****************************************************************************/
-
-#if 0 /* Not needed by host */
-void hid_putitem(FAR uint8_t *report, struct hid_rptitem_s *item)
-{
- uint16_t remaining = item->attrib.bitsize;
- uint16_t offset = item->bitoffset;
- uint32_t mask = (1 << 0);
-
- if (item->id)
- {
- report[0] = item->id;
- report++;
- }
-
- item->previous = item->value;
-
- while (remaining--)
- {
- if (item->value & (1 << (offset & 7)))
- {
- report[offset >> 3] |= mask;
- }
-
- offset++;
- mask <<= 1;
- }
-}
-#endif
-
-/****************************************************************************
- * Name: hid_reportsize
- *
- * Description:
- * Retrieves the size of a given HID report in bytes from it's Report ID.
- *
- * InputParameters:
- * rptinfo Pointer to a struct hid_rptinfo_s instance containing the parser output.
- * id Report ID of the report whose size is to be retrieved.
- * rpttype Type of the report whose size is to be determined, a valued from the
- * HID_ReportItemTypes_t enum.
- *
- * Size of the report in bytes, or 0 if the report does not exist.
- *
- ****************************************************************************/
-
-size_t hid_reportsize(FAR struct hid_rptinfo_s *rptinfo, uint8_t id, uint8_t rpttype)
-{
- int i;
- for (i = 0; i < CONFIG_HID_MAXIDS; i++)
- {
- size_t size = rptinfo->rptsize[i].size[rpttype];
-
- if (rptinfo->rptsize[i].id == id)
- {
- return ((size >> 3) + ((size & 0x07) ? 1 : 0));
- }
- }
-
- return 0;
-}
diff --git a/nuttx/drivers/usbhost/usbhost_enumerate.c b/nuttx/drivers/usbhost/usbhost_enumerate.c
deleted file mode 100644
index 26b93bf36..000000000
--- a/nuttx/drivers/usbhost/usbhost_enumerate.c
+++ /dev/null
@@ -1,518 +0,0 @@
-/*******************************************************************************
- * drivers/usbhost/usbhost_enumerate.c
- *
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
- * Authors: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- *******************************************************************************/
-
-/*******************************************************************************
- * Included Files
- *******************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <assert.h>
-#include <debug.h>
-
-#include <nuttx/arch.h>
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbhost.h>
-
-/*******************************************************************************
- * Definitions
- *******************************************************************************/
-
-/*******************************************************************************
- * Private Types
- *******************************************************************************/
-
-/*******************************************************************************
- * Private Function Prototypes
- *******************************************************************************/
-
-static inline uint16_t usbhost_getle16(const uint8_t *val);
-static void usbhost_putle16(uint8_t *dest, uint16_t val);
-
-static inline int usbhost_devdesc(const struct usb_devdesc_s *devdesc,
- struct usbhost_id_s *id);
-static inline int usbhost_configdesc(const uint8_t *configdesc, int desclen,
- struct usbhost_id_s *id);
-static inline int usbhost_classbind(FAR struct usbhost_driver_s *drvr,
- const uint8_t *configdesc, int desclen,
- struct usbhost_id_s *id, uint8_t funcaddr,
- FAR struct usbhost_class_s **class);
-
-/*******************************************************************************
- * Private Data
- *******************************************************************************/
-
-/*******************************************************************************
- * Public Data
- *******************************************************************************/
-
-/*******************************************************************************
- * Private Functions
- *******************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_getle16
- *
- * Description:
- * Get a (possibly unaligned) 16-bit little endian value.
- *
- *******************************************************************************/
-
-static inline uint16_t usbhost_getle16(const uint8_t *val)
-{
- return (uint16_t)val[1] << 8 | (uint16_t)val[0];
-}
-
-/****************************************************************************
- * Name: usbhost_putle16
- *
- * Description:
- * Put a (possibly unaligned) 16-bit little endian value.
- *
- *******************************************************************************/
-
-static void usbhost_putle16(uint8_t *dest, uint16_t val)
-{
- dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
- dest[1] = val >> 8;
-}
-
-/*******************************************************************************
- * Name: usbhost_devdesc
- *
- * Description:
- * A configuration descriptor has been obtained from the device. Find the
- * ID information for the class that supports this device.
- *
- *******************************************************************************/
-
-static inline int usbhost_devdesc(FAR const struct usb_devdesc_s *devdesc,
- FAR struct usbhost_id_s *id)
-{
- /* Clear the ID info */
-
- memset(id, 0, sizeof(struct usbhost_id_s));
-
- /* Pick off the class ID info */
-
- id->base = devdesc->classid;
- id->subclass = devdesc->subclass;
- id->proto = devdesc->protocol;
-
- /* Pick off the VID and PID as well (for vendor specfic devices) */
-
- id->vid = usbhost_getle16(devdesc->vendor);
- id->pid = usbhost_getle16(devdesc->product);
-
- uvdbg("class:%d subclass:%04x protocol:%04x vid:%d pid:%d\n",
- id->base, id->subclass, id->proto, id->vid, id->pid);
- return OK;
-}
-
-/*******************************************************************************
- * Name: usbhost_configdesc
- *
- * Description:
- * A configuration descriptor has been obtained from the device. Find the
- * ID information for the class that supports this device.
- *
- *******************************************************************************/
-
-static inline int usbhost_configdesc(const uint8_t *configdesc, int cfglen,
- struct usbhost_id_s *id)
-{
- struct usb_cfgdesc_s *cfgdesc;
- struct usb_ifdesc_s *ifdesc;
- int remaining;
-
- DEBUGASSERT(configdesc != NULL && cfglen >= USB_SIZEOF_CFGDESC);
-
- /* Verify that we were passed a configuration descriptor */
-
- cfgdesc = (struct usb_cfgdesc_s *)configdesc;
- uvdbg("cfg len:%d total len:%d\n", cfgdesc->len, cfglen);
-
- if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
- {
- return -EINVAL;
- }
-
- /* Skip to the next entry descriptor */
-
- configdesc += cfgdesc->len;
- remaining = cfglen - cfgdesc->len;
-
- /* Loop where there are more dscriptors to examine */
-
- memset(id, 0, sizeof(FAR struct usb_desc_s));
- while (remaining >= sizeof(struct usb_desc_s))
- {
- /* What is the next descriptor? Is it an interface descriptor? */
-
- ifdesc = (struct usb_ifdesc_s *)configdesc;
- if (ifdesc->type == USB_DESC_TYPE_INTERFACE)
- {
- /* Yes, extract the class information from the interface descriptor.
- * Typically these values are zero meaning that the "real" ID
- * information resides in the device descriptor.
- */
-
- DEBUGASSERT(remaining >= sizeof(struct usb_ifdesc_s));
- id->base = ifdesc->classid;
- id->subclass = ifdesc->subclass;
- id->proto = ifdesc->protocol;
- uvdbg("class:%d subclass:%d protocol:%d\n",
- id->base, id->subclass, id->proto);
- return OK;
- }
-
- /* Increment the address of the next descriptor */
-
- configdesc += ifdesc->len;
- remaining -= ifdesc->len;
- }
-
- return -ENOENT;
-}
-
-/*******************************************************************************
- * Name: usbhost_classbind
- *
- * Description:
- * A configuration descriptor has been obtained from the device. Try to
- * bind this configuration descriptor with a supported class.
- *
- *******************************************************************************/
-
-static inline int usbhost_classbind(FAR struct usbhost_driver_s *drvr,
- const uint8_t *configdesc, int desclen,
- struct usbhost_id_s *id, uint8_t funcaddr,
- FAR struct usbhost_class_s **class)
-{
- FAR struct usbhost_class_s *devclass;
- const struct usbhost_registry_s *reg;
- int ret = -EINVAL;
-
- /* Is there is a class implementation registered to support this device. */
-
- reg = usbhost_findclass(id);
- uvdbg("usbhost_findclass: %p\n", reg);
- if (reg)
- {
- /* Yes.. there is a class for this device. Get an instance of
- * its interface.
- */
-
- ret = -ENOMEM;
- devclass = CLASS_CREATE(reg, drvr, id);
- uvdbg("CLASS_CREATE: %p\n", devclass);
- if (devclass)
- {
- /* Then bind the newly instantiated class instance */
-
- ret = CLASS_CONNECT(devclass, configdesc, desclen, funcaddr);
- if (ret != OK)
- {
- /* On failures, call the class disconnect method which
- * should then free the allocated devclass instance.
- */
-
- udbg("CLASS_CONNECT failed: %d\n", ret);
- CLASS_DISCONNECTED(devclass);
- }
- else
- {
- *class = devclass;
- }
- }
- }
-
- uvdbg("Returning: %d\n", ret);
- return ret;
-}
-
-/*******************************************************************************
- * Public Functions
- *******************************************************************************/
-
-/*******************************************************************************
- * Name: usbhost_enumerate
- *
- * Description:
- * Enumerate the connected device. As part of this enumeration process,
- * the driver will (1) get the device's configuration descriptor, (2)
- * extract the class ID info from the configuration descriptor, (3) call
- * usbhost_findclass() to find the class that supports this device, (4)
- * call the create() method on the struct usbhost_registry_s interface
- * to get a class instance, and finally (5) call the configdesc() method
- * of the struct usbhost_class_s interface. After that, the class is in
- * charge of the sequence of operations.
- *
- * Input Parameters:
- * drvr - The USB host driver instance obtained as a parameter from the call to
- * the class create() method.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- * class - If the class driver for the device is successful located
- * and bound to the driver, the allocated class instance is returned into
- * this caller-provided memory location.
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * Assumptions:
- * - Only a single class bound to a single device is supported.
- * - Called from a single thread so no mutual exclusion is required.
- * - Never called from an interrupt handler.
- *
- *******************************************************************************/
-
-int usbhost_enumerate(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
- FAR struct usbhost_class_s **class)
-{
- struct usb_ctrlreq_s *ctrlreq;
- struct usbhost_id_s id;
- size_t maxlen;
- unsigned int cfglen;
- uint8_t maxpacketsize;
- uint8_t *buffer;
- int ret;
-
- DEBUGASSERT(drvr && class);
-
- /* Allocate descriptor buffers for use in this function. We will need two:
- * One for the request and one for the data buffer.
- */
-
- ret = DRVR_ALLOC(drvr, (FAR uint8_t **)&ctrlreq, &maxlen);
- if (ret != OK)
- {
- udbg("DRVR_ALLOC failed: %d\n", ret);
- return ret;
- }
-
- ret = DRVR_ALLOC(drvr, &buffer, &maxlen);
- if (ret != OK)
- {
- udbg("DRVR_ALLOC failed: %d\n", ret);
- goto errout;
- }
-
- /* Set max pkt size = 8 */
-
- DRVR_EP0CONFIGURE(drvr, 0, 8);
-
- /* Read first 8 bytes of the device descriptor */
-
- ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_GETDESCRIPTOR;
- usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8));
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, 8);
-
- ret = DRVR_CTRLIN(drvr, ctrlreq, buffer);
- if (ret != OK)
- {
- udbg("ERROR: GETDESCRIPTOR/DEVICE, DRVR_CTRLIN returned %d\n", ret);
- goto errout;
- }
-
- /* Extract the correct max packetsize from the device descriptor */
-
- maxpacketsize = ((struct usb_devdesc_s *)buffer)->mxpacketsize;
- uvdbg("maxpacksetsize: %d\n", maxpacketsize);
-
- /* And reconfigure EP0 */
-
- DRVR_EP0CONFIGURE(drvr, 0, maxpacketsize);
-
- /* Now read the full device descriptor */
-
- ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_GETDESCRIPTOR;
- usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_DEVICE << 8));
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, USB_SIZEOF_DEVDESC);
-
- ret = DRVR_CTRLIN(drvr, ctrlreq, buffer);
- if (ret != OK)
- {
- udbg("ERROR: GETDESCRIPTOR/DEVICE, DRVR_CTRLIN returned %d\n", ret);
- goto errout;
- }
-
- /* Get class identification information from the device descriptor. Most
- * devices set this to USB_CLASS_PER_INTERFACE (zero) and provide the
- * identification informatino in the interface descriptor(s). That allows
- * a device to support multiple, different classes.
- */
-
- (void)usbhost_devdesc((struct usb_devdesc_s *)buffer, &id);
-
- /* Set the USB device address to the value in the 'funcaddr' input */
-
- ctrlreq->type = USB_REQ_DIR_OUT|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_SETADDRESS;
- usbhost_putle16(ctrlreq->value, (uint16_t)funcaddr);
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, 0);
-
- ret = DRVR_CTRLOUT(drvr, ctrlreq, NULL);
- if (ret != OK)
- {
- udbg("ERROR: SETADDRESS DRVR_CTRLOUT returned %d\n", ret);
- goto errout;
- }
- usleep(2*1000);
-
- /* Modify control pipe with the provided USB device address */
-
- DRVR_EP0CONFIGURE(drvr, funcaddr, maxpacketsize);
-
- /* Get the configuration descriptor (only), index == 0. Should not be
- * hard-coded! More logic is needed in order to handle devices with
- * multiple configurations.
- */
-
- ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_GETDESCRIPTOR;
- usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8));
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, USB_SIZEOF_CFGDESC);
-
- ret = DRVR_CTRLIN(drvr, ctrlreq, buffer);
- if (ret != OK)
- {
- udbg("ERROR: GETDESCRIPTOR/CONFIG, DRVR_CTRLIN returned %d\n", ret);
- goto errout;
- }
-
- /* Extract the full size of the configuration data */
-
- cfglen = (unsigned int)usbhost_getle16(((struct usb_cfgdesc_s *)buffer)->totallen);
- uvdbg("sizeof config data: %d\n", cfglen);
-
- /* Get all of the configuration descriptor data, index == 0 (Should not be
- * hard-coded!)
- */
-
- ctrlreq->type = USB_REQ_DIR_IN|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_GETDESCRIPTOR;
- usbhost_putle16(ctrlreq->value, (USB_DESC_TYPE_CONFIG << 8));
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, cfglen);
-
- ret = DRVR_CTRLIN(drvr, ctrlreq, buffer);
- if (ret != OK)
- {
- udbg("ERROR: GETDESCRIPTOR/CONFIG, DRVR_CTRLIN returned %d\n", ret);
- goto errout;
- }
-
- /* Select device configuration 1 (Should not be hard-coded!) */
-
- ctrlreq->type = USB_REQ_DIR_OUT|USB_REQ_RECIPIENT_DEVICE;
- ctrlreq->req = USB_REQ_SETCONFIGURATION;
- usbhost_putle16(ctrlreq->value, 1);
- usbhost_putle16(ctrlreq->index, 0);
- usbhost_putle16(ctrlreq->len, 0);
-
- ret = DRVR_CTRLOUT(drvr, ctrlreq, NULL);
- if (ret != OK)
- {
- udbg("ERROR: SETCONFIGURATION, DRVR_CTRLOUT returned %d\n", ret);
- goto errout;
- }
-
- /* Free the descriptor buffer that we were using for the request buffer.
- * It is not needed further here but it may be needed by the class driver
- * during its connection operations.
- */
-
- DRVR_FREE(drvr, (uint8_t*)ctrlreq);
- ctrlreq = NULL;
-
- /* Was the class identification information provided in the device descriptor?
- * Or do we need to find it in the interface descriptor(s)?
- */
-
- if (id.base == USB_CLASS_PER_INTERFACE)
- {
- /* Get the class identification information for this device from the
- * interface descriptor(s). Hmmm.. More logic is need to handle the
- * case of multiple interface descriptors.
- */
-
- ret = usbhost_configdesc(buffer, cfglen, &id);
- if (ret != OK)
- {
- udbg("ERROR: usbhost_configdesc returned %d\n", ret);
- goto errout;
- }
- }
-
- /* Some devices may require some delay before initialization */
-
- usleep(100*1000);
-
- /* Parse the configuration descriptor and bind to the class instance for the
- * device. This needs to be the last thing done because the class driver
- * will begin configuring the device.
- */
-
- ret = usbhost_classbind(drvr, buffer, cfglen, &id, funcaddr, class);
- if (ret != OK)
- {
- udbg("ERROR: usbhost_classbind returned %d\n", ret);
- }
-
-errout:
- if (buffer)
- {
- DRVR_FREE(drvr, buffer);
- }
-
- if (ctrlreq)
- {
- DRVR_FREE(drvr, (uint8_t*)ctrlreq);
- }
- return ret;
-}
diff --git a/nuttx/drivers/usbhost/usbhost_findclass.c b/nuttx/drivers/usbhost/usbhost_findclass.c
deleted file mode 100644
index 3e38670cf..000000000
--- a/nuttx/drivers/usbhost/usbhost_findclass.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_findclass.c
- *
- * Copyright (C) 2010 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <debug.h>
-
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbhost.h>
-#include <arch/irq.h>
-
-#include "usbhost_registry.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_idmatch
- *
- * Description:
- * Check if the class ID matches what the host controller found.
- *
- * Input Parameters:
- * classid - ID info for the class under consideration.
- * devid - ID info reported by the device.
- *
- * Returned Values:
- * TRUE - the class will support this device.
- *
- ****************************************************************************/
-
-static bool usbhost_idmatch(const struct usbhost_id_s *classid,
- const struct usbhost_id_s *devid)
-{
- uvdbg("Compare to class:%d subclass:%d protocol:%d vid:%04x pid:%04x\n",
- classid->base, classid->subclass, classid->proto,
- classid->vid, classid->pid);
-
- /* The base class ID, subclass and protocol have to match up in any event */
-
- if (devid->base == classid->base &&
- devid->subclass == classid->subclass &&
- devid->proto == classid->proto)
- {
- /* If this is a vendor-specific class ID, then the VID and PID have to
- * match as well.
- */
-
- if (devid->base == USB_CLASS_VENDOR_SPEC)
- {
- /* Vendor specific... do the VID and PID also match? */
-
- if (devid->vid == classid->vid && devid->pid == classid->pid)
- {
- /* Yes.. then we have a match */
-
- return true;
- }
- }
- else
- {
- /* Not vendor specific? Then we have a match */
-
- return true;
- }
- }
-
- /* No match.. not supported */
-
- return false;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_findclass
- *
- * Description:
- * Find a USB host class implementation previously registered by
- * usbhost_registerclass(). On success, an instance of struct
- * usbhost_registry_s will be returned. That instance will contain all of
- * the information that will be needed to obtain and bind a struct
- * usbhost_class_s instance for the device.
- *
- * Input Parameters:
- * id - Identifies the USB device class that has connect to the USB host.
- *
- * Returned Values:
- * On success this function will return a non-NULL instance of struct
- * usbhost_registry_s. NULL will be returned on failure. This function
- * can only fail if (1) id is NULL, or (2) no USB host class is registered
- * that matches the device class ID.
- *
- ****************************************************************************/
-
-const struct usbhost_registry_s *usbhost_findclass(const struct usbhost_id_s *id)
-{
- struct usbhost_registry_s *class;
- irqstate_t flags;
- int ndx;
-
- DEBUGASSERT(id);
- uvdbg("Looking for class:%d subclass:%d protocol:%d vid:%04x pid:%04x\n",
- id->base, id->subclass, id->proto, id->vid, id->pid);
-
- /* g_classregistry is a singly-linkedlist of class ID information added by
- * calls to usbhost_registerclass(). Since this list is accessed from USB
- * host controller interrupt handling logic, accesses to this list must be
- * protected by disabling interrupts.
- */
-
- flags = irqsave();
-
- /* Examine each register class in the linked list */
-
- for (class = g_classregistry; class; class = class->flink)
- {
- /* If the registered class supports more than one ID, subclass, or
- * protocol, then try each.
- */
-
- uvdbg("Checking class:%p nids:%d\n", class, class->nids);
- for (ndx = 0; ndx < class->nids; ndx++)
- {
- /* Did we find a matching ID? */
-
- if (usbhost_idmatch(&class->id[ndx], id))
- {
- /* Yes.. restore interrupts and return the class info */
-
- irqrestore(flags);
- return class;
- }
- }
- }
-
- /* Not found... restore interrupts and return NULL */
-
- irqrestore(flags);
- return NULL;
-}
-
diff --git a/nuttx/drivers/usbhost/usbhost_hidkbd.c b/nuttx/drivers/usbhost/usbhost_hidkbd.c
deleted file mode 100644
index d6a9ceda3..000000000
--- a/nuttx/drivers/usbhost/usbhost_hidkbd.c
+++ /dev/null
@@ -1,2353 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_hidkbd.c
- *
- * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <poll.h>
-#include <semaphore.h>
-#include <time.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/arch.h>
-#include <nuttx/wqueue.h>
-
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbhost.h>
-#include <nuttx/usb/hid.h>
-
-#ifdef CONFIG_HIDKBD_ENCODED
-# include <nuttx/streams.h>
-# include <nuttx/input/kbd_codec.h>
-#endif
-
-/* Don't compile if prerequisites are not met */
-
-#if defined(CONFIG_USBHOST) && !defined(CONFIG_USBHOST_INT_DISABLE) && CONFIG_NFILE_DESCRIPTORS > 0
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-/* Configuration ************************************************************/
-/* This determines how often the USB keyboard will be polled in units of
- * of microseconds. The default is 100MS.
- */
-
-#ifndef CONFIG_HIDKBD_POLLUSEC
-# define CONFIG_HIDKBD_POLLUSEC (100*1000)
-#endif
-
-/* Worker thread is needed, unfortunately, to handle some cornercase failure
- * conditions. This is kind of wasteful and begs for a re-design.
- */
-
-#ifndef CONFIG_SCHED_WORKQUEUE
-# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
-#endif
-
-/* Signals must not be disabled as they are needed by usleep. Need to have
- * CONFIG_DISABLE_SIGNALS=n
- */
-
-#ifdef CONFIG_DISABLE_SIGNALS
-# warning "Signal support is required (CONFIG_DISABLE_SIGNALS)"
-#endif
-
-/* 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
-
-#ifndef CONFIG_HIDKBD_BUFSIZE
-# define CONFIG_HIDKBD_BUFSIZE 64
-#endif
-
-#ifndef CONFIG_HIDKBD_NPOLLWAITERS
-# define CONFIG_HIDKBD_NPOLLWAITERS 2
-#endif
-
-/* The default is to support scancode mapping for the standard 104 key
- * keyboard. Setting CONFIG_HIDKBD_RAWSCANCODES will disable all scancode
- * mapping; Setting CONFIG_HIDKBD_ALLSCANCODES will enable mapping of all
- * scancodes;
- */
-
-#ifndef CONFIG_HIDKBD_RAWSCANCODES
-# ifdef CONFIG_HIDKBD_ALLSCANCODES
-# define USBHID_NUMSCANCODES (USBHID_KBDUSE_MAX+1)
-# else
-# define USBHID_NUMSCANCODES 104
-# endif
-#endif
-
-/* We cant support encoding of special characters of unless the Keyboard
- * CODEC is enabled.
- */
-
-#ifndef CONFIG_LIB_KBDCODEC
-# undef CONFIG_HIDKBD_ENCODED
-#endif
-
-/* If we are using raw scancodes, then we cannot support encoding of
- * special characters either.
- */
-
-#ifdef CONFIG_HIDKBD_RAWSCANCODES
-# undef CONFIG_HIDKBD_ENCODED
-#endif
-
-/* Driver support ***********************************************************/
-/* This format is used to construct the /dev/kbd[n] device driver path. It
- * defined here so that it will be used consistently in all places.
- */
-
-#define DEV_FORMAT "/dev/kbd%c"
-#define DEV_NAMELEN 11
-
-/* Used in usbhost_cfgdesc() */
-
-#define USBHOST_IFFOUND 0x01 /* Required I/F descriptor found */
-#define USBHOST_EPINFOUND 0x02 /* Required interrupt IN EP descriptor found */
-#define USBHOST_EPOUTFOUND 0x04 /* Optional interrupt OUT EP descriptor found */
-#define USBHOST_RQDFOUND (USBHOST_IFFOUND|USBHOST_EPINFOUND)
-#define USBHOST_ALLFOUND (USBHOST_RQDFOUND|USBHOST_EPOUTFOUND)
-
-#define USBHOST_MAX_CREFS 0x7fff
-
-/* Debug ********************************************************************/
-/* Both CONFIG_DEBUG_INPUT and CONFIG_DEBUG_USB could apply to this file.
- * We assume here that CONFIG_DEBUG_INPUT might be enabled separately, but
- * CONFIG_DEBUG_USB implies both.
- */
-
-#ifndef CONFIG_DEBUG_INPUT
-# undef idbg
-# define idbg udbg
-# undef illdbg
-# define illdbg ulldbg
-# undef ivdbg
-# define ivdbg uvdbg
-# undef illvdbg
-# define illvdbg ullvdbg
-#endif
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This structure contains the internal, private state of the USB host
- * keyboard storage class.
- */
-
-struct usbhost_state_s
-{
- /* This is the externally visible portion of the state */
-
- struct usbhost_class_s class;
-
- /* This is an instance of the USB host driver bound to this class instance */
-
- struct usbhost_driver_s *drvr;
-
- /* The remainder of the fields are provide o the keyboard class driver */
-
- 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 */
- volatile bool open; /* TRUE: The keyboard device is open */
- volatile bool waiting; /* TRUE: waiting for keyboard data */
- uint8_t ifno; /* Interface number */
- int16_t crefs; /* Reference count on the driver instance */
- sem_t exclsem; /* Used to maintain mutual exclusive access */
- sem_t waitsem; /* Used to wait for keyboard data */
- 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 */
- struct work_s work; /* For cornercase error handling by the worker thread */
-
- /* Endpoints:
- * EP0 (Control):
- * - Receiving and responding to requests for USB control and class data.
- * - IN data when polled by the HID class driver (Get_Report)
- * - OUT data from the host.
- * EP Interrupt IN:
- * - Receiving asynchronous (unrequested) IN data from the device.
- * EP Interrrupt OUT (optional):
- * - Transmitting low latency OUT data to the device.
- * - If not present, EP0 used.
- */
-
- usbhost_ep_t epin; /* Interrupt IN endpoint */
- usbhost_ep_t epout; /* Optional interrupt OUT endpoint */
-
- /* The following is a list if poll structures of threads waiting for
- * driver events. The 'struct pollfd' reference for each open is also
- * retained in the f_priv field of the 'struct file'.
- */
-
-#ifndef CONFIG_DISABLE_POLL
- struct pollfd *fds[CONFIG_HIDKBD_NPOLLWAITERS];
-#endif
-
- /* Buffer used to collect and buffer incoming keyboard characters */
-
- volatile uint16_t headndx; /* Buffer head index */
- volatile uint16_t tailndx; /* Buffer tail index */
- uint8_t kbdbuffer[CONFIG_HIDKBD_BUFSIZE];
-};
-
-/* This type is used for encoding special characters */
-
-#ifdef CONFIG_HIDKBD_ENCODED
-struct usbhost_outstream_s
-{
- struct lib_outstream_s stream;
- FAR struct usbhost_state_s *priv;
-};
-#endif
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/* Semaphores */
-
-static void usbhost_takesem(sem_t *sem);
-#define usbhost_givesem(s) sem_post(s);
-
-/* Polling support */
-
-#ifndef CONFIG_DISABLE_POLL
-static void usbhost_pollnotify(FAR struct usbhost_state_s *dev);
-#else
-# define usbhost_pollnotify(dev)
-#endif
-
-/* Memory allocation services */
-
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void);
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class);
-
-/* Device name management */
-
-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);
-
-/* Keyboard polling thread */
-
-static void usbhost_destroy(FAR void *arg);
-static void usbhost_putbuffer(FAR struct usbhost_state_s *priv, uint8_t keycode);
-#ifdef CONFIG_HIDKBD_ENCODED
-static void usbhost_putstream(FAR struct lib_outstream_s *this, int ch);
-#endif
-static inline uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier);
-#ifdef CONFIG_HIDKBD_ENCODED
-static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv,
- uint8_t scancode, uint8_t modifier);
-#endif
-static int usbhost_kbdpoll(int argc, char *argv[]);
-
-/* Helpers for usbhost_connect() */
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static inline int usbhost_devinit(FAR struct usbhost_state_s *priv);
-
-/* (Little Endian) Data helpers */
-
-static inline uint16_t usbhost_getle16(const uint8_t *val);
-static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
-static inline uint32_t usbhost_getle32(const uint8_t *val);
-#if 0 /* Not used */
-static void usbhost_putle32(uint8_t *dest, uint32_t val);
-#endif
-
-/* 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);
-
-/* struct usbhost_registry_s methods */
-
-static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id);
-
-/* struct usbhost_class_s methods */
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static int usbhost_disconnected(FAR struct usbhost_class_s *class);
-
-/* Driver methods. We export the keyboard as a standard character driver */
-
-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 *filep,
- FAR const char *buffer, size_t len);
-#ifndef CONFIG_DISABLE_POLL
-static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
- bool setup);
-#endif
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* This structure provides the registry entry ID informatino that will be
- * used to associate the USB host keyboard class driver to a connected USB
- * device.
- */
-
-static const const struct usbhost_id_s g_id =
-{
- USB_CLASS_HID, /* base */
- USBHID_SUBCLASS_BOOTIF, /* subclass */
- USBHID_PROTOCOL_KEYBOARD, /* proto */
- 0, /* vid */
- 0 /* pid */
-};
-
-/* This is the USB host storage class's registry entry */
-
-static struct usbhost_registry_s g_skeleton =
-{
- NULL, /* flink */
- usbhost_create, /* create */
- 1, /* nids */
- &g_id /* id[] */
-};
-
-static const struct file_operations usbhost_fops =
-{
- usbhost_open, /* open */
- usbhost_close, /* close */
- usbhost_read, /* read */
- usbhost_write, /* write */
- 0, /* seek */
- 0 /* ioctl */
-#ifndef CONFIG_DISABLE_POLL
- , usbhost_poll /* poll */
-#endif
-};
-
-/* 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 */
-
-/* The following tables map keyboard scan codes to printable ASIC
- * characters. There is no support here for function keys or cursor
- * controls.
- */
-
-#ifndef CONFIG_HIDKBD_RAWSCANCODES
-#ifdef CONFIG_HIDKBD_ENCODED
-
-/* The first and last scancode values with encode-able values */
-
-#define FIRST_ENCODING USBHID_KBDUSE_ENTER /* 0x28 Keyboard Return (ENTER) */
-#ifndef CONFIG_HIDKBD_ALLSCANCODES
-# define LAST_ENCODING USBHID_KBDUSE_POWER /* 0x66 Keyboard Power */
-#else
-# define LAST_ENCODING USBHID_KBDUSE_KPDHEXADECIMAL /* 0xdd Keypad Hexadecimal */
-#endif
-
-#define USBHID_NUMENCODINGS (LAST_ENCODING - FIRST_ENCODING + 1)
-
-static const uint8_t encoding[USBHID_NUMENCODINGS] =
-{
- /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */
-
- KEYCODE_ENTER, 0, KEYCODE_FWDDEL, KEYCODE_BACKDEL, 0, 0, 0, 0,
-
- /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
-
- 0, KEYCODE_CAPSLOCK, KEYCODE_F1, KEYCODE_F2, KEYCODE_F3, KEYCODE_F4, KEYCODE_F5, KEYCODE_F6,
-
- /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
-
- KEYCODE_F7, KEYCODE_F8, KEYCODE_F9, KEYCODE_F10, KEYCODE_F11, KEYCODE_F12, KEYCODE_PRTSCRN, KEYCODE_SCROLLLOCK,
-
- /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
-
- KEYCODE_PAUSE, KEYCODE_INSERT, KEYCODE_HOME, KEYCODE_PAGEUP, KEYCODE_FWDDEL, KEYCODE_END, KEYCODE_PAGEDOWN, KEYCODE_RIGHT,
-
- /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
-
- KEYCODE_LEFT, KEYCODE_DOWN, KEYCODE_UP, KEYCODE_NUMLOCK, 0, 0, 0, 0,
-
- /* 0x58-0x5f: Enter,1-7 */
-
- KEYCODE_ENTER, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0x60-0x66: 8-9,0,.,Non-US \,Application,Power */
-
- 0, 0, 0, 0, 0, 0, KEYCODE_POWER,
-
-#ifdef CONFIG_HIDKBD_ALLSCANCODES
-
- 0, /* 0x67 = */
-
- /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
-
- KEYCODE_F13, KEYCODE_F14, KEYCODE_F15, KEYCODE_F16, KEYCODE_F17, KEYCODE_F18, KEYCODE_F19, KEYCODE_F20,
-
- /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
-
- KEYCODE_F21, KEYCODE_F22, KEYCODE_F23, KEYCODE_F24, KEYCODE_EXECUTE, KEYCODE_HELP, KEYCODE_MENU, KEYCODE_SELECT,
-
- /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
-
- KEYCODE_STOP, KEYCODE_AGAIN, KEYCODE_UNDO, KEYCODE_CUT, KEYCODE_COPY, KEYCODE_PASTE, KEYCODE_FIND, KEYCODE_MUTE,
-
- /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
-
- KEYCODE_VOLUP, KEYCODE_VOLDOWN, KEYCODE_LCAPSLOCK, KEYCODE_LNUMLOCK, KEYCODE_LSCROLLLOCK, 0, 0, 0,
-
- /* 0x88-0x8f: International 2-9 */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0x90-0x97: LAN 1-8 */
-
- KEYCODE_LANG1, KEYCODE_LANG2, KEYCODE_LANG3, KEYCODE_LANG4, KEYCODE_LANG5, KEYCODE_LANG6, KEYCODE_LANG7, KEYCODE_LANG8,
-
- /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
-
- 0, 0, KEYCODE_SYSREQ, KEYCODE_CANCEL, KEYCODE_CLEAR, 0, KEYCODE_ENTER, 0,
-
- /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0xa8-0xaf: (reserved) */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0xb8-0xbf: {,},tab,backspace,A-D */
-
- 0, 0, 0, KEYCODE_BACKDEL, 0, 0, 0, 0,
-
- /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
-
- 0, 0, 0, 0, 0, 0, 0, 0,
-
- /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
-
- KEYCODE_MEMSTORE, KEYCODE_MEMRECALL, KEYCODE_MEMCLEAR, KEYCODE_MEMADD, KEYCODE_MEMSUB, KEYCODE_MEMMUL, KEYCODE_MEMDIV, KEYCODE_NEGATE,
-
- /* 0xd8-0xdd: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
-
- KEYCODE_CLEAR, KEYCODE_CLEARENTRY, KEYCODE_BINARY, KEYCODE_OCTAL, KEYCODE_DECIMAL, KEYCODE_HEXADECIMAL
-#endif
-};
-
-#endif
-
-static const uint8_t ucmap[USBHID_NUMSCANCODES] =
-{
- 0, 0, 0, 0, 'A', 'B', 'C', 'D', /* 0x00-0x07: Reserved, errors, A-D */
- 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 0x08-0x0f: E-L */
- 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 0x10-0x17: M-T */
- 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', /* 0x18-0x1f: U-Z,!,@ */
- '#', '$', '%', '^', '&', '*', '(', ')', /* 0x20-0x27: #,$,%,^,&,*,(,) */
- '\n', '\033', '\177', 0, ' ', '_', '+', '{', /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */
- '}', '|', 0, ':', '"', '~', '<', '>', /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */
- '?', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
- 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
- '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */
- '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
-#ifdef CONFIG_HIDKBD_ALLSCANCODES
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
- 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
- 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
- 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
- '{', '}', '\t', \177, 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
- 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
- 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
-#endif
-};
-
-static const uint8_t lcmap[USBHID_NUMSCANCODES] =
-{
- 0, 0, 0, 0, 'a', 'b', 'c', 'd', /* 0x00-0x07: Reserved, errors, a-d */
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', /* 0x08-0x0f: e-l */
- 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 0x10-0x17: m-t */
- 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', /* 0x18-0x1f: u-z,1-2 */
- '3', '4', '5', '6', '7', '8', '9', '0', /* 0x20-0x27: 3-9,0 */
- '\n', '\033', '\177', '\t', ' ', '-', '=', '[', /* 0x28-0x2f: Enter,escape,del,tab,space,-,=,[ */
- ']', '\\', '\234', ';', '\'', '`', ',', '.', /* 0x30-0x37: ],\,Non-US pound,;,',grave accent,,,. */
- '/', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
- 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
- '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */
- '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
-#ifdef CONFIG_HIDKBD_ALLSCANCODES
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
- 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
- 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
- 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
- '{', '}', '\t', '\177', 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
- 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
- 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
- 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
-#endif
-};
-#endif /* CONFIG_HIDKBD_RAWSCANCODES */
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_takesem
- *
- * Description:
- * This is just a wrapper to handle the annoying behavior of semaphore
- * waits that return due to the receipt of a signal.
- *
- ****************************************************************************/
-
-static void usbhost_takesem(sem_t *sem)
-{
- /* Take the semaphore (perhaps waiting) */
-
- while (sem_wait(sem) != 0)
- {
- /* The only case that an error should occr here is if the wait was
- * awakened by a signal.
- */
-
- ASSERT(errno == EINTR);
- }
-}
-
-/****************************************************************************
- * Name: usbhost_pollnotify
- ****************************************************************************/
-
-#ifndef CONFIG_DISABLE_POLL
-static void usbhost_pollnotify(FAR struct usbhost_state_s *priv)
-{
- int i;
-
- for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++)
- {
- struct pollfd *fds = priv->fds[i];
- if (fds)
- {
- fds->revents |= (fds->events & POLLIN);
- if (fds->revents != 0)
- {
- uvdbg("Report events: %02x\n", fds->revents);
- sem_post(fds->sem);
- }
- }
- }
-}
-#endif
-
-/****************************************************************************
- * Name: usbhost_allocclass
- *
- * Description:
- * This is really part of the logic that implements the create() method
- * of struct usbhost_registry_s. This function allocates memory for one
- * new class instance.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s. NULL is returned on failure; this function will
- * will fail only if there are insufficient resources to create another
- * USB host class instance.
- *
- ****************************************************************************/
-
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
-{
- FAR struct usbhost_state_s *priv;
-
- DEBUGASSERT(!up_interrupt_context());
- priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s));
- uvdbg("Allocated: %p\n", priv);;
- return priv;
-}
-
-/****************************************************************************
- * Name: usbhost_freeclass
- *
- * Description:
- * Free a class instance previously allocated by usbhost_allocclass().
- *
- * Input Parameters:
- * class - A reference to the class instance to be freed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
-{
- DEBUGASSERT(class != NULL);
-
- /* Free the class instance. */
-
- uvdbg("Freeing: %p\n", class);;
- kfree(class);
-}
-
-/****************************************************************************
- * Name: Device name management
- *
- * Description:
- * Some tiny functions to coordinate management of device names.
- *
- ****************************************************************************/
-
-static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
-{
- irqstate_t flags;
- int devno;
-
- flags = irqsave();
- for (devno = 0; devno < 26; devno++)
- {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0)
- {
- g_devinuse |= bitno;
- priv->devchar = 'a' + devno;
- irqrestore(flags);
- return OK;
- }
- }
-
- irqrestore(flags);
- return -EMFILE;
-}
-
-static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
-{
- int devno = 'a' - priv->devchar;
-
- if (devno >= 0 && devno < 26)
- {
- irqstate_t flags = irqsave();
- g_devinuse &= ~(1 << devno);
- irqrestore(flags);
- }
-}
-
-static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
-{
- (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
-}
-
-/****************************************************************************
- * Name: usbhost_destroy
- *
- * Description:
- * The USB device has been disconnected and the refernce count on the USB
- * host class instance has gone to 1.. Time to destroy the USB host class
- * instance.
- *
- * Input Parameters:
- * arg - A reference to the class instance to be destroyed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_destroy(FAR void *arg)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
- char devname[DEV_NAMELEN];
-
- DEBUGASSERT(priv != NULL);
- uvdbg("crefs: %d\n", priv->crefs);
-
- /* Unregister the driver */
-
- uvdbg("Unregister driver\n");
- usbhost_mkdevname(priv, devname);
- (void)unregister_driver(devname);
-
- /* Release the device name used by this connection */
-
- usbhost_freedevno(priv);
-
- /* Free the interrupt endpoints */
-
- if (priv->epin)
- {
- DRVR_EPFREE(priv->drvr, priv->epin);
- }
-
- if (priv->epout)
- {
- DRVR_EPFREE(priv->drvr, priv->epout);
- }
-
- /* Free any transfer buffers */
-
- usbhost_tdfree(priv);
-
- /* Destroy the semaphores */
-
- sem_destroy(&priv->exclsem);
- sem_destroy(&priv->waitsem);
-
- /* Disconnect the USB host device */
-
- DRVR_DISCONNECT(priv->drvr);
-
- /* And free the class instance. Hmmm.. this may execute on the worker
- * thread and the work structure is part of what is getting freed. That
- * should be okay because once the work contained is removed from the
- * queue, it should not longer be accessed by the worker thread.
- */
-
- usbhost_freeclass(priv);
-}
-
-/****************************************************************************
- * Name: usbhost_putbuffer
- *
- * Description:
- * Add one character to the user buffer.
- *
- * Input Parameters:
- * priv - Driver internal state
- * keycode - The value to add to the user buffer
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putbuffer(FAR struct usbhost_state_s *priv,
- uint8_t keycode)
-{
- register unsigned int head;
- register unsigned int tail;
-
- /* Copy the next keyboard character into the user buffer. */
-
- head = priv->headndx;
- priv->kbdbuffer[head] = keycode;
-
- /* Increment the head index */
-
- if (++head >= CONFIG_HIDKBD_BUFSIZE)
- {
- head = 0;
- }
-
- /* If the buffer is full, then increment the tail index to make space. Is
- * it better to lose old keystrokes or new?
- */
-
- tail = priv->tailndx;
- if (tail == head)
- {
- if (++tail >= CONFIG_HIDKBD_BUFSIZE)
- {
- tail = 0;
- }
-
- /* Save the updated tail index */
-
- priv->tailndx = tail;
- }
-
- /* Save the updated head index */
-
- priv->headndx = head;
-}
-
-/****************************************************************************
- * Name: usbhost_putstream
- *
- * Description:
- * A wrapper for usbhost_putc that is compatibile with the lib_outstream_s
- * putc methos.
- *
- * Input Parameters:
- * stream - The struct lib_outstream_s reference
- * ch - The character to add to the user buffer
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_HIDKBD_ENCODED
-static void usbhost_putstream(FAR struct lib_outstream_s *stream, int ch)
-{
- FAR struct usbhost_outstream_s *privstream = (FAR struct usbhost_outstream_s *)stream;
-
- DEBUGASSERT(privstream && privstream->priv);
- usbhost_putbuffer(privstream->priv, (uint8_t)ch);
- stream->nput++;
-}
-#endif
-
-/****************************************************************************
- * Name: usbhost_mapscancode
- *
- * Description:
- * Map a keyboard scancode to a printable ASCII character. There is no
- * support here for function keys or cursor controls in this version of
- * the driver.
- *
- * Input Parameters:
- * scancode - Scan code to be mapped.
- * modifier - Ctrl,Alt,Shift,GUI modifier bits
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier)
-{
-#ifndef CONFIG_HIDKBD_RAWSCANCODES
- /* Range check */
-
- if (scancode >= USBHID_NUMSCANCODES)
- {
- return 0;
- }
-
- /* Is either shift key pressed? */
-
- if ((modifier & (USBHID_MODIFER_LSHIFT|USBHID_MODIFER_RSHIFT)) != 0)
- {
- return ucmap[scancode];
- }
- else
- {
- return lcmap[scancode];
- }
-#else
- return scancode;
-#endif
-}
-
-/****************************************************************************
- * Name: usbhost_encodescancode
- *
- * Description:
- * Check if the key has a special function encoding and, if it does, add
- * the encoded value to the user buffer.
- *
- * Input Parameters:
- * priv - Driver internal state
- * scancode - Scan code to be mapped.
- * modifier - Ctrl,Alt,Shift,GUI modifier bits
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_HIDKBD_ENCODED
-static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv,
- uint8_t scancode, uint8_t modifier)
-{
- uint8_t encoded;
-
- /* Check if the raw scancode is in a valid range */
-
- if (scancode >= FIRST_ENCODING && scancode <= LAST_ENCODING)
- {
- /* Yes the value is within range */
-
- encoded = encoding[scancode - FIRST_ENCODING];
- ivdbg(" scancode: %02x modifier: %02x encoded: %d\n",
- scancode, modifier, encoded);
-
- if (encoded)
- {
- struct usbhost_outstream_s usbstream;
-
- /* And it does correspond to a special function key */
-
- usbstream.stream.put = usbhost_putstream;
- usbstream.stream.nput = 0;
- usbstream.priv = priv;
-
- /* Add the special function value to the user buffer */
-
- kbd_specpress((enum kbd_keycode_e)encoded,
- (FAR struct lib_outstream_s *)&usbstream);
- }
- }
-}
-#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;
-#ifndef CONFIG_HIDKBD_NODEBOUNCE
- uint8_t lastkey[6] = {0, 0, 0, 0, 0, 0};
-#endif
-#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
- unsigned int npolls = 0;
-#endif
- unsigned int nerrors = 0;
- bool empty = true;
- bool newstate;
- 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 10100001
- * bRequest GET_REPORT (0x01)
- * wValue Report Type and Report 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_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
- ctrlreq->req = USBHID_REQUEST_GETREPORT;
-
- usbhost_putle16(ctrlreq->value, (USBHID_REPORTTYPE_INPUT << 8));
- usbhost_putle16(ctrlreq->index, priv->ifno);
- usbhost_putle16(ctrlreq->len, sizeof(struct usbhid_kbdreport_s));
-
- /* Send HID report request */
-
- ret = DRVR_CTRLIN(priv->drvr, ctrlreq, priv->tbuffer);
- usbhost_givesem(&priv->exclsem);
-
- /* Check for errors -- Bail if an excessive number of errors
- * are encountered.
- */
-
- if (ret != OK)
- {
- nerrors++;
- udbg("ERROR: GETREPORT/INPUT, DRVR_CTRLIN returned: %d/%d\n",
- ret, nerrors);
-
- if (nerrors > 200)
- {
- udbg("Too many errors... aborting: %d\n", nerrors);
- break;
- }
- }
-
- /* The report was received correctly. But ignore the keystrokes if no
- * task has opened the driver.
- */
-
- else if (priv->open)
- {
- struct usbhid_kbdreport_s *rpt = (struct usbhid_kbdreport_s *)priv->tbuffer;
- uint8_t keycode;
- int i;
-
- /* Add the newly received keystrokes to our internal buffer */
-
- usbhost_takesem(&priv->exclsem);
- for (i = 0; i < 6; i++)
- {
- /* Is this key pressed? But not pressed last time?
- * HID spec: "The order of keycodes in array fields has no
- * significance. Order determination is done by the host
- * software comparing the contents of the previous report to
- * the current report. If two or more keys are reported in
- * one report, their order is indeterminate. Keyboards may
- * buffer events that would have otherwise resulted in
- * multiple event in a single report.
- *
- * "'Repeat Rate' and 'Delay Before First Repeat' are
- * implemented by the host and not in the keyboard (this
- * means the BIOS in legacy mode). The host may use the
- * device report rate and the number of reports to determine
- * how long a key is being held down. Alternatively, the host
- * may use its own clock or the idle request for the timing
- * of these features."
- */
-
- if (rpt->key[i] != USBHID_KBDUSE_NONE
-#ifndef CONFIG_HIDKBD_NODEBOUNCE
- && rpt->key[i] != lastkey[i]
-#endif
- )
- {
- /* Yes.. Add it to the buffer. */
-
- /* Map the keyboard scancode to a printable ASCII
- * character. There is no support here for function keys
- * or cursor controls in this version of the driver.
- */
-
- keycode = usbhost_mapscancode(rpt->key[i], rpt->modifier);
- ivdbg("Key %d: %02x keycode:%c modifier: %02x\n",
- i, rpt->key[i], keycode ? keycode : ' ', rpt->modifier);
-
- /* Zero at this point means that the key does not map to a
- * printable character.
- */
-
- if (keycode != 0)
- {
- /* Handle control characters. Zero after this means
- * a valid, NUL character.
- */
-
- if ((rpt->modifier & (USBHID_MODIFER_LCTRL|USBHID_MODIFER_RCTRL)) != 0)
- {
- keycode &= 0x1f;
- }
-
- /* Copy the next keyboard character into the user
- * buffer.
- */
-
- usbhost_putbuffer(priv, keycode);
- }
-
- /* The zero might, however, map to a special keyboard action (such as a
- * cursor movement or function key). Attempt to encode the special key.
- */
-
-#ifdef CONFIG_HIDKBD_ENCODED
- else
- {
- usbhost_encodescancode(priv, rpt->key[i], rpt->modifier);
- }
-#endif
- }
-
- /* Save the scancode (or lack thereof) for key debouncing on
- * next keyboard report.
- */
-
-#ifndef CONFIG_HIDKBD_NODEBOUNCE
- lastkey[i] = rpt->key[i];
-#endif
- }
-
- /* Is there data available? */
-
- newstate = (priv->headndx == priv->tailndx);
- if (!newstate)
- {
- /* Yes.. Is there a thread waiting for keyboard data now? */
-
- if (priv->waiting)
- {
- /* Yes.. wake it up */
-
- usbhost_givesem(&priv->waitsem);
- priv->waiting = false;
- }
-
- /* Did we just transition from no data available to data
- * available? If so, wake up any threads waiting for the
- * POLLIN event.
- */
-
- if (empty)
- {
- usbhost_pollnotify(priv);
- }
- }
-
- empty = newstate;
- usbhost_givesem(&priv->exclsem);
- }
-
- /* If USB debug is on, then provide some periodic indication that
- * polling is still happening.
- */
-
-#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
- 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:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * priv - The USB host class instance.
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * Assumptions:
- * This function will *not* be called from an interrupt handler.
- *
- ****************************************************************************/
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usb_cfgdesc_s *cfgdesc;
- FAR struct usb_desc_s *desc;
- FAR struct usbhost_epdesc_s epindesc;
- FAR struct usbhost_epdesc_s epoutdesc;
- int remaining;
- uint8_t found = 0;
- bool done = false;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Verify that we were passed a configuration descriptor */
-
- cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
- if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
- {
- return -EINVAL;
- }
-
- /* Get the total length of the configuration descriptor (little endian).
- * It might be a good check to get the number of interfaces here too.
- */
-
- remaining = (int)usbhost_getle16(cfgdesc->totallen);
-
- /* Skip to the next entry descriptor */
-
- configdesc += cfgdesc->len;
- remaining -= cfgdesc->len;
-
- /* Loop where there are more dscriptors to examine */
-
- while (remaining >= sizeof(struct usb_desc_s) && !done)
- {
- /* What is the next descriptor? */
-
- desc = (FAR struct usb_desc_s *)configdesc;
- switch (desc->type)
- {
- /* Interface descriptor. We really should get the number of endpoints
- * from this descriptor too.
- */
-
- case USB_DESC_TYPE_INTERFACE:
- {
- FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc;
-
- uvdbg("Interface descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
-
- /* Did we already find what we needed from a preceding interface? */
-
- if ((found & USBHOST_RQDFOUND) == USBHOST_RQDFOUND)
- {
- /* Yes.. then break out of the loop and use the preceding
- * interface.
- */
-
- done = true;
- }
- else
- {
- /* Otherwise, save the interface number and discard any
- * endpoints previously found
- */
-
- priv->ifno = ifdesc->ifno;
- found = USBHOST_IFFOUND;
- }
- }
- break;
-
- /* HID descriptor */
-
- case USBHID_DESCTYPE_HID:
- uvdbg("HID descriptor\n");
- break;
-
- /* Endpoint descriptor. We expect one or two interrupt endpoints,
- * a required IN endpoint and an optional OUT endpoint.
- */
-
- case USB_DESC_TYPE_ENDPOINT:
- {
- FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc;
-
- uvdbg("Endpoint descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
-
- /* Check for an interrupt endpoint. */
-
- if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_INT)
- {
- /* Yes.. it is a interrupt endpoint. IN or OUT? */
-
- if (USB_ISEPOUT(epdesc->addr))
- {
- /* It is an interrupt OUT endpoint. There not be more than one
- * interrupt OUT endpoint.
- */
-
- if ((found & USBHOST_EPOUTFOUND) != 0)
- {
- /* Oops.. more than one endpoint. We don't know what to do with this. */
-
- return -EINVAL;
- }
- found |= USBHOST_EPOUTFOUND;
-
- /* Save the interrupt OUT endpoint information */
-
- epoutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- epoutdesc.in = false;
- epoutdesc.funcaddr = funcaddr;
- epoutdesc.xfrtype = USB_EP_ATTR_XFER_INT;
- epoutdesc.interval = epdesc->interval;
- epoutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Interrupt OUT EP addr:%d mxpacketsize:%d\n",
- epoutdesc.addr, epoutdesc.mxpacketsize);
- }
- else
- {
- /* It is an interrupt IN endpoint. There should be only
- * one interrupt IN endpoint.
- */
-
- if ((found & USBHOST_EPINFOUND) != 0)
- {
- /* Oops.. more than one endpint. We don't know what
- * to do with this.
- */
-
- return -EINVAL;
- }
- found |= USBHOST_EPINFOUND;
-
- /* Save the interrupt IN endpoint information */
-
- epindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- epindesc.in = 1;
- epindesc.funcaddr = funcaddr;
- epindesc.xfrtype = USB_EP_ATTR_XFER_INT;
- epindesc.interval = epdesc->interval;
- epindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Interrupt IN EP addr:%d mxpacketsize:%d\n",
- epindesc.addr, epindesc.mxpacketsize);
- }
- }
- }
- break;
-
- /* Other descriptors are just ignored for now */
-
- default:
- uvdbg("Other descriptor: %d\n", desc->type);
- break;
- }
-
- /* What we found everything that we are going to find? */
-
- if (found == USBHOST_ALLFOUND)
- {
- /* Yes.. then break out of the loop and use the preceding interface */
-
- done = true;
- }
-
- /* Increment the address of the next descriptor */
-
- configdesc += desc->len;
- remaining -= desc->len;
- }
-
- /* Sanity checking... did we find all of things that we need? */
-
- if ((found & USBHOST_RQDFOUND) != USBHOST_RQDFOUND)
- {
- ulldbg("ERROR: Found IF:%s EPIN:%s\n",
- (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_EPINFOUND) != 0 ? "YES" : "NO");
- return -EINVAL;
- }
-
- /* We are good... Allocate the endpoints. First, the required interrupt
- * IN endpoint.
- */
-
- ret = DRVR_EPALLOC(priv->drvr, &epindesc, &priv->epin);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate interrupt IN endpoint\n");
- return ret;
- }
-
- /* Then the optional interrupt OUT endpoint */
-
- ullvdbg("Found EPOOUT:%s\n",
- (found & USBHOST_EPOUTFOUND) != 0 ? "YES" : "NO");
-
- if ((found & USBHOST_EPOUTFOUND) != 0)
- {
- ret = DRVR_EPALLOC(priv->drvr, &epoutdesc, &priv->epout);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate interrupt OUT endpoint\n");
- (void)DRVR_EPFREE(priv->drvr, priv->epin);
- return ret;
- }
- }
-
- ullvdbg("Endpoints allocated\n");
- return OK;
-}
-
-/****************************************************************************
- * Name: usbhost_devinit
- *
- * Description:
- * The USB device has been successfully connected. This completes the
- * initialization operations. It is first called after the
- * configuration descriptor has been received.
- *
- * This function is called from the connect() method. This function always
- * executes on the thread of the caller of connect().
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-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 */
-
- ret = usbhost_tdalloc(priv);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate transfer buffer\n");
- return ret;
- }
-
- /* Increment the reference count. This will prevent usbhost_destroy() from
- * being called asynchronously if the device is removed.
- */
-
- priv->crefs++;
- DEBUGASSERT(priv->crefs == 2);
-
- /* 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("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)usbhost_kbdpoll, (const char **)NULL);
-#endif
- if (priv->pollpid == ERROR)
- {
- /* Failed to started the poll thread... probably due to memory resources */
-
- usbhost_givesem(&g_exclsem);
- ret = -ENOMEM;
- goto errout;
- }
-
- /* Now wait for the poll task to get properly initialized */
-
- 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, priv);
-
- /* 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;
-}
-
-/****************************************************************************
- * Name: usbhost_getle16
- *
- * Description:
- * Get a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * val - A pointer to the first byte of the little endian value.
- *
- * Returned Values:
- * A uint16_t representing the whole 16-bit integer value
- *
- ****************************************************************************/
-
-static inline uint16_t usbhost_getle16(const uint8_t *val)
-{
- return (uint16_t)val[1] << 8 | (uint16_t)val[0];
-}
-
-/****************************************************************************
- * Name: usbhost_putle16
- *
- * Description:
- * Put a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 16-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putle16(uint8_t *dest, uint16_t val)
-{
- dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
- dest[1] = val >> 8;
-}
-
-/****************************************************************************
- * Name: usbhost_getle32
- *
- * Description:
- * Get a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline uint32_t usbhost_getle32(const uint8_t *val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val);
-}
-
-/****************************************************************************
- * Name: usbhost_putle32
- *
- * Description:
- * Put a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-#if 0 /* Not used */
-static void usbhost_putle32(uint8_t *dest, uint32_t val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- usbhost_putle16(dest, (uint16_t)(val & 0xffff));
- usbhost_putle16(dest+2, (uint16_t)(val >> 16));
-}
-#endif
-
-/****************************************************************************
- * Name: usbhost_tdalloc
- *
- * Description:
- * Allocate transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
-{
- DEBUGASSERT(priv && priv->tbuffer == NULL);
- return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
-}
-
-/****************************************************************************
- * Name: usbhost_tdfree
- *
- * Description:
- * Free transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv)
-{
- int result = OK;
- DEBUGASSERT(priv);
-
- if (priv->tbuffer)
- {
- DEBUGASSERT(priv->drvr);
- result = DRVR_FREE(priv->drvr, priv->tbuffer);
- priv->tbuffer = NULL;
- priv->tbuflen = 0;
- }
- return result;
-}
-
-/****************************************************************************
- * struct usbhost_registry_s methods
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_create
- *
- * Description:
- * This function implements the create() method of struct usbhost_registry_s.
- * The create() method is a callback into the class implementation. It is
- * used to (1) create a new instance of the USB host class state and to (2)
- * bind a USB host driver "session" to the class instance. Use of this
- * create() method will support environments where there may be multiple
- * USB ports and multiple USB devices simultaneously connected.
- *
- * Input Parameters:
- * drvr - An instance of struct usbhost_driver_s that the class
- * implementation will "bind" to its state structure and will
- * subsequently use to communicate with the USB host driver.
- * id - In the case where the device supports multiple base classes,
- * subclasses, or protocols, this specifies which to configure for.
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s that can be used by the USB host driver to communicate
- * with the USB host class. NULL is returned on failure; this function
- * will fail only if the drvr input parameter is NULL or if there are
- * insufficient resources to create another USB host class instance.
- *
- ****************************************************************************/
-
-static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id)
-{
- FAR struct usbhost_state_s *priv;
-
- /* Allocate a USB host class instance */
-
- priv = usbhost_allocclass();
- if (priv)
- {
- /* Initialize the allocated storage class instance */
-
- memset(priv, 0, sizeof(struct usbhost_state_s));
-
- /* Assign a device number to this class instance */
-
- if (usbhost_allocdevno(priv) == OK)
- {
- /* Initialize class method function pointers */
-
- priv->class.connect = usbhost_connect;
- priv->class.disconnected = usbhost_disconnected;
-
- /* The initial reference count is 1... One reference is held by the driver */
-
- priv->crefs = 1;
-
- /* Initialize semaphores */
-
- sem_init(&priv->exclsem, 0, 1);
- sem_init(&priv->waitsem, 0, 0);
-
- /* Bind the driver to the storage class instance */
-
- priv->drvr = drvr;
-
- /* Return the instance of the USB keyboard class driver */
-
- return &priv->class;
- }
- }
-
- /* An error occurred. Free the allocation and return NULL on all failures */
-
- if (priv)
- {
- usbhost_freeclass(priv);
- }
- return NULL;
-}
-
-/****************************************************************************
- * struct usbhost_class_s methods
- ****************************************************************************/
-/****************************************************************************
- * Name: usbhost_connect
- *
- * Description:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to create().
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * NOTE that the class instance remains valid upon return with a failure. It is
- * the responsibility of the higher level enumeration logic to call
- * CLASS_DISCONNECTED to free up the class driver resources.
- *
- * Assumptions:
- * - This function will *not* be called from an interrupt handler.
- * - If this function returns an error, the USB host controller driver
- * must call to DISCONNECTED method to recover from the error
- *
- ****************************************************************************/
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Parse the configuration descriptor to get the endpoints */
-
- ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr);
- if (ret != OK)
- {
- udbg("usbhost_cfgdesc() failed: %d\n", ret);
- }
- else
- {
- /* Now configure the device and register the NuttX driver */
-
- ret = usbhost_devinit(priv);
- if (ret != OK)
- {
- udbg("usbhost_devinit() failed: %d\n", ret);
- }
- }
-
- /* ERROR handling: Do nothing. If we return and error during connection,
- * the driver is required to call the DISCONNECT method. Possibilities:
- *
- * - Failure occurred before the kbdpoll task was started successfully.
- * In this case, the disconnection will have to be handled on the worker
- * task.
- * - Failure occured after the kbdpoll task was started succesffuly. In
- * this case, the disconnetion can be performed on the kbdpoll thread.
- */
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_disconnected
- *
- * Description:
- * This function implements the disconnected() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to inform the class that the USB device has
- * been disconnected.
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to
- * create().
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value
- * is returned indicating the nature of the failure
- *
- * Assumptions:
- * This function may be called from an interrupt handler.
- *
- ****************************************************************************/
-
-static int usbhost_disconnected(struct usbhost_class_s *class)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
-
- DEBUGASSERT(priv != NULL);
-
- /* Set an indication to any users of the keyboard device that the device
- * is no longer available.
- */
-
- priv->disconnected = true;
- ullvdbg("Disconnected\n");
-
- /* Is there a thread waiting for keyboard data that will never come? */
-
- if (priv->waiting)
- {
- /* Yes.. wake it up */
-
- usbhost_givesem(&priv->waitsem);
- priv->waiting = false;
- }
-
- /* Possibilities:
- *
- * - Failure occurred before the kbdpoll task was started successfully.
- * In this case, the disconnection will have to be handled on the worker
- * task.
- * - Failure occured after the kbdpoll task was started succesffuly. In
- * this case, the disconnetion can be performed on the kbdpoll thread.
- */
-
- if (priv->polling)
- {
- /* The polling task is still alive. Signal the keyboard polling task.
- * When that task wakes up, it will decrement the reference count and,
- * perhaps, destroy the class instance. Then it will exit.
- */
-
- (void)kill(priv->pollpid, SIGALRM);
- }
- else
- {
- /* In the case where the failure occurs before the polling task was
- * started. Now what? We are probably executing from an interrupt
- * handler here. We will use the worker thread. This is kind of
- * wasteful and begs for a re-design.
- */
-
- DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
- }
-
- 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 && 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++;
- priv->open = true;
- 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;
-
- 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--;
-
- /* Is this the last reference (other than the one held by the USB host
- * controller driver)
- */
-
- if (priv->crefs <= 1)
- {
- irqstate_t flags;
-
- /* Yes.. then the driver is no longer open */
-
- priv->open = false;
- priv->headndx = 0;
- priv->tailndx = 0;
-
- /* We need to disable interrupts momentarily to assure that there are
- * no asynchronous disconnect events.
- */
-
- flags = irqsave();
-
- /* Check if the USB keyboard device is still connected. If the device is
- * no longer connected, then unregister the driver and free the driver
- * class instance.
- */
-
- if (priv->disconnected)
- {
- /* Destroy the class instance (we can't use priv after this; we can't
- * 'give' the semapore)
- */
-
- usbhost_destroy(priv);
- irqrestore(flags);
- return OK;
- }
- irqrestore(flags);
- }
-
- usbhost_givesem(&priv->exclsem);
- return OK;
-}
-
-/****************************************************************************
- * Name: usbhost_read
- *
- * Description:
- * Standard character driver read method.
- *
- ****************************************************************************/
-
-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;
- size_t nbytes;
- unsigned int tail;
- 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.
- */
-
- 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
- {
- /* Is there keyboard data now? */
-
- while (priv->tailndx == priv->headndx)
- {
- /* No.. were we open non-blocking? */
-
- if (filep->f_oflags & O_NONBLOCK)
- {
- /* Yes.. then return a failure */
-
- ret = -EAGAIN;
- goto errout;
- }
-
- /* Wait for data to be available */
-
- uvdbg("Waiting...\n");
-
- priv->waiting = true;
- usbhost_givesem(&priv->exclsem);
- usbhost_takesem(&priv->waitsem);
- usbhost_takesem(&priv->exclsem);
-
- /* Did the keyboard become disconnected while we were waiting */
-
- if (priv->disconnected)
- {
- ret = -ENODEV;
- goto errout;
- }
- }
-
- /* Read data from our internal buffer of received characters */
-
- for (tail = priv->tailndx, nbytes = 0;
- tail != priv->headndx && nbytes < len;
- nbytes++)
- {
- /* Copy the next keyboard character into the user buffer */
-
- *buffer++ = priv->kbdbuffer[tail];
-
- /* Handle wrap-around of the tail index */
-
- if (++tail >= CONFIG_HIDKBD_BUFSIZE)
- {
- tail = 0;
- }
- }
- ret = nbytes;
-
- /* Update the tail index (pehaps marking the buffer empty) */
-
- priv->tailndx = tail;
- }
-
-errout:
- usbhost_givesem(&priv->exclsem);
- return (ssize_t)ret;
-}
-
-/****************************************************************************
- * Name: usbhost_write
- *
- * Description:
- * Standard character driver write method.
- *
- ****************************************************************************/
-
-static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer, size_t len)
-{
- /* We won't try to write to the keyboard */
-
- return -ENOSYS;
-}
-
-/****************************************************************************
- * Name: usbhost_poll
- *
- * Description:
- * Standard character driver poll method.
- *
- ****************************************************************************/
-
-#ifndef CONFIG_DISABLE_POLL
-static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
- bool setup)
-{
- FAR struct inode *inode;
- FAR struct usbhost_state_s *priv;
- int ret = OK;
- int i;
-
- uvdbg("Entry\n");
- DEBUGASSERT(filep && filep->f_inode && fds);
- inode = filep->f_inode;
- priv = inode->i_private;
-
- /* Make sure that we have exclusive access to the private data structure */
-
- DEBUGASSERT(priv);
- 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.
- */
-
- 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 if (setup)
- {
- /* This is a request to set up the poll. Find an availableslot for
- * the poll structure reference
- */
-
- for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++)
- {
- /* Find an available slot */
-
- if (!priv->fds[i])
- {
- /* Bind the poll structure and this slot */
-
- priv->fds[i] = fds;
- fds->priv = &priv->fds[i];
- break;
- }
- }
-
- if (i >= CONFIG_HIDKBD_NPOLLWAITERS)
- {
- fds->priv = NULL;
- ret = -EBUSY;
- goto errout;
- }
-
- /* Should we immediately notify on any of the requested events? Notify
- * the POLLIN event if there is buffered keyboard data.
- */
-
- if (priv->headndx != priv->tailndx)
- {
- usbhost_pollnotify(priv);
- }
- }
- else
- {
- /* This is a request to tear down the poll. */
-
- struct pollfd **slot = (struct pollfd **)fds->priv;
- DEBUGASSERT(slot);
-
- /* Remove all memory of the poll setup */
-
- *slot = NULL;
- fds->priv = NULL;
- }
-
-errout:
- sem_post(&priv->exclsem);
- return ret;
-}
-#endif
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_kbdinit
- *
- * Description:
- * Initialize the USB storage HID keyboard class driver. This function
- * should be called be platform-specific code in order to initialize and
- * register support for the USB host HID keyboard class device.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success this function will return zero (OK); A negated errno value
- * will be returned on failure.
- *
- ****************************************************************************/
-
-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);
-}
-
-#endif /* CONFIG_USBHOST)&& !CONFIG_USBHOST_INT_DISABLE && CONFIG_NFILE_DESCRIPTORS */
-
-
diff --git a/nuttx/drivers/usbhost/usbhost_registerclass.c b/nuttx/drivers/usbhost/usbhost_registerclass.c
deleted file mode 100644
index f4d1b64af..000000000
--- a/nuttx/drivers/usbhost/usbhost_registerclass.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_registerclass.c
- *
- * Copyright (C) 2010 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <arch/irq.h>
-#include <nuttx/usb/usbhost.h>
-
-#include "usbhost_registry.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_registerclass
- *
- * Description:
- * Register a USB host class implementation. The caller provides an
- * instance of struct usbhost_registry_s that contains all of the
- * information that will be needed later to (1) associate the USB host
- * class implementation with a connected USB device, and (2) to obtain and
- * bind a struct usbhost_class_s instance for the device.
- *
- * Input Parameters:
- * class - An write-able instance of struct usbhost_registry_s that will be
- * maintained in a registry.
- *
- * Returned Values:
- * On success, this function will return zero (OK). Otherwise, a negated
- * errno value is returned.
- *
- ****************************************************************************/
-
-int usbhost_registerclass(struct usbhost_registry_s *class)
-{
- irqstate_t flags;
-
- uvdbg("Registering class:%p nids:%d\n", class, class->nids);
-
- /* g_classregistry is a singly-linkedlist of class ID information added by
- * calls to usbhost_registerclass(). Since this list is accessed from USB
- * host controller interrupt handling logic, accesses to this list must be
- * protected by disabling interrupts.
- */
-
- flags = irqsave();
-
- /* Add the new class ID info to the head of the list */
-
- class->flink = g_classregistry;
- g_classregistry = class;
-
- irqrestore(flags);
- return OK;
-}
-
diff --git a/nuttx/drivers/usbhost/usbhost_registry.c b/nuttx/drivers/usbhost/usbhost_registry.c
deleted file mode 100644
index fb2e900e2..000000000
--- a/nuttx/drivers/usbhost/usbhost_registry.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_registry.c
- *
- * Copyright (C) 2010 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <nuttx/usb/usbhost.h>
-
-#include "usbhost_registry.h"
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/* g_classregistry is a singly-linkedlist of class ID information added by
- * calls to usbhost_registerclass(). Since this list is accessed from USB
- * host controller interrupt handling logic, accesses to this list must be
- * protected by disabling interrupts.
- */
-
-struct usbhost_registry_s *g_classregistry;
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
diff --git a/nuttx/drivers/usbhost/usbhost_registry.h b/nuttx/drivers/usbhost/usbhost_registry.h
deleted file mode 100644
index 759a1c66e..000000000
--- a/nuttx/drivers/usbhost/usbhost_registry.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbdev_registry.h
- *
- * Copyright (C) 2010 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __DRIVERS_USBHOST_USBHOST_REGISTRY_H
-#define __DRIVERS_USBHOST_USBHOST_REGISTRY_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <nuttx/usb/usbhost.h>
-
-/****************************************************************************
- * Definitions
- ****************************************************************************/
-
-/* Configuration ************************************************************/
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-#undef EXTERN
-#if defined(__cplusplus)
-# define EXTERN extern "C"
-extern "C"
-{
-#else
-# define EXTERN extern
-#endif
-
-/* g_classregistry is a singly-linkedlist of class ID information added by
- * calls to usbhost_registerclass(). Since this list is accessed from USB
- * host controller interrupt handling logic, accesses to this list must be
- * protected by disabling interrupts.
- */
-
-EXTERN struct usbhost_registry_s *g_classregistry;
-
-/************************************************************************************
- * Public Function Prototypes
- ************************************************************************************/
-
-#undef EXTERN
-#if defined(__cplusplus)
-}
-#endif
-
-#endif /* #define __DRIVERS_USBHOST_USBHOST_REGISTRY_H */
diff --git a/nuttx/drivers/usbhost/usbhost_skeleton.c b/nuttx/drivers/usbhost/usbhost_skeleton.c
deleted file mode 100644
index c44a265e8..000000000
--- a/nuttx/drivers/usbhost/usbhost_skeleton.c
+++ /dev/null
@@ -1,1060 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_skeleton.c
- *
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <semaphore.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/arch.h>
-#include <nuttx/wqueue.h>
-
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbhost.h>
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Configuration ************************************************************/
-
-#ifndef CONFIG_SCHED_WORKQUEUE
-# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
-#endif
-
-/* Driver support ***********************************************************/
-/* 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/skel%c"
-#define DEV_NAMELEN 12
-
-/* Used in usbhost_cfgdesc() */
-
-#define USBHOST_IFFOUND 0x01
-#define USBHOST_BINFOUND 0x02
-#define USBHOST_BOUTFOUND 0x04
-#define USBHOST_ALLFOUND 0x07
-
-#define USBHOST_MAX_CREFS 0x7fff
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This structure contains the internal, private state of the USB host class
- * driver.
- */
-
-struct usbhost_state_s
-{
- /* This is the externally visible portion of the state */
-
- struct usbhost_class_s class;
-
- /* This is an instance of the USB host driver bound to this class instance */
-
- struct usbhost_driver_s *drvr;
-
- /* The remainder of the fields are provide to the class driver */
-
- char devchar; /* Character identifying the /dev/skel[n] device */
- volatile bool disconnected; /* TRUE: Device has been disconnected */
- uint8_t ifno; /* Interface number */
- 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 *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 */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/* Semaphores */
-
-static void usbhost_takesem(sem_t *sem);
-#define usbhost_givesem(s) sem_post(s);
-
-/* Memory allocation services */
-
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void);
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class);
-
-/* Device name management */
-
-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 */
-
-static void usbhost_destroy(FAR void *arg);
-
-/* Helpers for usbhost_connect() */
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static inline int usbhost_devinit(FAR struct usbhost_state_s *priv);
-
-/* (Little Endian) Data helpers */
-
-static inline uint16_t usbhost_getle16(const uint8_t *val);
-static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
-static inline uint32_t usbhost_getle32(const uint8_t *val);
-static void usbhost_putle32(uint8_t *dest, uint32_t val);
-
-/* Transfer descriptor memory management */
-
-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 */
-
-static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id);
-
-/* struct usbhost_class_s methods */
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static int usbhost_disconnected(FAR struct usbhost_class_s *class);
-
-/* Driver methods -- depend upon the type of NuttX driver interface exported */
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* This structure provides the registry entry ID informatino that will be
- * used to associate the USB class driver to a connected USB device.
- */
-
-static const const struct usbhost_id_s g_id =
-{
- 0, /* base -- Must be one of the USB_CLASS_* definitions in usb.h */
- 0, /* subclass -- depends on the device */
- 0, /* proto -- depends on the device */
- 0, /* vid */
- 0 /* pid */
-};
-
-/* This is the USB host storage class's registry entry */
-
-static struct usbhost_registry_s g_skeleton =
-{
- NULL, /* flink */
- usbhost_create, /* create */
- 1, /* nids */
- &g_id /* id[] */
-};
-
-/* This is a bitmap that is used to allocate device names /dev/skela-z. */
-
-static uint32_t g_devinuse;
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_takesem
- *
- * Description:
- * This is just a wrapper to handle the annoying behavior of semaphore
- * waits that return due to the receipt of a signal.
- *
- ****************************************************************************/
-
-static void usbhost_takesem(sem_t *sem)
-{
- /* Take the semaphore (perhaps waiting) */
-
- while (sem_wait(sem) != 0)
- {
- /* The only case that an error should occr here is if the wait was
- * awakened by a signal.
- */
-
- ASSERT(errno == EINTR);
- }
-}
-
-/****************************************************************************
- * Name: usbhost_allocclass
- *
- * Description:
- * This is really part of the logic that implements the create() method
- * of struct usbhost_registry_s. This function allocates memory for one
- * new class instance.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s. NULL is returned on failure; this function will
- * will fail only if there are insufficient resources to create another
- * USB host class instance.
- *
- ****************************************************************************/
-
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
-{
- FAR struct usbhost_state_s *priv;
-
- DEBUGASSERT(!up_interrupt_context());
- priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s));
- uvdbg("Allocated: %p\n", priv);;
- return priv;
-}
-
-/****************************************************************************
- * Name: usbhost_freeclass
- *
- * Description:
- * Free a class instance previously allocated by usbhost_allocclass().
- *
- * Input Parameters:
- * class - A reference to the class instance to be freed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
-{
- DEBUGASSERT(class != NULL);
-
- /* Free the class instance (perhaps calling sched_free() in case we are
- * executing from an interrupt handler.
- */
-
- uvdbg("Freeing: %p\n", class);;
- kfree(class);
-}
-
-/****************************************************************************
- * Name: Device name management
- *
- * Description:
- * Some tiny functions to coordinate management of device names.
- *
- ****************************************************************************/
-
-static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
-{
- irqstate_t flags;
- int devno;
-
- flags = irqsave();
- for (devno = 0; devno < 26; devno++)
- {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0)
- {
- g_devinuse |= bitno;
- priv->devchar = 'a' + devno;
- irqrestore(flags);
- return OK;
- }
- }
-
- irqrestore(flags);
- return -EMFILE;
-}
-
-static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
-{
- int devno = 'a' - priv->devchar;
-
- if (devno >= 0 && devno < 26)
- {
- irqstate_t flags = irqsave();
- g_devinuse &= ~(1 << devno);
- irqrestore(flags);
- }
-}
-
-static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
-{
- (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
-}
-
-/****************************************************************************
- * Name: usbhost_destroy
- *
- * Description:
- * The USB device has been disconnected and the refernce count on the USB
- * host class instance has gone to 1.. Time to destroy the USB host class
- * instance.
- *
- * Input Parameters:
- * arg - A reference to the class instance to be destroyed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_destroy(FAR void *arg)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
-
- DEBUGASSERT(priv != NULL);
- uvdbg("crefs: %d\n", priv->crefs);
-
- /* Unregister the driver */
-
- /* Release the device name used by this connection */
-
- usbhost_freedevno(priv);
-
- /* Free the endpoints */
-
- /* Free any transfer buffers */
-
- /* Destroy the semaphores */
-
- /* Disconnect the USB host device */
-
- DRVR_DISCONNECT(priv->drvr);
-
- /* And free the class instance. Hmmm.. this may execute on the worker
- * thread and the work structure is part of what is getting freed. That
- * should be okay because once the work contained is removed from the
- * queue, it should not longer be accessed by the worker thread.
- */
-
- usbhost_freeclass(priv);
-}
-
-/****************************************************************************
- * Name: usbhost_cfgdesc
- *
- * Description:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * priv - The USB host class instance.
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * Assumptions:
- * This function will *not* be called from an interrupt handler.
- *
- ****************************************************************************/
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usb_cfgdesc_s *cfgdesc;
- FAR struct usb_desc_s *desc;
- FAR struct usbhost_epdesc_s bindesc;
- FAR struct usbhost_epdesc_s boutdesc;
- int remaining;
- uint8_t found = 0;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Verify that we were passed a configuration descriptor */
-
- cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
- if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
- {
- return -EINVAL;
- }
-
- /* Get the total length of the configuration descriptor (little endian).
- * It might be a good check to get the number of interfaces here too.
- */
-
- remaining = (int)usbhost_getle16(cfgdesc->totallen);
-
- /* Skip to the next entry descriptor */
-
- configdesc += cfgdesc->len;
- remaining -= cfgdesc->len;
-
- /* Loop where there are more dscriptors to examine */
-
- while (remaining >= sizeof(struct usb_desc_s))
- {
- /* What is the next descriptor? */
-
- desc = (FAR struct usb_desc_s *)configdesc;
- switch (desc->type)
- {
- /* Interface descriptor. We really should get the number of endpoints
- * from this descriptor too.
- */
-
- case USB_DESC_TYPE_INTERFACE:
- {
- FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc;
-
- uvdbg("Interface descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
-
- /* Save the interface number and mark ONLY the interface found */
-
- priv->ifno = ifdesc->ifno;
- found = USBHOST_IFFOUND;
- }
- break;
-
- /* Endpoint descriptor. Here, we expect two bulk endpoints, an IN
- * and an OUT.
- */
-
- case USB_DESC_TYPE_ENDPOINT:
- {
- FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc;
-
- uvdbg("Endpoint descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
-
- /* Check for a bulk endpoint. */
-
- if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK)
- {
- /* Yes.. it is a bulk endpoint. IN or OUT? */
-
- if (USB_ISEPOUT(epdesc->addr))
- {
- /* It is an OUT bulk endpoint. There should be only one
- * bulk OUT endpoint.
- */
-
- if ((found & USBHOST_BOUTFOUND) != 0)
- {
- /* Oops.. more than one endpoint. We don't know
- * what to do with this.
- */
-
- return -EINVAL;
- }
- found |= USBHOST_BOUTFOUND;
-
- /* Save the bulk OUT endpoint information */
-
- boutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- boutdesc.in = false;
- boutdesc.funcaddr = funcaddr;
- boutdesc.xfrtype = USB_EP_ATTR_XFER_BULK;
- boutdesc.interval = epdesc->interval;
- boutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n",
- boutdesc.addr, boutdesc.mxpacketsize);
- }
- else
- {
- /* It is an IN bulk endpoint. There should be only one
- * bulk IN endpoint.
- */
-
- if ((found & USBHOST_BINFOUND) != 0)
- {
- /* Oops.. more than one endpoint. We don't know
- * what to do with this.
- */
-
- return -EINVAL;
- }
- found |= USBHOST_BINFOUND;
-
- /* Save the bulk IN endpoint information */
-
- bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- bindesc.in = 1;
- bindesc.funcaddr = funcaddr;
- bindesc.xfrtype = USB_EP_ATTR_XFER_BULK;
- bindesc.interval = epdesc->interval;
- bindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n",
- bindesc.addr, bindesc.mxpacketsize);
- }
- }
- }
- break;
-
- /* Other descriptors are just ignored for now */
-
- default:
- break;
- }
-
- /* If we found everything we need with this interface, then break out
- * of the loop early.
- */
-
- if (found == USBHOST_ALLFOUND)
- {
- break;
- }
-
- /* Increment the address of the next descriptor */
-
- configdesc += desc->len;
- remaining -= desc->len;
- }
-
- /* Sanity checking... did we find all of things that we need? */
-
- if (found != USBHOST_ALLFOUND)
- {
- ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
- (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
- return -EINVAL;
- }
-
- /* We are good... Allocate the endpoints */
-
- ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->epout);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate Bulk OUT endpoint\n");
- return ret;
- }
-
- ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->epin);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate Bulk IN endpoint\n");
- (void)DRVR_EPFREE(priv->drvr, priv->epout);
- return ret;
- }
-
- ullvdbg("Endpoints allocated\n");
- return OK;
-}
-
-/****************************************************************************
- * Name: usbhost_devinit
- *
- * Description:
- * The USB device has been successfully connected. This completes the
- * initialization operations. It is first called after the
- * configuration descriptor has been received.
- *
- * This function is called from the connect() method. This function always
- * executes on the thread of the caller of connect().
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline int usbhost_devinit(FAR struct usbhost_state_s *priv)
-{
- int ret = OK;
-
- /* Set aside a transfer buffer for exclusive use by the class driver */
-
- /* Increment the reference count. This will prevent usbhost_destroy() from
- * being called asynchronously if the device is removed.
- */
-
- priv->crefs++;
- DEBUGASSERT(priv->crefs == 2);
-
- /* Configure the device */
-
- /* Register the driver */
-
- if (ret == OK)
- {
- char devname[DEV_NAMELEN];
-
- uvdbg("Register block driver\n");
- usbhost_mkdevname(priv, devname);
- // ret = register_blockdriver(devname, &g_bops, 0, priv);
- }
-
- /* Check if we successfully initialized. We now have to be concerned
- * about asynchronous modification of crefs because the block
- * driver has been registerd.
- */
-
- if (ret == OK)
- {
- usbhost_takesem(&priv->exclsem);
- DEBUGASSERT(priv->crefs >= 2);
-
- /* 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 block device driver */
-
- uvdbg("Successfully initialized\n");
- priv->crefs--;
- usbhost_givesem(&priv->exclsem);
- }
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_getle16
- *
- * Description:
- * Get a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * val - A pointer to the first byte of the little endian value.
- *
- * Returned Values:
- * A uint16_t representing the whole 16-bit integer value
- *
- ****************************************************************************/
-
-static inline uint16_t usbhost_getle16(const uint8_t *val)
-{
- return (uint16_t)val[1] << 8 | (uint16_t)val[0];
-}
-
-/****************************************************************************
- * Name: usbhost_putle16
- *
- * Description:
- * Put a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 16-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putle16(uint8_t *dest, uint16_t val)
-{
- dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
- dest[1] = val >> 8;
-}
-
-/****************************************************************************
- * Name: usbhost_getle32
- *
- * Description:
- * Get a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline uint32_t usbhost_getle32(const uint8_t *val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val);
-}
-
-/****************************************************************************
- * Name: usbhost_putle32
- *
- * Description:
- * Put a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putle32(uint8_t *dest, uint32_t val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- usbhost_putle16(dest, (uint16_t)(val & 0xffff));
- usbhost_putle16(dest+2, (uint16_t)(val >> 16));
-}
-
-/****************************************************************************
- * Name: usbhost_talloc
- *
- * Description:
- * Allocate transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
-{
- DEBUGASSERT(priv && priv->tbuffer == NULL);
- return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
-}
-
-/****************************************************************************
- * Name: usbhost_tfree
- *
- * Description:
- * Free transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
-{
- int result = OK;
- DEBUGASSERT(priv);
-
- if (priv->tbuffer)
- {
- DEBUGASSERT(priv->drvr);
- result = DRVR_FREE(priv->drvr, priv->tbuffer);
- priv->tbuffer = NULL;
- priv->tbuflen = 0;
- }
- return result;
-}
-
-/****************************************************************************
- * struct usbhost_registry_s methods
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_create
- *
- * Description:
- * This function implements the create() method of struct usbhost_registry_s.
- * The create() method is a callback into the class implementation. It is
- * used to (1) create a new instance of the USB host class state and to (2)
- * bind a USB host driver "session" to the class instance. Use of this
- * create() method will support environments where there may be multiple
- * USB ports and multiple USB devices simultaneously connected.
- *
- * Input Parameters:
- * drvr - An instance of struct usbhost_driver_s that the class
- * implementation will "bind" to its state structure and will
- * subsequently use to communicate with the USB host driver.
- * id - In the case where the device supports multiple base classes,
- * subclasses, or protocols, this specifies which to configure for.
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s that can be used by the USB host driver to communicate
- * with the USB host class. NULL is returned on failure; this function
- * will fail only if the drvr input parameter is NULL or if there are
- * insufficient resources to create another USB host class instance.
- *
- ****************************************************************************/
-
-static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id)
-{
- FAR struct usbhost_state_s *priv;
-
- /* Allocate a USB host class instance */
-
- priv = usbhost_allocclass();
- if (priv)
- {
- /* Initialize the allocated storage class instance */
-
- memset(priv, 0, sizeof(struct usbhost_state_s));
-
- /* Assign a device number to this class instance */
-
- if (usbhost_allocdevno(priv) == OK)
- {
- /* Initialize class method function pointers */
-
- priv->class.connect = usbhost_connect;
- priv->class.disconnected = usbhost_disconnected;
-
- /* The initial reference count is 1... One reference is held by the driver */
-
- priv->crefs = 1;
-
- /* Initialize semphores (this works okay in the interrupt context) */
-
- sem_init(&priv->exclsem, 0, 1);
-
- /* Bind the driver to the storage class instance */
-
- priv->drvr = drvr;
-
- /* Return the instance of the USB class driver */
-
- return &priv->class;
- }
- }
-
- /* An error occurred. Free the allocation and return NULL on all failures */
-
- if (priv)
- {
- usbhost_freeclass(priv);
- }
- return NULL;
-}
-
-/****************************************************************************
- * struct usbhost_class_s methods
- ****************************************************************************/
-/****************************************************************************
- * Name: usbhost_connect
- *
- * Description:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to create().
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * NOTE that the class instance remains valid upon return with a failure. It is
- * the responsibility of the higher level enumeration logic to call
- * CLASS_DISCONNECTED to free up the class driver resources.
- *
- * Assumptions:
- * - This function will *not* be called from an interrupt handler.
- * - If this function returns an error, the USB host controller driver
- * must call to DISCONNECTED method to recover from the error
- *
- ****************************************************************************/
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Parse the configuration descriptor to get the endpoints */
-
- ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr);
- if (ret != OK)
- {
- udbg("usbhost_cfgdesc() failed: %d\n", ret);
- }
- else
- {
- /* Now configure the device and register the NuttX driver */
-
- ret = usbhost_devinit(priv);
- if (ret != OK)
- {
- udbg("usbhost_devinit() failed: %d\n", ret);
- }
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_disconnected
- *
- * Description:
- * This function implements the disconnected() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to inform the class that the USB device has
- * been disconnected.
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to
- * create().
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value
- * is returned indicating the nature of the failure
- *
- * Assumptions:
- * This function may be called from an interrupt handler.
- *
- ****************************************************************************/
-
-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 device that the device is no
- * longer available.
- */
-
- flags = irqsave();
- priv->disconnected = true;
-
- /* 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
- * block driver.
- */
-
- 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);
- DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
- }
- else
- {
- /* Do the work now */
-
- usbhost_destroy(priv);
- }
- }
-
- irqrestore(flags);
- return OK;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_skelinit
- *
- * Description:
- * Initialize the USB class driver. This function should be called
- * be platform-specific code in order to initialize and register support
- * for the USB host class device.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success this function will return zero (OK); A negated errno value
- * will be returned on failure.
- *
- ****************************************************************************/
-
-int usbhost_skelinit(void)
-{
- /* Perform any one-time initialization of the class implementation */
-
- /* Advertise our availability to support (certain) devices */
-
- return usbhost_registerclass(&g_skeleton);
-}
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
deleted file mode 100644
index 2b14676d7..000000000
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ /dev/null
@@ -1,2244 +0,0 @@
-/****************************************************************************
- * drivers/usbhost/usbhost_storage.c
- *
- * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <semaphore.h>
-#include <assert.h>
-#include <errno.h>
-#include <debug.h>
-
-#include <nuttx/kmalloc.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/arch.h>
-#include <nuttx/wqueue.h>
-#include <nuttx/scsi.h>
-
-#include <nuttx/usb/usb.h>
-#include <nuttx/usb/usbhost.h>
-#include <nuttx/usb/storage.h>
-
-/* Don't compile if prerequisites are not met */
-
-#if defined(CONFIG_USBHOST) && !defined(CONFIG_USBHOST_BULK_DISABLE) && \
- !defined(CONFIG_DISABLE_MOUNTPOINT) && CONFIG_NFILE_DESCRIPTORS > 0
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Configuration ************************************************************/
-
-#ifndef CONFIG_SCHED_WORKQUEUE
-# warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
-#endif
-
-/* If the create() method is called by the USB host device driver from an
- * interrupt handler, then it will be unable to call kmalloc() in order to
- * allocate a new class instance. If the create() method is called from the
- * interrupt level, then class instances must be pre-allocated.
- */
-
-#ifndef CONFIG_USBHOST_NPREALLOC
-# define CONFIG_USBHOST_NPREALLOC 0
-#endif
-
-#if CONFIG_USBHOST_NPREALLOC > 26
-# error "Currently limited to 26 devices /dev/sda-z"
-#endif
-
-/* Driver support ***********************************************************/
-/* This format is used to construct the /dev/sd[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
-
-/* Used in usbhost_connect() */
-
-#define USBHOST_IFFOUND 0x01
-#define USBHOST_BINFOUND 0x02
-#define USBHOST_BOUTFOUND 0x04
-#define USBHOST_ALLFOUND 0x07
-
-#define USBHOST_MAX_RETRIES 100
-#define USBHOST_MAX_CREFS 0x7fff
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* This structure contains the internal, private state of the USB host mass
- * storage class.
- */
-
-struct usbhost_state_s
-{
- /* This is the externally visible portion of the state */
-
- struct usbhost_class_s class;
-
- /* This is an instance of the USB host driver bound to this class instance */
-
- struct usbhost_driver_s *drvr;
-
- /* 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 */
- uint8_t ifno; /* Interface number */
- int16_t crefs; /* Reference count on the driver instance */
- uint16_t blocksize; /* Block size of USB mass storage device */
- 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 *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 */
-};
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-/* Semaphores */
-
-static void usbhost_takesem(sem_t *sem);
-#define usbhost_givesem(s) sem_post(s);
-
-/* Memory allocation services */
-
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void);
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class);
-
-/* Device name management */
-
-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);
-
-/* CBW/CSW debug helpers */
-
-#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
-static void usbhost_dumpcbw(FAR struct usbmsc_cbw_s *cbw);
-static void usbhost_dumpcsw(FAR struct usbmsc_csw_s *csw);
-#else
-# define usbhost_dumpcbw(cbw);
-# define usbhost_dumpcsw(csw);
-#endif
-
-/* CBW helpers */
-
-static inline void usbhost_requestsensecbw(FAR struct usbmsc_cbw_s *cbw);
-static inline void usbhost_testunitreadycbw(FAR struct usbmsc_cbw_s *cbw);
-static inline void usbhost_readcapacitycbw(FAR struct usbmsc_cbw_s *cbw);
-static inline void usbhost_inquirycbw (FAR struct usbmsc_cbw_s *cbw);
-static inline void usbhost_readcbw (size_t startsector, uint16_t blocksize,
- unsigned int nsectors,
- FAR struct usbmsc_cbw_s *cbw);
-static inline void usbhost_writecbw(size_t startsector, uint16_t blocksize,
- unsigned int nsectors,
- FAR struct usbmsc_cbw_s *cbw);
-/* Command helpers */
-
-static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv);
-static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv);
-static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv);
-static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv);
-static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv);
-
-/* Worker thread actions */
-
-static void usbhost_destroy(FAR void *arg);
-
-/* Helpers for usbhost_connect() */
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv);
-
-/* (Little Endian) Data helpers */
-
-static inline uint16_t usbhost_getle16(const uint8_t *val);
-static inline uint16_t usbhost_getbe16(const uint8_t *val);
-static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
-static inline void usbhost_putbe16(uint8_t *dest, uint16_t val);
-static inline uint32_t usbhost_getle32(const uint8_t *val);
-static inline uint32_t usbhost_getbe32(const uint8_t *val);
-static void usbhost_putle32(uint8_t *dest, uint32_t val);
-static void usbhost_putbe32(uint8_t *dest, uint32_t val);
-
-/* Transfer descriptor memory management */
-
-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 usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv);
-
-/* struct usbhost_registry_s methods */
-
-static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id);
-
-/* struct usbhost_class_s methods */
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr);
-static int usbhost_disconnected(FAR struct usbhost_class_s *class);
-
-/* struct block_operations methods */
-
-static int usbhost_open(FAR struct inode *inode);
-static int usbhost_close(FAR struct inode *inode);
-static ssize_t usbhost_read(FAR struct inode *inode, FAR unsigned char *buffer,
- size_t startsector, unsigned int nsectors);
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t usbhost_write(FAR struct inode *inode,
- FAR const unsigned char *buffer, size_t startsector,
- unsigned int nsectors);
-#endif
-static int usbhost_geometry(FAR struct inode *inode,
- FAR struct geometry *geometry);
-static int usbhost_ioctl(FAR struct inode *inode, int cmd,
- unsigned long arg);
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-/* 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.
- */
-
-static const const struct usbhost_id_s g_id =
-{
- USB_CLASS_MASS_STORAGE, /* base */
- USBMSC_SUBCLASS_SCSI, /* subclass */
- USBMSC_PROTO_BULKONLY, /* proto */
- 0, /* vid */
- 0 /* pid */
-};
-
-/* This is the USB host storage class's registry entry */
-
-static struct usbhost_registry_s g_storage =
-{
- NULL, /* flink */
- usbhost_create, /* create */
- 1, /* nids */
- &g_id /* id[] */
-};
-
-/* Block driver operations. This is the interface exposed to NuttX by the
- * class that permits it to behave like a block driver.
- */
-
-static const struct block_operations g_bops =
-{
- usbhost_open, /* open */
- usbhost_close, /* close */
- usbhost_read, /* read */
-#ifdef CONFIG_FS_WRITABLE
- usbhost_write, /* write */
-#else
- NULL, /* write */
-#endif
- usbhost_geometry, /* geometry */
- usbhost_ioctl /* ioctl */
-};
-
-/* This is an array of pre-allocated USB host storage class instances */
-
-#if CONFIG_USBHOST_NPREALLOC > 0
-static struct usbhost_state_s g_prealloc[CONFIG_USBHOST_NPREALLOC];
-#endif
-
-/* This is a list of free, pre-allocated USB host storage class instances */
-
-#if CONFIG_USBHOST_NPREALLOC > 0
-static struct usbhost_state_s *g_freelist;
-#endif
-
-/* This is a bitmap that is used to allocate device names /dev/sda-z. */
-
-static uint32_t g_devinuse;
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_takesem
- *
- * Description:
- * This is just a wrapper to handle the annoying behavior of semaphore
- * waits that return due to the receipt of a signal.
- *
- ****************************************************************************/
-
-static void usbhost_takesem(sem_t *sem)
-{
- /* Take the semaphore (perhaps waiting) */
-
- while (sem_wait(sem) != 0)
- {
- /* The only case that an error should occr here is if the wait was
- * awakened by a signal.
- */
-
- ASSERT(errno == EINTR);
- }
-}
-
-/****************************************************************************
- * Name: usbhost_allocclass
- *
- * Description:
- * This is really part of the logic that implements the create() method
- * of struct usbhost_registry_s. This function allocates memory for one
- * new class instance.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s. NULL is returned on failure; this function will
- * will fail only if there are insufficient resources to create another
- * USB host class instance.
- *
- ****************************************************************************/
-
-#if CONFIG_USBHOST_NPREALLOC > 0
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
-{
- struct usbhost_state_s *priv;
- irqstate_t flags;
-
- /* We may be executing from an interrupt handler so we need to take one of
- * our pre-allocated class instances from the free list.
- */
-
- flags = irqsave();
- priv = g_freelist;
- if (priv)
- {
- g_freelist = priv->class.flink;
- priv->class.flink = NULL;
- }
- irqrestore(flags);
- ullvdbg("Allocated: %p\n", priv);;
- return priv;
-}
-#else
-static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
-{
- FAR struct usbhost_state_s *priv;
-
- /* We are not executing from an interrupt handler so we can just call
- * kmalloc() to get memory for the class instance.
- */
-
- DEBUGASSERT(!up_interrupt_context());
- priv = (FAR struct usbhost_state_s *)kmalloc(sizeof(struct usbhost_state_s));
- uvdbg("Allocated: %p\n", priv);;
- return priv;
-}
-#endif
-
-/****************************************************************************
- * Name: usbhost_freeclass
- *
- * Description:
- * Free a class instance previously allocated by usbhost_allocclass().
- *
- * Input Parameters:
- * class - A reference to the class instance to be freed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-#if CONFIG_USBHOST_NPREALLOC > 0
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
-{
- irqstate_t flags;
- DEBUGASSERT(class != NULL);
-
- ullvdbg("Freeing: %p\n", class);;
-
- /* Just put the pre-allocated class structure back on the freelist */
-
- flags = irqsave();
- class->class.flink = g_freelist;
- g_freelist = class;
- irqrestore(flags);
-}
-#else
-static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
-{
- DEBUGASSERT(class != NULL);
-
- /* Free the class instance (calling sched_free() in case we are executing
- * from an interrupt handler.
- */
-
- uvdbg("Freeing: %p\n", class);;
- kfree(class);
-}
-#endif
-
-/****************************************************************************
- * Name: Device name management
- *
- * Description:
- * Some tiny functions to coordinate management of mass storage device names.
- *
- ****************************************************************************/
-
-static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
-{
- irqstate_t flags;
- int devno;
-
- flags = irqsave();
- for (devno = 0; devno < 26; devno++)
- {
- uint32_t bitno = 1 << devno;
- if ((g_devinuse & bitno) == 0)
- {
- g_devinuse |= bitno;
- priv->sdchar = 'a' + devno;
- irqrestore(flags);
- return OK;
- }
- }
-
- irqrestore(flags);
- return -EMFILE;
-}
-
-static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
-{
- int devno = 'a' - priv->sdchar;
-
- if (devno >= 0 && devno < 26)
- {
- irqstate_t flags = irqsave();
- g_devinuse &= ~(1 << devno);
- irqrestore(flags);
- }
-}
-
-static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv, char *devname)
-{
- (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->sdchar);
-}
-
-/****************************************************************************
- * Name: CBW/CSW debug helpers
- *
- * Description:
- * The following functions are helper functions used to dump CBWs and CSWs.
- *
- * Input Parameters:
- * cbw/csw - A reference to the CBW/CSW to dump.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-#if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_VERBOSE)
-static void usbhost_dumpcbw(FAR struct usbmsc_cbw_s *cbw)
-{
- int i;
-
- uvdbg("CBW:\n");
- uvdbg(" signature: %08x\n", usbhost_getle32(cbw->signature));
- uvdbg(" tag: %08x\n", usbhost_getle32(cbw->tag));
- uvdbg(" datlen: %08x\n", usbhost_getle32(cbw->datlen));
- uvdbg(" flags: %02x\n", cbw->flags);
- uvdbg(" lun: %02x\n", cbw->lun);
- uvdbg(" cdblen: %02x\n", cbw->cdblen);
-
- uvdbg("CDB:\n");
- for (i = 0; i < cbw->cdblen; i += 8)
- {
- uvdbg(" %02x %02x %02x %02x %02x %02x %02x %02x\n",
- cbw->cdb[i], cbw->cdb[i+1], cbw->cdb[i+2], cbw->cdb[i+3],
- cbw->cdb[i+4], cbw->cdb[i+5], cbw->cdb[i+6], cbw->cdb[i+7]);
- }
-}
-
-static void usbhost_dumpcsw(FAR struct usbmsc_csw_s *csw)
-{
- uvdbg("CSW:\n");
- uvdbg(" signature: %08x\n", usbhost_getle32(csw->signature));
- uvdbg(" tag: %08x\n", usbhost_getle32(csw->tag));
- uvdbg(" residue: %08x\n", usbhost_getle32(csw->residue));
- uvdbg(" status: %02x\n", csw->status);
-}
-#endif
-
-/****************************************************************************
- * Name: CBW helpers
- *
- * Description:
- * The following functions are helper functions used to format CBWs.
- *
- * Input Parameters:
- * cbw - A reference to allocated and initialized CBW to be built.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline void usbhost_requestsensecbw(FAR struct usbmsc_cbw_s *cbw)
-{
- FAR struct scsicmd_requestsense_s *reqsense;
-
- /* Format the CBW */
-
- usbhost_putle32(cbw->datlen, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
- cbw->flags = USBMSC_CBWFLAG_IN;
- cbw->cdblen = SCSICMD_REQUESTSENSE_SIZEOF;
-
- /* Format the CDB */
-
- reqsense = (FAR struct scsicmd_requestsense_s *)cbw->cdb;
- reqsense->opcode = SCSI_CMD_REQUESTSENSE;
- reqsense->alloclen = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
-
- usbhost_dumpcbw(cbw);
-}
-
-static inline void usbhost_testunitreadycbw(FAR struct usbmsc_cbw_s *cbw)
-{
- /* Format the CBW */
-
- cbw->cdblen = SCSICMD_TESTUNITREADY_SIZEOF;
-
- /* Format the CDB */
-
- cbw->cdb[0] = SCSI_CMD_TESTUNITREADY;
-
- usbhost_dumpcbw(cbw);
-}
-
-static inline void usbhost_readcapacitycbw(FAR struct usbmsc_cbw_s *cbw)
-{
- FAR struct scsicmd_readcapacity10_s *rcap10;
-
- /* Format the CBW */
-
- usbhost_putle32(cbw->datlen, SCSIRESP_READCAPACITY10_SIZEOF);
- cbw->flags = USBMSC_CBWFLAG_IN;
- cbw->cdblen = SCSICMD_READCAPACITY10_SIZEOF;
-
- /* Format the CDB */
-
- rcap10 = (FAR struct scsicmd_readcapacity10_s *)cbw->cdb;
- rcap10->opcode = SCSI_CMD_READCAPACITY10;
-
- usbhost_dumpcbw(cbw);
-}
-
-static inline void usbhost_inquirycbw (FAR struct usbmsc_cbw_s *cbw)
-{
- FAR struct scscicmd_inquiry_s *inq;
-
- /* Format the CBW */
-
- usbhost_putle32(cbw->datlen, SCSIRESP_INQUIRY_SIZEOF);
- cbw->flags = USBMSC_CBWFLAG_IN;
- cbw->cdblen = SCSICMD_INQUIRY_SIZEOF;
-
- /* Format the CDB */
-
- inq = (FAR struct scscicmd_inquiry_s *)cbw->cdb;
- inq->opcode = SCSI_CMD_INQUIRY;
- usbhost_putbe16(inq->alloclen, SCSIRESP_INQUIRY_SIZEOF);
-
- usbhost_dumpcbw(cbw);
-}
-
-static inline void
-usbhost_readcbw (size_t startsector, uint16_t blocksize,
- unsigned int nsectors, FAR struct usbmsc_cbw_s *cbw)
-{
- FAR struct scsicmd_read10_s *rd10;
-
- /* Format the CBW */
-
- usbhost_putle32(cbw->datlen, blocksize * nsectors);
- cbw->flags = USBMSC_CBWFLAG_IN;
- cbw->cdblen = SCSICMD_READ10_SIZEOF;
-
- /* Format the CDB */
-
- rd10 = (FAR struct scsicmd_read10_s *)cbw->cdb;
- rd10->opcode = SCSI_CMD_READ10;
- usbhost_putbe32(rd10->lba, startsector);
- usbhost_putbe16(rd10->xfrlen, nsectors);
-
- usbhost_dumpcbw(cbw);
-}
-
-static inline void
-usbhost_writecbw(size_t startsector, uint16_t blocksize,
- unsigned int nsectors, FAR struct usbmsc_cbw_s *cbw)
-{
- FAR struct scsicmd_write10_s *wr10;
-
- /* Format the CBW */
-
- usbhost_putle32(cbw->datlen, blocksize * nsectors);
- cbw->cdblen = SCSICMD_WRITE10_SIZEOF;
-
- /* Format the CDB */
-
- wr10 = (FAR struct scsicmd_write10_s *)cbw->cdb;
- wr10->opcode = SCSI_CMD_WRITE10;
- usbhost_putbe32(wr10->lba, startsector);
- usbhost_putbe16(wr10->xfrlen, nsectors);
-
- usbhost_dumpcbw(cbw);
-}
-
-/****************************************************************************
- * Name: Command helpers
- *
- * Description:
- * The following functions are helper functions used to send commands.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline int usbhost_maxlunreq(FAR struct usbhost_state_s *priv)
-{
- FAR struct usb_ctrlreq_s *req = (FAR struct usb_ctrlreq_s *)priv->tbuffer;
- DEBUGASSERT(priv && priv->tbuffer);
- int ret;
-
- /* Request maximum logical unit number. NOTE: On an IN transaction, The
- * req and buffer pointers passed to DRVR_CTRLIN may refer to the same
- * allocated memory.
- */
-
- uvdbg("Request maximum logical unit number\n");
- memset(req, 0, sizeof(struct usb_ctrlreq_s));
- req->type = USB_DIR_IN|USB_REQ_TYPE_CLASS|USB_REQ_RECIPIENT_INTERFACE;
- req->req = USBMSC_REQ_GETMAXLUN;
- usbhost_putle16(req->len, 1);
-
- ret = DRVR_CTRLIN(priv->drvr, req, priv->tbuffer);
- if (ret != OK)
- {
- /* Devices that do not support multiple LUNs may stall this command.
- * On a failure, a single LUN is assumed.
- */
-
- *(priv->tbuffer) = 0;
- }
- return OK;
-}
-
-static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_cbw_s *cbw;
- int result;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (!cbw)
- {
- udbg("ERROR: Failed to create CBW\n");
- return -ENOMEM;
- }
-
- /* Construct and send the CBW */
-
- usbhost_testunitreadycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer);
- }
- }
-
- return result;
-}
-
-static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_cbw_s *cbw;
- int result;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (!cbw)
- {
- udbg("ERROR: Failed to create CBW\n");
- return -ENOMEM;
- }
-
- /* Construct and send the CBW */
-
- usbhost_requestsensecbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Receive the sense data response */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
- if (result == OK)
- {
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer);
- }
- }
- }
-
- return result;
-}
-
-static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_cbw_s *cbw;
- FAR struct scsiresp_readcapacity10_s *resp;
- int result;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (!cbw)
- {
- udbg("ERROR: Failed to create CBW\n");
- return -ENOMEM;
- }
-
- /* Construct and send the CBW */
-
- usbhost_readcapacitycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Receive the read capacity CBW IN response */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
- if (result == OK)
- {
- /* Save the capacity information */
-
- resp = (FAR struct scsiresp_readcapacity10_s *)priv->tbuffer;
- priv->nblocks = usbhost_getbe32(resp->lba) + 1;
- priv->blocksize = usbhost_getbe32(resp->blklen);
-
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer);
- }
- }
- }
-
- return result;
-}
-
-static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_cbw_s *cbw;
- FAR struct scsiresp_inquiry_s *resp;
- int result;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (!cbw)
- {
- udbg("ERROR: Failed to create CBW\n");
- return -ENOMEM;
- }
-
- /* Construct and send the CBW */
-
- usbhost_inquirycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Receive the CBW IN response */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- 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->tbuffer;
-
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer);
- }
- }
- }
-
- return result;
-}
-
-/****************************************************************************
- * Name: usbhost_destroy
- *
- * Description:
- * The USB mass storage device has been disconnected and the refernce count
- * on the USB host class instance has gone to 1.. Time to destroy the USB
- * host class instance.
- *
- * Input Parameters:
- * arg - A reference to the class instance to be destroyed.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_destroy(FAR void *arg)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
- char devname[DEV_NAMELEN];
-
- DEBUGASSERT(priv != NULL);
- uvdbg("crefs: %d\n", priv->crefs);
-
- /* Unregister the block driver */
-
- usbhost_mkdevname(priv, devname);
- (void)unregister_blockdriver(devname);
-
- /* Release the device name used by this connection */
-
- usbhost_freedevno(priv);
-
- /* Free the bulk endpoints */
-
- if (priv->bulkout)
- {
- DRVR_EPFREE(priv->drvr, priv->bulkout);
- }
-
- if (priv->bulkin)
- {
- DRVR_EPFREE(priv->drvr, priv->bulkin);
- }
-
- /* Free any transfer buffers */
-
- usbhost_tfree(priv);
-
- /* Destroy the semaphores */
-
- sem_destroy(&priv->exclsem);
-
- /* Disconnect the USB host device */
-
- DRVR_DISCONNECT(priv->drvr);
-
- /* And free the class instance. Hmmm.. this may execute on the worker
- * thread and the work structure is part of what is getting freed. That
- * should be okay because once the work contained is removed from the
- * queue, it should not longer be accessed by the worker thread.
- */
-
- usbhost_freeclass(priv);
-}
-
-/****************************************************************************
- * Name: usbhost_cfgdesc
- *
- * Description:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * priv - The USB host class instance.
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * Assumptions:
- * This function will *not* be called from an interrupt handler.
- *
- ****************************************************************************/
-
-static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usb_cfgdesc_s *cfgdesc;
- FAR struct usb_desc_s *desc;
- FAR struct usbhost_epdesc_s bindesc;
- FAR struct usbhost_epdesc_s boutdesc;
- int remaining;
- uint8_t found = 0;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Verify that we were passed a configuration descriptor */
-
- cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
- if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
- {
- return -EINVAL;
- }
-
- /* Get the total length of the configuration descriptor (little endian).
- * It might be a good check to get the number of interfaces here too.
- */
-
- remaining = (int)usbhost_getle16(cfgdesc->totallen);
-
- /* Skip to the next entry descriptor */
-
- configdesc += cfgdesc->len;
- remaining -= cfgdesc->len;
-
- /* Loop where there are more dscriptors to examine */
-
- while (remaining >= sizeof(struct usb_desc_s))
- {
- /* What is the next descriptor? */
-
- desc = (FAR struct usb_desc_s *)configdesc;
- switch (desc->type)
- {
- /* Interface descriptor. We really should get the number of endpoints
- * from this descriptor too.
- */
-
- case USB_DESC_TYPE_INTERFACE:
- {
- FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc;
-
- uvdbg("Interface descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
-
- /* Save the interface number and mark ONLY the interface found */
-
- priv->ifno = ifdesc->ifno;
- found = USBHOST_IFFOUND;
- }
- break;
-
- /* Endpoint descriptor. We expect two bulk endpoints, an IN and an
- * OUT.
- */
-
- case USB_DESC_TYPE_ENDPOINT:
- {
- FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc;
-
- uvdbg("Endpoint descriptor\n");
- DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
-
- /* Check for a bulk endpoint. We only support the bulk-only
- * protocol so I suppose anything else should really be an error.
- */
-
- if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK)
- {
- /* Yes.. it is a bulk endpoint. IN or OUT? */
-
- if (USB_ISEPOUT(epdesc->addr))
- {
- /* It is an OUT bulk endpoint. There should be only one
- * bulk OUT endpoint.
- */
-
- if ((found & USBHOST_BOUTFOUND) != 0)
- {
- /* Oops.. more than one endpoint. We don't know
- * what to do with this.
- */
-
- return -EINVAL;
- }
- found |= USBHOST_BOUTFOUND;
-
- /* Save the bulk OUT endpoint information */
-
- boutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- boutdesc.in = false;
- boutdesc.funcaddr = funcaddr;
- boutdesc.xfrtype = USB_EP_ATTR_XFER_BULK;
- boutdesc.interval = epdesc->interval;
- boutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n",
- boutdesc.addr, boutdesc.mxpacketsize);
- }
- else
- {
- /* It is an IN bulk endpoint. There should be only one
- * bulk IN endpoint.
- */
-
- if ((found & USBHOST_BINFOUND) != 0)
- {
- /* Oops.. more than one endpoint. We don't know
- * what to do with this.
- */
-
- return -EINVAL;
- }
- found |= USBHOST_BINFOUND;
-
- /* Save the bulk IN endpoint information */
-
- bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- bindesc.in = 1;
- bindesc.funcaddr = funcaddr;
- bindesc.xfrtype = USB_EP_ATTR_XFER_BULK;
- bindesc.interval = epdesc->interval;
- bindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n",
- bindesc.addr, bindesc.mxpacketsize);
- }
- }
- }
- break;
-
- /* Other descriptors are just ignored for now */
-
- default:
- break;
- }
-
- /* If we found everything we need with this interface, then break out
- * of the loop early.
- */
-
- if (found == USBHOST_ALLFOUND)
- {
- break;
- }
-
- /* Increment the address of the next descriptor */
-
- configdesc += desc->len;
- remaining -= desc->len;
- }
-
- /* Sanity checking... did we find all of things that we need? Hmmm.. I wonder..
- * can we work read-only or write-only if only one bulk endpoint found?
- */
-
- if (found != USBHOST_ALLFOUND)
- {
- ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
- (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
- return -EINVAL;
- }
-
- /* We are good... Allocate the endpoints */
-
- ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->bulkout);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate Bulk OUT endpoint\n");
- return ret;
- }
-
- ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->bulkin);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate Bulk IN endpoint\n");
- (void)DRVR_EPFREE(priv->drvr, priv->bulkout);
- return ret;
- }
-
- ullvdbg("Endpoints allocated\n");
- return OK;
-}
-
-/****************************************************************************
- * Name: usbhost_initvolume
- *
- * Description:
- * The USB mass storage device has been successfully connected. This
- * completes the initialization operations. It is first called after the
- * configuration descriptor has been received.
- *
- * This function is called from the connect() method. This function always
- * executes on the thread of the caller of connect().
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_csw_s *csw;
- unsigned int retries;
- int ret = OK;
-
- DEBUGASSERT(priv != NULL);
-
- /* Set aside a transfer buffer for exclusive use by the mass storage driver */
-
- ret = usbhost_talloc(priv);
- if (ret != OK)
- {
- udbg("ERROR: Failed to allocate transfer buffer\n");
- return ret;
- }
-
- /* Increment the reference count. This will prevent usbhost_destroy() from
- * being called asynchronously if the device is removed.
- */
-
- priv->crefs++;
- DEBUGASSERT(priv->crefs == 2);
-
- /* Request the maximum logical unit number */
-
- uvdbg("Get max LUN\n");
- ret = usbhost_maxlunreq(priv);
-
- for (retries = 0; retries < USBHOST_MAX_RETRIES /* && ret == OK */; retries++)
- {
- uvdbg("Test unit ready, retries=%d\n", retries);
-
- /* Wait just a bit */
-
- usleep(50*1000);
-
- /* Send TESTUNITREADY to see if the unit is ready */
-
- ret = usbhost_testunitready(priv);
- if (ret == OK)
- {
- /* Is the unit is ready */
-
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status == 0)
- {
- /* Yes... break out of the loop */
-
- break;
- }
-
- /* No.. Request mode sense information. The REQUEST SENSE command
- * is sent only "to clear interlocked unit attention conditions."
- * The returned status is ignored here.
- */
-
- uvdbg("Request sense\n");
- ret = usbhost_requestsense(priv);
- }
- }
-
- /* Did the unit become ready? Did an error occur? Or did we time out? */
-
- if (retries >= USBHOST_MAX_RETRIES)
- {
- udbg("ERROR: Timeout!\n");
- ret = -ETIMEDOUT;
- }
-
- if (ret == OK)
- {
- /* Get the capacity of the volume */
-
- uvdbg("Read capacity\n");
- ret = usbhost_readcapacity(priv);
- if (ret == OK)
- {
- /* Check the CSW for errors */
-
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status != 0)
- {
- udbg("ERROR: CSW status error: %d\n", csw->status);
- ret = -ENODEV;
- }
- }
- }
-
- /* Get information about the volume */
-
- if (ret == OK)
- {
- /* Inquiry */
-
- uvdbg("Inquiry\n");
- ret = usbhost_inquiry(priv);
- if (ret == OK)
- {
- /* Check the CSW for errors */
-
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status != 0)
- {
- udbg("ERROR: CSW status error: %d\n", csw->status);
- ret = -ENODEV;
- }
- }
- }
-
- /* Register the block driver */
-
- if (ret == OK)
- {
- char devname[DEV_NAMELEN];
-
- uvdbg("Register block driver\n");
- usbhost_mkdevname(priv, devname);
- ret = register_blockdriver(devname, &g_bops, 0, priv);
- }
-
- /* Check if we successfully initialized. We now have to be concerned
- * about asynchronous modification of crefs because the block
- * driver has been registerd.
- */
-
- if (ret == OK)
- {
- usbhost_takesem(&priv->exclsem);
- DEBUGASSERT(priv->crefs >= 2);
-
- /* Decrement the reference count */
-
- priv->crefs--;
-
- /* Handle a corner case where (1) open() has been called so the
- * reference count was > 2, but the device has been disconnected.
- * In this case, the class instance needs to persist until close()
- * is called.
- */
-
- if (priv->crefs <= 1 && priv->disconnected)
- {
- /* The will cause the enumeration logic to disconnect
- * the class driver.
- */
-
- ret = -ENODEV;
- }
-
- /* Release the semaphore... there is a race condition here.
- * Decrementing the reference count and releasing the semaphore
- * allows usbhost_destroy() to execute (on the worker thread);
- * the class driver instance could get destoryed before we are
- * ready to handle it!
- */
-
- usbhost_givesem(&priv->exclsem);
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_getle16
- *
- * Description:
- * Get a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * val - A pointer to the first byte of the little endian value.
- *
- * Returned Values:
- * A uint16_t representing the whole 16-bit integer value
- *
- ****************************************************************************/
-
-static inline uint16_t usbhost_getle16(const uint8_t *val)
-{
- return (uint16_t)val[1] << 8 | (uint16_t)val[0];
-}
-
-/****************************************************************************
- * Name: usbhost_getbe16
- *
- * Description:
- * Get a (possibly unaligned) 16-bit big endian value.
- *
- * Input Parameters:
- * val - A pointer to the first byte of the big endian value.
- *
- * Returned Values:
- * A uint16_t representing the whole 16-bit integer value
- *
- ****************************************************************************/
-
-static inline uint16_t usbhost_getbe16(const uint8_t *val)
-{
- return (uint16_t)val[0] << 8 | (uint16_t)val[1];
-}
-
-/****************************************************************************
- * Name: usbhost_putle16
- *
- * Description:
- * Put a (possibly unaligned) 16-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 16-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putle16(uint8_t *dest, uint16_t val)
-{
- dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
- dest[1] = val >> 8;
-}
-
-/****************************************************************************
- * Name: usbhost_putbe16
- *
- * Description:
- * Put a (possibly unaligned) 16-bit big endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 16-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putbe16(uint8_t *dest, uint16_t val)
-{
- dest[0] = val >> 8; /* Big endian means MS byte first in byte stream */
- dest[1] = val & 0xff;
-}
-
-/****************************************************************************
- * Name: usbhost_getle32
- *
- * Description:
- * Get a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline uint32_t usbhost_getle32(const uint8_t *val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- return (uint32_t)usbhost_getle16(&val[2]) << 16 | (uint32_t)usbhost_getle16(val);
-}
-
-/****************************************************************************
- * Name: usbhost_getbe32
- *
- * Description:
- * Get a (possibly unaligned) 32-bit big endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static inline uint32_t usbhost_getbe32(const uint8_t *val)
-{
- /* Big endian means MS halfword first in byte stream */
-
- return (uint32_t)usbhost_getbe16(val) << 16 | (uint32_t)usbhost_getbe16(&val[2]);
-}
-
-/****************************************************************************
- * Name: usbhost_putle32
- *
- * Description:
- * Put a (possibly unaligned) 32-bit little endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the little endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putle32(uint8_t *dest, uint32_t val)
-{
- /* Little endian means LS halfword first in byte stream */
-
- usbhost_putle16(dest, (uint16_t)(val & 0xffff));
- usbhost_putle16(dest+2, (uint16_t)(val >> 16));
-}
-
-/****************************************************************************
- * Name: usbhost_putbe32
- *
- * Description:
- * Put a (possibly unaligned) 32-bit big endian value.
- *
- * Input Parameters:
- * dest - A pointer to the first byte to save the big endian value.
- * val - The 32-bit value to be saved.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_putbe32(uint8_t *dest, uint32_t val)
-{
- /* Big endian means MS halfword first in byte stream */
-
- usbhost_putbe16(dest, (uint16_t)(val >> 16));
- usbhost_putbe16(dest+2, (uint16_t)(val & 0xffff));
-}
-
-/****************************************************************************
- * Name: usbhost_talloc
- *
- * Description:
- * Allocate transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_talloc(FAR struct usbhost_state_s *priv)
-{
- DEBUGASSERT(priv && priv->tbuffer == NULL);
- return DRVR_ALLOC(priv->drvr, &priv->tbuffer, &priv->tbuflen);
-}
-
-/****************************************************************************
- * Name: usbhost_tfree
- *
- * Description:
- * Free transfer buffer memory.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * On sucess, zero (OK) is returned. On failure, an negated errno value
- * is returned to indicate the nature of the failure.
- *
- ****************************************************************************/
-
-static inline int usbhost_tfree(FAR struct usbhost_state_s *priv)
-{
- int result = OK;
- DEBUGASSERT(priv);
-
- if (priv->tbuffer)
- {
- DEBUGASSERT(priv->drvr);
- result = DRVR_FREE(priv->drvr, priv->tbuffer);
- priv->tbuffer = NULL;
- priv->tbuflen = 0;
- }
- return result;
-}
-
-/****************************************************************************
- * Name: usbhost_cbwalloc
- *
- * Description:
- * Initialize a CBW (re-using the allocated transfer buffer). Upon
- * successful return, the CBW is cleared and has the CBW signature in place.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv)
-{
- FAR struct usbmsc_cbw_s *cbw = NULL;
-
- DEBUGASSERT(priv->tbuffer && priv->tbuflen >= sizeof(struct usbmsc_cbw_s))
-
- /* Intialize the CBW sructure */
-
- cbw = (FAR struct usbmsc_cbw_s *)priv->tbuffer;
- memset(cbw, 0, sizeof(struct usbmsc_cbw_s));
- usbhost_putle32(cbw->signature, USBMSC_CBW_SIGNATURE);
- return cbw;
-}
-
-/****************************************************************************
- * struct usbhost_registry_s methods
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_create
- *
- * Description:
- * This function implements the create() method of struct usbhost_registry_s.
- * The create() method is a callback into the class implementation. It is
- * used to (1) create a new instance of the USB host class state and to (2)
- * bind a USB host driver "session" to the class instance. Use of this
- * create() method will support environments where there may be multiple
- * USB ports and multiple USB devices simultaneously connected.
- *
- * Input Parameters:
- * drvr - An instance of struct usbhost_driver_s that the class
- * implementation will "bind" to its state structure and will
- * subsequently use to communicate with the USB host driver.
- * id - In the case where the device supports multiple base classes,
- * subclasses, or protocols, this specifies which to configure for.
- *
- * Returned Values:
- * On success, this function will return a non-NULL instance of struct
- * usbhost_class_s that can be used by the USB host driver to communicate
- * with the USB host class. NULL is returned on failure; this function
- * will fail only if the drvr input parameter is NULL or if there are
- * insufficient resources to create another USB host class instance.
- *
- ****************************************************************************/
-
-static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
- FAR const struct usbhost_id_s *id)
-{
- FAR struct usbhost_state_s *priv;
-
- /* Allocate a USB host mass storage class instance */
-
- priv = usbhost_allocclass();
- if (priv)
- {
- /* Initialize the allocated storage class instance */
-
- memset(priv, 0, sizeof(struct usbhost_state_s));
-
- /* Assign a device number to this class instance */
-
- if (usbhost_allocdevno(priv) == OK)
- {
- /* Initialize class method function pointers */
-
- priv->class.connect = usbhost_connect;
- priv->class.disconnected = usbhost_disconnected;
-
- /* The initial reference count is 1... One reference is held by the driver */
-
- priv->crefs = 1;
-
- /* Initialize semphores (this works okay in the interrupt context) */
-
- sem_init(&priv->exclsem, 0, 1);
-
- /* Bind the driver to the storage class instance */
-
- 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 &priv->class;
- }
- }
-
- /* An error occurred. Free the allocation and return NULL on all failures */
-
- if (priv)
- {
- usbhost_freeclass(priv);
- }
- return NULL;
-}
-
-/****************************************************************************
- * struct usbhost_class_s methods
- ****************************************************************************/
-/****************************************************************************
- * Name: usbhost_connect
- *
- * Description:
- * This function implements the connect() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to provide the device's configuration
- * descriptor to the class so that the class may initialize properly
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to create().
- * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
- * desclen - The length in bytes of the configuration descriptor.
- * funcaddr - The USB address of the function containing the endpoint that EP0
- * controls
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
- *
- * NOTE that the class instance remains valid upon return with a failure. It is
- * the responsibility of the higher level enumeration logic to call
- * CLASS_DISCONNECTED to free up the class driver resources.
- *
- * Assumptions:
- * - This function will *not* be called from an interrupt handler.
- * - If this function returns an error, the USB host controller driver
- * must call to DISCONNECTED method to recover from the error
- *
- ****************************************************************************/
-
-static int usbhost_connect(FAR struct usbhost_class_s *class,
- FAR const uint8_t *configdesc, int desclen,
- uint8_t funcaddr)
-{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
- int ret;
-
- DEBUGASSERT(priv != NULL &&
- configdesc != NULL &&
- desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Parse the configuration descriptor to get the bulk I/O endpoints */
-
- ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr);
- if (ret != OK)
- {
- udbg("usbhost_cfgdesc() failed: %d\n", ret);
- }
- else
- {
- /* Now configure the LUNs and register the block driver(s) */
-
- ret = usbhost_initvolume(priv);
- if (ret != OK)
- {
- udbg("usbhost_initvolume() failed: %d\n", ret);
- }
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_disconnected
- *
- * Description:
- * This function implements the disconnected() method of struct
- * usbhost_class_s. This method is a callback into the class
- * implementation. It is used to inform the class that the USB device has
- * been disconnected.
- *
- * Input Parameters:
- * class - The USB host class entry previously obtained from a call to
- * create().
- *
- * Returned Values:
- * On success, zero (OK) is returned. On a failure, a negated errno value
- * is returned indicating the nature of the failure
- *
- * Assumptions:
- * This function may be called from an interrupt handler.
- *
- ****************************************************************************/
-
-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
- * is no longer available.
- */
-
- flags = irqsave();
- priv->disconnected = true;
-
- /* 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
- * block driver.
- */
-
- 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);
- DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
- }
- else
- {
- /* Do the work now */
-
- usbhost_destroy(priv);
- }
- }
-
- irqrestore(flags);
- return OK;
-}
-
-/****************************************************************************
- * struct block_operations methods
- ****************************************************************************/
-/****************************************************************************
- * Name: usbhost_open
- *
- * Description: Open the block device
- *
- ****************************************************************************/
-
-static int usbhost_open(FAR struct inode *inode)
-{
- FAR struct usbhost_state_s *priv;
- irqstate_t flags;
- int ret;
-
- uvdbg("Entry\n");
- DEBUGASSERT(inode && inode->i_private);
- priv = (FAR struct usbhost_state_s *)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 mass storage 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 block 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: close the block device
- *
- ****************************************************************************/
-
-static int usbhost_close(FAR struct inode *inode)
-{
- FAR struct usbhost_state_s *priv;
- irqstate_t flags;
-
- uvdbg("Entry\n");
- DEBUGASSERT(inode && inode->i_private);
- priv = (FAR struct usbhost_state_s *)inode->i_private;
-
- /* Decrement the reference count on the block 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 block 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 mass storage device is still connected. If the
- * storage device is not connected and the reference count just
- * decremented to one, then unregister the block driver and free
- * the class instance.
- */
-
- if (priv->crefs <= 1 && priv->disconnected)
- {
- /* Destroy the class instance */
-
- DEBUGASSERT(priv->crefs == 1);
- usbhost_destroy(priv);
- }
-
- irqrestore(flags);
- return OK;
-}
-
-/****************************************************************************
- * Name: usbhost_read
- *
- * Description:
- * Read the specified numer of sectors from the read-ahead buffer or from
- * the physical device.
- *
- ****************************************************************************/
-
-static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
- size_t startsector, unsigned int nsectors)
-{
- FAR struct usbhost_state_s *priv;
- ssize_t ret = 0;
- int result;
-
- DEBUGASSERT(inode && inode->i_private);
- priv = (FAR struct usbhost_state_s *)inode->i_private;
- uvdbg("startsector: %d nsectors: %d sectorsize: %d\n",
- startsector, nsectors, priv->blocksize);
-
- /* Check if the mass storage device is still connected */
-
- if (priv->disconnected)
- {
- /* No... the block driver is no longer bound to the class. That means that
- * the USB storage device is no longer connected. Refuse any attempt to read
- * from the device.
- */
-
- ret = -ENODEV;
- }
- else if (nsectors > 0)
- {
- FAR struct usbmsc_cbw_s *cbw;
-
- usbhost_takesem(&priv->exclsem);
-
- /* Assume allocation failure */
-
- ret = -ENOMEM;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (cbw)
- {
- /* Loop in the event that EAGAIN is returned (mean that the
- * transaction was NAKed and we should try again.
- */
-
- do
- {
- /* Assume some device failure */
-
- ret = -ENODEV;
-
- /* Construct and send the CBW */
-
- usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Receive the user data */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- buffer, priv->blocksize * nsectors);
- if (result == OK)
- {
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- FAR struct usbmsc_csw_s *csw;
-
- /* Check the CSW status */
-
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status == 0)
- {
- ret = nsectors;
- }
- }
- }
- }
- } while (result == -EAGAIN);
- }
-
- usbhost_givesem(&priv->exclsem);
- }
-
- /* On success, return the number of blocks read */
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_write
- *
- * Description:
- * Write the specified number of sectors to the write buffer or to the
- * physical device.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_FS_WRITABLE
-static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffer,
- size_t startsector, unsigned int nsectors)
-{
- FAR struct usbhost_state_s *priv;
- ssize_t ret;
- int result;
-
- uvdbg("sector: %d nsectors: %d sectorsize: %d\n");
- DEBUGASSERT(inode && inode->i_private);
- priv = (FAR struct usbhost_state_s *)inode->i_private;
-
- /* Check if the mass storage device is still connected */
-
- if (priv->disconnected)
- {
- /* No... the block driver is no longer bound to the class. That means that
- * the USB storage device is no longer connected. Refuse any attempt to
- * write to the device.
- */
-
- ret = -ENODEV;
- }
- else
- {
- FAR struct usbmsc_cbw_s *cbw;
-
- usbhost_takesem(&priv->exclsem);
-
- /* Assume allocation failure */
-
- ret = -ENOMEM;
-
- /* Initialize a CBW (re-using the allocated transfer buffer) */
-
- cbw = usbhost_cbwalloc(priv);
- if (cbw)
- {
- /* Assume some device failure */
-
- ret = -ENODEV;
-
- /* Construct and send the CBW */
-
- usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
- {
- /* Send the user data */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)buffer, priv->blocksize * nsectors);
- if (result == OK)
- {
- /* Receive the CSW */
-
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
- if (result == OK)
- {
- FAR struct usbmsc_csw_s *csw;
-
- /* Check the CSW status */
-
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status == 0)
- {
- ret = nsectors;
- }
- }
- }
- }
- }
-
- usbhost_givesem(&priv->exclsem);
- }
-
- /* On success, return the number of blocks written */
-
- return ret;
-}
-#endif
-
-/****************************************************************************
- * Name: usbhost_geometry
- *
- * Description: Return device geometry
- *
- ****************************************************************************/
-
-static int usbhost_geometry(FAR struct inode *inode, struct geometry *geometry)
-{
- FAR struct usbhost_state_s *priv;
- int ret = -EINVAL;
-
- uvdbg("Entry\n");
- DEBUGASSERT(inode && inode->i_private);
-
- /* Check if the mass storage device is still connected */
-
- priv = (FAR struct usbhost_state_s *)inode->i_private;
- if (priv->disconnected)
- {
- /* No... the block driver is no longer bound to the class. That means that
- * the USB storage device is no longer connected. Refuse to return any
- * geometry info.
- */
-
- ret = -ENODEV;
- }
- else if (geometry)
- {
- /* Return the geometry of the USB mass storage device */
-
- usbhost_takesem(&priv->exclsem);
-
- geometry->geo_available = true;
- geometry->geo_mediachanged = false;
-#ifdef CONFIG_FS_WRITABLE
- geometry->geo_writeenabled = true;
-#else
- geometry->geo_writeenabled = false;
-#endif
- geometry->geo_nsectors = priv->nblocks;
- geometry->geo_sectorsize = priv->blocksize;
- usbhost_givesem(&priv->exclsem);
-
- uvdbg("nsectors: %ld sectorsize: %d\n",
- (long)geometry->geo_nsectors, geometry->geo_sectorsize);
-
- ret = OK;
- }
-
- return ret;
-}
-
-/****************************************************************************
- * Name: usbhost_ioctl
- *
- * Description: Return device geometry
- *
- ****************************************************************************/
-
-static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
-{
- FAR struct usbhost_state_s *priv;
- int ret;
-
- uvdbg("Entry\n");
- DEBUGASSERT(inode && inode->i_private);
- priv = (FAR struct usbhost_state_s *)inode->i_private;
-
- /* Check if the mass storage device is still connected */
-
- if (priv->disconnected)
- {
- /* No... the block driver is no longer bound to the class. That means that
- * the USB storage device is no longer connected. Refuse to process any
- * ioctl commands.
- */
-
- ret = -ENODEV;
- }
- else
- {
- /* Process the IOCTL by command */
-
- usbhost_takesem(&priv->exclsem);
- switch (cmd)
- {
- /* Add support for ioctl commands here */
-
- default:
- ret = -ENOTTY;
- break;
- }
- usbhost_givesem(&priv->exclsem);
- }
- return ret;
-}
-
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Name: usbhost_storageinit
- *
- * Description:
- * Initialize the USB host storage class. This function should be called
- * be platform-specific code in order to initialize and register support
- * for the USB host storage class.
- *
- * Input Parameters:
- * None
- *
- * Returned Values:
- * On success this function will return zero (OK); A negated errno value
- * will be returned on failure.
- *
- ****************************************************************************/
-
-int usbhost_storageinit(void)
-{
- /* If we have been configured to use pre-allocated storage class instances,
- * then place all of the pre-allocated USB host storage class instances
- * into a free list.
- */
-
-#if CONFIG_USBHOST_NPREALLOC > 0
- int i;
-
- g_freelist = NULL;
- for (i = 0; i < CONFIG_USBHOST_NPREALLOC; i++)
- {
- struct usbhost_state_s *class = &g_prealloc[i];
- class->class.flink = g_freelist;
- g_freelist = class;
- }
-#endif
-
- /* Advertise our availability to support (certain) mass storage devices */
-
- return usbhost_registerclass(&g_storage);
-}
-
-#endif /* CONFIG_USBHOST && !CONFIG_USBHOST_BULK_DISABLE && !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 */