diff options
Diffstat (limited to 'nuttx/drivers/usbdev/usbmsc.c')
-rw-r--r-- | nuttx/drivers/usbdev/usbmsc.c | 1778 |
1 files changed, 0 insertions, 1778 deletions
diff --git a/nuttx/drivers/usbdev/usbmsc.c b/nuttx/drivers/usbdev/usbmsc.c deleted file mode 100644 index 68b61814a..000000000 --- a/nuttx/drivers/usbdev/usbmsc.c +++ /dev/null @@ -1,1778 +0,0 @@ -/**************************************************************************** - * drivers/usbdev/usbmsc.c - * - * Copyright (C) 2008-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * Mass storage class device. Bulk-only with SCSI subclass. - * - * References: - * "Universal Serial Bus Mass Storage Class, Specification Overview," - * Revision 1.2, USB Implementer's Forum, June 23, 2003. - * - * "Universal Serial Bus Mass Storage Class, Bulk-Only Transport," - * Revision 1.0, USB Implementer's Forum, September 31, 1999. - * - * "SCSI Primary Commands - 3 (SPC-3)," American National Standard - * for Information Technology, May 4, 2005 - * - * "SCSI Primary Commands - 4 (SPC-4)," American National Standard - * for Information Technology, July 19, 2008 - * - * "SCSI Block Commands -2 (SBC-2)," American National Standard - * for Information Technology, November 13, 2004 - * - * "SCSI Multimedia Commands - 3 (MMC-3)," American National Standard - * for Information Technology, November 12, 2001 - * - * 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 <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <pthread.h> -#include <string.h> -#include <errno.h> -#include <queue.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/arch.h> -#include <nuttx/fs/fs.h> -#include <nuttx/usb/usb.h> -#include <nuttx/usb/storage.h> -#include <nuttx/usb/usbdev.h> -#include <nuttx/usb/usbdev_trace.h> - -#include "usbmsc.h" - -#ifdef CONFIG_USBMSC_COMPOSITE -# include <nuttx/usb/composite.h> -# include "composite.h" -#endif - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* The internal version of the class driver */ - -struct usbmsc_driver_s -{ - struct usbdevclass_driver_s drvr; - FAR struct usbmsc_dev_s *dev; -}; - -/* This is what is allocated */ - -struct usbmsc_alloc_s -{ - struct usbmsc_dev_s dev; - struct usbmsc_driver_s drvr; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Class Driver Support *****************************************************/ - -static void usbmsc_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); -static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len); -static void usbmsc_freereq(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req); - -/* Class Driver Operations (most at interrupt level) ************************/ - -static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); -static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout, - size_t outlen); -static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev); - -/* Initialization/Uninitialization ******************************************/ - -static void usbmsc_lununinitialize(struct usbmsc_lun_s *lun); -#ifdef CONFIG_USBMSC_COMPOSITE -static int usbmsc_exportluns(FAR void *handle); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* Driver operations ********************************************************/ - -static struct usbdevclass_driverops_s g_driverops = -{ - usbmsc_bind, /* bind */ - usbmsc_unbind, /* unbind */ - usbmsc_setup, /* setup */ - usbmsc_disconnect, /* disconnect */ - NULL, /* suspend */ - NULL /* resume */ -}; - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Class Driver Support - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_ep0incomplete - * - * Description: - * Handle completion of EP0 control operations - * - ****************************************************************************/ - -static void usbmsc_ep0incomplete(FAR struct usbdev_ep_s *ep, - FAR struct usbdev_req_s *req) -{ - if (req->result || req->xfrd != req->len) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_REQRESULT), - (uint16_t)-req->result); - } -} - -/**************************************************************************** - * Name: usbmsc_allocreq - * - * Description: - * Allocate a request instance along with its buffer - * - ****************************************************************************/ - -static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep, - uint16_t len) -{ - FAR struct usbdev_req_s *req; - - req = EP_ALLOCREQ(ep); - if (req != NULL) - { - req->len = len; - req->buf = EP_ALLOCBUFFER(ep, len); - if (!req->buf) - { - EP_FREEREQ(ep, req); - req = NULL; - } - } - return req; -} - -/**************************************************************************** - * Name: usbmsc_freereq - * - * Description: - * Free a request instance along with its buffer - * - ****************************************************************************/ - -static void usbmsc_freereq(FAR struct usbdev_ep_s *ep, struct usbdev_req_s *req) -{ - if (ep != NULL && req != NULL) - { - if (req->buf != NULL) - { - EP_FREEBUFFER(ep, req->buf); - } - EP_FREEREQ(ep, req); - } -} - -/**************************************************************************** - * Class Driver Interfaces - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_bind - * - * Description: - * Invoked when the driver is bound to a USB device driver - * - ****************************************************************************/ - -static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct usbmsc_dev_s *priv = ((FAR struct usbmsc_driver_s*)driver)->dev; - FAR struct usbmsc_req_s *reqcontainer; - irqstate_t flags; - int ret = OK; - int i; - - usbtrace(TRACE_CLASSBIND, 0); - - /* Bind the structures */ - - priv->usbdev = dev; - - /* Save the reference to our private data structure in EP0 so that it - * can be recovered in ep0 completion events (Unless we are part of - * a composite device and, in that case, the composite device owns - * EP0). - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - dev->ep0->priv = priv; -#endif - - /* The configured EP0 size should match the reported EP0 size. We could - * easily adapt to the reported EP0 size, but then we could not use the - * const, canned descriptors. - */ - - DEBUGASSERT(CONFIG_USBMSC_EP0MAXPACKET == dev->ep0->maxpacket); - - /* Preallocate control request */ - - priv->ctrlreq = usbmsc_allocreq(dev->ep0, USBMSC_MXDESCLEN); - if (priv->ctrlreq == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCCTRLREQ), 0); - ret = -ENOMEM; - goto errout; - } - priv->ctrlreq->callback = usbmsc_ep0incomplete; - - /* Pre-allocate all endpoints... the endpoints will not be functional - * until the SET CONFIGURATION request is processed in usbmsc_setconfig. - * This is done here because there may be calls to kmalloc and the SET - * CONFIGURATION processing probably occurrs within interrupt handling - * logic where kmalloc calls will fail. - */ - - /* Pre-allocate the IN bulk endpoint */ - - priv->epbulkin = DEV_ALLOCEP(dev, USBMSC_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkin) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkin->priv = priv; - - /* Pre-allocate the OUT bulk endpoint */ - - priv->epbulkout = DEV_ALLOCEP(dev, USBMSC_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK); - if (!priv->epbulkout) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTALLOCFAIL), 0); - ret = -ENODEV; - goto errout; - } - priv->epbulkout->priv = priv; - - /* Pre-allocate read requests */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkout, CONFIG_USBMSC_BULKOUTREQLEN); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDALLOCREQ), - (uint16_t)-ret); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbmsc_rdcomplete; - } - - /* Pre-allocate write request containers and put in a free list */ - - for (i = 0; i < CONFIG_USBMSC_NWRREQS; i++) - { - reqcontainer = &priv->wrreqs[i]; - reqcontainer->req = usbmsc_allocreq(priv->epbulkin, CONFIG_USBMSC_BULKINREQLEN); - if (reqcontainer->req == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRALLOCREQ), - (uint16_t)-ret); - ret = -ENOMEM; - goto errout; - } - reqcontainer->req->priv = reqcontainer; - reqcontainer->req->callback = usbmsc_wrcomplete; - - flags = irqsave(); - sq_addlast((sq_entry_t*)reqcontainer, &priv->wrreqlist); - irqrestore(flags); - } - - /* Report if we are selfpowered (unless we are part of a composite device) */ - -#ifndef CONFIG_USBMSC_COMPOSITE -#ifdef CONFIG_USBDEV_SELFPOWERED - DEV_SETSELFPOWERED(dev); -#endif - - /* And pull-up the data line for the soft connect function (unless we are - * part of a composite device) - */ - - DEV_CONNECT(dev); -#endif - return OK; - -errout: - usbmsc_unbind(driver, dev); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_unbind - * - * Description: - * Invoked when the driver is unbound from a USB device driver - * - ****************************************************************************/ - -static void usbmsc_unbind(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *reqcontainer; - irqstate_t flags; - int i; - - usbtrace(TRACE_CLASSUNBIND, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDINVALIDARGS), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct usbmsc_driver_s*)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND1), 0); - return; - } -#endif - - /* The worker thread should have already been stopped by the - * driver un-initialize logic. - */ - - DEBUGASSERT(priv->thstate == USBMSC_STATE_TERMINATED); - - /* Make sure that we are not already unbound */ - - if (priv != NULL) - { - /* Make sure that the endpoints have been unconfigured. If - * we were terminated gracefully, then the configuration should - * already have been reset. If not, then calling usbmsc_resetconfig - * should cause the endpoints to immediately terminate all - * transfers and return the requests to us (with result == -ESHUTDOWN) - */ - - usbmsc_resetconfig(priv); - up_mdelay(50); - - /* Free the pre-allocated control request */ - - if (priv->ctrlreq != NULL) - { - usbmsc_freereq(dev->ep0, priv->ctrlreq); - priv->ctrlreq = NULL; - } - - /* Free pre-allocated read requests (which should all have - * been returned to the free list at this time -- we don't check) - */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - reqcontainer = &priv->rdreqs[i]; - if (reqcontainer->req) - { - usbmsc_freereq(priv->epbulkout, reqcontainer->req); - reqcontainer->req = NULL; - } - } - - /* Free the bulk OUT endpoint */ - - if (priv->epbulkout) - { - DEV_FREEEP(dev, priv->epbulkout); - priv->epbulkout = NULL; - } - - /* Free write requests that are not in use (which should be all - * of them - */ - - flags = irqsave(); - while (!sq_empty(&priv->wrreqlist)) - { - reqcontainer = (struct usbmsc_req_s *)sq_remfirst(&priv->wrreqlist); - if (reqcontainer->req != NULL) - { - usbmsc_freereq(priv->epbulkin, reqcontainer->req); - } - } - - /* Free the bulk IN endpoint */ - - if (priv->epbulkin) - { - DEV_FREEEP(dev, priv->epbulkin); - priv->epbulkin = NULL; - } - - irqrestore(flags); - } -} - -/**************************************************************************** - * Name: usbmsc_setup - * - * Description: - * Invoked for ep0 control requests. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev, - FAR const struct usb_ctrlreq_s *ctrl, - FAR uint8_t *dataout, size_t outlen) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbdev_req_s *ctrlreq; - uint16_t value; - uint16_t index; - uint16_t len; - int ret = -EOPNOTSUPP; - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0 || !ctrl) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETUPINVALIDARGS), 0); - return -EIO; - } -#endif - - /* Extract reference to private data */ - - usbtrace(TRACE_CLASSSETUP, ctrl->req); - priv = ((FAR struct usbmsc_driver_s *)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND2), 0); - return -ENODEV; - } -#endif - ctrlreq = priv->ctrlreq; - - /* Extract the little-endian 16-bit values to host order */ - - value = GETUINT16(ctrl->value); - index = GETUINT16(ctrl->index); - len = GETUINT16(ctrl->len); - - uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n", - ctrl->type, ctrl->req, value, index, len); - - if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD) - { - /********************************************************************** - * Standard Requests - **********************************************************************/ - - switch (ctrl->req) - { - case USB_REQ_GETDESCRIPTOR: - { - /* The value field specifies the descriptor type in the MS byte and the - * descriptor index in the LS byte (order is little endian) - */ - - switch (ctrl->value[1]) - { - /* If the mass storage device is used in as part of a composite - * device, then the device descriptor is is provided by logic - * in the composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_DEVICE: - { - ret = USB_SIZEOF_DEVDESC; - memcpy(ctrlreq->buf, usbmsc_getdevdesc(), ret); - } - break; -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the device qualifier descriptor is provided by logic in the - * composite device implementation. - */ - -#if !defined(CONFIG_USBMSC_COMPOSITE) && defined(CONFIG_USBDEV_DUALSPEED) - case USB_DESC_TYPE_DEVICEQUALIFIER: - { - ret = USB_SIZEOF_QUALDESC; - memcpy(ctrlreq->buf, usbmsc_getqualdesc(), ret); - } - break; - - case USB_DESC_TYPE_OTHERSPEEDCONFIG: -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the configuration descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_CONFIG: - { -#ifdef CONFIG_USBDEV_DUALSPEED - ret = usbmsc_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->value[1]); -#else - ret = usbmsc_mkcfgdesc(ctrlreq->buf); -#endif - } - break; -#endif - - /* If the mass storage device is used in as part of a composite device, - * then the language string descriptor is provided by logic in the - * composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_DESC_TYPE_STRING: - { - /* index == language code. */ - - ret = usbmsc_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf); - } - break; -#endif - - default: - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETUNKNOWNDESC), value); - } - break; - } - } - break; - - case USB_REQ_SETCONFIGURATION: - { - if (ctrl->type == 0) - { - /* Signal the worker thread to instantiate the new configuration */ - - priv->theventset |= USBMSC_EVENT_CFGCHANGE; - priv->thvalue = value; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - break; - - /* If the mass storage device is used in as part of a composite device, - * then the overall composite class configuration is managed by logic - * in the composite device implementation. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - case USB_REQ_GETCONFIGURATION: - { - if (ctrl->type == USB_DIR_IN) - { - ctrlreq->buf[0] = priv->config; - ret = 1; - } - } - break; -#endif - - case USB_REQ_SETINTERFACE: - { - if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE) - { - if (priv->config == USBMSC_CONFIGID && - index == USBMSC_INTERFACEID && - value == USBMSC_ALTINTERFACEID) - { - /* Signal to instantiate the interface change */ - - priv->theventset |= USBMSC_EVENT_IFCHANGE; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - } - break; - - case USB_REQ_GETINTERFACE: - { - if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) && - priv->config == USBMSC_CONFIGIDNONE) - { - if (index != USBMSC_INTERFACEID) - { - ret = -EDOM; - } - else - { - ctrlreq->buf[0] = USBMSC_ALTINTERFACEID; - ret = 1; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req); - break; - } - } - else if ((ctrl->type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS) - { - /********************************************************************** - * Bulk-Only Mass Storage Class Requests - **********************************************************************/ - - /* Verify that we are configured */ - - if (!priv->config) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOTCONFIGURED), 0); - return ret; - } - - switch (ctrl->req) - { - case USBMSC_REQ_MSRESET: /* Reset mass storage device and interface */ - { - if (ctrl->type == USBMSC_TYPE_SETUPOUT && value == 0 && len == 0) - { - /* Only one interface is supported */ - - if (index != USBMSC_INTERFACEID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_MSRESETNDX), index); - ret = -EDOM; - } - else - { - /* Signal to stop the current operation and reinitialize state */ - - priv->theventset |= USBMSC_EVENT_RESET; - pthread_cond_signal(&priv->cond); - - /* Return here... the response will be provided later by the - * worker thread. - */ - - return OK; - } - } - } - break; - - case USBMSC_REQ_GETMAXLUN: /* Return number LUNs supported */ - { - if (ctrl->type == USBMSC_TYPE_SETUPIN && value == 0 && len == 1) - { - /* Only one interface is supported */ - - if (index != USBMSC_INTERFACEID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_GETMAXLUNNDX), index); - ret = -EDOM; - } - else - { - ctrlreq->buf[0] = priv->nluns - 1; - ret = 1; - } - } - } - break; - - default: - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BADREQUEST), ctrl->req); - break; - } - } - else - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNSUPPORTEDTYPE), ctrl->type); - } - - /* Respond to the setup command if data was returned. On an error return - * value (ret < 0), the USB driver will stall EP0. - */ - - if (ret >= 0) - { - /* Configure the response */ - - ctrlreq->len = MIN(len, ret); - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - - /* Send the response -- either directly to the USB controller or - * indirectly in the case where this class is a member of a composite - * device. - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - ret = EP_SUBMIT(dev->ep0, ctrlreq); -#else - ret = composite_ep0submit(driver, dev, ctrlreq); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPRESPQ), (uint16_t)-ret); -#if 0 /* Not necessary */ - ctrlreq->result = OK; - usbmsc_ep0incomplete(dev->ep0, ctrlreq); -#endif - } - } - - return ret; -} - -/**************************************************************************** - * Name: usbmsc_disconnect - * - * Description: - * Invoked after all transfers have been stopped, when the host is - * disconnected. This function is probably called from the context of an - * interrupt handler. - * - ****************************************************************************/ - -static void usbmsc_disconnect(FAR struct usbdevclass_driver_s *driver, - FAR struct usbdev_s *dev) -{ - struct usbmsc_dev_s *priv; - irqstate_t flags; - - usbtrace(TRACE_CLASSDISCONNECT, 0); - -#ifdef CONFIG_DEBUG - if (!driver || !dev || !dev->ep0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DISCONNECTINVALIDARGS), 0); - return; - } -#endif - - /* Extract reference to private data */ - - priv = ((FAR struct usbmsc_driver_s *)driver)->dev; - -#ifdef CONFIG_DEBUG - if (!priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EP0NOTBOUND3), 0); - return; - } -#endif - - /* Reset the configuration */ - - flags = irqsave(); - usbmsc_resetconfig(priv); - - /* Signal the worker thread */ - - priv->theventset |= USBMSC_EVENT_DISCONNECT; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - - /* Perform the soft connect function so that we will we can be - * re-enumerated (unless we are part of a composite device) - */ - -#ifndef CONFIG_USBMSC_COMPOSITE - DEV_CONNECT(dev); -#endif -} - -/**************************************************************************** - * Initialization/Un-Initialization - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_lununinitialize - ****************************************************************************/ - -static void usbmsc_lununinitialize(struct usbmsc_lun_s *lun) -{ - /* Has a block driver has been bound to the LUN? */ - - if (lun->inode) - { - /* Close the block driver */ - - (void)close_blockdriver(lun->inode); - } - - memset(lun, 0, sizeof(struct usbmsc_lun_s *)); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ -/**************************************************************************** - * Internal Interfaces - ****************************************************************************/ - -/**************************************************************************** - * Name: usbmsc_setconfig - * - * Description: - * Set the device configuration by allocating and configuring endpoints and - * by allocating and queuing read and write requests. - * - ****************************************************************************/ - -int usbmsc_setconfig(FAR struct usbmsc_dev_s *priv, uint8_t config) -{ - FAR struct usbmsc_req_s *privreq; - FAR struct usbdev_req_s *req; -#ifdef CONFIG_USBDEV_DUALSPEED - FAR const struct usb_epdesc_s *epdesc; - bool hispeed = (priv->usbdev->speed == USB_SPEED_HIGH); - uint16_t bulkmxpacket; -#endif - int i; - int ret = 0; - -#if CONFIG_DEBUG - if (priv == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETCONFIGINVALIDARGS), 0); - return -EIO; - } -#endif - - if (config == priv->config) - { - /* Already configured -- Do nothing */ - - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALREADYCONFIGURED), 0); - return OK; - } - - /* Discard the previous configuration data */ - - usbmsc_resetconfig(priv); - - /* Was this a request to simply discard the current configuration? */ - - if (config == USBMSC_CONFIGIDNONE) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGNONE), 0); - return OK; - } - - /* We only accept one configuration */ - - if (config != USBMSC_CONFIGID) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_CONFIGIDBAD), 0); - return -EINVAL; - } - - /* Configure the IN bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - bulkmxpacket = USBMSC_BULKMAXPACKET(hispeed); - epdesc = USBMSC_EPBULKINDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkin, epdesc, false); -#else - ret = EP_CONFIGURE(priv->epbulkin, - usbmsc_getepdesc(USBMSC_EPFSBULKIN), false); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKINCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkin->priv = priv; - - /* Configure the OUT bulk endpoint */ - -#ifdef CONFIG_USBDEV_DUALSPEED - epdesc = USBMSC_EPBULKOUTDESC(hispeed); - ret = EP_CONFIGURE(priv->epbulkout, epdesc, true); -#else - ret = EP_CONFIGURE(priv->epbulkout, - usbmsc_getepdesc(USBMSC_EPFSBULKOUT), true); -#endif - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EPBULKOUTCONFIGFAIL), 0); - goto errout; - } - - priv->epbulkout->priv = priv; - - /* Queue read requests in the bulk OUT endpoint */ - - for (i = 0; i < CONFIG_USBMSC_NRDREQS; i++) - { - privreq = &priv->rdreqs[i]; - req = privreq->req; - req->len = CONFIG_USBMSC_BULKOUTREQLEN; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSUBMIT), (uint16_t)-ret); - goto errout; - } - } - - priv->config = config; - return OK; - -errout: - usbmsc_resetconfig(priv); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_resetconfig - * - * Description: - * Mark the device as not configured and disable all endpoints. - * - ****************************************************************************/ - -void usbmsc_resetconfig(FAR struct usbmsc_dev_s *priv) -{ - /* Are we configured? */ - - if (priv->config != USBMSC_CONFIGIDNONE) - { - /* Yes.. but not anymore */ - - priv->config = USBMSC_CONFIGIDNONE; - - /* Disable endpoints. This should force completion of all pending - * transfers. - */ - - EP_DISABLE(priv->epbulkin); - EP_DISABLE(priv->epbulkout); - } -} - -/**************************************************************************** - * Name: usbmsc_wrcomplete - * - * Description: - * Handle completion of write request. This function probably executes - * in the context of an interrupt handler. - * - ****************************************************************************/ - -void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *privreq; - irqstate_t flags; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRCOMPLETEINVALIDARGS), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct usbmsc_dev_s*)ep->priv; - privreq = (FAR struct usbmsc_req_s *)req->priv; - - /* Return the write request to the free list */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)privreq, &priv->wrreqlist); - irqrestore(flags); - - /* Process the received data unless this is some unusual condition */ - - switch (req->result) - { - case OK: /* Normal completion */ - usbtrace(TRACE_CLASSWRCOMPLETE, req->xfrd); - break; - - case -ESHUTDOWN: /* Disconnection */ - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRSHUTDOWN), 0); - break; - - default: /* Some other error occurred */ - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRUNEXPECTED), - (uint16_t)-req->result); - break; - }; - - /* Inform the worker thread that a write request has been returned */ - - priv->theventset |= USBMSC_EVENT_WRCOMPLETE; - pthread_cond_signal(&priv->cond); -} - -/**************************************************************************** - * Name: usbmsc_rdcomplete - * - * Description: - * Handle completion of read request on the bulk OUT endpoint. This - * is handled like the receipt of serial data on the "UART" - * - ****************************************************************************/ - -void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req) -{ - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_req_s *privreq; - irqstate_t flags; - int ret; - - /* Sanity check */ - -#ifdef CONFIG_DEBUG - if (!ep || !ep->priv || !req || !req->priv) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETEINVALIDARGS), 0); - return; - } -#endif - - /* Extract references to private data */ - - priv = (FAR struct usbmsc_dev_s*)ep->priv; - privreq = (FAR struct usbmsc_req_s *)req->priv; - - /* Process the received data unless this is some unusual condition */ - - switch (req->result) - { - case 0: /* Normal completion */ - { - usbtrace(TRACE_CLASSRDCOMPLETE, req->xfrd); - - /* Add the filled read request from the rdreqlist */ - - flags = irqsave(); - sq_addlast((sq_entry_t*)privreq, &priv->rdreqlist); - irqrestore(flags); - - /* Signal the worker thread that there is received data to be processed */ - - priv->theventset |= USBMSC_EVENT_RDCOMPLETE; - pthread_cond_signal(&priv->cond); - } - break; - - case -ESHUTDOWN: /* Disconnection */ - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDSHUTDOWN), 0); - - /* Drop the read request... it will be cleaned up later */ - } - break; - - default: /* Some other error occurred */ - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDUNEXPECTED), - (uint16_t)-req->result); - - /* Return the read request to the bulk out endpoint for re-filling */ - - req = privreq->req; - req->priv = privreq; - req->callback = usbmsc_rdcomplete; - - ret = EP_SUBMIT(priv->epbulkout, req); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETERDSUBMIT), - (uint16_t)-ret); - } - } - break; - } -} - -/**************************************************************************** - * Name: usbmsc_deferredresponse - * - * Description: - * Some EP0 setup request cannot be responded to immediately becuase they - * require some asynchronous action from the SCSI worker thread. This - * function is provided for the SCSI thread to make that deferred response. - * The specific requests that require this deferred response are: - * - * 1. USB_REQ_SETCONFIGURATION, - * 2. USB_REQ_SETINTERFACE, or - * 3. USBMSC_REQ_MSRESET - * - * In all cases, the success reponse is a zero-length packet; the failure - * response is an EP0 stall. - * - * Input parameters: - * priv - Private state structure for this USB storage instance - * stall - true is the action failed and a stall is required - * - ****************************************************************************/ - -void usbmsc_deferredresponse(FAR struct usbmsc_dev_s *priv, bool failed) -{ - FAR struct usbdev_s *dev; - FAR struct usbdev_req_s *ctrlreq; - int ret; - -#ifdef CONFIG_DEBUG - if (!priv || !priv->usbdev || !priv->ctrlreq) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEFERREDRESPINVALIDARGS), 0); - return; - } -#endif - - dev = priv->usbdev; - ctrlreq = priv->ctrlreq; - - /* If no error occurs, respond to the deferred setup command with a null - * packet. - */ - - if (!failed) - { - ctrlreq->len = 0; - ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT; - ret = EP_SUBMIT(dev->ep0, ctrlreq); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEFERREDRESPSUBMIT), - (uint16_t)-ret); -#if 0 /* Not necessary */ - ctrlreq->result = OK; - usbmsc_ep0incomplete(dev->ep0, ctrlreq); -#endif - } - } - else - { - /* On a failure, the USB driver will stall. */ - - usbtrace(TRACE_DEVERROR(USBMSC_TRACEERR_DEFERREDRESPSTALLED), 0); - EP_STALL(dev->ep0); - } -} - -/**************************************************************************** - * User Interfaces - ****************************************************************************/ -/**************************************************************************** - * Name: usbmsc_configure - * - * Description: - * One-time initialization of the USB storage driver. The initialization - * sequence is as follows: - * - * 1. Call usbmsc_configure to perform one-time initialization specifying - * the number of luns. - * 2. Call usbmsc_bindlun to configure each supported LUN - * 3. Call usbmsc_exportluns when all LUNs are configured - * - * Input Parameters: - * nluns - the number of LUNs that will be registered - * handle - Location to return a handle that is used in other API calls. - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ****************************************************************************/ - -int usbmsc_configure(unsigned int nluns, void **handle) -{ - FAR struct usbmsc_alloc_s *alloc; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_driver_s *drvr; - int ret; - -#ifdef CONFIG_DEBUG - if (nluns > 15) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_TOOMANYLUNS), 0); - return -EDOM; - } -#endif - - /* Allocate the structures needed */ - - alloc = (FAR struct usbmsc_alloc_s*)kmalloc(sizeof(struct usbmsc_alloc_s)); - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCDEVSTRUCT), 0); - return -ENOMEM; - } - - /* Initialize the USB storage driver structure */ - - priv = &alloc->dev; - memset(priv, 0, sizeof(struct usbmsc_dev_s)); - - pthread_mutex_init(&priv->mutex, NULL); - pthread_cond_init(&priv->cond, NULL); - sq_init(&priv->wrreqlist); - - priv->nluns = nluns; - - /* Allocate the LUN table */ - - priv->luntab = (struct usbmsc_lun_s*)kmalloc(priv->nluns*sizeof(struct usbmsc_lun_s)); - if (!priv->luntab) - { - ret = -ENOMEM; - goto errout; - } - memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s)); - - /* Initialize the USB class driver structure */ - - drvr = &alloc->drvr; -#ifdef CONFIG_USBDEV_DUALSPEED - drvr->drvr.speed = USB_SPEED_HIGH; -#else - drvr->drvr.speed = USB_SPEED_FULL; -#endif - drvr->drvr.ops = &g_driverops; - drvr->dev = priv; - - /* Return the handle and success */ - - *handle = (FAR void*)alloc; - return OK; - -errout: - usbmsc_uninitialize(alloc); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_bindlun - * - * Description: - * Bind the block driver specified by drvrpath to a USB storage LUN. - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * drvrpath - the full path to the block driver - * startsector - A sector offset into the block driver to the start of the - * partition on drvrpath (0 if no partitions) - * nsectors - The number of sectors in the partition (if 0, all sectors - * to the end of the media will be exported). - * lunno - the LUN to bind to - * - * Returned Value: - * 0 on success; a negated errno on failure. - * - ****************************************************************************/ - -int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath, - unsigned int lunno, off_t startsector, size_t nsectors, - bool readonly) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_lun_s *lun; - FAR struct inode *inode; - struct geometry geo; - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc || !drvrpath || startsector < 0 || nsectors < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINLUNINVALIDARGS1), 0); - return -EINVAL; - } -#endif - - priv = &alloc->dev; - -#ifdef CONFIG_DEBUG - if (!priv->luntab) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INTERNALCONFUSION1), 0); - return -EIO; - } - - if (lunno > priv->nluns) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS2), 0); - return -EINVAL; - } -#endif - - lun = &priv->luntab[lunno]; - -#ifdef CONFIG_DEBUG - if (lun->inode != NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_LUNALREADYBOUND), 0); - return -EBUSY; - } -#endif - - /* Open the block driver */ - - ret = open_blockdriver(drvrpath, 0, &inode); - if (ret < 0) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BLKDRVEOPEN), 0); - return ret; - } - - /* Get the drive geometry */ - - if (!inode || !inode->u.i_bops || !inode->u.i_bops->geometry || - inode->u.i_bops->geometry(inode, &geo) != OK || !geo.geo_available) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_NOGEOMETRY), 0); - return -ENODEV; - } - - /* Verify that the partition parameters are valid */ - - if (startsector >= geo.geo_nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS3), 0); - return -EDOM; - } - else if (nsectors == 0) - { - nsectors = geo.geo_nsectors - startsector; - } - else if (startsector + nsectors >= geo.geo_nsectors) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_BINDLUNINVALIDARGS4), 0); - return -EDOM; - } - - /* Initialize the LUN structure */ - - memset(lun, 0, sizeof(struct usbmsc_lun_s *)); - - /* Allocate an I/O buffer big enough to hold one hardware sector. SCSI commands - * are processed one at a time so all LUNs may share a single I/O buffer. The - * I/O buffer will be allocated so that is it as large as the largest block - * device sector size - */ - - if (!priv->iobuffer) - { - priv->iobuffer = (uint8_t*)kmalloc(geo.geo_sectorsize); - if (!priv->iobuffer) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCIOBUFFER), geo.geo_sectorsize); - return -ENOMEM; - } - priv->iosize = geo.geo_sectorsize; - } - else if (priv->iosize < geo.geo_sectorsize) - { - void *tmp; - tmp = (uint8_t*)realloc(priv->iobuffer, geo.geo_sectorsize); - if (!tmp) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_REALLOCIOBUFFER), geo.geo_sectorsize); - return -ENOMEM; - } - - priv->iobuffer = (uint8_t*)tmp; - priv->iosize = geo.geo_sectorsize; - } - - lun->inode = inode; - lun->startsector = startsector; - lun->nsectors = nsectors; - lun->sectorsize = geo.geo_sectorsize; - - /* If the driver does not support the write method, then this is read-only */ - - if (!inode->u.i_bops->write) - { - lun->readonly = true; - } - return OK; -} - -/**************************************************************************** - * Name: usbmsc_unbindlun - * - * Description: - * Un-bind the block driver for the specified LUN - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * lun - the LUN to unbind from - * - * Returned Value: - * 0 on success; a negated errno on failure. - * - ****************************************************************************/ - -int usbmsc_unbindlun(FAR void *handle, unsigned int lunno) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_lun_s *lun; - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDLUNINVALIDARGS1), 0); - return -EINVAL; - } -#endif - - priv = &alloc->dev; - -#ifdef CONFIG_DEBUG - if (!priv->luntab) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_INTERNALCONFUSION2), 0); - return -EIO; - } - - if (lunno > priv->nluns) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNBINDLUNINVALIDARGS2), 0); - return -EINVAL; - } -#endif - - lun = &priv->luntab[lunno]; - pthread_mutex_lock(&priv->mutex); - -#ifdef CONFIG_DEBUG - if (lun->inode == NULL) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_LUNNOTBOUND), 0); - ret = -EBUSY; - } - else -#endif - { - /* Close the block driver */ - - usbmsc_lununinitialize(lun); - ret = OK; - } - - pthread_mutex_unlock(&priv->mutex); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_exportluns - * - * Description: - * After all of the LUNs have been bound, this function may be called - * in order to export those LUNs in the USB storage device. - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * - * Returned Value: - * 0 on success; a negated errno on failure - * - ****************************************************************************/ - -#ifdef CONFIG_USBMSC_COMPOSITE -static -#endif -int usbmsc_exportluns(FAR void *handle) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - FAR struct usbmsc_driver_s *drvr; - irqstate_t flags; -#ifdef SDCC - pthread_attr_t attr; -#endif - int ret; - -#ifdef CONFIG_DEBUG - if (!alloc) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_EXPORTLUNSINVALIDARGS), 0); - return -ENXIO; - } -#endif - - priv = &alloc->dev; - drvr = &alloc->drvr; - - /* Start the worker thread */ - - pthread_mutex_lock(&priv->mutex); - priv->thstate = USBMSC_STATE_NOTSTARTED; - priv->theventset = USBMSC_EVENT_NOEVENTS; - -#ifdef SDCC - (void)pthread_attr_init(&attr); - ret = pthread_create(&priv->thread, &attr, usbmsc_workerthread, (pthread_addr_t)priv); -#else - ret = pthread_create(&priv->thread, NULL, usbmsc_workerthread, (pthread_addr_t)priv); -#endif - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_THREADCREATE), (uint16_t)-ret); - goto errout_with_mutex; - } - - /* Register the USB storage class driver (unless we are part of a composite device) */ - -#ifndef CONFIG_USBMSC_COMPOSITE - ret = usbdev_register(&drvr->drvr); - if (ret != OK) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_DEVREGISTER), (uint16_t)-ret); - goto errout_with_mutex; - } -#endif - - /* Signal to start the thread */ - - flags = irqsave(); - priv->theventset |= USBMSC_EVENT_READY; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - -errout_with_mutex: - pthread_mutex_unlock(&priv->mutex); - return ret; -} - -/**************************************************************************** - * Name: usbmsc_classobject - * - * Description: - * Register USB mass storage device and return the class object. - * - * Input Parameters: - * classdev - The location to return the CDC serial class' device - * instance. - * - * Returned Value: - * 0 on success; a negated errno on failure - - * - ****************************************************************************/ - -#ifdef CONFIG_USBMSC_COMPOSITE -int usbmsc_classobject(FAR void *handle, - FAR struct usbdevclass_driver_s **classdev) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - int ret; - - DEBUGASSERT(handle && classdev); - - /* Export the LUNs as with the "standalone" USB mass storage driver, but - * don't register the class instance with the USB device infrastructure. - */ - - ret = usbmsc_exportluns(handle); - if (ret == OK) - { - /* On sucess, return an (typed) instance of the class instance */ - - *classdev = &alloc->drvr.drvr; - } - return ret; -} -#endif - -/**************************************************************************** - * Name: usbmsc_uninitialize - * - * Description: - * Un-initialize the USB storage class driver - * - * Input Parameters: - * handle - The handle returned by a previous call to usbmsc_configure(). - * - * Returned Value: - * None - * - ****************************************************************************/ - -void usbmsc_uninitialize(FAR void *handle) -{ - FAR struct usbmsc_alloc_s *alloc = (FAR struct usbmsc_alloc_s *)handle; - FAR struct usbmsc_dev_s *priv; - irqstate_t flags; -#ifdef SDCC - pthread_addr_t result1, result2; - pthread_attr_t attr; -#endif - void *value; - int i; - -#ifdef CONFIG_DEBUG - if (!handle) - { - usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_UNINITIALIZEINVALIDARGS), 0); - return; - } -#endif - priv = &alloc->dev; - - /* If the thread hasn't already exitted, tell it to exit now */ - - if (priv->thstate != USBMSC_STATE_NOTSTARTED) - { - /* The thread was started.. Is it still running? */ - - pthread_mutex_lock(&priv->mutex); - if (priv->thstate != USBMSC_STATE_TERMINATED) - { - /* Yes.. Ask the thread to stop */ - - flags = irqsave(); - priv->theventset |= USBMSC_EVENT_TERMINATEREQUEST; - pthread_cond_signal(&priv->cond); - irqrestore(flags); - } - pthread_mutex_unlock(&priv->mutex); - - /* Wait for the thread to exit. This is necessary even if the - * thread has already exitted in order to collect the join - * garbage - */ - - (void)pthread_join(priv->thread, &value); - } - priv->thread = 0; - - /* Unregister the driver (unless we are a part of a composite device */ - -#ifndef CONFIG_USBMSC_COMPOSITE - usbdev_unregister(&alloc->drvr.drvr); -#endif - - /* Uninitialize and release the LUNs */ - - for (i = 0; i < priv->nluns; ++i) - { - usbmsc_lununinitialize(&priv->luntab[i]); - } - kfree(priv->luntab); - - /* Release the I/O buffer */ - - if (priv->iobuffer) - { - kfree(priv->iobuffer); - } - - /* Uninitialize and release the driver structure */ - - pthread_mutex_destroy(&priv->mutex); - pthread_cond_destroy(&priv->cond); - - kfree(priv); -} |