From 7dbcc71e0d488e0cdab6aaca6eb874cd532f5df9 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 2 Apr 2020 11:46:53 -0600 Subject: [PATCH] Check return from nxsem_wait_uninterruptible() Resolution of Issue 619 will require multiple steps, this part of the first step in that resolution: Every call to nxsem_wait_uninterruptible() must handle the return value from nxsem_wait_uninterruptible properly. This commit is for all USB host drivers under arch/. --- arch/arm/src/efm32/efm32_usbhost.c | 968 ++++++------ arch/arm/src/efm32/hardware/efm32_usb.h | 25 +- arch/arm/src/imxrt/imxrt_ehci.c | 551 ++++--- arch/arm/src/lpc17xx_40xx/lpc17_40_usbhost.c | 993 +++++++------ arch/arm/src/lpc31xx/lpc31_ehci.c | 1381 ++++++++++-------- arch/arm/src/lpc43xx/lpc43_ehci.c | 1316 +++++++++-------- arch/arm/src/lpc54xx/lpc54_usb0_ohci.c | 832 ++++++----- arch/arm/src/s32k1xx/s32k1xx_lpi2c.c | 20 +- arch/arm/src/sama5/sam_ehci.c | 1082 +++++++------- arch/arm/src/sama5/sam_ohci.c | 770 +++++----- arch/arm/src/sama5/sam_twi.c | 23 +- arch/arm/src/stm32/stm32_otgfshost.c | 783 +++++----- arch/arm/src/stm32/stm32_otghshost.c | 756 +++++----- arch/arm/src/stm32f7/stm32_otghost.c | 654 +++++---- arch/arm/src/stm32h7/stm32_otghost.c | 656 +++++---- arch/arm/src/stm32l4/stm32l4_otgfshost.c | 800 +++++----- 16 files changed, 6610 insertions(+), 5000 deletions(-) diff --git a/arch/arm/src/efm32/efm32_usbhost.c b/arch/arm/src/efm32/efm32_usbhost.c index b09ecca4cb..c39fd987ce 100644 --- a/arch/arm/src/efm32/efm32_usbhost.c +++ b/arch/arm/src/efm32/efm32_usbhost.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/efm32/efm32_usbhost.c * - * Copyright (C) 2014-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -131,7 +116,7 @@ # undef CONFIG_EFM32_USBHOST_PKTDUMP #endif -/* HCD Setup *******************************************************************/ +/* HCD Setup ****************************************************************/ /* Hardware capabilities */ @@ -143,10 +128,10 @@ #define EFM32_MAX_PKTCOUNT 256 /* Max packet count */ #define EFM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */ -/* Delays **********************************************************************/ +/* Delays *******************************************************************/ -#define EFM32_READY_DELAY 200000 /* In loop counts */ -#define EFM32_FLUSH_DELAY 200000 /* In loop counts */ +#define EFM32_READY_DELAY 200000 /* In loop counts */ +#define EFM32_FLUSH_DELAY 200000 /* In loop counts */ #define EFM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define EFM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -160,7 +145,7 @@ # define MAX(a, b) (((a) > (b)) ? (a) : (b)) #endif -/* Tracing *********************************************************************/ +/* Tracing ******************************************************************/ #define TR_FMT1 false #define TR_FMT2 true @@ -268,7 +253,7 @@ struct efm32_usbhost_s volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ - struct efm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + struct efm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -298,7 +283,7 @@ struct efm32_usbhost_trace_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_EFM32_USBHOST_REGDEBUG static void efm32_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -319,21 +304,23 @@ static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits, # define efm32_pktdump(m,b,n) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void efm32_takesem(sem_t *sem); +static int efm32_takesem(sem_t *sem); #define efm32_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t efm32_getle16(const uint8_t *val); -/* Channel management **********************************************************/ +/* Channel management *******************************************************/ static int efm32_chan_alloc(FAR struct efm32_usbhost_s *priv); -static inline void efm32_chan_free(FAR struct efm32_usbhost_s *priv, int chidx); +static inline void efm32_chan_free(FAR struct efm32_usbhost_s *priv, + int chidx); static inline void efm32_chan_freeall(FAR struct efm32_usbhost_s *priv); -static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx); +static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, + int chidx); static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx, enum efm32_chreason_e chreason); static int efm32_chan_waitsetup(FAR struct efm32_usbhost_s *priv, @@ -348,7 +335,8 @@ static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv, static void efm32_chan_wakeup(FAR struct efm32_usbhost_s *priv, FAR struct efm32_chan_s *chan); static int efm32_ctrlchan_alloc(FAR struct efm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct efm32_ctrlinfo_s *ctrlep); static int efm32_ctrlep_alloc(FAR struct efm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -357,9 +345,10 @@ static int efm32_xfrep_alloc(FAR struct efm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); -/* Control/data transfer logic *************************************************/ +/* Control/data transfer logic **********************************************/ -static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx); +static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t efm32_getframe(void); #endif @@ -382,9 +371,11 @@ static int efm32_in_asynch(FAR struct efm32_usbhost_s *priv, int chidx, FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, FAR void *arg); #endif -static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx); -static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, + int chidx); +static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void efm32_out_next(FAR struct efm32_usbhost_s *priv, FAR struct efm32_chan_s *chan); @@ -393,7 +384,7 @@ static int efm32_out_asynch(FAR struct efm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ /* Lower level interrupt handlers */ @@ -430,7 +421,7 @@ static void efm32_gint_disable(void); static inline void efm32_hostinit_enable(void); static void efm32_txfe_enable(FAR struct efm32_usbhost_s *priv, int chidx); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int efm32_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -441,26 +432,29 @@ static int efm32_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int efm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); static int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int efm32_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int efm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int efm32_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int efm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int efm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int efm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int efm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -475,7 +469,7 @@ static int efm32_connect(FAR struct usbhost_driver_s *drvr, static void efm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static void efm32_portreset(FAR struct efm32_usbhost_s *priv); static void efm32_flush_txfifos(uint32_t txfnum); @@ -490,9 +484,9 @@ static inline int efm32_hw_initialize(FAR struct efm32_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct efm32_usbhost_s g_usbhost; @@ -510,68 +504,109 @@ static struct usbhost_connection_s g_usbconn = static const struct efm32_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] = { - TRENTRY(USBHOST_TRACE1_DEVDISCONN, TR_FMT1, "OTGFS ERROR: Host Port %d. Device disconnected\n"), - TRENTRY(USBHOST_TRACE1_IRQATTACH, TR_FMT1, "OTGFS ERROR: Failed to attach IRQ\n"), - TRENTRY(USBHOST_TRACE1_TRNSFRFAILED, TR_FMT1, "OTGFS ERROR: Transfer Failed. ret=%d\n"), - TRENTRY(USBHOST_TRACE1_SENDSETUP, TR_FMT1, "OTGFS ERROR: ctrl_sendsetup() failed with: %d\n"), - TRENTRY(USBHOST_TRACE1_SENDDATA, TR_FMT1, "OTGFS ERROR: ctrl_senddata() failed with: %d\n"), - TRENTRY(USBHOST_TRACE1_RECVDATA, TR_FMT1, "OTGFS ERROR: ctrl_recvdata() failed with: %d\n"), + TRENTRY(USBHOST_TRACE1_DEVDISCONN, TR_FMT1, + "OTGFS ERROR: Host Port %d. Device disconnected\n"), + TRENTRY(USBHOST_TRACE1_IRQATTACH, TR_FMT1, + "OTGFS ERROR: Failed to attach IRQ\n"), + TRENTRY(USBHOST_TRACE1_TRNSFRFAILED, TR_FMT1, + "OTGFS ERROR: Transfer Failed. ret=%d\n"), + TRENTRY(USBHOST_TRACE1_SENDSETUP, TR_FMT1, + "OTGFS ERROR: ctrl_sendsetup() failed with: %d\n"), + TRENTRY(USBHOST_TRACE1_SENDDATA, TR_FMT1, + "OTGFS ERROR: ctrl_senddata() failed with: %d\n"), + TRENTRY(USBHOST_TRACE1_RECVDATA, TR_FMT1, + "OTGFS ERROR: ctrl_recvdata() failed with: %d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(USBHOST_VTRACE1_CONNECTED, TR_FMT1, "OTGFS Host Port %d connected.\n"), - TRENTRY(USBHOST_VTRACE1_DISCONNECTED, TR_FMT1, "OTGFS Host Port %d disconnected.\n"), - TRENTRY(USBHOST_VTRACE1_GINT, TR_FMT1, "OTGFS Handling Interrupt. Entry Point.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_SOF, TR_FMT1, "OTGFS Handle the start of frame interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_RXFLVL, TR_FMT1, "OTGFS Handle the RxFIFO non-empty interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_NPTXFE, TR_FMT1, "OTGFS Handle the non-periodic TxFIFO empty interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_PTXFE, TR_FMT1, "OTGFS Handle the periodic TxFIFO empty interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HC, TR_FMT1, "OTGFS Handle the host channels interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT, TR_FMT1, "OTGFS Handle the host port interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_POCCHNG, TR_FMT1, "OTGFS HPRT: Port Over-Current Change.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_PCDET, TR_FMT1, "OTGFS HPRT: Port Connect Detect.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_PENCHNG, TR_FMT1, "OTGFS HPRT: Port Enable Changed.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_LSDEV, TR_FMT1, "OTGFS HPRT: Low Speed Device Connected.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_FSDEV, TR_FMT1, "OTGFS HPRT: Full Speed Device Connected.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_LSFSSW, TR_FMT1, "OTGFS HPRT: Host Switch: LS -> FS.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_HPRT_FSLSSW, TR_FMT1, "OTGFS HPRT: Host Switch: FS -> LS.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_DISC, TR_FMT1, "OTGFS Handle the disconnect detected interrupt.\n"), - TRENTRY(USBHOST_VTRACE1_GINT_IPXFR, TR_FMT1, "OTGFS Handle the incomplete periodic transfer.\n"), + TRENTRY(USBHOST_VTRACE1_CONNECTED, TR_FMT1, + "OTGFS Host Port %d connected.\n"), + TRENTRY(USBHOST_VTRACE1_DISCONNECTED, TR_FMT1, + "OTGFS Host Port %d disconnected.\n"), + TRENTRY(USBHOST_VTRACE1_GINT, TR_FMT1, + "OTGFS Handling Interrupt. Entry Point.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_SOF, TR_FMT1, + "OTGFS Handle the start of frame interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_RXFLVL, TR_FMT1, + "OTGFS Handle the RxFIFO non-empty interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_NPTXFE, TR_FMT1, + "OTGFS Handle the non-periodic TxFIFO empty interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_PTXFE, TR_FMT1, + "OTGFS Handle the periodic TxFIFO empty interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HC, TR_FMT1, + "OTGFS Handle the host channels interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT, TR_FMT1, + "OTGFS Handle the host port interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_POCCHNG, TR_FMT1, + "OTGFS HPRT: Port Over-Current Change.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_PCDET, TR_FMT1, + "OTGFS HPRT: Port Connect Detect.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_PENCHNG, TR_FMT1, + "OTGFS HPRT: Port Enable Changed.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_LSDEV, TR_FMT1, + "OTGFS HPRT: Low Speed Device Connected.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_FSDEV, TR_FMT1, + "OTGFS HPRT: Full Speed Device Connected.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_LSFSSW, TR_FMT1, + "OTGFS HPRT: Host Switch: LS -> FS.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_HPRT_FSLSSW, TR_FMT1, + "OTGFS HPRT: Host Switch: FS -> LS.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_DISC, TR_FMT1, + "OTGFS Handle the disconnect detected interrupt.\n"), + TRENTRY(USBHOST_VTRACE1_GINT_IPXFR, TR_FMT1, + "OTGFS Handle the incomplete periodic transfer.\n"), #endif }; static const struct efm32_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] = { - TRENTRY(USBHOST_TRACE2_CLIP, TR_FMT2, "OTGFS CLIP: chidx: %d buflen: %d\n"), + TRENTRY(USBHOST_TRACE2_CLIP, TR_FMT2, + "OTGFS CLIP: chidx: %d buflen: %d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(USBHOST_VTRACE2_CHANWAKEUP_IN, TR_FMT2, "OTGFS EP%d(IN) wake up with result: %d\n"), - TRENTRY(USBHOST_VTRACE2_CHANWAKEUP_OUT, TR_FMT2, "OTGFS EP%d(OUT) wake up with result: %d\n"), - TRENTRY(USBHOST_VTRACE2_CTRLIN, TR_FMT2, "OTGFS CTRL_IN type: %02x req: %02x\n"), - TRENTRY(USBHOST_VTRACE2_CTRLOUT, TR_FMT2, "OTGFS CTRL_OUT type: %02x req: %02x\n"), - TRENTRY(USBHOST_VTRACE2_INTRIN, TR_FMT2, "OTGFS INTR_IN chidx: %02x len: %02x\n"), - TRENTRY(USBHOST_VTRACE2_INTROUT, TR_FMT2, "OTGFS INTR_OUT chidx: %02x len: %02x\n"), - TRENTRY(USBHOST_VTRACE2_BULKIN, TR_FMT2, "OTGFS BULK_IN chidx: %02x len: %02x\n"), - TRENTRY(USBHOST_VTRACE2_BULKOUT, TR_FMT2, "OTGFS BULK_OUT chidx: %02x len: %02x\n"), - TRENTRY(USBHOST_VTRACE2_ISOCIN, TR_FMT2, "OTGFS ISOC_IN chidx: %02x len: %04d\n"), - TRENTRY(USBHOST_VTRACE2_ISOCOUT, TR_FMT2, "OTGFS ISOC_OUT chidx: %02x req: %02x\n"), - TRENTRY(USBHOST_VTRACE2_STARTTRANSFER, TR_FMT2, "OTGFS Transfer chidx: %d buflen: %d\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_CTRL_IN, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,IN ,CTRL)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_CTRL_OUT, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,OUT,CTRL)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_INTR_IN, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,IN ,INTR)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_INTR_OUT, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,OUT,INTR)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_BULK_IN, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,IN ,BULK)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_BULK_OUT, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,OUT,BULK)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_ISOC_IN, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,IN ,ISOC)\n"), - TRENTRY(USBHOST_VTRACE2_CHANCONF_ISOC_OUT, TR_FMT2, "OTGFS Channel configured. chidx: %d: (EP%d,OUT,ISOC)\n"), - TRENTRY(USBHOST_VTRACE2_CHANHALT, TR_FMT2, "OTGFS Channel halted. chidx: %d, reason: %d\n"), + TRENTRY(USBHOST_VTRACE2_CHANWAKEUP_IN, TR_FMT2, + "OTGFS EP%d(IN) wake up with result: %d\n"), + TRENTRY(USBHOST_VTRACE2_CHANWAKEUP_OUT, TR_FMT2, + "OTGFS EP%d(OUT) wake up with result: %d\n"), + TRENTRY(USBHOST_VTRACE2_CTRLIN, TR_FMT2, + "OTGFS CTRL_IN type: %02x req: %02x\n"), + TRENTRY(USBHOST_VTRACE2_CTRLOUT, TR_FMT2, + "OTGFS CTRL_OUT type: %02x req: %02x\n"), + TRENTRY(USBHOST_VTRACE2_INTRIN, TR_FMT2, + "OTGFS INTR_IN chidx: %02x len: %02x\n"), + TRENTRY(USBHOST_VTRACE2_INTROUT, TR_FMT2, + "OTGFS INTR_OUT chidx: %02x len: %02x\n"), + TRENTRY(USBHOST_VTRACE2_BULKIN, TR_FMT2, + "OTGFS BULK_IN chidx: %02x len: %02x\n"), + TRENTRY(USBHOST_VTRACE2_BULKOUT, TR_FMT2, + "OTGFS BULK_OUT chidx: %02x len: %02x\n"), + TRENTRY(USBHOST_VTRACE2_ISOCIN, TR_FMT2, + "OTGFS ISOC_IN chidx: %02x len: %04d\n"), + TRENTRY(USBHOST_VTRACE2_ISOCOUT, TR_FMT2, + "OTGFS ISOC_OUT chidx: %02x req: %02x\n"), + TRENTRY(USBHOST_VTRACE2_STARTTRANSFER, TR_FMT2, + "OTGFS Transfer chidx: %d buflen: %d\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_CTRL_IN, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,CTRL)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_CTRL_OUT, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,CTRL)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_INTR_IN, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,INTR)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_INTR_OUT, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,INTR)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_BULK_IN, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,BULK)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_BULK_OUT, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,BULK)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_ISOC_IN, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,IN ,ISOC)\n"), + TRENTRY(USBHOST_VTRACE2_CHANCONF_ISOC_OUT, TR_FMT2, + "OTGFS Channel configured. chidx: %d: (EP%d,OUT,ISOC)\n"), + TRENTRY(USBHOST_VTRACE2_CHANHALT, TR_FMT2, + "OTGFS Channel halted. chidx: %d, reason: %d\n"), #endif }; #endif /* HAVE_USBHOST_TRACE */ -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -607,8 +642,8 @@ static void efm32_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -706,7 +741,8 @@ static void efm32_putreg(uint32_t addr, uint32_t val) * ****************************************************************************/ -static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t setbits) +static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits, + uint32_t setbits) { efm32_putreg(addr, (((efm32_getreg(addr)) & ~clrbits) | setbits)); } @@ -720,9 +756,9 @@ static inline void efm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t set * ****************************************************************************/ -static void efm32_takesem(sem_t *sem) +static int efm32_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** @@ -828,7 +864,7 @@ static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx) /* Clear any old pending interrupts for this host channel. */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), 0xffffffff); + efm32_putreg(EFM32_USB_HC_INT(chidx), 0xffffffff); /* Enable channel interrupts required for transfers on this channel. */ @@ -929,7 +965,7 @@ static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx) break; } - efm32_putreg(EFM32_USB_HCn_INTMSK(chidx), regval); + efm32_putreg(EFM32_USB_HC_INTMSK(chidx), regval); /* Enable the top level host channel interrupt. */ @@ -969,7 +1005,7 @@ static void efm32_chan_configure(FAR struct efm32_usbhost_s *priv, int chidx) /* Write the channel configuration */ - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), regval); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), regval); } /**************************************************************************** @@ -989,24 +1025,24 @@ static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(USBHOST_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_FS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx - * before reallocating the channel for other transactions. The OTG_FS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." */ - hcchar = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + hcchar = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); hcchar |= (USB_HC_CHAR_CHDIS | USB_HC_CHAR_CHENA); /* Get the endpoint type from the HCCHAR register */ @@ -1015,13 +1051,13 @@ static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0. */ if (eptype == USB_HC_CHAR_EPTYPE_CONTROL || @@ -1029,14 +1065,16 @@ static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx, { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = efm32_getreg(EFM32_USB_GNPTXSTS) & _USB_GNPTXSTS_NPTXFSPCAVAIL_MASK; + avail = efm32_getreg(EFM32_USB_GNPTXSTS) & + _USB_GNPTXSTS_NPTXFSPCAVAIL_MASK; } else /* if (eptype == USB_HCCHAR_EPTYP_ISOC || * eptype == USB_HC_CHAR_EPTYPE_INT) */ { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = efm32_getreg(EFM32_USB_HPTXSTS) & _USB_HPTXSTS_PTXFSPCAVAIL_MASK; + avail = efm32_getreg(EFM32_USB_HPTXSTS) & + _USB_HPTXSTS_PTXFSPCAVAIL_MASK; } /* Check if there is any space available in the Tx FIFO. */ @@ -1050,26 +1088,27 @@ static void efm32_chan_halt(FAR struct efm32_usbhost_s *priv, int chidx, /* Unmask the CHannel Halted (CHH) interrupt */ - intmsk = efm32_getreg(EFM32_USB_HCn_INTMSK(chidx)); + intmsk = efm32_getreg(EFM32_USB_HC_INTMSK(chidx)); intmsk |= USB_HC_INTMSK_CHHLTDMSK; - efm32_putreg(EFM32_USB_HCn_INTMSK(chidx), intmsk); + efm32_putreg(EFM32_USB_HC_INTMSK(chidx), intmsk); /* Halt the channel by setting CHDIS (and maybe CHENA) in the HCCHAR */ - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), hcchar); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), hcchar); } /**************************************************************************** * Name: efm32_chan_waitsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the transfer). + * We do this to minimize race conditions. This logic would have to be + * expanded if we want to have more than one packet in flight at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1083,8 +1122,9 @@ static int efm32_chan_waitsetup(FAR struct efm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1103,10 +1143,11 @@ static int efm32_chan_waitsetup(FAR struct efm32_usbhost_s *priv, * Name: efm32_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1125,8 +1166,9 @@ static int efm32_chan_asynchsetup(FAR struct efm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1158,17 +1200,17 @@ static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv, int ret; /* Disable interrupts so that the following operations will be atomic. On - * the OTG FS global interrupt needs to be disabled. However, here we disable - * all interrupts to exploit that fact that interrupts will be re-enabled - * while we wait. + * the OTG FS global interrupt needs to be disabled. However, here we + * disable all interrupts to exploit that fact that interrupts will be re- + * enabled while we wait. */ flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1178,13 +1220,17 @@ static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv, * wait here. */ - nxsem_wait_uninterruptible(&chan->waitsem); + ret = nxsem_wait_uninterruptible(&chan->waitsem); } - while (chan->waiter); + while (chan->waiter && ret >= 0); /* The transfer is complete re-enable interrupts and return the result */ - ret = -(int)chan->result; + if (ret >= 0) + { + ret = -(int)chan->result; + } + leave_critical_section(flags); return ret; } @@ -1259,7 +1305,8 @@ static void efm32_chan_wakeup(FAR struct efm32_usbhost_s *priv, ****************************************************************************/ static int efm32_ctrlchan_alloc(FAR struct efm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct efm32_ctrlinfo_s *ctrlep) { FAR struct efm32_chan_s *chan; @@ -1326,8 +1373,8 @@ static int efm32_ctrlchan_alloc(FAR struct efm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -1342,8 +1389,8 @@ static int efm32_ctrlep_alloc(FAR struct efm32_usbhost_s *priv, FAR struct efm32_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1351,7 +1398,8 @@ static int efm32_ctrlep_alloc(FAR struct efm32_usbhost_s *priv, /* Allocate a container for the control endpoint */ - ctrlep = (FAR struct efm32_ctrlinfo_s *)kmm_malloc(sizeof(struct efm32_ctrlinfo_s)); + ctrlep = (FAR struct efm32_ctrlinfo_s *) + kmm_malloc(sizeof(struct efm32_ctrlinfo_s)); if (ctrlep == NULL) { uerr("ERROR: Failed to allocate control endpoint container\n"); @@ -1375,7 +1423,7 @@ static int efm32_ctrlep_alloc(FAR struct efm32_usbhost_s *priv, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_xfrep_alloc * * Description: @@ -1388,13 +1436,13 @@ static int efm32_ctrlep_alloc(FAR struct efm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_xfrep_alloc(FAR struct efm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -1404,8 +1452,8 @@ static int efm32_xfrep_alloc(FAR struct efm32_usbhost_s *priv, FAR struct efm32_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1420,10 +1468,10 @@ static int efm32_xfrep_alloc(FAR struct efm32_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint point + * type is encoded in the same way in the endpoint descriptor as it is in + * the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1530,16 +1578,16 @@ static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx) chan->npackets = (uint8_t)npackets; - /* Setup the HCn_TSIZ register */ + /* Setup the HC_TSIZ register */ regval = ((uint32_t)chan->buflen << _USB_HC_TSIZ_XFERSIZE_SHIFT) | ((uint32_t)npackets << _USB_HC_TSIZ_PKTCNT_SHIFT) | ((uint32_t)chan->pid << _USB_HC_TSIZ_PID_SHIFT); - efm32_putreg(EFM32_USB_HCn_TSIZ(chidx), regval); + efm32_putreg(EFM32_USB_HC_TSIZ(chidx), regval); /* Setup the HCCHAR register: Frame oddness and host channel enable */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); /* Set/clear the Odd Frame bit. Check for an even frame; if so set Odd * Frame. This field is applicable for only periodic (isochronous and @@ -1557,7 +1605,7 @@ static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx) regval &= ~USB_HC_CHAR_CHDIS; regval |= USB_HC_CHAR_CHENA; - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), regval); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), regval); /* If this is an out transfer, then we need to do more.. we need to copy * the outgoing data into the correct TxFIFO. @@ -1788,8 +1836,8 @@ static int efm32_ctrl_senddata(FAR struct efm32_usbhost_s *priv, * Name: efm32_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1866,7 +1914,8 @@ static int efm32_in_setup(FAR struct efm32_usbhost_s *priv, int chidx) /* Setup the IN data PID */ usbhost_vtrace2(USBHOST_VTRACE2_BULKIN, chidx, chan->buflen); - chan->pid = chan->indata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; + chan->pid = + chan->indata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; } break; @@ -1875,7 +1924,8 @@ static int efm32_in_setup(FAR struct efm32_usbhost_s *priv, int chidx) /* Setup the IN data PID */ usbhost_vtrace2(USBHOST_VTRACE2_INTRIN, chidx, chan->buflen); - chan->pid = chan->indata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; + chan->pid = + chan->indata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; } break; } @@ -2121,7 +2171,8 @@ static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx) /* Setup the OUT data PID */ usbhost_vtrace2(USBHOST_VTRACE2_BULKOUT, chidx, chan->buflen); - chan->pid = chan->outdata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; + chan->pid = + chan->outdata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; } break; @@ -2130,7 +2181,8 @@ static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx) /* Setup the OUT data PID */ usbhost_vtrace2(USBHOST_VTRACE2_INTROUT, chidx, chan->buflen); - chan->pid = chan->outdata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; + chan->pid = + chan->outdata1 ? EFM32_USB_PID_DATA1 : EFM32_USB_PID_DATA0; /* Toggle the OUT data PID for the next transfer */ @@ -2153,8 +2205,9 @@ static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx) * ****************************************************************************/ -static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen) { FAR struct efm32_chan_s *chan; clock_t start; @@ -2231,14 +2284,14 @@ static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ efm32_flush_txfifos(USB_GRSTCTL_TXFNUM_FALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2415,8 +2468,8 @@ static void efm32_gint_wrpacket(FAR struct efm32_usbhost_s *priv, * Description: * USB OTG FS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2439,8 +2492,8 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, * HCINTMSK register to get the set of enabled HC interrupts. */ - pending = efm32_getreg(EFM32_USB_HCn_INT(chidx)); - regval = efm32_getreg(EFM32_USB_HCn_INTMSK(chidx)); + pending = efm32_getreg(EFM32_USB_HC_INT(chidx)); + regval = efm32_getreg(EFM32_USB_HC_INTMSK(chidx)); /* AND the two to get the set of enabled, pending HC interrupts */ @@ -2453,7 +2506,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, { /* Clear the pending the ACK response received/transmitted (ACK) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_ACK); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_ACK); } /* Check for a pending STALL response receive (STALL) interrupt */ @@ -2462,7 +2515,8 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, { /* Clear the NAK and STALL Conditions. */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), (USB_HC_INT_NAK | USB_HC_INT_STALL)); + efm32_putreg(EFM32_USB_HC_INT(chidx), + USB_HC_INT_NAK | USB_HC_INT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2489,7 +2543,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, /* Clear the NAK and data toggle error conditions */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), + efm32_putreg(EFM32_USB_HC_INT(chidx), (USB_HC_INT_NAK | USB_HC_INT_DATATGLERR)); } @@ -2503,7 +2557,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, /* Clear the FRaMe OverRun (FRMOR) condition */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_FRMOVRUN); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_FRMOVRUN); } /* Check for a pending TransFeR Completed (XFRC) interrupt */ @@ -2512,7 +2566,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, { /* Clear the TransFeR Completed (XFRC) condition */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_XFERCOMPL); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_XFERCOMPL); /* Then handle the transfer completion event based on the endpoint type */ @@ -2528,15 +2582,15 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, * logic as each packet was received. */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_NAK); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_NAK); } else if (chan->eptype == EFM32_USB_EPTYPE_INTR) { /* Force the next transfer on an ODD frame */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); regval |= USB_HC_CHAR_ODDFRM; - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), regval); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), regval); /* Set the request done state */ @@ -2550,9 +2604,9 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, { /* Mask the CHannel Halted (CHH) interrupt */ - regval = efm32_getreg(EFM32_USB_HCn_INTMSK(chidx)); + regval = efm32_getreg(EFM32_USB_HC_INTMSK(chidx)); regval &= ~USB_HC_INT_CHHLTD; - efm32_putreg(EFM32_USB_HCn_INTMSK(chidx), regval); + efm32_putreg(EFM32_USB_HC_INTMSK(chidx), regval); /* Update the request state based on the host state machine state */ @@ -2577,11 +2631,11 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, } else if (chan->chreason == CHREASON_NAK) { - /* Halt on NAK only happens on an INTR channel. Fetch the HCCHAR register - * and check for an interrupt endpoint. + /* Halt on NAK only happens on an INTR channel. Fetch the HCCHAR + * register and check for an interrupt endpoint. */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); if ((regval & _USB_HC_CHAR_EPTYPE_MASK) == USB_HC_CHAR_EPTYPE_INT) { /* Toggle the IN data toggle (Used by Bulk and INTR only) */ @@ -2602,7 +2656,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, /* Clear the CHannel Halted (CHH) condition */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_CHHLTD); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_CHHLTD); } /* Check for a pending Transaction ERror (TXERR) interrupt */ @@ -2617,7 +2671,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, /* Clear the Transaction ERror (TXERR) condition */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_XACTERR); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_XACTERR); } /* Check for a pending NAK response received (NAK) interrupt */ @@ -2651,10 +2705,10 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, * CHENA is set */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); regval |= USB_HC_CHAR_CHENA; regval &= ~USB_HC_CHAR_CHDIS; - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), regval); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), regval); } #else /* Halt all transfers on the NAK -- the CHH interrupt is expected next */ @@ -2664,7 +2718,7 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, /* Clear the NAK condition */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_NAK); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_NAK); } /* Check for a transfer complete event */ @@ -2678,8 +2732,8 @@ static inline void efm32_gint_hcinisr(FAR struct efm32_usbhost_s *priv, * Description: * USB OTG FS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2702,8 +2756,8 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, * HCINTMSK register to get the set of enabled HC interrupts. */ - pending = efm32_getreg(EFM32_USB_HCn_INT(chidx)); - regval = efm32_getreg(EFM32_USB_HCn_INTMSK(chidx)); + pending = efm32_getreg(EFM32_USB_HC_INT(chidx)); + regval = efm32_getreg(EFM32_USB_HC_INTMSK(chidx)); /* AND the two to get the set of enabled, pending HC interrupts */ @@ -2716,7 +2770,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, { /* Clear the pending the ACK response received/transmitted (ACK) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_ACK); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_ACK); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ @@ -2729,7 +2783,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the FRaMe OverRun (FRMOR) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_FRMOVRUN); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_FRMOVRUN); } /* Check for a pending TransFeR Completed (XFRC) interrupt */ @@ -2750,7 +2804,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the TransFeR Completed (XFRC) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_XFERCOMPL); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_XFERCOMPL); } /* Check for a pending STALL response receive (STALL) interrupt */ @@ -2759,7 +2813,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, { /* Clear the pending the STALL response receiv (STALL) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_STALL); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2778,7 +2832,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the NAK response received (NAK) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_NAK); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_NAK); } /* Check for a pending Transaction ERror (TXERR) interrupt */ @@ -2793,7 +2847,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the Transaction ERror (TXERR) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_XACTERR); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_XACTERR); } /* Check for a pending Data Toggle ERRor (DTERR) interrupt */ @@ -2808,7 +2862,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), + efm32_putreg(EFM32_USB_HC_INT(chidx), (USB_HC_INT_DATATGLERR | USB_HC_INT_NAK)); } @@ -2818,9 +2872,9 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, { /* Mask the CHannel Halted (CHH) interrupt */ - regval = efm32_getreg(EFM32_USB_HCn_INTMSK(chidx)); + regval = efm32_getreg(EFM32_USB_HC_INTMSK(chidx)); regval &= ~USB_HC_INT_CHHLTD; - efm32_putreg(EFM32_USB_HCn_INTMSK(chidx), regval); + efm32_putreg(EFM32_USB_HC_INTMSK(chidx), regval); if (chan->chreason == CHREASON_XFRC) { @@ -2832,13 +2886,14 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, * the endpoint type. */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); /* Is it a bulk endpoint? Were an odd number of packets * transferred? */ - if ((regval & _USB_HC_CHAR_EPTYPE_MASK) == USB_HC_CHAR_EPTYPE_BULK && + if ((regval & _USB_HC_CHAR_EPTYPE_MASK) == + USB_HC_CHAR_EPTYPE_BULK && (chan->npackets & 1) != 0) { /* Yes to both... toggle the data out PID */ @@ -2875,7 +2930,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, /* Clear the pending the CHannel Halted (CHH) interrupt */ - efm32_putreg(EFM32_USB_HCn_INT(chidx), USB_HC_INT_CHHLTD); + efm32_putreg(EFM32_USB_HC_INT(chidx), USB_HC_INT_CHHLTD); } /* Check for a transfer complete event */ @@ -3021,7 +3076,7 @@ static inline void efm32_gint_rxflvlisr(FAR struct efm32_usbhost_s *priv) /* Get the host channel characteristics register (HCCHAR) for this channel */ - hcchar = efm32_getreg(EFM32_USB_HCn_CHAR(chidx)); + hcchar = efm32_getreg(EFM32_USB_HC_CHAR(chidx)); /* Then process the interrupt according to the packet status */ @@ -3058,14 +3113,14 @@ static inline void efm32_gint_rxflvlisr(FAR struct efm32_usbhost_s *priv) /* Check if more packets are expected */ - hctsiz = efm32_getreg(EFM32_USB_HCn_TSIZ(chidx)); + hctsiz = efm32_getreg(EFM32_USB_HC_TSIZ(chidx)); if ((hctsiz & _USB_HC_TSIZ_PKTCNT_MASK) != 0) { /* Re-activate the channel when more packets are expected */ hcchar |= USB_HC_CHAR_CHENA; hcchar &= ~USB_HC_CHAR_CHDIS; - efm32_putreg(EFM32_USB_HCn_CHAR(chidx), hcchar); + efm32_putreg(EFM32_USB_HC_CHAR(chidx), hcchar); } } } @@ -3107,8 +3162,8 @@ static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3167,7 +3222,8 @@ static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); @@ -3196,8 +3252,8 @@ static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3290,7 +3346,7 @@ static inline void efm32_gint_hcisr(FAR struct efm32_usbhost_s *priv) { /* Yes... read the HCCHAR register to get the direction bit */ - hcchar = efm32_getreg(EFM32_USB_HCn_CHAR(i)); + hcchar = efm32_getreg(EFM32_USB_HC_CHAR(i)); /* Was this an interrupt on an IN or an OUT channel? */ @@ -3330,15 +3386,15 @@ static inline void efm32_gint_hprtisr(FAR struct efm32_usbhost_s *priv) hprt = efm32_getreg(EFM32_USB_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ - newhprt = hprt & ~(USB_HPRT_PRTENA | USB_HPRT_PRTCONNDET | USB_HPRT_PRTENCHNG | - USB_HPRT_PRTOVRCURRCHNG); + newhprt = hprt & ~(USB_HPRT_PRTENA | USB_HPRT_PRTCONNDET | + USB_HPRT_PRTENCHNG | USB_HPRT_PRTOVRCURRCHNG); - /* Check for Port Overcurrent CHaNGe (POCCHNG) */ + /* Check for Port Over-current CHaNGe (POCCHNG) */ if ((hprt & USB_HPRT_PRTOVRCURRCHNG) != 0) { @@ -3398,7 +3454,8 @@ static inline void efm32_gint_hprtisr(FAR struct efm32_usbhost_s *priv) /* Are we switching from FS to LS? */ - if ((hcfg & _USB_HCFG_FSLSPCLKSEL_MASK) != USB_HCFG_FSLSPCLKSEL_DIV8) + if ((hcfg & _USB_HCFG_FSLSPCLKSEL_MASK) != + USB_HCFG_FSLSPCLKSEL_DIV8) { usbhost_vtrace1(USBHOST_VTRACE1_GINT_HPRT_FSLSSW, 0); @@ -3420,7 +3477,8 @@ static inline void efm32_gint_hprtisr(FAR struct efm32_usbhost_s *priv) /* Are we switching from LS to FS? */ - if ((hcfg & _USB_HCFG_FSLSPCLKSEL_MASK) != USB_HCFG_FSLSPCLKSEL_DIV1) + if ((hcfg & _USB_HCFG_FSLSPCLKSEL_MASK) != + USB_HCFG_FSLSPCLKSEL_DIV1) { usbhost_vtrace1(USBHOST_VTRACE1_GINT_HPRT_LSFSSW, 0); @@ -3478,9 +3536,9 @@ static inline void efm32_gint_ipxfrisr(FAR struct efm32_usbhost_s *priv) * CHDIS : Set to stop transmitting/receiving data on a channel */ - regval = efm32_getreg(EFM32_USB_HCn_CHAR(0)); + regval = efm32_getreg(EFM32_USB_HC_CHAR(0)); regval |= (USB_HC_CHAR_CHDIS | USB_HC_CHAR_CHENA); - efm32_putreg(EFM32_USB_HCn_CHAR(0), regval); + efm32_putreg(EFM32_USB_HC_CHAR(0), regval); /* Clear the incomplete isochronous OUT interrupt */ @@ -3500,7 +3558,8 @@ static int efm32_gint_isr(int irq, FAR void *context, FAR void *arg) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct efm32_usbhost_s *priv = &g_usbhost; @@ -3511,8 +3570,8 @@ static int efm32_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3687,7 +3746,8 @@ static inline void efm32_hostinit_enable(void) /* If OTG were supported, we would need to enable the following as well: * * USB_GINTMSK_OTGINTMSK : OTG interrupt - * USB_GINTMSK_SESSREQINTMSK : Session request/new session detected interrupt + * USB_GINTMSK_SESSREQINTMSK : Session request/new session detected + * interrupt * USB_GINTMSK_CONIDSTSCHNGMSK : Connector ID status change */ @@ -3781,17 +3841,17 @@ static void efm32_txfe_enable(FAR struct efm32_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or - * disconnected. This function will not return until either (1) a device is - * connected or disconnect to/from any hub port or until (2) some failure - * occurs. On a failure, a negated errno value is returned indicating the - * nature of the failure + * disconnected. This function will not return until either (1) a device + * is connected or disconnect to/from any hub port or until (2) some + * failure occurs. On a failure, a negated errno value is returned + * indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3805,6 +3865,7 @@ static int efm32_wait(FAR struct usbhost_connection_s *conn, FAR struct efm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3829,7 +3890,8 @@ static int efm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3846,7 +3908,8 @@ static int efm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3854,7 +3917,11 @@ static int efm32_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - efm32_takesem(&priv->pscsem); + ret = efm32_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3878,8 +3945,8 @@ static int efm32_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3931,7 +3998,8 @@ static int efm32_rh_enumerate(FAR struct efm32_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = efm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = efm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -3987,47 +4055,54 @@ static int efm32_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_ep0configure * * Description: * Configure endpoint 0. This method is normally used internally by the - * enumerate() method but is made available at the interface to support an - * external implementation of the enumeration logic. + * enumerate() method but is made available at the interface to support + * an external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize) +static int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; FAR struct efm32_ctrlinfo_s *ep0info = (FAR struct efm32_ctrlinfo_s *)ep0; FAR struct efm32_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); - /* We must have exclusive access to the USB host hardware and state structures */ + /* We must have exclusive access to the USB host hardware and state + * structures. + */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4051,27 +4126,27 @@ static int efm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep return OK; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4080,15 +4155,21 @@ static int efm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); - /* We must have exclusive access to the USB host hardware and state structures */ + /* We must have exclusive access to the USB host hardware and state + * structures. + */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require @@ -4109,35 +4190,40 @@ static int efm32_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; + int ret; DEBUGASSERT(priv); /* We must have exclusive access to the USB host hardware and state structures */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* A single channel is represent by an index in the range of 0 to * EFM32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated @@ -4154,7 +4240,9 @@ static int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct efm32_ctrlinfo_s *ctrlep = (FAR struct efm32_ctrlinfo_s *)ep; + FAR struct efm32_ctrlinfo_s *ctrlep = + (FAR struct efm32_ctrlinfo_s *)ep; + efm32_chan_free(priv, ctrlep->inndx); efm32_chan_free(priv, ctrlep->outndx); @@ -4171,27 +4259,28 @@ static int efm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: efm32_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4225,19 +4314,20 @@ static int efm32_alloc(FAR struct usbhost_driver_s *drvr, * Name: efm32_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4253,32 +4343,34 @@ static int efm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4301,30 +4393,31 @@ static int efm32_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int efm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int efm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4338,29 +4431,31 @@ static int efm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. * req - Describes the request to be sent. This request must lie in memory * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4390,9 +4485,15 @@ static int efm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, buflen = efm32_getle16(req->len); - /* We must have exclusive access to the USB host hardware and state structures */ + /* We must have exclusive access to the USB host hardware and state + * structures. + */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4475,7 +4576,11 @@ static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4544,26 +4649,26 @@ static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: - * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4577,12 +4682,14 @@ static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; ssize_t nbytes; + int ret; uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4590,7 +4697,11 @@ static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the USB host hardware and state structures */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4621,20 +4732,21 @@ static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4657,7 +4769,11 @@ static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - efm32_takesem(&priv->exclsem); + ret = efm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4675,7 +4791,7 @@ static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: efm32_cancel * * Description: @@ -4683,16 +4799,16 @@ static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int efm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4706,8 +4822,8 @@ static int efm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < EFM32_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being canceled. */ flags = enter_critical_section(); @@ -4762,7 +4878,7 @@ static int efm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: efm32_connect * * Description: @@ -4771,17 +4887,17 @@ static int efm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int efm32_connect(FAR struct usbhost_driver_s *drvr, @@ -4818,15 +4934,18 @@ static int efm32_connect(FAR struct usbhost_driver_s *drvr, * Name: efm32_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4844,20 +4963,17 @@ static void efm32_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: efm32_portreset * * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in * OTG_FS_GOTGINT), which indicates that the bus is stable again after the - * electrical debounce caused by the attachment of a pull-up resistor on DP - * (FS) or DM (LS). + * electrical debounce caused by the attachment of a pull-up resistor on + * DP (FS) or DM (LS). * * Input Parameters: * priv -- USB host driver private data structure. @@ -5013,9 +5129,9 @@ static void efm32_vbusdrive(FAR struct efm32_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from efm32_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from efm32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5072,7 +5188,8 @@ static void efm32_host_initialize(FAR struct efm32_usbhost_s *priv) /* Set up the host periodic Tx FIFO size register (HPTXFSIZ) */ regval = (offset | - (CONFIG_EFM32_OTGFS_PTXFIFO_SIZE << _USB_HPTXFSIZ_PTXFSIZE_SHIFT)); + (CONFIG_EFM32_OTGFS_PTXFIFO_SIZE << + _USB_HPTXFSIZ_PTXFSIZE_SHIFT)); efm32_putreg(EFM32_USB_HPTXFSIZ, regval); /* If OTG were supported, we would need to clear HNP enable bit in the @@ -5088,8 +5205,8 @@ static void efm32_host_initialize(FAR struct efm32_usbhost_s *priv) for (i = 0; i < EFM32_NHOST_CHANNELS; i++) { - efm32_putreg(EFM32_USB_HCn_INT(i), 0xffffffff); - efm32_putreg(EFM32_USB_HCn_INTMSK(i), 0); + efm32_putreg(EFM32_USB_HC_INT(i), 0xffffffff); + efm32_putreg(EFM32_USB_HC_INTMSK(i), 0); } /* Driver Vbus +5V (the smoke test). Should be done elsewhere in OTG @@ -5223,7 +5340,8 @@ static inline int efm32_hw_initialize(FAR struct efm32_usbhost_s *priv) * 3. Program the USB_HPRT.PRTPWR bit to 1. This drives VBUS on the USB. * 4. Wait for the USB_HPRT.PRTCONNDET interrupt. This indicates that a * device is connect to the port. - * 5. Program the USB_HPRT.PRTRST bit to 1. This starts the reset process. + * 5. Program the USB_HPRT.PRTRST bit to 1. This starts the reset + * process. * 6. Wait at least 10 ms for the reset process to complete. * 7. Program the USB_HPRT.PRTRST bit to 0. * 8. Wait for the USB_HPRT.PRTENCHNG interrupt. @@ -5232,7 +5350,8 @@ static inline int efm32_hw_initialize(FAR struct efm32_usbhost_s *priv) * selected PHY clock. At this point, the host is up and running and * the port register begins to report device disconnects, etc. The * port is active with SOFs occurring down the enabled port. - * 11. Program the RXFSIZE register to select the size of the receive FIFO. + * 11. Program the RXFSIZE register to select the size of the receive + * FIFO. * 12. Program the NPTXFSIZE register to select the size and the start * address of the Non-periodic Transmit FIFO for non-periodic * transactions. @@ -5323,7 +5442,8 @@ FAR struct usbhost_connection_s *efm32_usbhost_initialize(int controller) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct efm32_usbhost_s *priv = &g_usbhost; diff --git a/arch/arm/src/efm32/hardware/efm32_usb.h b/arch/arm/src/efm32/hardware/efm32_usb.h index 2aeccb4893..233d188f6f 100644 --- a/arch/arm/src/efm32/hardware/efm32_usb.h +++ b/arch/arm/src/efm32/hardware/efm32_usb.h @@ -75,6 +75,7 @@ /******************************************************************************************************************************* * Pre-processor Definitions *******************************************************************************************************************************/ + /* General definitions */ #define EFM32_USB_EPTYPE_CTRL (0) /* Control */ @@ -130,7 +131,7 @@ #define EFM32_USB_HAINTMSK_OFFSET 0x3c418 /* Host All Channels Interrupt Mask Register */ #define EFM32_USB_HPRT_OFFSET 0x3c440 /* Host Port Control and Status Register */ -#define EFM32_USB_HCn_OFFSET(n) (0x3c500 + ((n) << 5)) +#define EFM32_USB_HC_OFFSET(n) (0x3c500 + ((n) << 5)) #define EFM32_USB_HC0_OFFSET 0x3c500 /* Host Channel 0 Offset */ #define EFM32_USB_HC1_OFFSET 0x3c520 /* Host Channel 1 Offset */ #define EFM32_USB_HC2_OFFSET 0x3c540 /* Host Channel 2 Offset */ @@ -146,11 +147,11 @@ #define EFM32_USB_HC12_OFFSET 0x3c680 /* Host Channel 12 Offset */ #define EFM32_USB_HC13_OFFSET 0x3c6a0 /* Host Channel 13 Offset */ -#define EFM32_USB_HCn_CHAR_OFFSET 0x00000 /* Host Channel n Characteristics Register */ -#define EFM32_USB_HCn_INT_OFFSET 0x00008 /* Host Channel n Interrupt Register */ -#define EFM32_USB_HCn_INTMSK_OFFSET 0x0000c /* Host Channel n Interrupt Mask Register */ -#define EFM32_USB_HCn_TSIZ_OFFSET 0x00010 /* Host Channel n Transfer Size Register */ -#define EFM32_USB_HCn_DMAADDR_OFFSET 0x00014 /* Host Channel n DMA Address Register */ +#define EFM32_USB_HC_CHAR_OFFSET 0x00000 /* Host Channel n Characteristics Register */ +#define EFM32_USB_HC_INT_OFFSET 0x00008 /* Host Channel n Interrupt Register */ +#define EFM32_USB_HC_INTMSK_OFFSET 0x0000c /* Host Channel n Interrupt Mask Register */ +#define EFM32_USB_HC_TSIZ_OFFSET 0x00010 /* Host Channel n Transfer Size Register */ +#define EFM32_USB_HC_DMAADDR_OFFSET 0x00014 /* Host Channel n DMA Address Register */ #define EFM32_USB_DCFG_OFFSET 0x3c800 /* Device Configuration Register */ #define EFM32_USB_DCTL_OFFSET 0x3c804 /* Device Control Register */ @@ -334,7 +335,7 @@ #define EFM32_USB_HAINTMSK (EFM32_USB_BASE+EFM32_USB_HAINTMSK_OFFSET) #define EFM32_USB_HPRT (EFM32_USB_BASE+EFM32_USB_HPRT_OFFSET) -#define EFM32_USB_HCn_BASE(n) (EFM32_USB_BASE+EFM32_USB_HCn_OFFSET(n)) +#define EFM32_USB_HC_BASE(n) (EFM32_USB_BASE+EFM32_USB_HC_OFFSET(n)) #define EFM32_USB_HC0_BASE (EFM32_USB_BASE+EFM32_USB_HC0_OFFSET) #define EFM32_USB_HC1_BASE (EFM32_USB_BASE+EFM32_USB_HC1_OFFSET) #define EFM32_USB_HC2_BASE (EFM32_USB_BASE+EFM32_USB_HC2_OFFSET) @@ -350,11 +351,11 @@ #define EFM32_USB_HC12_BASE (EFM32_USB_BASE+EFM32_USB_HC12_OFFSET) #define EFM32_USB_HC13_BASE (EFM32_USB_BASE+EFM32_USB_HC13_OFFSET) -#define EFM32_USB_HCn_CHAR(n) (EFM32_USB_HCn_BASE(n)+EFM32_USB_HCn_CHAR_OFFSET) -#define EFM32_USB_HCn_INT(n) (EFM32_USB_HCn_BASE(n)+EFM32_USB_HCn_INT_OFFSET) -#define EFM32_USB_HCn_INTMSK(n) (EFM32_USB_HCn_BASE(n)+EFM32_USB_HCn_INTMSK_OFFSET) -#define EFM32_USB_HCn_TSIZ(n) (EFM32_USB_HCn_BASE(n)+EFM32_USB_HCn_TSIZ_OFFSET) -#define EFM32_USB_HCn_DMAADDR(n) (EFM32_USB_HCn_BASE(n)+EFM32_USB_HCn_DMAADDR_OFFSET) +#define EFM32_USB_HC_CHAR(n) (EFM32_USB_HC_BASE(n)+EFM32_USB_HC_CHAR_OFFSET) +#define EFM32_USB_HC_INT(n) (EFM32_USB_HC_BASE(n)+EFM32_USB_HC_INT_OFFSET) +#define EFM32_USB_HC_INTMSK(n) (EFM32_USB_HC_BASE(n)+EFM32_USB_HC_INTMSK_OFFSET) +#define EFM32_USB_HC_TSIZ(n) (EFM32_USB_HC_BASE(n)+EFM32_USB_HC_TSIZ_OFFSET) +#define EFM32_USB_HC_DMAADDR(n) (EFM32_USB_HC_BASE(n)+EFM32_USB_HC_DMAADDR_OFFSET) #define EFM32_USB_DCFG (EFM32_USB_BASE+EFM32_USB_DCFG_OFFSET) #define EFM32_USB_DCTL (EFM32_USB_BASE+EFM32_USB_DCTL_OFFSET) diff --git a/arch/arm/src/imxrt/imxrt_ehci.c b/arch/arm/src/imxrt/imxrt_ehci.c index d506d937bd..e3f6485dbf 100644 --- a/arch/arm/src/imxrt/imxrt_ehci.c +++ b/arch/arm/src/imxrt/imxrt_ehci.c @@ -141,7 +141,7 @@ #define HCOR ((volatile struct ehci_hcor_s *)IMXRT_USBOTG_HCOR_BASE) -/* Interrupts **************************************************************** +/* Interrupts *************************************************************** * This is the set of interrupts handled by this driver. */ @@ -159,7 +159,7 @@ #define FRAME_LIST_SIZE 1024 -/* DMA ***********************************************************************/ +/* DMA **********************************************************************/ /* For now, we are assuming an identity mapping between physical and virtual * address spaces. @@ -168,7 +168,7 @@ #define imxrt_physramaddr(a) (a) #define imxrt_virtramaddr(a) (a) -/* USB trace *****************************************************************/ +/* USB trace ****************************************************************/ #ifdef HAVE_USBHOST_TRACE # define TR_FMT1 false @@ -433,7 +433,8 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, /* Semaphores ***************************************************************/ -static void imxrt_takesem(sem_t *sem); +static int imxrt_takesem(sem_t *sem); +static int imxrt_takesem_uninterruptible(sem_t *sem); #define imxrt_givesem(s) nxsem_post(s); /* Allocators ***************************************************************/ @@ -460,7 +461,8 @@ static int imxrt_qtd_invalidate(struct imxrt_qtd_s *qtd, uint32_t **bp, void *arg); static int imxrt_qh_invalidate(struct imxrt_qh_s *qh); #endif -static int imxrt_qtd_flush(struct imxrt_qtd_s *qtd, uint32_t **bp, void *arg); +static int imxrt_qtd_flush(struct imxrt_qtd_s *qtd, uint32_t **bp, + void *arg); static int imxrt_qh_flush(struct imxrt_qh_s *qh); /* Endpoint Transfer Handling ***********************************************/ @@ -487,14 +489,14 @@ static struct imxrt_qh_s *imxrt_qh_create(struct imxrt_rhport_s *rhport, struct imxrt_epinfo_s *epinfo); static int imxrt_qtd_addbpl(struct imxrt_qtd_s *qtd, const void *buffer, size_t buflen); -static struct imxrt_qtd_s *imxrt_qtd_setupphase(struct imxrt_epinfo_s *epinfo, - const struct usb_ctrlreq_s *req); +static struct imxrt_qtd_s *imxrt_qtd_setupphase( + struct imxrt_epinfo_s *epinfo, const struct usb_ctrlreq_s *req); static struct imxrt_qtd_s *imxrt_qtd_dataphase(struct imxrt_epinfo_s *epinfo, void *buffer, int buflen, uint32_t tokenbits); static struct imxrt_qtd_s *imxrt_qtd_statusphase(uint32_t tokenbits); -static ssize_t imxrtimxrt_virtramaddr_async_setup(struct imxrt_rhport_s *rhport, - struct imxrt_epinfo_s *epinfo, const struct usb_ctrlreq_s *req, - uint8_t *buffer, size_t buflen); +static ssize_t imxrtimxrt_virtramaddr_async_setup( + struct imxrt_rhport_s *rhport, struct imxrt_epinfo_s *epinfo, + const struct usb_ctrlreq_s *req, uint8_t *buffer, size_t buflen); #ifndef CONFIG_USBHOST_INT_DISABLE static int imxrt_intr_setup(struct imxrt_rhport_s *rhport, struct imxrt_epinfo_s *epinfo, uint8_t *buffer, size_t buflen); @@ -542,7 +544,8 @@ static int imxrt_epalloc(FAR struct usbhost_driver_s *drvr, static int imxrt_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int imxrt_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int imxrt_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int imxrt_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int imxrt_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); static int imxrt_iofree(FAR struct usbhost_driver_s *drvr, @@ -566,7 +569,7 @@ static int imxrt_connect(FAR struct usbhost_driver_s *drvr, static void imxrt_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static int imxrt_reset(void); @@ -645,69 +648,119 @@ static struct imxrt_qtd_s *g_qtdpool; static const struct imxrt_ehci_trace_s g_trace1[TRACE1_NSTRINGS] = { - TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, "EHCI ERROR: System error: %06x\n"), - TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qtd_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate a QH\n"), - TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, "EHCI ERROR: Buffer too big. Remaining %d\n"), - TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate request qTD"), - TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qtd_addbpl failed: %d\n"), - TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate data buffer qTD, 0"), - TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, "EHCI ERROR: Device disconnected %d\n"), - TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qh_create failed\n"), - TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qtd_setupphase failed\n"), + TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, + "EHCI ERROR: System error: %06x\n"), + TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qtd_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate a QH\n"), + TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, + "EHCI ERROR: Buffer too big. Remaining %d\n"), + TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate request qTD"), + TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qtd_addbpl failed: %d\n"), + TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate data buffer qTD, 0"), + TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, + "EHCI ERROR: Device disconnected %d\n"), + TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qh_create failed\n"), + TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qtd_setupphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qtd_dataphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qtd_statusphase failed\n"), - TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, "EHCI ERROR: Transfer failed %d\n"), - TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, "EHCI ERROR: imxrt_qh_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, "EHCI: Host System Error Interrupt\n"), - TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), - TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate EP info structure\n"), - TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, "EHCI ERROR: Support for transfer type %d not implemented\n"), - TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), - TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the QH pool\n"), + TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qtd_dataphase failed\n"), + TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qtd_statusphase failed\n"), + TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, + "EHCI ERROR: Transfer failed %d\n"), + TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_qh_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, + "EHCI: Host System Error Interrupt\n"), + TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, + "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), + TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate EP info structure\n"), + TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, + "EHCI ERROR: Support for transfer type %d not implemented\n"), + TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, + "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), + TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the QH pool\n"), - TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the qTD pool\n"), - TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the periodic frame list\n"), - TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, "EHCI ERROR: imxrt_reset failed: %d\n"), - TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), - TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, "EHCI ERROR: Failed to attach IRQ%d\n"), + TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the qTD pool\n"), + TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the periodic frame list\n"), + TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, + "EHCI ERROR: imxrt_reset failed: %d\n"), + TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, + "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), + TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, + "EHCI ERROR: Failed to attach IRQ%d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, "EHCI Connect Status Change: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, "EHCI Already connected: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, "EHCI Already disconnected: %06x\n"), - TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, "EHCI Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, "EHCI Async Advance Interrupt\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, + "EHCI Connect Status Change: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, + "EHCI Already connected: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, + "EHCI Already disconnected: %06x\n"), + TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, + "EHCI Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, + "EHCI Async Advance Interrupt\n"), - TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, "EHCI Hub port %d: Enumerate the device\n"), - TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, "EHCI Enumeration not connected\n"), - TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, "EHCI Initializing EHCI Stack\n"), - TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, "EHCI HCCPARAMS=%06x\n"), - TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, "EHCI USB EHCI Initialized\n"), + TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, + "EHCI Hub port %d: Enumerate the device\n"), + TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, + "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, + "EHCI Enumeration not connected\n"), + TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, + "EHCI Initializing EHCI Stack\n"), + TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, + "EHCI HCCPARAMS=%06x\n"), + TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, + "EHCI USB EHCI Initialized\n"), #endif }; static const struct imxrt_ehci_trace_s g_trace2[TRACE2_NSTRINGS] = { - TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, "EHCI EP%d Stalled: TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, "EHCI ERROR: EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), + TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, + "EHCI EP%d Stalled: TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, + "EHCI ERROR: EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, + "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, "EHCI Async transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, "EHCI Intr Transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, "EHCI IOC EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, "EHCI PORTSC%d: %04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, "EHCI RHPort%d connected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, "EHCI RHport%d disconnected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, "EHCI RHPort%d connected: %d\n"), + TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, + "EHCI Async transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, + "EHCI Intr Transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, + "EHCI IOC EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, + "EHCI PORTSC%d: %04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, + "EHCI RHPort%d connected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, + "EHCI RHport%d disconnected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, + "EHCI RHPort%d connected: %d\n"), - TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, "EHCI EPALLOC: EP%d TYPE=%d\n"), - TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), - TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, "EHCI HCIVERSION %x.%02x\n"), - TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, "EHCI nports=%d, HCSPARAMS=%04x\n"), + TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, + "EHCI EPALLOC: EP%d TYPE=%d\n"), + TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, + "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), + TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, + "EHCI HCIVERSION %x.%02x\n"), + TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, + "EHCI nports=%d, HCSPARAMS=%04x\n"), #endif }; #endif /* HAVE_USBHOST_TRACE */ @@ -1019,9 +1072,43 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, * ****************************************************************************/ -static void imxrt_takesem(sem_t *sem) +static int imxrt_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: imxrt_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int imxrt_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -1139,8 +1226,9 @@ static int imxrt_qh_foreach(struct imxrt_qh_s *qh, uint32_t **bp, DEBUGASSERT(qh && handler); while (qh) { - /* Is this the end of the list? Check the horizontal link pointer (HLP) - * terminate (T) bit. If T==1, then the HLP address is not valid. + /* Is this the end of the list? Check the horizontal link pointer + * (HLP) terminate (T) bit. If T==1, then the HLP address is not + * valid. */ physaddr = imxrt_swap32(qh->hw.hlp); @@ -1177,8 +1265,8 @@ static int imxrt_qh_foreach(struct imxrt_qh_s *qh, uint32_t **bp, * unlinking the entry! But that is okay because we already have the * next QH pointer. * - * Notice that we do not manage the back pointer (bp). If the call-out - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qh, bp, arg); @@ -1286,8 +1374,8 @@ static int imxrt_qtd_foreach(struct imxrt_qh_s *qh, foreach_qtd_t handler, * Name: imxrt_qtd_discard * * Description: - * This is a imxrt_qtd_foreach callback. It simply unlinks the QTD, updates - * the back pointer, and frees the QTD structure. + * This is a imxrt_qtd_foreach callback. It simply unlinks the QTD, + * updates the back pointer, and frees the QTD structure. * ****************************************************************************/ @@ -1390,8 +1478,8 @@ static int imxrt_qh_invalidate(struct imxrt_qh_s *qh) * Name: imxrt_qtd_flush * * Description: - * This is a callback from imxrt_qtd_foreach. It simply flushes D-cache for - * address range of the qTD entry. + * This is a callback from imxrt_qtd_foreach. It simply flushes D-cache + * for address range of the qTD entry. * ****************************************************************************/ @@ -1598,23 +1686,30 @@ static int imxrt_ioc_setup(struct imxrt_rhport_s *rhport, * Description: * Wait for the IOC event. * - * Assumption: The caller does *NOT* hold the EHCI exclsem. That would cause - * a deadlock when the bottom-half, worker thread needs to take the semaphore. + * Assumption: The caller does *NOT* hold the EHCI exclsem. That would + * cause a deadlock when the bottom-half, worker thread needs to take the + * semaphore. * ****************************************************************************/ static int imxrt_ioc_wait(struct imxrt_epinfo_s *epinfo) { + int ret = OK; + /* Wait for the IOC event. Loop to handle any false alarm semaphore - * counts. + * counts. Return an error if the task is canceled. */ while (epinfo->iocwait) { - imxrt_takesem(&epinfo->iocsem); + ret = imxrt_takesem(&epinfo->iocsem); + if (ret < 0) + { + break; + } } - return epinfo->result; + return ret < 0 ? ret : epinfo->result; } /**************************************************************************** @@ -1641,8 +1736,8 @@ static void imxrt_qh_enqueue(struct imxrt_qh_s *qhead, struct imxrt_qh_s *qh) /* Add the new QH to the head of the asynchronous queue list. * - * First, attach the old head as the new QH HLP and flush the new QH and its - * attached qTDs to RAM. + * First, attach the old head as the new QH HLP and flush the new QH and + * its attached qTDs to RAM. */ qh->hw.hlp = qhead->hw.hlp; @@ -1813,8 +1908,8 @@ static int imxrt_qtd_addbpl(struct imxrt_qtd_s *qtd, const void *buffer, uint32_t next; int ndx; - /* Flush the contents of the data buffer to RAM so that the correct contents - * will be accessed for an OUT DMA. + /* Flush the contents of the data buffer to RAM so that the correct + * contents will be accessed for an OUT DMA. */ up_flush_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); @@ -2326,11 +2421,12 @@ errout_with_qh: * millisecond period a transaction should be executed for the queue * head. Software must ensure that all queue heads in the periodic * schedule have S-Mask set to a non-zero value. An S-mask with a zero - * value in the context of the periodic schedule yields undefined results. + * value in the context of the periodic schedule yields undefined + * results. * - * "If the desired poll rate is greater than one frame, system software can - * use a combination of queue head linking and S-Mask values to spread - * interrupts of equal poll rates through the schedule so that the + * "If the desired poll rate is greater than one frame, system software + * can use a combination of queue head linking and S-Mask values to + * spread interrupts of equal poll rates through the schedule so that the * periodic bandwidth is allocated and managed in the most efficient * manner possible." * @@ -2471,6 +2567,7 @@ errout_with_qh: static ssize_t imxrt_transfer_wait(struct imxrt_epinfo_s *epinfo) { int ret; + int ret2; /* Release the EHCI semaphore while we wait. Other threads need the * opportunity to access the EHCI resources while we wait. @@ -2481,7 +2578,9 @@ static ssize_t imxrt_transfer_wait(struct imxrt_epinfo_s *epinfo) * or we will deadlock while waiting (because the working thread that * wakes this thread up needs the exclsem). */ -#warning REVISIT + + /* REVISIT */ + imxrt_givesem(&g_ehci.exclsem); /* Wait for the IOC completion event */ @@ -2492,7 +2591,11 @@ static ssize_t imxrt_transfer_wait(struct imxrt_epinfo_s *epinfo) * this upon return. */ - imxrt_takesem(&g_ehci.exclsem); + ret2 = imxrt_takesem_uninterruptible(&g_ehci.exclsem); + if (ret >= 0 && ret2 < 0) + { + ret = ret2; + } #if 0 /* Does not seem to be needed */ /* Was there a data buffer? Was this an OUT transfer? */ @@ -2512,7 +2615,9 @@ static ssize_t imxrt_transfer_wait(struct imxrt_epinfo_s *epinfo) } #endif - /* Did imxrt_ioc_wait() report an error? */ + /* Did imxrt_ioc_wait() or imxrt_takesem_uninterruptible() report an + * error? + */ if (ret < 0) { @@ -2690,10 +2795,10 @@ static int imxrt_qtd_ioccheck(struct imxrt_qtd_s *qtd, uint32_t **bp, * Name: imxrt_qh_ioccheck * * Description: - * This function is a imxrt_qh_foreach() callback function. It services one - * QH in the asynchronous queue. It check all attached qTD structures and - * remove all of the structures that are no longer active. if all of the - * qTD structures are removed, then QH itself will also be removed. + * This function is a imxrt_qh_foreach() callback function. It services + * one QH in the asynchronous queue. It check all attached qTD structures + * and remove all of the structures that are no longer active. if all of + * the qTD structures are removed, then QH itself will also be removed. * ****************************************************************************/ @@ -2718,7 +2823,7 @@ static int imxrt_qh_ioccheck(struct imxrt_qh_s *qh, uint32_t **bp, void *arg) epinfo = qh->epinfo; DEBUGASSERT(epinfo); - /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area + /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area * represent a transaction working space for the host controller. The * general operational model is that the host controller can detect * whether the overlay area contains a description of an active transfer. @@ -2739,6 +2844,7 @@ static int imxrt_qh_ioccheck(struct imxrt_qh_s *qh, uint32_t **bp, void *arg) /* Yes... we cannot process the QH while it is still active. Return * zero to visit the next QH in the list. */ + *bp = &qh->hw.hlp; return OK; } @@ -2821,6 +2927,7 @@ static int imxrt_qh_ioccheck(struct imxrt_qh_s *qh, uint32_t **bp, void *arg) epinfo->iocwait = false; imxrt_givesem(&epinfo->iocsem); } + #ifdef CONFIG_USBHOST_ASYNCH /* No.. Is there a pending asynchronous transfer? */ @@ -2858,7 +2965,8 @@ static int imxrt_qh_ioccheck(struct imxrt_qh_s *qh, uint32_t **bp, void *arg) ****************************************************************************/ #ifdef CONFIG_USBHOST_ASYNCH -static int imxrt_qtd_cancel(struct imxrt_qtd_s *qtd, uint32_t **bp, void *arg) +static int imxrt_qtd_cancel(struct imxrt_qtd_s *qtd, uint32_t **bp, + void *arg) { DEBUGASSERT(qtd != NULL && bp != NULL); @@ -2891,10 +2999,10 @@ static int imxrt_qtd_cancel(struct imxrt_qtd_s *qtd, uint32_t **bp, void *arg) * Name: imxrt_qh_cancel * * Description: - * This function is a imxrt_qh_foreach() callback function. It cancels one - * QH in the asynchronous queue. It will remove all attached qTD structures - * and remove all of the structures that are no longer active. Then QH - * itself will also be removed. + * This function is a imxrt_qh_foreach() callback function. It cancels + * one QH in the asynchronous queue. It will remove all attached qTD + * structures and remove all of the structures that are no longer active. + * Then QH itself will also be removed. * ****************************************************************************/ @@ -2968,7 +3076,7 @@ static int imxrt_qh_cancel(struct imxrt_qh_s *qh, uint32_t **bp, void *arg) * Description: * EHCI USB Interrupt (USBINT) "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 on the completion of a USB + * "The Host Controller sets this bit to 1 on the completion of a USB * transaction, which results in the retirement of a Transfer Descriptor * that had its IOC bit set. * @@ -2991,7 +3099,8 @@ static inline void imxrt_ioc_bottomhalf(void) */ up_invalidate_dcache((uintptr_t)&g_asynchead.hw, - (uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s)); + (uintptr_t)&g_asynchead.hw + + sizeof(struct ehci_qh_s)); /* Set the back pointer to the forward QH pointer of the asynchronous * queue head. @@ -3216,7 +3325,7 @@ static inline void imxrt_async_advance_bottomhalf(void) * Name: imxrt_ehci_bottomhalf * * Description: - * EHCI "Bottom Half" interrupt handler + * EHCI "Bottom Half" interrupt handler. Runs on a work queue thread. * ****************************************************************************/ @@ -3229,7 +3338,7 @@ static void imxrt_ehci_bottomhalf(FAR void *arg) * real option (other than to reschedule and delay). */ - imxrt_takesem(&g_ehci.exclsem); + imxrt_takesem_uninterruptible(&g_ehci.exclsem); /* Handle all unmasked interrupt sources * USB Interrupt (USBINT) @@ -3297,7 +3406,8 @@ static void imxrt_ehci_bottomhalf(FAR void *arg) * if the frame list size (as programmed in the Frame List Size field of * the USBCMD register) is 1024, the Frame Index Register rolls over * every time FRINDEX[13] toggles. Similarly, if the size is 512, the - * Host Controller sets this bit to a one every time FRINDEX[12] toggles." + * Host Controller sets this bit to a one every time FRINDEX[12] + * toggles." */ #if 0 /* Not used */ @@ -3378,9 +3488,9 @@ static int imxrt_ehci_interrupt(int irq, FAR void *context, FAR void *arg) pending = usbsts & regval; if (pending != 0) { - /* Schedule interrupt handling work for the high priority worker thread - * so that we are not pressed for time and so that we can interrupt with - * other USB threads gracefully. + /* Schedule interrupt handling work for the high priority worker + * thread so that we are not pressed for time and so that we can + * interrupt with other USB threads gracefully. * * The worker should be available now because we implement a handshake * by controlling the EHCI interrupts. @@ -3436,9 +3546,10 @@ static int imxrt_wait(FAR struct usbhost_connection_s *conn, { irqstate_t flags; int rhpndx; + int ret; - /* Loop until a change in the connection state changes on one of the root - * hub ports or until an error occurs. + /* Loop until the connection state changes on one of the root hub ports or + * until an error occurs. */ flags = enter_critical_section(); @@ -3497,7 +3608,11 @@ static int imxrt_wait(FAR struct usbhost_connection_s *conn, */ g_ehci.pscwait = true; - imxrt_takesem(&g_ehci.pscsem); + ret = imxrt_takesem(&g_ehci.pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3521,8 +3636,8 @@ static int imxrt_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3577,8 +3692,8 @@ static int imxrt_rh_enumerate(FAR struct usbhost_connection_s *conn, * 01b K-state Low-speed device, release ownership of port * * NOTE: Low-speed devices could be detected by examining the PORTSC PSPD - * field after resetting the device. The more conventional way here, however, - * also appears to work. + * field after resetting the device. The more conventional way here, + * however, also appears to work. */ regval = imxrt_getreg(&HCOR->portsc[rhpndx]); @@ -3623,7 +3738,7 @@ static int imxrt_rh_enumerate(FAR struct usbhost_connection_s *conn, /* Put the root hub port in reset. * - * Paragraph 2.3.9: + * EHCI Paragraph 2.3.9: * * "The HCHalted bit in the USBSTS register should be a zero before * software attempts to use [the Port Reset] bit. The host controller @@ -3635,12 +3750,12 @@ static int imxrt_rh_enumerate(FAR struct usbhost_connection_s *conn, /* EHCI paragraph 2.3.9: * * "When software writes a one to [the Port Reset] bit (from a zero), the - * bus reset sequence as defined in the USB Specification Revision 2.0 is - * started. Software writes a zero to this bit to terminate the bus reset - * sequence. Software must keep this bit at a one long enough to ensure - * the reset sequence, as specified in the USB Specification Revision 2.0, - * completes. Note: when software writes this bit to a one, it must also - * write a zero to the Port Enable bit." + * bus reset sequence as defined in the USB Specification Revision 2.0 + * is started. Software writes a zero to this bit to terminate the bus + * reset sequence. Software must keep this bit at a one long enough to + * ensure the reset sequence, as specified in the USB Specification + * Revision 2.0, completes. Note: when software writes this bit to a + * one, it must also write a zero to the Port Enable bit." */ regaddr = &HCOR->portsc[RHPNDX(rhport)]; @@ -3799,18 +3914,18 @@ static int imxrt_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * 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. A funcaddr of zero will be received - * if no address is yet assigned to the device. - * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. + * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or - * received from the endpoint in a single data packet + * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3822,21 +3937,25 @@ static int imxrt_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t speed, uint16_t maxpacketsize) { struct imxrt_epinfo_s *epinfo = (struct imxrt_epinfo_s *)ep0; + int ret; DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048); /* We must have exclusive access to the EHCI data structures. */ - imxrt_takesem(&g_ehci.exclsem); + ret = imxrt_takesem(&g_ehci.exclsem); + if (ret >= 0) + { + /* Remember the new device address and max packet size */ - /* Remember the new device address and max packet size */ + epinfo->devaddr = funcaddr; + epinfo->speed = speed; + epinfo->maxpacket = maxpacketsize; - epinfo->devaddr = funcaddr; - epinfo->speed = speed; - epinfo->maxpacket = maxpacketsize; + imxrt_givesem(&g_ehci.exclsem); + } - imxrt_givesem(&g_ehci.exclsem); - return OK; + return ret; } /**************************************************************************** @@ -3846,15 +3965,15 @@ static int imxrt_ep0configure(FAR struct usbhost_driver_s *drvr, * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the - * call to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. - * ep - A memory location provided by the caller in which to receive - * the allocated endpoint descriptor. + * ep - A memory location provided by the caller in which to receive the + * allocated endpoint descriptor. * * Returned Value: * On success, zero (OK) is returned. On a failure, a negated errno value - * is returned indicating the nature of the failure + * is returned indicating the nature of the failure. * * Assumptions: * This function will *not* be called from an interrupt handler. @@ -3868,8 +3987,8 @@ static int imxrt_epalloc(FAR struct usbhost_driver_s *drvr, struct imxrt_epinfo_s *epinfo; struct usbhost_hubport_s *hport; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && @@ -3888,7 +4007,8 @@ static int imxrt_epalloc(FAR struct usbhost_driver_s *drvr, /* Allocate a endpoint information structure */ - epinfo = (struct imxrt_epinfo_s *)kmm_zalloc(sizeof(struct imxrt_epinfo_s)); + epinfo = (struct imxrt_epinfo_s *) + kmm_zalloc(sizeof(struct imxrt_epinfo_s)); if (!epinfo) { usbhost_trace1(EHCI_TRACE1_EPALLOC_FAILED, 0); @@ -3926,7 +4046,7 @@ static int imxrt_epalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/***************************************************************************** +/**************************************************************************** * Name: imxrt_epfree * * Description: @@ -3976,16 +4096,16 @@ static int imxrt_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. - * buffer - The address of a memory location provided by the caller in which - * to return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which - * to return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4070,13 +4190,13 @@ static int imxrt_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int imxrt_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4109,8 +4229,8 @@ static int imxrt_ioalloc(FAR struct usbhost_driver_s *drvr, * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -4133,9 +4253,9 @@ static int imxrt_iofree(FAR struct usbhost_driver_s *drvr, * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer - * may be queued; Neither these methods nor the transfer() method can be - * called again until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. @@ -4155,8 +4275,8 @@ static int imxrt_iofree(FAR struct usbhost_driver_s *drvr, * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4191,7 +4311,11 @@ static int imxrt_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the EHCI hardware and data structures. */ - imxrt_takesem(&g_ehci.exclsem); + ret = imxrt_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4228,8 +4352,8 @@ static int imxrt_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer) { - /* imxrt_ctrlin can handle both directions. We just need to work around the - * differences in the function signatures. + /* imxrt_ctrlin can handle both directions. We just need to work around + * the differences in the function signatures. */ return imxrt_ctrlin(drvr, ep0, req, (uint8_t *)buffer); @@ -4240,8 +4364,8 @@ static int imxrt_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the @@ -4287,7 +4411,11 @@ static ssize_t imxrt_transfer(FAR struct usbhost_driver_s *drvr, /* We must have exclusive access to the EHCI hardware and data structures. */ - imxrt_takesem(&g_ehci.exclsem); + ret = imxrt_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4363,16 +4491,16 @@ errout_with_sem: * ep - The IN or OUT endpoint descriptor for the device endpoint on * which to perform the transfer. * buffer - A buffer containing the data to be sent (OUT endpoint) or - * received (IN endpoint). buffer must have been allocated using - * DRVR_ALLOC + * received (IN endpoint). buffer must have been allocated + * using DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. * arg - The arbitrary parameter that will be passed to the callback * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4393,7 +4521,11 @@ static int imxrt_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the EHCI hardware and data structures. */ - imxrt_takesem(&g_ehci.exclsem); + ret = imxrt_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the callback well BEFORE initiating the transfer. */ @@ -4460,12 +4592,12 @@ errout_with_sem: * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the * call to the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which - * an asynchronous transfer should be transferred. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * ****************************************************************************/ @@ -4493,7 +4625,11 @@ static int imxrt_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * interrupt level. */ - imxrt_takesem(&g_ehci.exclsem); + ret = imxrt_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Sample and reset all transfer termination information. This will * prevent any callbacks from occurring while are performing the @@ -4601,12 +4737,12 @@ static int imxrt_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Find and remove the QH. There are four possibilities: * * 1) The transfer has already completed and the QH is no longer in the - * list. In this case, imxrt_hq_foreach will return zero + * list. In this case, sam_hq_foreach will return zero * 2a) The transfer is not active and still pending. It was removed from - * the list and imxrt_hq_foreach will return one. + * the list and sam_hq_foreach will return one. * 2b) The is active but not yet complete. This is currently handled the * same as 2a). REVISIT: This needs to be fixed. - * 3) Some bad happened and imxrt_hq_foreach returned an error code < 0. + * 3) Some bad happened and sam_hq_foreach returned an error code < 0. */ ret = imxrt_qh_foreach(qh, &bp, imxrt_qh_cancel, epinfo); @@ -4657,17 +4793,17 @@ errout_with_sem: * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - *****************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int imxrt_connect(FAR struct usbhost_driver_s *drvr, @@ -4711,10 +4847,10 @@ static int imxrt_connect(FAR struct usbhost_driver_s *drvr, * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. - * hport - The port from which the device is being disconnected. Might be a - * port on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4781,11 +4917,11 @@ static int imxrt_reset(void) uint32_t regval; unsigned int timeout; - /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to 0, - * the Host Controller completes the current transaction on the USB and then - * halts. The HC Halted bit in the status register indicates when the Hos - * Controller has finished the transaction and has entered the stopped - * state..." + /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to + * 0, the Host Controller completes the current transaction on the USB and + * then halts. The HC Halted bit in the status register indicates when the + * Host Controller has finished the transaction and has entered the + * stopped state..." */ imxrt_putreg(0, &HCOR->usbcmd); @@ -4852,6 +4988,7 @@ static int imxrt_reset(void) /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: imxrt_ehci_initialize * @@ -4960,8 +5097,8 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) rhport->ep0.speed = USB_SPEED_FULL; rhport->ep0.maxpacket = 8; - /* The EP0 iocsem semaphore is used for signaling and, hence, should not - * have priority inheritance enabled. + /* The EP0 iocsem semaphore is used for signaling and, hence, should + * not have priority inheritance enabled. */ nxsem_init(&rhport->ep0.iocsem, 0, 0); @@ -5048,7 +5185,7 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) imxrt_clockall_usboh3(); - /* Reset the controller from the OTG peripheral */ + /* Reset the controller from the OTG peripheral */ putreg32(USBDEV_USBCMD_RST, IMXRT_USBDEV_USBCMD); while ((getreg32(IMXRT_USBDEV_USBCMD) & USBDEV_USBCMD_RST) != 0); @@ -5078,8 +5215,8 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) } /* Re-program the USB host controller. As implemented, imxrt_reset() - * requires the host mode setup in order to work. However, we lose the host - * configuration in the reset. + * requires the host mode setup in order to work. However, we lose the + * host configuration in the reset. */ # ifdef CONFIG_IMXRT_EHCI_SDIS @@ -5223,7 +5360,7 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) return NULL; } - /* Interrupt Configuration *************************************************/ + /* Interrupt Configuration ************************************************/ ret = irq_attach(IMXRT_IRQ_USBOTG1, imxrt_ehci_interrupt, NULL); if (ret != 0) @@ -5253,8 +5390,8 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) } /* If there is a USB device in the slot at power up, then we will not get - * the status change interrupt to signal us that the device is connected. We - * need to set the initial connected state accordingly. + * the status change interrupt to signal us that the device is connected. + * We need to set the initial connected state accordingly. */ for (i = 0; i < IMXRT_EHCI_NRHPORT; i++) @@ -5272,7 +5409,7 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) return &g_ehciconn; } -/***************************************************************************** +/**************************************************************************** * Name: usbhost_trformat1 and usbhost_trformat2 * * Description: @@ -5283,7 +5420,7 @@ FAR struct usbhost_connection_s *imxrt_ehci_initialize(int controller) * printf. The returned format is expected to handle two unsigned integer * values. * - *****************************************************************************/ + ****************************************************************************/ #ifdef HAVE_USBHOST_TRACE FAR const char *usbhost_trformat1(uint16_t id) diff --git a/arch/arm/src/lpc17xx_40xx/lpc17_40_usbhost.c b/arch/arm/src/lpc17xx_40xx/lpc17_40_usbhost.c index 61279e83cf..efba0413f1 100644 --- a/arch/arm/src/lpc17xx_40xx/lpc17_40_usbhost.c +++ b/arch/arm/src/lpc17xx_40xx/lpc17_40_usbhost.c @@ -74,11 +74,11 @@ * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ +/* Configuration ************************************************************/ /* All I/O buffers must lie in AHB SRAM because of the OHCI DMA. It might be - * okay if no I/O buffers are used *IF* the application can guarantee that all - * end-user I/O buffers reside in AHB SRAM. + * okay if no I/O buffers are used *IF* the application can guarantee that + * all end-user I/O buffers reside in AHB SRAM. */ #if LPC17_40_IOBUFFERS < 1 @@ -93,7 +93,8 @@ # undef CONFIG_LPC17_40_USBHOST_REGDEBUG #endif -/* OHCI Setup ******************************************************************/ +/* OHCI Setup ***************************************************************/ + /* Frame Interval / Periodic Start */ #define BITS_PER_FRAME 12000 @@ -129,7 +130,7 @@ # define usbhost_dumpgpio() #endif -/* USB Host Memory *************************************************************/ +/* USB Host Memory **********************************************************/ /* Helper definitions */ @@ -142,7 +143,7 @@ #define MIN_PERINTERVAL 2 #define MAX_PERINTERVAL 32 -/* Descriptors *****************************************************************/ +/* Descriptors **************************************************************/ /* TD delay interrupt value */ @@ -218,8 +219,8 @@ struct lpc17_40_xfrinfo_s /* The OCHI expects the size of an endpoint descriptor to be 16 bytes. * However, the size allocated for an endpoint descriptor is 32 bytes in - * lpc17_40_ohciram.h. This extra 16-bytes is used by the OHCI host driver in - * order to maintain additional endpoint-specific data. + * lpc17_40_ohciram.h. This extra 16-bytes is used by the OHCI host driver + * in order to maintain additional endpoint-specific data. */ struct lpc17_40_ed_s @@ -232,8 +233,11 @@ struct lpc17_40_ed_s uint8_t xfrtype; /* 16: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */ uint8_t interval; /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */ - sem_t wdhsem; /* 18: Semaphore used to wait for Writeback Done Head event */ - /* Unused bytes may follow, depending on the size of sem_t */ + sem_t wdhsem; /* 18: Semaphore used to wait for Writeback + * Done Head event */ + + /* Unused bytes may follow, depending on the size of sem_t */ + /* Pointer to structure that manages asynchronous transfers on this pipe */ struct lpc17_40_xfrinfo_s *xfrinfo; @@ -241,8 +245,8 @@ struct lpc17_40_ed_s /* The OCHI expects the size of an transfer descriptor to be 16 bytes. * However, the size allocated for an endpoint descriptor is 32 bytes in - * lpc17_40_ohciram.h. This extra 16-bytes is used by the OHCI host driver in - * order to maintain additional endpoint-specific data. + * lpc17_40_ohciram.h. This extra 16-bytes is used by the OHCI host driver + * in order to maintain additional endpoint-specific data. */ struct lpc17_40_gtd_s @@ -262,14 +266,15 @@ struct lpc17_40_gtd_s struct lpc17_40_list_s { struct lpc17_40_list_s *flink; /* Link to next buffer in the list */ - /* Variable length buffer data follows */ + + /* Variable length buffer data follows */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_LPC17_40_USBHOST_REGDEBUG static void lpc17_40_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -281,19 +286,20 @@ static void lpc17_40_putreg(uint32_t val, uint32_t addr); # define lpc17_40_putreg(val,addr) putreg32(val,addr) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void lpc17_40_takesem(sem_t *sem); +static int lpc17_40_takesem(sem_t *sem); +static int lpc17_40_takesem_uninterruptible(sem_t *sem); #define lpc17_40_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t lpc17_40_getle16(const uint8_t *val); #if 0 /* Not used */ static void lpc17_40_putle16(uint8_t *dest, uint16_t val); #endif -/* OHCI memory pool helper functions *******************************************/ +/* OHCI memory pool helper functions ****************************************/ static inline void lpc17_40_edfree(struct lpc17_40_ed_s *ed); static struct lpc17_40_gtd_s *lpc17_40_tdalloc(void); @@ -307,105 +313,111 @@ static void lpc17_40_freeio(uint8_t *buffer); static struct lpc17_40_xfrinfo_s *lpc17_40_alloc_xfrinfo(void); static void lpc17_40_free_xfrinfo(struct lpc17_40_xfrinfo_s *xfrinfo); -/* ED list helper functions ****************************************************/ +/* ED list helper functions *************************************************/ static inline int lpc17_40_addctrled(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); static inline int lpc17_40_remctrled(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); static inline int lpc17_40_addbulked(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); static inline int lpc17_40_rembulked(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) static unsigned int lpc17_40_getinterval(uint8_t interval); -static void lpc17_40_setinttab(uint32_t value, unsigned int interval, unsigned int offset); +static void lpc17_40_setinttab(uint32_t value, unsigned int interval, + unsigned int offset); #endif static inline int lpc17_40_addinted(struct lpc17_40_usbhost_s *priv, - const struct usbhost_epdesc_s *epdesc, - struct lpc17_40_ed_s *ed); + const struct usbhost_epdesc_s *epdesc, + struct lpc17_40_ed_s *ed); static inline int lpc17_40_reminted(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); static inline int lpc17_40_addisoced(struct lpc17_40_usbhost_s *priv, - const struct usbhost_epdesc_s *epdesc, - struct lpc17_40_ed_s *ed); + const struct usbhost_epdesc_s *epdesc, + struct lpc17_40_ed_s *ed); static inline int lpc17_40_remisoced(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); + struct lpc17_40_ed_s *ed); -/* Descriptor helper functions *************************************************/ +/* Descriptor helper functions **********************************************/ static int lpc17_40_enqueuetd(struct lpc17_40_usbhost_s *priv, + struct lpc17_40_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen); +static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s *ed, uint32_t dirpid, - uint32_t toggle, volatile uint8_t *buffer, - size_t buflen); -static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s *ed, - uint32_t dirpid, uint8_t *buffer, size_t buflen); + uint8_t *buffer, size_t buflen); -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int lpc17_40_wait(struct usbhost_connection_s *conn, - struct usbhost_hubport_s **hport); + struct usbhost_hubport_s **hport); static int lpc17_40_rh_enumerate(struct usbhost_connection_s *conn, - struct usbhost_hubport_s *hport); + struct usbhost_hubport_s *hport); static int lpc17_40_enumerate(struct usbhost_connection_s *conn, - struct usbhost_hubport_s *hport); + struct usbhost_hubport_s *hport); static int lpc17_40_ep0configure(struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int lpc17_40_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); static int lpc17_40_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int lpc17_40_alloc(struct usbhost_driver_s *drvr, - uint8_t **buffer, size_t *maxlen); + uint8_t **buffer, size_t *maxlen); static int lpc17_40_free(struct usbhost_driver_s *drvr, uint8_t *buffer); static int lpc17_40_ioalloc(struct usbhost_driver_s *drvr, - uint8_t **buffer, size_t buflen); + uint8_t **buffer, size_t buflen); static int lpc17_40_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer); static int lpc17_40_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - const struct usb_ctrlreq_s *req, - uint8_t *buffer); + const struct usb_ctrlreq_s *req, + uint8_t *buffer); static int lpc17_40_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - const struct usb_ctrlreq_s *req, - const uint8_t *buffer); + const struct usb_ctrlreq_s *req, + const uint8_t *buffer); static int lpc17_40_transfer_common(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *buffer, - size_t buflen); + struct lpc17_40_ed_s *ed, + uint8_t *buffer, size_t buflen); #if LPC17_40_IOBUFFERS > 0 static int lpc17_40_dma_alloc(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *userbuffer, - size_t buflen, uint8_t **alloc); + struct lpc17_40_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t **alloc); static void lpc17_40_dma_free(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *userbuffer, - size_t buflen, uint8_t *alloc); + struct lpc17_40_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t *alloc); #endif -static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen); +static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void lpc17_40_asynch_completion(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed); -static int lpc17_40_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen, - usbhost_asynch_t callback, FAR void *arg); + struct lpc17_40_ed_s *ed); +static int lpc17_40_asynch(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen, usbhost_asynch_t callback, + FAR void *arg); #endif -static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); +static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep); #ifdef CONFIG_USBHOST_HUB static int lpc17_40_connect(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_hubport_s *hport, - bool connected); + FAR struct usbhost_hubport_s *hport, + bool connected); #endif static void lpc17_40_disconnect(struct usbhost_driver_s *drvr, - struct usbhost_hubport_s *hport); + struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static inline void lpc17_40_ep0init(struct lpc17_40_usbhost_s *priv); @@ -413,9 +425,9 @@ static inline void lpc17_40_ep0init(struct lpc17_40_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct lpc17_40_usbhost_s g_usbhost; @@ -440,11 +452,8 @@ static struct lpc17_40_list_s *g_iofree; /* List of unused I/O buffers */ /* Pool and freelist of transfer structures */ static struct lpc17_40_list_s *g_xfrfree; -static struct lpc17_40_xfrinfo_s g_xfrbuffers[CONFIG_LPC17_40_USBHOST_NPREALLOC]; - -/**************************************************************************** - * Public Data - ****************************************************************************/ +static struct lpc17_40_xfrinfo_s + g_xfrbuffers[CONFIG_LPC17_40_USBHOST_NPREALLOC]; /**************************************************************************** * Private Functions @@ -481,8 +490,8 @@ static void lpc17_40_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -581,9 +590,43 @@ static void lpc17_40_putreg(uint32_t val, uint32_t addr) * ****************************************************************************/ -static void lpc17_40_takesem(sem_t *sem) +static int lpc17_40_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: lpc17_40_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int lpc17_40_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -652,8 +695,8 @@ static struct lpc17_40_gtd_s *lpc17_40_tdalloc(void) struct lpc17_40_gtd_s *ret; irqstate_t flags; - /* Disable interrupts momentarily so that lpc17_40_tdfree is not called from the - * interrupt handler. + /* Disable interrupts momentarily so that lpc17_40_tdfree is not called + * from the interrupt handler. */ flags = enter_critical_section(); @@ -674,7 +717,8 @@ static struct lpc17_40_gtd_s *lpc17_40_tdalloc(void) * Return an transfer descriptor to the free list * * Assumptions: - * - Only called from the WDH interrupt handler (and during initialization). + * - Only called from the WDH interrupt handler (and during + * initialization). * - Interrupts are disabled in any case. * ****************************************************************************/ @@ -713,6 +757,7 @@ static uint8_t *lpc17_40_tballoc(void) { g_tbfree = ((struct lpc17_40_list_s *)ret)->flink; } + return ret; } @@ -852,7 +897,7 @@ static void lpc17_40_free_xfrinfo(struct lpc17_40_xfrinfo_s *xfrinfo) ****************************************************************************/ static inline int lpc17_40_addctrled(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { irqstate_t flags; uint32_t regval; @@ -890,7 +935,7 @@ static inline int lpc17_40_addctrled(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static inline int lpc17_40_remctrled(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { struct lpc17_40_ed_s *curr; struct lpc17_40_ed_s *prev; @@ -907,10 +952,14 @@ static inline int lpc17_40_remctrled(struct lpc17_40_usbhost_s *priv, /* Find the ED in the control list. */ - head = (struct lpc17_40_ed_s *)lpc17_40_getreg(LPC17_40_USBHOST_CTRLHEADED); + head = (struct lpc17_40_ed_s *) + lpc17_40_getreg(LPC17_40_USBHOST_CTRLHEADED); + for (prev = NULL, curr = head; curr && curr != ed; - prev = curr, curr = (struct lpc17_40_ed_s *)curr->hw.nexted); + prev = curr, curr = (struct lpc17_40_ed_s *)curr->hw.nexted) + { + } /* It would be a bug if we do not find the ED in the control list. */ @@ -972,7 +1021,7 @@ static inline int lpc17_40_remctrled(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static inline int lpc17_40_addbulked(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_BULK_DISABLE irqstate_t flags; @@ -1014,7 +1063,7 @@ static inline int lpc17_40_addbulked(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static inline int lpc17_40_rembulked(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_BULK_DISABLE struct lpc17_40_ed_s *curr; @@ -1032,10 +1081,14 @@ static inline int lpc17_40_rembulked(struct lpc17_40_usbhost_s *priv, /* Find the ED in the bulk list. */ - head = (struct lpc17_40_ed_s *)lpc17_40_getreg(LPC17_40_USBHOST_BULKHEADED); + head = (struct lpc17_40_ed_s *) + lpc17_40_getreg(LPC17_40_USBHOST_BULKHEADED); + for (prev = NULL, curr = head; curr && curr != ed; - prev = curr, curr = (struct lpc17_40_ed_s *)curr->hw.nexted); + prev = curr, curr = (struct lpc17_40_ed_s *)curr->hw.nexted) + { + } /* It would be a bug if we do not find the ED in the bulk list. */ @@ -1096,9 +1149,10 @@ static inline int lpc17_40_rembulked(struct lpc17_40_usbhost_s *priv, #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) static unsigned int lpc17_40_getinterval(uint8_t interval) { - /* The bInterval field of the endpoint descriptor contains the polling interval - * for interrupt and isochronous endpoints. For other types of endpoint, this - * value should be ignored. bInterval is provided in units of 1MS frames. + /* The bInterval field of the endpoint descriptor contains the polling + * interval for interrupt and isochronous endpoints. For other types of + * endpoint, this value should be ignored. bInterval is provided in units + * of 1MS frames. */ if (interval < 3) @@ -1128,13 +1182,14 @@ static unsigned int lpc17_40_getinterval(uint8_t interval) * Name: lpc17_40_setinttab * * Description: - * Set the interrupt table to the selected value using the provided interval - * and offset. + * Set the interrupt table to the selected value using the provided + * interval and offset. * ****************************************************************************/ #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) -static void lpc17_40_setinttab(uint32_t value, unsigned int interval, unsigned int offset) +static void lpc17_40_setinttab(uint32_t value, unsigned int interval, + unsigned int offset) { unsigned int i; for (i = offset; i < HCCA_INTTBL_WSIZE; i += interval) @@ -1150,23 +1205,24 @@ static void lpc17_40_setinttab(uint32_t value, unsigned int interval, unsigned i * Description: * Helper function to add an ED to the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ static inline int lpc17_40_addinted(struct lpc17_40_usbhost_s *priv, - const struct usbhost_epdesc_s *epdesc, - struct lpc17_40_ed_s *ed) + const struct usbhost_epdesc_s *epdesc, + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_INT_DISABLE unsigned int interval; @@ -1174,8 +1230,8 @@ static inline int lpc17_40_addinted(struct lpc17_40_usbhost_s *priv, uint32_t head; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ regval = lpc17_40_getreg(LPC17_40_USBHOST_CTRL); @@ -1221,6 +1277,7 @@ static inline int lpc17_40_addinted(struct lpc17_40_usbhost_s *priv, interval = priv->outinterval; } } + uinfo("min interval: %d offset: %d\n", interval, offset); /* Get the head of the first of the duplicated entries. The first offset @@ -1259,22 +1316,23 @@ static inline int lpc17_40_addinted(struct lpc17_40_usbhost_s *priv, * Description: * Helper function to remove an ED from the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ static inline int lpc17_40_reminted(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_INT_DISABLE struct lpc17_40_ed_s *head; @@ -1284,8 +1342,8 @@ static inline int lpc17_40_reminted(struct lpc17_40_usbhost_s *priv, unsigned int offset; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ regval = lpc17_40_getreg(LPC17_40_USBHOST_CTRL); @@ -1372,8 +1430,8 @@ static inline int lpc17_40_reminted(struct lpc17_40_usbhost_s *priv, priv->outinterval = interval; } - /* Set the head ED in all of the appropriate entries of the HCCA interrupt - * table (head might be NULL). + /* Set the head ED in all of the appropriate entries of the HCCA + * interrupt table (head might be NULL). */ lpc17_40_setinttab((uint32_t)head, interval, offset); @@ -1403,8 +1461,8 @@ static inline int lpc17_40_reminted(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static inline int lpc17_40_addisoced(struct lpc17_40_usbhost_s *priv, - const struct usbhost_epdesc_s *epdesc, - struct lpc17_40_ed_s *ed) + const struct usbhost_epdesc_s *epdesc, + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_ISOC_DISABLE # warning "Isochronous endpoints not yet supported" @@ -1421,7 +1479,7 @@ static inline int lpc17_40_addisoced(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static inline int lpc17_40_remisoced(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { #ifndef CONFIG_USBHOST_ISOC_DISABLE # warning "Isochronous endpoints not yet supported" @@ -1439,8 +1497,9 @@ static inline int lpc17_40_remisoced(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static int lpc17_40_enqueuetd(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint32_t dirpid, - uint32_t toggle, volatile uint8_t *buffer, size_t buflen) + struct lpc17_40_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen) { struct lpc17_40_gtd_s *td; int ret = -ENOMEM; @@ -1452,7 +1511,8 @@ static int lpc17_40_enqueuetd(struct lpc17_40_usbhost_s *priv, { /* Initialize the allocated TD and link it before the common tail TD. */ - td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK); + td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | + GTD_STATUS_CC_MASK); TDTAIL->hw.ctrl = 0; td->hw.cbp = (uint32_t)buffer; TDTAIL->hw.cbp = 0; @@ -1480,14 +1540,16 @@ static int lpc17_40_enqueuetd(struct lpc17_40_usbhost_s *priv, * Name: lpc17_40_wdhwait * * Description: - * Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * ****************************************************************************/ -static int lpc17_40_wdhwait(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s *ed) +static int lpc17_40_wdhwait(struct lpc17_40_usbhost_s *priv, + struct lpc17_40_ed_s *ed) { struct lpc17_40_xfrinfo_s *xfrinfo; irqstate_t flags = enter_critical_section(); @@ -1500,8 +1562,9 @@ static int lpc17_40_wdhwait(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_ if (priv->connected) { - /* Yes.. then set wdhwait to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set wdhwait to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ xfrinfo->wdhwait = true; @@ -1517,17 +1580,18 @@ static int lpc17_40_wdhwait(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_ * * Description: * Process a IN or OUT request on the control endpoint. This function - * will enqueue the request and wait for it to complete. Only one transfer - * may be queued; Neither these methods nor the transfer() method can be - * called again until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * ****************************************************************************/ -static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s *ed, - uint32_t dirpid, uint8_t *buffer, size_t buflen) +static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, + struct lpc17_40_ed_s *ed, uint32_t dirpid, + uint8_t *buffer, size_t buflen) { struct lpc17_40_xfrinfo_s *xfrinfo; uint32_t toggle; @@ -1555,8 +1619,8 @@ static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s ed->xfrinfo = xfrinfo; - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ ret = lpc17_40_wdhwait(priv, ed); @@ -1583,8 +1647,8 @@ static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s ret = lpc17_40_enqueuetd(priv, ed, dirpid, toggle, buffer, buflen); if (ret == OK) { - /* Set ControlListFilled. This bit is used to indicate whether there are - * TDs on the Control list. + /* Set ControlListFilled. This bit is used to indicate whether there + * are TDs on the Control list. */ regval = lpc17_40_getreg(LPC17_40_USBHOST_CMDST); @@ -1593,11 +1657,15 @@ static int lpc17_40_ctrltd(struct lpc17_40_usbhost_s *priv, struct lpc17_40_ed_s /* Wait for the Writeback Done Head interrupt */ - lpc17_40_takesem(&ed->wdhsem); + ret = lpc17_40_takesem(&ed->wdhsem); + if (ret < 0) + { + /* Task has been canceled */ + } /* Check the TD completion status bits */ - if (xfrinfo->tdstatus == TD_CC_NOERROR) + else if (xfrinfo->tdstatus == TD_CC_NOERROR) { ret = OK; } @@ -1690,7 +1758,8 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) } else { - uwarn("WARNING: Spurious status change (connected)\n"); + uwarn("WARNING: Spurious status change " + "(connected)\n"); } /* The LSDA (Low speed device attached) bit is valid @@ -1746,13 +1815,15 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) } else { - uwarn("WARNING: Spurious status change (disconnected)\n"); + uwarn("WARNING: Spurious status change " + "(disconnected)\n"); } } /* Clear the status change interrupt */ - lpc17_40_putreg(OHCI_RHPORTST_CSC, LPC17_40_USBHOST_RHPORTST1); + lpc17_40_putreg(OHCI_RHPORTST_CSC, + LPC17_40_USBHOST_RHPORTST1); } /* Check for port reset status change */ @@ -1761,7 +1832,8 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) { /* Release the RH port from reset */ - lpc17_40_putreg(OHCI_RHPORTST_PRSC, LPC17_40_USBHOST_RHPORTST1); + lpc17_40_putreg(OHCI_RHPORTST_PRSC, + LPC17_40_USBHOST_RHPORTST1); } } @@ -1772,17 +1844,18 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) struct lpc17_40_gtd_s *td; struct lpc17_40_gtd_s *next; - /* The host controller just wrote the list of finished TDs into the HCCA - * done head. This may include multiple packets that were transferred - * in the preceding frame. + /* The host controller just wrote the list of finished TDs into + * the HCCA done head. This may include multiple packets that + * were transferred in the preceding frame. * - * Remove the TD(s) from the Writeback Done Head in the HCCA and return - * them to the free list. Note that this is safe because the hardware - * will not modify the writeback done head again until the WDH bit is - * cleared in the interrupt status register. + * Remove the TD(s) from the Writeback Done Head in the HCCA and + * return them to the free list. Note that this is safe because + * the hardware will not modify the writeback done head again + * until the WDH bit is cleared in the interrupt status register. */ - td = (struct lpc17_40_gtd_s *)(HCCA->donehead & HCCA_DONEHEAD_MASK); + td = (struct lpc17_40_gtd_s *) + (HCCA->donehead & HCCA_DONEHEAD_MASK); HCCA->donehead = 0; next = NULL; @@ -1797,7 +1870,9 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) */ if ((uintptr_t)td < LPC17_40_TDFREE_BASE || - (uintptr_t)td >= (LPC17_40_TDFREE_BASE + LPC17_40_TD_SIZE*CONFIG_LP17_USBHOST_NTDS)) + (uintptr_t)td >= (LPC17_40_TDFREE_BASE + + LPC17_40_TD_SIZE * + CONFIG_LP17_USBHOST_NTDS)) { break; } @@ -1807,26 +1882,29 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) ed = td->ed; DEBUGASSERT(ed != NULL); - /* If there is a transfer in progress, then the xfrinfo pointer will be - * non-NULL. But it appears that a NULL pointer may be received with a - * spurious interrupt such as may occur after a transfer is cancelled. + /* If there is a transfer in progress, then the xfrinfo + * pointer will be non-NULL. But it appears that a NULL + * pointer may be received with a spurious interrupt such as + * may occur after a transfer is cancelled. */ xfrinfo = ed->xfrinfo; if (xfrinfo) { - /* Save the condition code from the (single) TD status/control - * word. + /* Save the condition code from the (single) TD + * status/control word. */ - xfrinfo->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + xfrinfo->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> + GTD_STATUS_CC_SHIFT; #ifdef CONFIG_DEBUG_USB if (xfrinfo->tdstatus != TD_CC_NOERROR) { /* The transfer failed for some reason... dump some diagnostic info. */ - uerr("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d RHPORTST1:%08x\n", + uerr("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d " + "RHPORTST1:%08x\n", ed->xfrtype, td->hw.ctrl, xfrinfo->tdstatus, lpc17_40_getreg(LPC17_40_USBHOST_RHPORTST1)); } @@ -1902,10 +1980,6 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) return OK; } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ - /**************************************************************************** * Name: lpc17_40_wait * @@ -1913,10 +1987,10 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or @@ -1932,11 +2006,12 @@ static int lpc17_40_usbinterrupt(int irq, void *context, FAR void *arg) ****************************************************************************/ static int lpc17_40_wait(struct usbhost_connection_s *conn, - struct usbhost_hubport_s **hport) + struct usbhost_hubport_s **hport) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)&g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; flags = enter_critical_section(); for (; ; ) @@ -1983,7 +2058,8 @@ static int lpc17_40_wait(struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -1991,7 +2067,11 @@ static int lpc17_40_wait(struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - lpc17_40_takesem(&priv->pscsem); + ret = lpc17_40_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -2015,8 +2095,8 @@ static int lpc17_40_wait(struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -2024,7 +2104,7 @@ static int lpc17_40_wait(struct usbhost_connection_s *conn, ****************************************************************************/ static int lpc17_40_rh_enumerate(struct usbhost_connection_s *conn, - struct usbhost_hubport_s *hport) + struct usbhost_hubport_s *hport) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)&g_usbhost; DEBUGASSERT(conn != NULL && hport != NULL && hport->port == 0); @@ -2043,20 +2123,25 @@ static int lpc17_40_rh_enumerate(struct usbhost_connection_s *conn, /* USB 2.0 spec says at least 50ms delay before port reset */ - nxsig_usleep(100*1000); + nxsig_usleep(100 * 1000); - /* Put RH port 1 in reset (the LPC176x supports only a single downstream port) */ + /* Put RH port 1 in reset (the LPC176x supports only a single downstream + * port). + */ lpc17_40_putreg(OHCI_RHPORTST_PRS, LPC17_40_USBHOST_RHPORTST1); /* Wait for the port reset to complete */ - while ((lpc17_40_getreg(LPC17_40_USBHOST_RHPORTST1) & OHCI_RHPORTST_PRS) != 0); + while ((lpc17_40_getreg(LPC17_40_USBHOST_RHPORTST1) & OHCI_RHPORTST_PRS) + != 0) + { + } /* Release RH port 1 from reset and wait a bit */ lpc17_40_putreg(OHCI_RHPORTST_PRSC, LPC17_40_USBHOST_RHPORTST1); - nxsig_usleep(200*1000); + nxsig_usleep(200 * 1000); return OK; } @@ -2095,7 +2180,7 @@ static int lpc17_40_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_ep0configure * * Description: @@ -2104,37 +2189,45 @@ static int lpc17_40_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * mps (maxpacketsize) - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc17_40_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) +static int lpc17_40_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct lpc17_40_ed_s *ed; uint32_t hwctrl; + int ret; - DEBUGASSERT(drvr != NULL && ep0 != NULL && funcaddr < 128 && maxpacketsize < 2048); + DEBUGASSERT(drvr != NULL && ep0 != NULL && funcaddr < 128 && + maxpacketsize < 2048); ed = (struct lpc17_40_ed_s *)ep0; /* We must have exclusive access to EP0 and the control list */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Set the EP0 ED control word */ @@ -2155,47 +2248,54 @@ static int lpc17_40_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0 return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc17_40_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct usbhost_hubport_s *hport; struct lpc17_40_ed_s *ed; - int ret = -ENOMEM; + int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(priv && epdesc && ep && priv->connected); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list and the interrupt table. */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + ret = -ENOMEM; /* Take the next ED from the beginning of the free list */ @@ -2251,6 +2351,7 @@ static int lpc17_40_epalloc(struct usbhost_driver_s *drvr, ed->hw.ctrl |= ED_CONTROL_F; } #endif + uinfo("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl); /* Initialize the semaphore that is used to wait for the endpoint @@ -2297,7 +2398,8 @@ static int lpc17_40_epalloc(struct usbhost_driver_s *drvr, { /* No.. destroy it and report the error */ - uerr("ERROR: Failed to queue ED for transfer type: %d\n", ed->xfrtype); + uerr("ERROR: Failed to queue ED for transfer type: %d\n", + ed->xfrtype); nxsem_destroy(&ed->wdhsem); lpc17_40_edfree(ed); } @@ -2313,25 +2415,25 @@ static int lpc17_40_epalloc(struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc17_40_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -2341,13 +2443,18 @@ static int lpc17_40_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* There should not be any pending, real TDs linked to this ED */ - DEBUGASSERT(ed && (ed->hw.headp & ED_HEADP_ADDR_MASK) == LPC17_40_TDTAIL_ADDR); + DEBUGASSERT(ed != NULL && + (ed->hw.headp & ED_HEADP_ADDR_MASK) == LPC17_40_TDTAIL_ADDR); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list and the interrupt table. */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Remove the ED to the correct list depending on the transfer type */ @@ -2389,27 +2496,28 @@ static int lpc17_40_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: lpc17_40_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2418,15 +2526,22 @@ static int lpc17_40_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) ****************************************************************************/ static int lpc17_40_alloc(struct usbhost_driver_s *drvr, - uint8_t **buffer, size_t *maxlen) + uint8_t **buffer, size_t *maxlen) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; + int ret; + DEBUGASSERT(priv && buffer && maxlen); - int ret = -ENOMEM; /* We must have exclusive access to the transfer buffer pool */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + ret = -ENOMEM; *buffer = lpc17_40_tballoc(); if (*buffer) @@ -2443,19 +2558,20 @@ static int lpc17_40_alloc(struct usbhost_driver_s *drvr, * Name: lpc17_40_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Never called from an interrupt handler. @@ -2465,45 +2581,49 @@ static int lpc17_40_alloc(struct usbhost_driver_s *drvr, static int lpc17_40_free(struct usbhost_driver_s *drvr, uint8_t *buffer) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; + int ret; + DEBUGASSERT(buffer); /* We must have exclusive access to the transfer buffer pool */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem_uninterruptible(&priv->exclsem); lpc17_40_tbfree(buffer); lpc17_40_givesem(&priv->exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc17_40_ioalloc(struct usbhost_driver_s *drvr, - uint8_t **buffer, size_t buflen) + uint8_t **buffer, size_t buflen) { DEBUGASSERT(drvr && buffer); @@ -2524,28 +2644,28 @@ static int lpc17_40_ioalloc(struct usbhost_driver_s *drvr, #endif } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc17_40_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) { @@ -2565,29 +2685,31 @@ static int lpc17_40_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) * Description: * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2596,8 +2718,8 @@ static int lpc17_40_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) ****************************************************************************/ static int lpc17_40_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - const struct usb_ctrlreq_s *req, - uint8_t *buffer) + const struct usb_ctrlreq_s *req, + uint8_t *buffer) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct lpc17_40_ed_s *ed = (struct lpc17_40_ed_s *)ep0; @@ -2612,10 +2734,15 @@ static int lpc17_40_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } len = lpc17_40_getle16(req->len); - ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, USB_SIZEOF_CTRLREQ); + ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, + USB_SIZEOF_CTRLREQ); if (ret == OK) { if (len) @@ -2634,13 +2761,13 @@ static int lpc17_40_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, } static int lpc17_40_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - const struct usb_ctrlreq_s *req, - const uint8_t *buffer) + const struct usb_ctrlreq_s *req, + const uint8_t *buffer) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct lpc17_40_ed_s *ed = (struct lpc17_40_ed_s *)ep0; uint16_t len; - int ret; + int ret; DEBUGASSERT(priv != NULL && ed != NULL && req != NULL); @@ -2650,15 +2777,21 @@ static int lpc17_40_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } len = lpc17_40_getle16(req->len); - ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, USB_SIZEOF_CTRLREQ); + ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, + USB_SIZEOF_CTRLREQ); if (ret == OK) { if (len) { - ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_OUT, (uint8_t *)buffer, len); + ret = lpc17_40_ctrltd(priv, ed, GTD_STATUS_DP_OUT, + (uint8_t *)buffer, len); } if (ret == OK) @@ -2680,15 +2813,16 @@ static int lpc17_40_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * * Assumptions: @@ -2698,8 +2832,8 @@ static int lpc17_40_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, ****************************************************************************/ static int lpc17_40_transfer_common(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *buffer, - size_t buflen) + struct lpc17_40_ed_s *ed, + uint8_t *buffer, size_t buflen) { struct lpc17_40_xfrinfo_s *xfrinfo; uint32_t dirpid; @@ -2731,7 +2865,8 @@ static int lpc17_40_transfer_common(struct lpc17_40_usbhost_s *priv, /* Then enqueue the transfer */ xfrinfo->tdstatus = TD_CC_NOERROR; - ret = lpc17_40_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); + ret = lpc17_40_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, + buflen); if (ret == OK) { /* BulkListFilled. This bit is used to indicate whether there are any @@ -2753,20 +2888,21 @@ static int lpc17_40_transfer_common(struct lpc17_40_usbhost_s *priv, * Name: lpc17_40_dma_alloc * * Description: - * Allocate DMA memory to perform a transfer, copying user data as necessary + * Allocate DMA memory to perform a transfer, copying user data as + * necessary * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * userbuffer - The user buffer containing the data to be sent (OUT endpoint) - * or received (IN endpoint). + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * userbuffer - The user buffer containing the data to be sent (OUT + * endpoint) or received (IN endpoint). * buflen - The length of the data to be sent or received. * alloc - The location to return the allocated DMA buffer. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2776,13 +2912,14 @@ static int lpc17_40_transfer_common(struct lpc17_40_usbhost_s *priv, #if LPC17_40_IOBUFFERS > 0 static int lpc17_40_dma_alloc(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *userbuffer, - size_t buflen, uint8_t **alloc) + struct lpc17_40_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t **alloc) { uint8_t *newbuffer; if ((uintptr_t)userbuffer < LPC17_40_SRAM_BANK0 || - (uintptr_t)userbuffer >= (LPC17_40_SRAM_BANK0 + LPC17_40_BANK0_SIZE + LPC17_40_BANK1_SIZE)) + (uintptr_t)userbuffer >= (LPC17_40_SRAM_BANK0 + LPC17_40_BANK0_SIZE + + LPC17_40_BANK1_SIZE)) { /* Will the transfer fit in an IO buffer? */ @@ -2829,16 +2966,16 @@ static int lpc17_40_dma_alloc(struct lpc17_40_usbhost_s *priv, * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * userbuffer - The user buffer containing the data to be sent (OUT endpoint) - * or received (IN endpoint). + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * userbuffer - The user buffer containing the data to be sent (OUT + * endpoint) or received (IN endpoint). * buflen - The length of the data to be sent or received. * alloc - The allocated DMA buffer to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2847,8 +2984,8 @@ static int lpc17_40_dma_alloc(struct lpc17_40_usbhost_s *priv, ****************************************************************************/ static void lpc17_40_dma_free(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed, uint8_t *userbuffer, - size_t buflen, uint8_t *newbuffer) + struct lpc17_40_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t *newbuffer) { irqstate_t flags; @@ -2882,26 +3019,27 @@ static void lpc17_40_dma_free(struct lpc17_40_usbhost_s *priv, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -2915,8 +3053,9 @@ static void lpc17_40_dma_free(struct lpc17_40_usbhost_s *priv, * ****************************************************************************/ -static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen) +static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, uint8_t *buffer, + size_t buflen) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct lpc17_40_ed_s *ed = (struct lpc17_40_ed_s *)ep; @@ -2930,11 +3069,16 @@ static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, DEBUGASSERT(priv && ed && buffer && buflen > 0); - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Allocate a structure to retain the information needed when the transfer * completes. @@ -2978,8 +3122,8 @@ static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ ret = lpc17_40_wdhwait(priv, ed); @@ -3002,7 +3146,11 @@ static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* Wait for the Writeback Done Head interrupt */ - lpc17_40_takesem(&ed->wdhsem); + ret = lpc17_40_takesem(&ed->wdhsem); + if (ret < 0) + { + return ret; + } /* Check the TD completion status bits */ @@ -3038,6 +3186,7 @@ static ssize_t lpc17_40_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, } errout_with_wdhwait: + /* Make sure that there is no outstanding request on this endpoint */ xfrinfo->wdhwait = false; @@ -3050,6 +3199,7 @@ errout_with_buffers: #endif errout_with_xfrinfo: + /* Make sure that there is no outstanding request on this endpoint */ lpc17_40_free_xfrinfo(xfrinfo); @@ -3069,8 +3219,8 @@ errout_with_sem: * * Input Parameters: * priv - Internal driver state structure. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which the - * transfer was performed. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which the transfer was performed. * * Returned Value: * None @@ -3082,7 +3232,7 @@ errout_with_sem: #ifdef CONFIG_USBHOST_ASYNCH static void lpc17_40_asynch_completion(struct lpc17_40_usbhost_s *priv, - struct lpc17_40_ed_s *ed) + struct lpc17_40_ed_s *ed) { struct lpc17_40_xfrinfo_s *xfrinfo; usbhost_asynch_t callback; @@ -3130,7 +3280,8 @@ static void lpc17_40_asynch_completion(struct lpc17_40_usbhost_s *priv, #if LPC17_40_IOBUFFERS > 0 /* Free any temporary IO buffers */ - lpc17_40_dma_free(priv, ed, xfrinfo->buffer, xfrinfo->buflen, xfrinfo->alloc); + lpc17_40_dma_free(priv, ed, xfrinfo->buffer, xfrinfo->buflen, + xfrinfo->alloc); #endif /* Extract the callback information before freeing the buffer */ @@ -3163,20 +3314,21 @@ static void lpc17_40_asynch_completion(struct lpc17_40_usbhost_s *priv, * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3186,24 +3338,29 @@ static void lpc17_40_asynch_completion(struct lpc17_40_usbhost_s *priv, #ifdef CONFIG_USBHOST_ASYNCH static int lpc17_40_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen, - usbhost_asynch_t callback, void *arg) + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; struct lpc17_40_ed_s *ed = (struct lpc17_40_ed_s *)ep; struct lpc17_40_xfrinfo_s *xfrinfo; int ret; - DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && buffer && buflen > 0 && callback); + DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && buffer && buflen > 0 && + callback); - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt table. */ - lpc17_40_takesem(&priv->exclsem); + ret = lpc17_40_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } - /* Allocate a structure to retain the information needed when the asynchronous - * transfer completes. + /* Allocate a structure to retain the information needed when the + * asynchronous transfer completes. */ DEBUGASSERT(ed->xfrinfo == NULL); @@ -3278,7 +3435,7 @@ errout_with_sem: } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_cancel * * Description: @@ -3286,18 +3443,19 @@ errout_with_sem: * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ -static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) +static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep) { #ifdef CONFIG_USBHOST_ASYNCH struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; @@ -3320,8 +3478,8 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) xfrinfo = ed->xfrinfo; if (xfrinfo) { - /* It might be possible for no transfer to be in progress (callback == NULL - * and wdhwait == false) + /* It might be possible for no transfer to be in progress (callback == + * NULL and wdhwait == false) */ #ifdef CONFIG_USBHOST_ASYNCH @@ -3344,7 +3502,8 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Remove the TDs attached to the ED, keeping the ED in the list */ - td = (struct lpc17_40_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); + td = (struct lpc17_40_gtd_s *) + (ed->hw.headp & ED_HEADP_ADDR_MASK); ed->hw.headp = LPC17_40_TDTAIL_ADDR; ed->xfrinfo = NULL; @@ -3355,9 +3514,12 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } else { - /* Remove the TDs attached to the ED, keeping the Ed in the list */ + /* Remove the TDs attached to the ED, keeping the Ed in the + * list. + */ - td = (struct lpc17_40_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); + td = (struct lpc17_40_gtd_s *) + (ed->hw.headp & ED_HEADP_ADDR_MASK); ed->hw.headp = LPC17_40_TDTAIL_ADDR; ed->xfrinfo = NULL; } @@ -3400,7 +3562,9 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) #ifdef CONFIG_USBHOST_ASYNCH else { - /* Otherwise, perform the callback and free the transfer structure */ + /* Otherwise, perform the callback and free the transfer + * structure. + */ lpc17_40_asynch_completion(priv, ed); } @@ -3421,7 +3585,7 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc17_40_connect * * Description: @@ -3430,22 +3594,22 @@ static int lpc17_40_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int lpc17_40_connect(FAR struct usbhost_driver_s *drvr, - FAR struct usbhost_hubport_s *hport, - bool connected) + FAR struct usbhost_hubport_s *hport, + bool connected) { struct lpc17_40_usbhost_s *priv = (struct lpc17_40_usbhost_s *)drvr; DEBUGASSERT(priv != NULL && hport != NULL); @@ -3454,7 +3618,8 @@ static int lpc17_40_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -3475,17 +3640,18 @@ static int lpc17_40_connect(FAR struct usbhost_driver_s *drvr, * Name: lpc17_40_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not call the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might + * be a port on a hub. * * Returned Value: * None @@ -3497,15 +3663,12 @@ static int lpc17_40_connect(FAR struct usbhost_driver_s *drvr, ****************************************************************************/ static void lpc17_40_disconnect(struct usbhost_driver_s *drvr, - struct usbhost_hubport_s *hport) + struct usbhost_hubport_s *hport) { DEBUGASSERT(hport != NULL); hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: lpc17_40_ep0init * @@ -3585,7 +3748,8 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) int i; /* Sanity checks. NOTE: If certain OS features are enabled, it may be - * necessary to increase the size of LPC17_40_ED/TD_SIZE in lpc17_40_ohciram.h + * necessary to increase the size of LPC17_40_ED/TD_SIZE in + * lpc17_40_ohciram.h */ DEBUGASSERT(controller == 0); @@ -3593,6 +3757,7 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) DEBUGASSERT(sizeof(struct lpc17_40_gtd_s) <= LPC17_40_TD_SIZE); /* Initialize the state data structure */ + /* Initialize the device operations */ drvr = &priv->drvr; @@ -3635,8 +3800,8 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) nxsem_init(&priv->pscsem, 0, 0); nxsem_init(&priv->exclsem, 0, 1); - /* The pscsem semaphore is used for signaling and, hence, should not have - * priority inheritance enabled. + /* The pscsem semaphore is used for signaling and, hence, should not + * have priority inheritance enabled. */ nxsem_setprotocol(&priv->pscsem, SEM_PRIO_NONE); @@ -3646,8 +3811,8 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) priv->outinterval = MAX_PERINTERVAL; #endif - /* Enable power by setting PCUSB in the PCONP register. Disable interrupts - * because this register may be shared with other drivers. + /* Enable power by setting PCUSB in the PCONP register. Disable + * interrupts because this register may be shared with other drivers. */ flags = enter_critical_section(); @@ -3656,11 +3821,12 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) lpc17_40_putreg(regval, LPC17_40_SYSCON_PCONP); leave_critical_section(flags); - /* Enable clocking on USB (USB PLL clocking was initialized in very low- - * evel clock setup logic (see lpc17_40_clockconfig.c)). We do still need - * to set up USBOTG CLKCTRL to enable clocking. + /* Enable clocking on USB (USB PLL clocking was initialized in very + * low-level clock setup logic (see lpc17_40_clockconfig.c)). We do still + * need* to set up USBOTG CLKCTRL to enable clocking. * - * NOTE: The PORTSEL clock needs to be enabled only when accessing OTGSTCTRL + * NOTE: The PORTSEL clock needs to be enabled only when accessing + * OTGSTCTRL */ lpc17_40_putreg(LPC17_40_CLKCTRL_ENABLES, LPC17_40_USBOTG_CLKCTRL); @@ -3688,7 +3854,8 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) /* Now we can turn off the PORTSEL clock */ - lpc17_40_putreg((LPC17_40_CLKCTRL_ENABLES & ~USBOTG_CLK_PORTSELCLK), LPC17_40_USBOTG_CLKCTRL); + lpc17_40_putreg((LPC17_40_CLKCTRL_ENABLES & ~USBOTG_CLK_PORTSELCLK), + LPC17_40_USBOTG_CLKCTRL); /* Configure I/O pins */ @@ -3707,13 +3874,21 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) #if 0 /* Useful if you have doubts about the layout */ uinfo("AHB SRAM:\n"); - uinfo(" HCCA: %08x %d\n", LPC17_40_HCCA_BASE, LPC17_40_HCCA_SIZE); - uinfo(" TDTAIL: %08x %d\n", LPC17_40_TDTAIL_ADDR, LPC17_40_TD_SIZE); - uinfo(" EDCTRL: %08x %d\n", LPC17_40_EDCTRL_ADDR, LPC17_40_ED_SIZE); - uinfo(" EDFREE: %08x %d\n", LPC17_40_EDFREE_BASE, LPC17_40_ED_SIZE); - uinfo(" TDFREE: %08x %d\n", LPC17_40_TDFREE_BASE, LPC17_40_EDFREE_SIZE); - uinfo(" TBFREE: %08x %d\n", LPC17_40_TBFREE_BASE, LPC17_40_TBFREE_SIZE); - uinfo(" IOFREE: %08x %d\n", LPC17_40_IOFREE_BASE, LPC17_40_IOBUFFERS * CONFIG_LPC17_40_USBHOST_IOBUFSIZE); + uinfo(" HCCA: %08x %d\n", + LPC17_40_HCCA_BASE, LPC17_40_HCCA_SIZE); + uinfo(" TDTAIL: %08x %d\n", + LPC17_40_TDTAIL_ADDR, LPC17_40_TD_SIZE); + uinfo(" EDCTRL: %08x %d\n", + LPC17_40_EDCTRL_ADDR, LPC17_40_ED_SIZE); + uinfo(" EDFREE: %08x %d\n", + LPC17_40_EDFREE_BASE, LPC17_40_ED_SIZE); + uinfo(" TDFREE: %08x %d\n", + LPC17_40_TDFREE_BASE, LPC17_40_EDFREE_SIZE); + uinfo(" TBFREE: %08x %d\n", + LPC17_40_TBFREE_BASE, LPC17_40_TBFREE_SIZE); + uinfo(" IOFREE: %08x %d\n", + LPC17_40_IOFREE_BASE, + LPC17_40_IOBUFFERS * CONFIG_LPC17_40_USBHOST_IOBUFSIZE); #endif /* Initialize all the TDs, EDs and HCCA to 0 */ @@ -3831,7 +4006,7 @@ struct usbhost_connection_s *lpc17_40_usbhost_initialize(int controller) /* Enable OHCI interrupts */ - lpc17_40_putreg((LPC17_40_ALL_INTS | OHCI_INT_MIE), LPC17_40_USBHOST_INTEN); + lpc17_40_putreg(LPC17_40_ALL_INTS | OHCI_INT_MIE, LPC17_40_USBHOST_INTEN); /* Attach USB host controller interrupt handler */ diff --git a/arch/arm/src/lpc31xx/lpc31_ehci.c b/arch/arm/src/lpc31xx/lpc31_ehci.c index 28a975bd5e..aefb843886 100644 --- a/arch/arm/src/lpc31xx/lpc31_ehci.c +++ b/arch/arm/src/lpc31xx/lpc31_ehci.c @@ -1,36 +1,20 @@ /**************************************************************************** * arch/arm/src/lpc31xx/lpc31_ehci.c * - * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -72,7 +56,9 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ + /* Pre-requisites */ #if !defined(CONFIG_SCHED_WORKQUEUE) @@ -89,8 +75,8 @@ # define CONFIG_LPC31_EHCI_NQHS (LPC31_EHCI_NRHPORT + 1) #endif -/* Configurable number of Queue Element Transfer Descriptor (qTDs). The default - * is one per root hub plus three from EP0. +/* Configurable number of Queue Element Transfer Descriptor (qTDs). The + * default is one per root hub plus three from EP0. */ #ifndef CONFIG_LPC31_EHCI_NQTDS @@ -121,7 +107,8 @@ #undef CONFIG_USBHOST_ISOC_DISABLE #define CONFIG_USBHOST_ISOC_DISABLE 1 -/* Registers *******************************************************************/ +/* Registers ****************************************************************/ + /* Traditionally, NuttX specifies register locations using individual * register offsets from a base address. That tradition is broken here and, * instead, register blocks are represented as structures. This is done here @@ -141,7 +128,8 @@ #define HCOR ((volatile struct ehci_hcor_s *)LPC31_USBOTG_HCOR_BASE) -/* Interrupts ******************************************************************/ +/* Interrupts ***************************************************************/ + /* This is the set of interrupts handled by this driver */ #define EHCI_HANDLED_INTS (EHCI_INT_USBINT | EHCI_INT_USBERRINT | \ @@ -149,16 +137,17 @@ EHCI_INT_AAINT) /* The periodic frame list is a 4K-page aligned array of Frame List Link - * pointers. The length of the frame list may be programmable. The programmability - * of the periodic frame list is exported to system software via the HCCPARAMS - * register. If non-programmable, the length is 1024 elements. If programmable, - * the length can be selected by system software as one of 256, 512, or 1024 - * elements. + * pointers. The length of the frame list may be programmable. The + * programmability of the periodic frame list is exported to system software + * via the HCCPARAMS register. If non-programmable, the length is 1024 + * elements. If programmable, the length can be selected by system software + * as one of 256, 512, or 1024 elements. */ #define FRAME_LIST_SIZE 1024 -/* DMA *************************************************************************/ +/* DMA **********************************************************************/ + /* For now, we are assuming an identity mapping between physical and virtual * address spaces. */ @@ -166,7 +155,7 @@ #define lpc31_physramaddr(a) (a) #define lpc31_virtramaddr(a) (a) -/* USB trace *******************************************************************/ +/* USB trace ****************************************************************/ #ifdef HAVE_USBHOST_TRACE # define TR_FMT1 false @@ -191,6 +180,7 @@ /**************************************************************************** * Private Types ****************************************************************************/ + /* Internal representation of the EHCI Queue Head (QH) */ struct lpc31_epinfo_s; @@ -229,7 +219,8 @@ struct lpc31_list_s /* List traversal callout functions */ typedef int (*foreach_qh_t)(struct lpc31_qh_s *qh, uint32_t **bp, void *arg); -typedef int (*foreach_qtd_t)(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); +typedef int (*foreach_qtd_t)(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); /* This structure describes one endpoint. */ @@ -282,15 +273,15 @@ struct lpc31_rhport_s struct lpc31_ehci_s { - volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */ + volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */ - sem_t exclsem; /* Support mutually exclusive access */ - sem_t pscsem; /* Semaphore to wait for port status change events */ + sem_t exclsem; /* Support mutually exclusive access */ + sem_t pscsem; /* Semaphore to wait for port status change events */ - struct lpc31_epinfo_s ep0; /* Endpoint 0 */ - struct lpc31_list_s *qhfree; /* List of free Queue Head (QH) structures */ - struct lpc31_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ - struct work_s work; /* Supports interrupt bottom half */ + struct lpc31_epinfo_s ep0; /* Endpoint 0 */ + struct lpc31_list_s *qhfree; /* List of free Queue Head (QH) structures */ + struct lpc31_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ + struct work_s work; /* Supports interrupt bottom half */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -394,7 +385,7 @@ struct lpc31_ehci_trace_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ static uint16_t lpc31_read16(const uint8_t *addr); static uint32_t lpc31_read32(const uint8_t *addr); @@ -425,43 +416,48 @@ static inline void lpc31_putreg(uint32_t regval, volatile uint32_t *regaddr); static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, unsigned int delay); -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void lpc31_takesem(sem_t *sem); +static int lpc31_takesem(sem_t *sem); +static int lpc31_takesem_uninterruptible(sem_t *sem); #define lpc31_givesem(s) nxsem_post(s); -/* Allocators ******************************************************************/ +/* Allocators ***************************************************************/ static struct lpc31_qh_s *lpc31_qh_alloc(void); static void lpc31_qh_free(struct lpc31_qh_s *qh); static struct lpc31_qtd_s *lpc31_qtd_alloc(void); static void lpc31_qtd_free(struct lpc31_qtd_s *qtd); -/* List Management *************************************************************/ +/* List Management **********************************************************/ static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t handler, void *arg); static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, void *arg); -static int lpc31_qtd_discard(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc31_qtd_discard(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc31_qh_discard(struct lpc31_qh_s *qh); -/* Cache Operations ************************************************************/ +/* Cache Operations *********************************************************/ #if 0 /* Not used */ -static int lpc31_qtd_invalidate(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc31_qtd_invalidate(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc31_qh_invalidate(struct lpc31_qh_s *qh); #endif -static int lpc31_qtd_flush(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc31_qtd_flush(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc31_qh_flush(struct lpc31_qh_s *qh); -/* Endpoint Transfer Handling **************************************************/ +/* Endpoint Transfer Handling ***********************************************/ #ifdef CONFIG_LPC31_EHCI_REGDEBUG static void lpc31_qtd_print(struct lpc31_qtd_s *qtd); static void lpc31_qh_print(struct lpc31_qh_s *qh); -static int lpc31_qtd_dump(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); -static int lpc31_qh_dump(struct lpc31_qh_s *qh, uint32_t **bp, void *arg); +static int lpc31_qtd_dump(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); +static int lpc31_qh_dump(struct lpc31_qh_s *qh, uint32_t **bp, void *arg); #else # define lpc31_qtd_print(qtd) # define lpc31_qh_print(qh) @@ -479,8 +475,8 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, struct lpc31_epinfo_s *epinfo); static int lpc31_qtd_addbpl(struct lpc31_qtd_s *qtd, const void *buffer, size_t buflen); -static struct lpc31_qtd_s *lpc31_qtd_setupphase(struct lpc31_epinfo_s *epinfo, - const struct usb_ctrlreq_s *req); +static struct lpc31_qtd_s *lpc31_qtd_setupphase( + struct lpc31_epinfo_s *epinfo, const struct usb_ctrlreq_s *req); static struct lpc31_qtd_s *lpc31_qtd_dataphase(struct lpc31_epinfo_s *epinfo, void *buffer, int buflen, uint32_t tokenbits); static struct lpc31_qtd_s *lpc31_qtd_statusphase(uint32_t tokenbits); @@ -499,12 +495,15 @@ static inline int lpc31_ioc_async_setup(struct lpc31_rhport_s *rhport, static void lpc31_asynch_completion(struct lpc31_epinfo_s *epinfo); #endif -/* Interrupt Handling **********************************************************/ +/* Interrupt Handling *******************************************************/ -static int lpc31_qtd_ioccheck(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); -static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg); +static int lpc31_qtd_ioccheck(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); +static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, + void *arg); #ifdef CONFIG_USBHOST_ASYNCH -static int lpc31_qtd_cancel(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc31_qtd_cancel(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc31_qh_cancel(struct lpc31_qh_s *qh, uint32_t **bp, void *arg); #endif static inline void lpc31_ioc_bottomhalf(void); @@ -514,7 +513,7 @@ static inline void lpc31_async_advance_bottomhalf(void); static void lpc31_ehci_bottomhalf(FAR void *arg); static int lpc31_ehci_interrupt(int irq, FAR void *context, FAR void *arg); -/* USB Host Controller Operations **********************************************/ +/* USB Host Controller Operations *******************************************/ static int lpc31_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -523,23 +522,26 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); -static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize); +static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize); static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); static int lpc31_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int lpc31_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int lpc31_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int lpc31_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int lpc31_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int lpc31_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, @@ -553,16 +555,17 @@ static int lpc31_connect(FAR struct usbhost_driver_s *drvr, static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static int lpc31_reset(void); /**************************************************************************** * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. + +/* In this driver implementation, support is provided for only a single + * USB device. All status information can be simply retained in a single + * global instance. */ static struct lpc31_ehci_s g_ehci; @@ -631,69 +634,119 @@ static struct lpc31_qtd_s *g_qtdpool; static const struct lpc31_ehci_trace_s g_trace1[TRACE1_NSTRINGS] = { - TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, "EHCI ERROR: System error: %06x\n"), - TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate a QH\n"), - TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, "EHCI ERROR: Buffer too big. Remaining %d\n"), - TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate request qTD"), - TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_addbpl failed: %d\n"), - TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate data buffer qTD, 0"), - TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, "EHCI ERROR: Device disconnected %d\n"), - TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qh_create failed\n"), - TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_setupphase failed\n"), + TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, + "EHCI ERROR: System error: %06x\n"), + TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qtd_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate a QH\n"), + TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, + "EHCI ERROR: Buffer too big. Remaining %d\n"), + TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate request qTD"), + TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qtd_addbpl failed: %d\n"), + TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate data buffer qTD, 0"), + TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, + "EHCI ERROR: Device disconnected %d\n"), + TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qh_create failed\n"), + TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qtd_setupphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_dataphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qtd_statusphase failed\n"), - TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, "EHCI ERROR: Transfer failed %d\n"), - TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc31_qh_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, "EHCI: Host System Error Interrupt\n"), - TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), - TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate EP info structure\n"), - TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, "EHCI ERROR: Support for transfer type %d not implemented\n"), - TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), - TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the QH pool\n"), + TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qtd_dataphase failed\n"), + TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qtd_statusphase failed\n"), + TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, + "EHCI ERROR: Transfer failed %d\n"), + TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_qh_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, + "EHCI: Host System Error Interrupt\n"), + TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, + "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), + TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate EP info structure\n"), + TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, + "EHCI ERROR: Support for transfer type %d not implemented\n"), + TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, + "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), + TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the QH pool\n"), - TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the qTD pool\n"), - TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the periodic frame list\n"), - TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, "EHCI ERROR: lpc31_reset failed: %d\n"), - TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), - TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, "EHCI ERROR: Failed to attach IRQ%d\n"), + TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the qTD pool\n"), + TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the periodic frame list\n"), + TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, + "EHCI ERROR: lpc31_reset failed: %d\n"), + TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, + "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), + TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, + "EHCI ERROR: Failed to attach IRQ%d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, "EHCI Connect Status Change: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, "EHCI Already connected: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, "EHCI Already disconnected: %06x\n"), - TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, "EHCI Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, "EHCI Async Advance Interrupt\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, + "EHCI Connect Status Change: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, + "EHCI Already connected: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, + "EHCI Already disconnected: %06x\n"), + TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, + "EHCI Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, + "EHCI Async Advance Interrupt\n"), - TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, "EHCI Hub port %d: Enumerate the device\n"), - TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, "EHCI Enumeration not connected\n"), - TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, "EHCI Initializing EHCI Stack\n"), - TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, "EHCI HCCPARAMS=%06x\n"), - TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, "EHCI USB EHCI Initialized\n"), + TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, + "EHCI Hub port %d: Enumerate the device\n"), + TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, + "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, + "EHCI Enumeration not connected\n"), + TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, + "EHCI Initializing EHCI Stack\n"), + TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, + "EHCI HCCPARAMS=%06x\n"), + TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, + "EHCI USB EHCI Initialized\n"), #endif }; static const struct lpc31_ehci_trace_s g_trace2[TRACE2_NSTRINGS] = { - TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, "EHCI EP%d Stalled: TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, "EHCI ERROR: EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), + TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, + "EHCI EP%d Stalled: TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, + "EHCI ERROR: EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, + "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, "EHCI Async transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, "EHCI Intr Transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, "EHCI IOC EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, "EHCI PORTSC%d: %04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, "EHCI RHPort%d connected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, "EHCI RHport%d disconnected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, "EHCI RHPort%d connected: %d\n"), + TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, + "EHCI Async transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, + "EHCI Intr Transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, + "EHCI IOC EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, + "EHCI PORTSC%d: %04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, + "EHCI RHPort%d connected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, + "EHCI RHport%d disconnected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, + "EHCI RHPort%d connected: %d\n"), - TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, "EHCI EPALLOC: EP%d TYPE=%d\n"), - TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), - TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, "EHCI HCIVERSION %x.%02x\n"), - TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, "EHCI nports=%d, HCSPARAMS=%04x\n"), + TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, + "EHCI EPALLOC: EP%d TYPE=%d\n"), + TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, + "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), + TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, + "EHCI HCIVERSION %x.%02x\n"), + TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, + "EHCI nports=%d, HCSPARAMS=%04x\n"), #endif }; #endif /* HAVE_USBHOST_TRACE */ @@ -701,9 +754,7 @@ static const struct lpc31_ehci_trace_s g_trace2[TRACE2_NSTRINGS] = /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Register Operations - ****************************************************************************/ + /**************************************************************************** * Name: lpc31_read16 * @@ -839,15 +890,16 @@ static void lpc31_printreg(volatile uint32_t *regaddr, uint32_t regval, ****************************************************************************/ #ifdef CONFIG_LPC31_EHCI_REGDEBUG -static void lpc31_checkreg(volatile uint32_t *regaddr, uint32_t regval, bool iswrite) +static void lpc31_checkreg(volatile uint32_t *regaddr, uint32_t regval, + bool iswrite) { static uint32_t *prevaddr = NULL; static uint32_t preval = 0; static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (regaddr == prevaddr && regval == preval && prevwrite == iswrite) @@ -997,9 +1049,6 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, return (regval == donebits) ? OK : -ETIMEDOUT; } -/**************************************************************************** - * Semaphores - ****************************************************************************/ /**************************************************************************** * Name: lpc31_takesem * @@ -1009,14 +1058,45 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, * ****************************************************************************/ -static void lpc31_takesem(sem_t *sem) +static int lpc31_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** - * Allocators + * Name: lpc31_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * ****************************************************************************/ + +static int lpc31_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; +} + /**************************************************************************** * Name: lpc31_qh_alloc * @@ -1067,8 +1147,8 @@ static void lpc31_qh_free(struct lpc31_qh_s *qh) * Name: lpc31_qtd_alloc * * Description: - * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from the - * free list + * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from + * the free list * * Assumption: Caller holds the exclsem * @@ -1094,8 +1174,8 @@ static struct lpc31_qtd_s *lpc31_qtd_alloc(void) * Name: lpc31_qtd_free * * Description: - * Free a Queue Element Transfer Descriptor (qTD) by returning it to the free - * list + * Free a Queue Element Transfer Descriptor (qTD) by returning it to the + * free list * * Assumption: Caller holds the exclsem * @@ -1111,10 +1191,6 @@ static void lpc31_qtd_free(struct lpc31_qtd_s *qtd) g_ehci.qtdfree = entry; } -/**************************************************************************** - * List Management - ****************************************************************************/ - /**************************************************************************** * Name: lpc31_qh_foreach * @@ -1125,8 +1201,8 @@ static void lpc31_qtd_free(struct lpc31_qtd_s *qtd) * ****************************************************************************/ -static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t handler, - void *arg) +static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, + foreach_qh_t handler, void *arg) { struct lpc31_qh_s *next; uintptr_t physaddr; @@ -1135,8 +1211,9 @@ static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t h DEBUGASSERT(qh && handler); while (qh) { - /* Is this the end of the list? Check the horizontal link pointer (HLP) - * terminate (T) bit. If T==1, then the HLP address is not valid. + /* Is this the end of the list? Check the horizontal link pointer + * (HLP) terminate (T) bit. If T==1, then the HLP address is not + * valid. */ physaddr = lpc31_swap32(qh->hw.hlp); @@ -1151,7 +1228,8 @@ static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t h * the end of the asynchronous queue? */ - else if (lpc31_virtramaddr(physaddr & QH_HLP_MASK) == (uintptr_t)&g_asynchead) + else if (lpc31_virtramaddr(physaddr & QH_HLP_MASK) == + (uintptr_t)&g_asynchead) { /* That will also terminate the loop */ @@ -1170,16 +1248,16 @@ static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t h /* Perform the user action on this entry. The action might result in * unlinking the entry! But that is okay because we already have the - * next QH pointer. + * next qTD pointer. * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qh, bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1204,7 +1282,8 @@ static int lpc31_qh_foreach(struct lpc31_qh_s *qh, uint32_t **bp, foreach_qh_t h * ****************************************************************************/ -static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, void *arg) +static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, + void *arg) { struct lpc31_qtd_s *qtd; struct lpc31_qtd_s *next; @@ -1216,7 +1295,7 @@ static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, void /* Handle the special case where the queue is empty */ - bp = &qh->fqp; /* Start of qTDs in original list */ + bp = &qh->fqp; /* Start of qTDs in original list */ physaddr = lpc31_swap32(*bp); /* Physical address of first qTD in CPU order */ if ((physaddr & QTD_NQP_T) != 0) @@ -1253,14 +1332,14 @@ static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, void * unlinking the entry! But that is okay because we already have the * next qTD pointer. * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qtd, &bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1280,12 +1359,13 @@ static int lpc31_qtd_foreach(struct lpc31_qh_s *qh, foreach_qtd_t handler, void * Name: lpc31_qtd_discard * * Description: - * This is a lpc31_qtd_foreach callback. It simply unlinks the QTD, updates - * the back pointer, and frees the QTD structure. + * This is a lpc31_qtd_foreach callback. It simply unlinks the QTD, + * updates the back pointer, and frees the QTD structure. * ****************************************************************************/ -static int lpc31_qtd_discard(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc31_qtd_discard(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg) { DEBUGASSERT(qtd && bp && *bp); @@ -1334,21 +1414,18 @@ static int lpc31_qh_discard(struct lpc31_qh_s *qh) return ret; } -/**************************************************************************** - * Cache Operations - ****************************************************************************/ - /**************************************************************************** * Name: lpc31_qtd_invalidate * * Description: - * This is a callback from lpc31_qtd_foreach. It simply invalidates D-cache for - * address range of the qTD entry. + * This is a callback from lpc31_qtd_foreach. It simply invalidates D- + * cache for address range of the qTD entry. * ****************************************************************************/ #if 0 /* Not used */ -static int lpc31_qtd_invalidate(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc31_qtd_invalidate(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg) { /* Invalidate the D-Cache, i.e., force reloading of the D-Cache from memory * memory over the specified address range. @@ -1386,16 +1463,17 @@ static int lpc31_qh_invalidate(struct lpc31_qh_s *qh) * Name: lpc31_qtd_flush * * Description: - * This is a callback from lpc31_qtd_foreach. It simply flushes D-cache for - * address range of the qTD entry. + * This is a callback from lpc31_qtd_foreach. It simply flushes D-cache + * for address range of the qTD entry. * ****************************************************************************/ static int lpc31_qtd_flush(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) { - /* Flush the D-Cache, i.e., make the contents of the memory match the contents - * of the D-Cache in the specified address range and invalidate the D-Cache - * to force re-loading of the data from memory when next accessed. + /* Flush the D-Cache, i.e., make the contents of the memory match the + * contents of the D-Cache in the specified address range and invalidate + * the D-Cache to force re-loading of the data from memory when next + * accessed. */ up_flush_dcache((uintptr_t)&qtd->hw, @@ -1414,9 +1492,9 @@ static int lpc31_qtd_flush(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) static int lpc31_qh_flush(struct lpc31_qh_s *qh) { - /* Flush the QH first. This will write the contents of the D-cache to RAM and - * invalidate the contents of the D-cache so that the next access will be - * reloaded from D-Cache. + /* Flush the QH first. This will write the contents of the D-cache to RAM + * and invalidate the contents of the D-cache so that the next access will + * be reloaded from D-Cache. */ up_flush_dcache((uintptr_t)&qh->hw, @@ -1427,10 +1505,6 @@ static int lpc31_qh_flush(struct lpc31_qh_s *qh) return lpc31_qtd_foreach(qh, lpc31_qtd_flush, NULL); } -/**************************************************************************** - * Endpoint Transfer Handling - ****************************************************************************/ - /**************************************************************************** * Name: lpc31_qtd_print * @@ -1498,8 +1572,8 @@ static void lpc31_qh_print(struct lpc31_qh_s *qh) * Name: lpc31_qtd_dump * * Description: - * This is a lpc31_qtd_foreach callout function. It dumps the context of one - * qTD + * This is a lpc31_qtd_foreach call-out function. It dumps the context of + * one qTD * ****************************************************************************/ @@ -1515,8 +1589,8 @@ static int lpc31_qtd_dump(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc31_qh_dump * * Description: - * This is a lpc31_qh_foreach callout function. It dumps a QH structure and - * all of the qTD structures linked to the QH. + * This is a lpc31_qh_foreach callout function. It dumps a QH structure + * and all of the qTD structures linked to the QH. * ****************************************************************************/ @@ -1532,8 +1606,8 @@ static int lpc31_qh_dump(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) * Name: lpc31_ehci_speed * * Description: - * Map a speed enumeration value per Chapter 9 of the USB specification to the - * speed enumeration required in the EHCI queue head. + * Map a speed enumeration value per Chapter 9 of the USB specification to + * the speed enumeration required in the EHCI queue head. * ****************************************************************************/ @@ -1548,15 +1622,16 @@ static inline uint8_t lpc31_ehci_speed(uint8_t usbspeed) * * Description: * Set the request for the IOC event well BEFORE enabling the transfer (as - * soon as we are absolutely committed to the to avoid transfer). We do this - * to minimize race conditions. This logic would have to be expanded if we - * want to have more than one packet in flight at a time! + * soon as we are absolutely committed to the to avoid transfer). We do + * this to minimize race conditions. This logic would have to be expanded + * if we want to have more than one packet in flight at a time! * * Assumption: The caller holds tex EHCI exclsem * ****************************************************************************/ -static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport, struct lpc31_epinfo_s *epinfo) +static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport, + struct lpc31_epinfo_s *epinfo) { irqstate_t flags; int ret = -ENODEV; @@ -1597,21 +1672,30 @@ static int lpc31_ioc_setup(struct lpc31_rhport_s *rhport, struct lpc31_epinfo_s * Description: * Wait for the IOC event. * - * Assumption: The caller does *NOT* hold the EHCI exclsem. That would cause - * a deadlock when the bottom-half, worker thread needs to take the semaphore. + * Assumption: The caller does *NOT* hold the EHCI exclsem. That would + * cause a deadlock when the bottom-half, worker thread needs to take the + * semaphore. * ****************************************************************************/ static int lpc31_ioc_wait(struct lpc31_epinfo_s *epinfo) { - /* Wait for the IOC event. Loop to handle any false alarm semaphore counts. */ + int ret = OK; + + /* Wait for the IOC event. Loop to handle any false alarm semaphore + * counts. Return an error if the task is canceled. + */ while (epinfo->iocwait) { - lpc31_takesem(&epinfo->iocsem); + ret = lpc31_takesem(&epinfo->iocsem); + if (ret < 0) + { + break; + } } - return epinfo->result; + return ret < 0 ? ret : epinfo->result; } /**************************************************************************** @@ -1638,15 +1722,15 @@ static void lpc31_qh_enqueue(struct lpc31_qh_s *qhead, struct lpc31_qh_s *qh) /* Add the new QH to the head of the asynchronous queue list. * - * First, attach the old head as the new QH HLP and flush the new QH and its - * attached qTDs to RAM. + * First, attach the old head as the new QH HLP and flush the new QH and + * its attached qTDs to RAM. */ qh->hw.hlp = qhead->hw.hlp; lpc31_qh_flush(qh); - /* Then set the new QH as the first QH in the asychronous queue and flush the - * modified head to RAM. + /* Then set the new QH as the first QH in the asynchronous queue and flush + * the modified head to RAM. */ physaddr = (uintptr_t)lpc31_physramaddr((uintptr_t)qh); @@ -1701,7 +1785,8 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | ((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | - ((uint32_t)lpc31_ehci_speed(epinfo->speed) << QH_EPCHAR_EPS_SHIFT) | + ((uint32_t)lpc31_ehci_speed(epinfo->speed) << + QH_EPCHAR_EPS_SHIFT) | QH_EPCHAR_DTC | ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((uint32_t)8 << QH_EPCHAR_RL_SHIFT); @@ -1800,38 +1885,39 @@ static struct lpc31_qh_s *lpc31_qh_create(struct lpc31_rhport_s *rhport, * ****************************************************************************/ -static int lpc31_qtd_addbpl(struct lpc31_qtd_s *qtd, const void *buffer, size_t buflen) +static int lpc31_qtd_addbpl(struct lpc31_qtd_s *qtd, const void *buffer, + size_t buflen) { uint32_t physaddr; uint32_t nbytes; uint32_t next; int ndx; - /* Flush the contents of the data buffer to RAM so that the correct contents - * will be accessed for an OUT DMA. + /* Flush the contents of the data buffer to RAM so that the correct + * contents will be accessed for an OUT DMA. */ up_flush_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); - /* Loop, adding the aligned physical addresses of the buffer to the buffer page - * list. Only the first entry need not be aligned (because only the first - * entry has the offset field). The subsequent entries must begin on 4KB - * address boundaries. + /* Loop, adding the aligned physical addresses of the buffer to the buffer + * page list. Only the first entry need not be aligned (because only the + * first entry has the offset field). The subsequent entries must begin on + * 4KB address boundaries. */ physaddr = (uint32_t)lpc31_physramaddr((uintptr_t)buffer); for (ndx = 0; ndx < 5; ndx++) { - /* Write the physical address of the buffer into the qTD buffer pointer - * list. + /* Write the physical address of the buffer into the qTD buffer + * pointer list. */ qtd->hw.bpl[ndx] = lpc31_swap32(physaddr); - /* Get the next buffer pointer (in the case where we will have to transfer - * more then one chunk). This buffer must be aligned to a 4KB address - * boundary. + /* Get the next buffer pointer (in the case where we will have to + * transfer more then one chunk). This buffer must be aligned to a + * 4KB address boundary. */ next = (physaddr + 4096) & ~4095; @@ -1875,8 +1961,9 @@ static int lpc31_qtd_addbpl(struct lpc31_qtd_s *qtd, const void *buffer, size_t * ****************************************************************************/ -static struct lpc31_qtd_s *lpc31_qtd_setupphase(struct lpc31_epinfo_s *epinfo, - const struct usb_ctrlreq_s *req) +static struct lpc31_qtd_s * + lpc31_qtd_setupphase(struct lpc31_epinfo_s *epinfo, + const struct usb_ctrlreq_s *req) { struct lpc31_qtd_s *qtd; uint32_t regval; @@ -2055,13 +2142,13 @@ static struct lpc31_qtd_s *lpc31_qtd_statusphase(uint32_t tokenbits) * Name: lpc31_async_setup * * Description: - * Process a IN or OUT request on any asynchronous endpoint (bulk or control). - * This function will enqueue the request and wait for it to complete. Bulk - * data transfers differ in that req == NULL and there are not SETUP or STATUS - * phases. + * Process a IN or OUT request on any asynchronous endpoint (bulk or + * control). This function will enqueue the request and wait for it to + * complete. Bulk data transfers differ in that req == NULL and there are + * not SETUP or STATUS phases. * - * This is a blocking function; it will not return until the control transfer - * has completed. + * This is a blocking function; it will not return until the control + * transfer has completed. * * Assumption: The caller holds the EHCI exclsem. * @@ -2097,8 +2184,8 @@ static int lpc31_async_setup(struct lpc31_rhport_s *rhport, DEBUGASSERT(rhport && epinfo); - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ DEBUGASSERT(req || (buffer && buflen > 0)); @@ -2155,8 +2242,8 @@ static int lpc31_async_setup(struct lpc31_rhport_s *rhport, toggle = QTD_TOKEN_TOGGLE; } - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ alt = NULL; @@ -2312,19 +2399,20 @@ errout_with_qh: * into the periodic frame list. * * Paragraph 4.10.7 "Adding Interrupt Queue Heads to the Periodic Schedule" - * "The link path(s) from the periodic frame list to a queue head establishes - * in which frames a transaction can be executed for the queue head. Queue - * heads are linked into the periodic schedule so they are polled at - * the appropriate rate. System software sets a bit in a queue head's - * S-Mask to indicate which micro-frame with-in a 1 millisecond period a - * transaction should be executed for the queue head. Software must ensure - * that all queue heads in the periodic schedule have S-Mask set to a non- - * zero value. An S-mask with a zero value in the context of the periodic - * schedule yields undefined results. + * "The link path(s) from the periodic frame list to a queue head + * establishes in which frames a transaction can be executed for the + * queue head. Queue heads are linked into the periodic schedule so they + * are polled at the appropriate rate. System software sets a bit in a + * queue head's S-Mask to indicate which micro-frame with-in a 1 + * millisecond period a transaction should be executed for the queue + * head. Software must ensure that all queue heads in the periodic + * schedule have S-Mask set to a non-zero value. An S-mask with a zero + * value in the context of the periodic schedule yields undefined + * results. * - * "If the desired poll rate is greater than one frame, system software can - * use a combination of queue head linking and S-Mask values to spread - * interrupts of equal poll rates through the schedule so that the + * "If the desired poll rate is greater than one frame, system software + * can use a combination of queue head linking and S-Mask values to + * spread interrupts of equal poll rates through the schedule so that the * periodic bandwidth is allocated and managed in the most efficient * manner possible." * @@ -2454,16 +2542,18 @@ errout_with_qh: * EHCI resources could be very different upon return. * * Returned Value: - * On success, this function returns the number of bytes actually transferred. - * For control transfers, this size includes the size of the control request - * plus the size of the data (which could be short); For bulk transfers, this - * will be the number of data bytes transfers (which could be short). + * On success, this function returns the number of bytes actually + * transferred. For control transfers, this size includes the size of the + * control request plus the size of the data (which could be short); for + * bulk transfers, this will be the number of data bytes transfers (which + * could be short). * ****************************************************************************/ static ssize_t lpc31_transfer_wait(struct lpc31_epinfo_s *epinfo) { int ret; + int ret2; /* Release the EHCI semaphore while we wait. Other threads need the * opportunity to access the EHCI resources while we wait. @@ -2485,7 +2575,11 @@ static ssize_t lpc31_transfer_wait(struct lpc31_epinfo_s *epinfo) * this upon return. */ - lpc31_takesem(&g_ehci.exclsem); + ret2 = lpc31_takesem_uninterruptible(&g_ehci.exclsem); + if (ret2 < 0) + { + ret = ret2; + } #if 0 /* Does not seem to be needed */ /* Was there a data buffer? Was this an OUT transfer? */ @@ -2505,7 +2599,9 @@ static ssize_t lpc31_transfer_wait(struct lpc31_epinfo_s *epinfo) } #endif - /* Did lpc31_ioc_wait() report an error? */ + /* Did lpc31_ioc_wait() or lpc31_takesem_uninterruptible() report an + * error? + */ if (ret < 0) { @@ -2543,8 +2639,9 @@ static ssize_t lpc31_transfer_wait(struct lpc31_epinfo_s *epinfo) #ifdef CONFIG_USBHOST_ASYNCH static inline int lpc31_ioc_async_setup(struct lpc31_rhport_s *rhport, - struct lpc31_epinfo_s *epinfo, - usbhost_asynch_t callback, FAR void *arg) + struct lpc31_epinfo_s *epinfo, + usbhost_asynch_t callback, + FAR void *arg) { irqstate_t flags; int ret = -ENODEV; @@ -2630,21 +2727,18 @@ static void lpc31_asynch_completion(struct lpc31_epinfo_s *epinfo) } #endif -/**************************************************************************** - * EHCI Interrupt Handling - ****************************************************************************/ - /**************************************************************************** * Name: lpc31_qtd_ioccheck * * Description: - * This function is a lpc31_qtd_foreach() callback function. It services one - * qTD in the asynchronous queue. It removes all of the qTD structures that - * are no longer active. + * This function is a lpc32_qtd_foreach() callback function. It services + * one qTD in the asynchronous queue. It removes all of the qTD + * structures that are no longer active. * ****************************************************************************/ -static int lpc31_qtd_ioccheck(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc31_qtd_ioccheck(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg) { struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)arg; DEBUGASSERT(qtd && epinfo); @@ -2685,10 +2779,10 @@ static int lpc31_qtd_ioccheck(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc31_qh_ioccheck * * Description: - * This function is a lpc31_qh_foreach() callback function. It services one - * QH in the asynchronous queue. It check all attached qTD structures and - * remove all of the structures that are no longer active. if all of the - * qTD structures are removed, then QH itself will also be removed. + * This function is a lpc31_qh_foreach() callback function. It services + * one QH in the asynchronous queue. It check all attached qTD structures + * and remove all of the structures that are no longer active. if all of + * the qTD structures are removed, then QH itself will also be removed. * ****************************************************************************/ @@ -2713,14 +2807,15 @@ static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) epinfo = qh->epinfo; DEBUGASSERT(epinfo); - /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area represent - * a transaction working space for the host controller. The general - * operational model is that the host controller can detect whether the - * overlay area contains a description of an active transfer. If it does - * not contain an active transfer, then it follows the Queue Head Horizontal - * Link Pointer to the next queue head. The host controller will never follow - * the Next Transfer Queue Element or Alternate Queue Element pointers unless - * it is actively attempting to advance the queue ..." + /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area + * represent a transaction working space for the host controller. The + * general operational model is that the host controller can detect + * whether the overlay area contains a description of an active transfer. + * If it does not contain an active transfer, then it follows the Queue + * Head Horizontal Link Pointer to the next queue head. The host + * controller will never follow the Next Transfer Queue Element or + * Alternate Queue Element pointers unless it is actively attempting to + * advance the queue ..." */ /* Is the qTD still active? */ @@ -2733,6 +2828,7 @@ static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) /* Yes... we cannot process the QH while it is still active. Return * zero to visit the next QH in the list. */ + *bp = &qh->hw.hlp; return OK; } @@ -2775,16 +2871,18 @@ static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) { /* An error occurred */ - epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> QH_TOKEN_STATUS_SHIFT; + epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> + QH_TOKEN_STATUS_SHIFT; - /* The HALT condition is set on a variety of conditions: babble, error - * counter countdown to zero, or a STALL. If we can rule out babble - * (babble bit not set) and if the error counter is non-zero, then we can - * assume a STALL. In this case, we return -PERM to inform the class - * driver of the stall condition. + /* The HALT condition is set on a variety of conditions: babble, + * error counter countdown to zero, or a STALL. If we can rule + * out babble (babble bit not set) and if the error counter is + * non-zero, then we can assume a STALL. In this case, we return + * -PERM to inform the class driver of the stall condition. */ - if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == QH_TOKEN_HALTED && + if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == + QH_TOKEN_HALTED && (token & QH_TOKEN_CERR_MASK) != 0) { /* It is a stall, Note that the data toggle is reset @@ -2831,7 +2929,8 @@ static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) } else { - /* Otherwise, the horizontal link pointer of this QH will become the next back pointer. + /* Otherwise, the horizontal link pointer of this QH will become the + * next back pointer. */ *bp = &qh->hw.hlp; @@ -2844,13 +2943,14 @@ static int lpc31_qh_ioccheck(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) * Name: lpc31_qtd_cancel * * Description: - * This function is a lpc31_qtd_foreach() callback function. It removes each - * qTD attached to a QH. + * This function is a lpc31_qtd_foreach() callback function. It removes + * each qTD attached to a QH. * ****************************************************************************/ #ifdef CONFIG_USBHOST_ASYNCH -static int lpc31_qtd_cancel(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc31_qtd_cancel(struct lpc31_qtd_s *qtd, uint32_t **bp, + void *arg) { DEBUGASSERT(qtd != NULL && bp != NULL); @@ -2883,10 +2983,10 @@ static int lpc31_qtd_cancel(struct lpc31_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc31_qh_cancel * * Description: - * This function is a lpc31_qh_foreach() callback function. It cancels one - * QH in the asynchronous queue. It will remove all attached qTD structures - * and remove all of the structures that are no longer active. Then QH - * itself will also be removed. + * This function is a imxrt_qh_foreach() callback function. It cancels + * one QH in the asynchronous queue. It will remove all attached qTD + * structures and remove all of the structures that are no longer active. + * Then QH itself will also be removed. * ****************************************************************************/ @@ -2960,13 +3060,13 @@ static int lpc31_qh_cancel(struct lpc31_qh_s *qh, uint32_t **bp, void *arg) * Description: * EHCI USB Interrupt (USBINT) "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 on the completion of a USB - * transaction, which results in the retirement of a Transfer Descriptor that - * had its IOC bit set. + * "The Host Controller sets this bit to 1 on the completion of a USB + * transaction, which results in the retirement of a Transfer Descriptor + * that had its IOC bit set. * - * "The Host Controller also sets this bit to 1 when a short packet is detected - * (actual number of bytes received was less than the expected number of - * bytes)." + * "The Host Controller also sets this bit to 1 when a short packet is + * detected (actual number of bytes received was less than the expected + * number of bytes)." * * Assumptions: The caller holds the EHCI exclsem * @@ -2979,17 +3079,20 @@ static inline void lpc31_ioc_bottomhalf(void) int ret; /* Check the Asynchronous Queue */ + /* Make sure that the head of the asynchronous queue is invalidated */ up_invalidate_dcache((uintptr_t)&g_asynchead.hw, - (uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s)); + (uintptr_t)&g_asynchead.hw + + sizeof(struct ehci_qh_s)); /* Set the back pointer to the forward QH pointer of the asynchronous * queue head. */ bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc31_qh_s *) + lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); /* If the asynchronous queue is empty, then the forward point in the * asynchronous queue head will point back to the queue head. @@ -3010,6 +3113,7 @@ static inline void lpc31_ioc_bottomhalf(void) #ifndef CONFIG_USBHOST_INT_DISABLE /* Check the Interrupt Queue */ + /* Make sure that the head of the interrupt queue is invalidated */ up_invalidate_dcache((uintptr_t)&g_intrhead.hw, @@ -3020,7 +3124,8 @@ static inline void lpc31_ioc_bottomhalf(void) */ bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc31_qh_s *) + lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); if (qh) { /* Then traverse and operate on every QH and qTD in the asynchronous @@ -3042,19 +3147,19 @@ static inline void lpc31_ioc_bottomhalf(void) * Description: * EHCI Port Change Detect "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to a one when any port for which the Port - * Owner bit is set to zero ... has a change bit transition from a zero to a - * one or a Force Port Resume bit transition from a zero to a one as a result - * of a J-K transition detected on a suspended port. This bit will also be set - * as a result of the Connect Status Change being set to a one after system - * software has relinquished ownership of a connected port by writing a one - * to a port's Port Owner bit... + * "The Host Controller sets this bit to a one when any port for which the + * Port Owner bit is set to zero ... has a change bit transition from a + * zero to a one or a Force Port Resume bit transition from a zero to a + * one as a result of a J-K transition detected on a suspended port. + * This bit will also be set as a result of the Connect Status Change + * being set to a one after system software has relinquished ownership of + * a connected port by writing a one to a port's Port Owner bit... * * "This bit is allowed to be maintained in the Auxiliary power well. - * Alternatively, it is also acceptable that on a D3 to D0 transition of the - * EHCI HC device, this bit is loaded with the OR of all of the PORTSC change - * bits (including: Force port resume, over-current change, enable/disable - * change and connect status change)." + * Alternatively, it is also acceptable that on a D3 to D0 transition of + * the EHCI HC device, this bit is loaded with the OR of all of the PORTSC + * change bits (including: Force port resume, over-current change, + * enable/disable change and connect status change)." * ****************************************************************************/ @@ -3117,7 +3222,7 @@ static inline void lpc31_portsc_bottomhalf(void) /* Yes.. disconnect the device */ usbhost_vtrace2(EHCI_VTRACE2_PORTSC_DISCONND, - rhpndx+1, g_ehci.pscwait); + rhpndx + 1, g_ehci.pscwait); rhport->connected = false; rhport->lowspeed = false; @@ -3165,10 +3270,11 @@ static inline void lpc31_portsc_bottomhalf(void) * Description: * EHCI Host System Error "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 when a serious error occurs during a - * host system access involving the Host Controller module. ... When this - * error occurs, the Host Controller clears the Run/Stop bit in the Command - * register to prevent further execution of the scheduled TDs." + * "The Host Controller sets this bit to 1 when a serious error occurs + * during a host system access involving the Host Controller module. ... + * When this error occurs, the Host Controller clears the Run/Stop bit + * in the Command register to prevent further execution of the scheduled + * TDs." * ****************************************************************************/ @@ -3185,10 +3291,10 @@ static inline void lpc31_syserr_bottomhalf(void) * EHCI Async Advance "Bottom Half" interrupt handler * * "System software can force the host controller to issue an interrupt the - * next time the host controller advances the asynchronous schedule by writing - * a one to the Interrupt on Async Advance Doorbell bit in the USBCMD - * register. This status bit indicates the assertion of that interrupt - * source." + * next time the host controller advances the asynchronous schedule by + * writing a one to the Interrupt on Async Advance Doorbell bit in the + * USBCMD register. This status bit indicates the assertion of that + * interrupt source." * ****************************************************************************/ @@ -3211,14 +3317,15 @@ static void lpc31_ehci_bottomhalf(FAR void *arg) { uint32_t pending = (uint32_t)arg; - /* We need to have exclusive access to the EHCI data structures. Waiting here - * is not a good thing to do on the worker thread, but there is no real option - * (other than to reschedule and delay). + /* We need to have exclusive access to the EHCI data structures. Waiting + * here is not a good thing to do on the worker thread, but there is no + * real option (other than to reschedule and delay). */ - lpc31_takesem(&g_ehci.exclsem); + lpc31_takesem_uninterruptible(&g_ehci.exclsem); /* Handle all unmasked interrupt sources */ + /* USB Interrupt (USBINT) * * "The Host Controller sets this bit to 1 on the completion of a USB @@ -3278,13 +3385,14 @@ static void lpc31_ehci_bottomhalf(FAR void *arg) /* Frame List Rollover * - * "The Host Controller sets this bit to a one when the Frame List Index ... - * rolls over from its maximum value to zero. The exact value at which - * the rollover occurs depends on the frame list size. For example, if - * the frame list size (as programmed in the Frame List Size field of the - * USBCMD register) is 1024, the Frame Index Register rolls over every - * time FRINDEX[13] toggles. Similarly, if the size is 512, the Host - * Controller sets this bit to a one every time FRINDEX[12] toggles." + * "The Host Controller sets this bit to a one when the Frame List Index + * ... rolls over from its maximum value to zero. The exact value at + * which the rollover occurs depends on the frame list size. For example, + * if the frame list size (as programmed in the Frame List Size field of + * the USBCMD register) is 1024, the Frame Index Register rolls over + * every time FRINDEX[13] toggles. Similarly, if the size is 512, the + * Host Controller sets this bit to a one every time FRINDEX[12] + * toggles." */ #if 0 /* Not used */ @@ -3363,9 +3471,9 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context, FAR void *arg) pending = usbsts & regval; if (pending != 0) { - /* Schedule interrupt handling work for the high priority worker thread - * so that we are not pressed for time and so that we can interrupt with - * other USB threads gracefully. + /* Schedule interrupt handling work for the high priority worker + * thread so that we are not pressed for time and so that we can + * interrupt with other USB threads gracefully. * * The worker should be available now because we implement a handshake * by controlling the EHCI interrupts. @@ -3391,9 +3499,6 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context, FAR void *arg) return OK; } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ /**************************************************************************** * Name: lpc31_wait * @@ -3401,8 +3506,8 @@ static int lpc31_ehci_interrupt(int irq, FAR void *context, FAR void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from the + * call to the USB driver initialization logic. * hport - The location to return the hub port descriptor that detected the * connection related event. * @@ -3424,9 +3529,10 @@ static int lpc31_wait(FAR struct usbhost_connection_s *conn, { irqstate_t flags; int rhpndx; + int ret; - /* Loop until a change in the connection state changes on one of the root hub - * ports or until an error occurs. + /* Loop until the connection state changes on one of the root hub ports or + * until an error occurs. */ flags = enter_critical_section(); @@ -3485,7 +3591,11 @@ static int lpc31_wait(FAR struct usbhost_connection_s *conn, */ g_ehci.pscwait = true; - lpc31_takesem(&g_ehci.pscsem); + ret = lpc31_takesem(&g_ehci.pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3503,14 +3613,14 @@ static int lpc31_wait(FAR struct usbhost_connection_s *conn, * charge of the sequence of operations. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from - * the call to the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. * hport - The descriptor of the hub port that has the newly connected - * device. + * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3548,7 +3658,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, * reset for 50Msec, not wait 50Msec before resetting. */ - nxsig_usleep(100*1000); + nxsig_usleep(100 * 1000); /* Paragraph 2.3.9: * @@ -3565,8 +3675,8 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, * 01b K-state Low-speed device, release ownership of port * * NOTE: Low-speed devices could be detected by examining the PORTSC PSPD - * field after resetting the device. The more conventional way here, however, - * also appears to work. + * field after resetting the device. The more conventional way here, + * however, also appears to work. */ regval = lpc31_getreg(&HCOR->portsc[rhpndx]); @@ -3621,7 +3731,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, /* Put the root hub port in reset. * - * Paragraph 2.3.9: + * EHCI Paragraph 2.3.9: * * "The HCHalted bit in the USBSTS register should be a zero before * software attempts to use [the Port Reset] bit. The host controller @@ -3630,15 +3740,15 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, DEBUGASSERT((lpc31_getreg(&HCOR->usbsts) & EHCI_USBSTS_HALTED) == 0); - /* EHCI paragraph 2.3.9: + /* EHCI Paragraph 2.3.9: * * "When software writes a one to [the Port Reset] bit (from a zero), the - * bus reset sequence as defined in the USB Specification Revision 2.0 is - * started. Software writes a zero to this bit to terminate the bus reset - * sequence. Software must keep this bit at a one long enough to ensure - * the reset sequence, as specified in the USB Specification Revision 2.0, - * completes. Note: when software writes this bit to a one, it must also - * write a zero to the Port Enable bit." + * bus reset sequence as defined in the USB Specification Revision 2.0 + * is started. Software writes a zero to this bit to terminate the bus + * reset sequence. Software must keep this bit at a one long enough to + * ensure the reset sequence, as specified in the USB Specification + * Revision 2.0, completes. Note: when software writes this bit to a + * one, it must also write a zero to the Port Enable bit." */ regaddr = &HCOR->portsc[RHPNDX(rhport)]; @@ -3651,7 +3761,7 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, * 50 ms." */ - nxsig_usleep(50*1000); + nxsig_usleep(50 * 1000); regval = lpc31_getreg(regaddr); regval &= ~EHCI_PORTSC_RESET; @@ -3672,35 +3782,36 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, */ while ((lpc31_getreg(regaddr) & EHCI_PORTSC_RESET) != 0); - nxsig_usleep(200*1000); + nxsig_usleep(200 * 1000); - /* EHCI Paragraph 4.2.2: + /* Paragraph 4.2.2: * * "... The reset process is actually complete when software reads a zero - * in the PortReset bit. The EHCI Driver checks the PortEnable bit in the - * PORTSC register. If set to a one, the connected device is a high-speed - * device and EHCI Driver (root hub emulator) issues a change report to the - * hub driver and the hub driver continues to enumerate the attached device." + * in the PortReset bit. The EHCI Driver checks the PortEnable bit in + * the PORTSC register. If set to a one, the connected device is a high- + * speed device and EHCI Driver (root hub emulator) issues a change + * report to the hub driver and the hub driver continues to enumerate + * the attached device." * - * "At the time the EHCI Driver receives the port reset and enable request - * the LineStatus bits might indicate a low-speed device. Additionally, - * when the port reset process is complete, the PortEnable field may - * indicate that a full-speed device is attached. In either case the EHCI - * driver sets the PortOwner bit in the PORTSC register to a one to - * release port ownership to a companion host controller." + * "At the time the EHCI Driver receives the port reset and enable + * request the LineStatus bits might indicate a low-speed device. + * Additionally, when the port reset process is complete, the PortEnable + * field may indicate that a full-speed device is attached. In either + * case the EHCI driver sets the PortOwner bit in the PORTSC register to + * a one to release port ownership to a companion host controller." * * LPC31xx User Manual Paragraph 6.1.3: * * "In a standard EHCI controller design, the EHCI host controller driver * detects a Full speed (FS) or Low speed (LS) device by noting if the - * port enable bit is set after the port reset operation. The port enable - * will only be set in a standard EHCI controller implementation after the - * port reset operation and when the host and device negotiate a High-Speed - * connection (i.e. Chirp completes successfully). Since this controller has - * an embedded Transaction Translator, the port enable will always be set - * after the port reset operation regardless of the result of the host device - * chirp result and the resulting port speed will be indicated by the PSPD - * field in PORTSC1. + * port enable bit is set after the port reset operation. The port + * enable will only be set in a standard EHCI controller implementation + * after the port reset operation and when the host and device negotiate + * a High-Speed connection (i.e. Chirp completes successfully). Since + * this controller has an embedded Transaction Translator, the port + * enable will always be set after the port reset operation regardless + * of the result of the host device chirp result and the resulting port + * speed will be indicated by the PSPD field in PORTSC1." */ regval = lpc31_getreg(&HCOR->portsc[rhpndx]); @@ -3751,7 +3862,8 @@ static int lpc31_rh_enumerate(FAR struct usbhost_connection_s *conn, else { DEBUGASSERT(hport->speed == USB_SPEED_LOW); - DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS); + DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == + USBDEV_PRTSC1_PSPD_LS); } return OK; @@ -3789,8 +3901,9 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, hport->port + 1, -ret); - /* If this is a root hub port, then marking the hub port not connected will - * cause lpc31_wait() to return and we will try the connection again. + /* If this is a root hub port, then marking the hub port not connected + * will cause sam_wait() to return and we will try the connection + * again. */ hport->connected = false; @@ -3799,7 +3912,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_ep0configure * * Description: @@ -3808,78 +3921,85 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * 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. A funcaddr of zero will be received if no address is yet assigned - * to the device. + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) +static int lpc31_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)ep0; + int ret; DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048); /* We must have exclusive access to the EHCI data structures. */ - lpc31_takesem(&g_ehci.exclsem); + ret = lpc31_takesem(&g_ehci.exclsem); + if (ret >= 0) + { + /* Remember the new device address and max packet size */ - /* Remember the new device address and max packet size */ + epinfo->devaddr = funcaddr; + epinfo->speed = speed; + epinfo->maxpacket = maxpacketsize; - epinfo->devaddr = funcaddr; - epinfo->speed = speed; - epinfo->maxpacket = maxpacketsize; + lpc31_givesem(&g_ehci.exclsem); + } - lpc31_givesem(&g_ehci.exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, - const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const FAR struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct lpc31_epinfo_s *epinfo; struct usbhost_hubport_s *hport; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ - DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && ep != NULL); + DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && + ep != NULL); hport = epdesc->hport; /* Terse output only if we are tracing */ @@ -3894,7 +4014,8 @@ static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, /* Allocate a endpoint information structure */ - epinfo = (struct lpc31_epinfo_s *)kmm_zalloc(sizeof(struct lpc31_epinfo_s)); + epinfo = (struct lpc31_epinfo_s *) + kmm_zalloc(sizeof(struct lpc31_epinfo_s)); if (!epinfo) { usbhost_trace1(EHCI_TRACE1_EPALLOC_FAILED, 0); @@ -3924,33 +4045,33 @@ static int lpc31_epalloc(FAR struct usbhost_driver_s *drvr, nxsem_init(&epinfo->iocsem, 0, 0); nxsem_setprotocol(&epinfo->iocsem, SEM_PRIO_NONE); - /* Success.. return an opaque reference to the endpoint information structure - * instance + /* Success.. return an opaque reference to the endpoint information + * structure instance */ *ep = (usbhost_ep_t)epinfo; return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The endpint to be freed. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The endpint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc31_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -3970,10 +4091,11 @@ static int lpc31_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: lpc31_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * allocate the request/descriptor memory. If the underlying hardware does - * not support such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc(). * * This interface was optimized under a particular assumption. It was * assumed that the driver maintains a pool of small, pre-allocated buffers @@ -3981,16 +4103,16 @@ static int lpc31_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. - * buffer - The address of a memory location provided by the caller in which - * to return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which - * to return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4004,12 +4126,13 @@ static int lpc31_alloc(FAR struct usbhost_driver_s *drvr, int ret = -ENOMEM; DEBUGASSERT(drvr && buffer && maxlen); - /* The only special requirements for transfer/descriptor buffers are that (1) - * they be aligned to a cache line boundary and (2) they are a multiple of the - * cache line size in length. + /* The only special requirements for transfer/descriptor buffers are that + * (1) they be aligned to a cache line boundary and (2) they are a + * multiple of the cache line size in length. */ - *buffer = (FAR uint8_t *)kmm_memalign(ARM_DCACHE_LINESIZE, LPC31_EHCI_BUFSIZE); + *buffer = (FAR uint8_t *) + kmm_memalign(ARM_DCACHE_LINESIZE, LPC31_EHCI_BUFSIZE); if (*buffer) { *maxlen = LPC31_EHCI_BUFSIZE; @@ -4023,19 +4146,20 @@ static int lpc31_alloc(FAR struct usbhost_driver_s *drvr, * Name: lpc31_free * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * free that request/descriptor memory. If the underlying hardware does not - * support such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4052,42 +4176,44 @@ static int lpc31_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kumm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kumm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are variable- + * sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc31_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, - size_t buflen) +static int lpc31_ioalloc(FAR struct usbhost_driver_s *drvr, + FAR uint8_t **buffer, size_t buflen) { DEBUGASSERT(drvr && buffer && buflen > 0); - /* The only special requirements for I/O buffers are that (1) they be aligned to a - * cache line boundary, (2) they are a multiple of the cache line size in length, - * and (3) they might need to be user accessible (depending on how the class driver - * implements its buffering). + /* The only special requirements for I/O buffers are that (1) they be + * aligned to a cache line boundary, (2) they are a multiple of the cache + * line size in length, and (3) they might need to be user accessible + * (depending on how the class driver implements its buffering). */ buflen = (buflen + DCACHE_LINEMASK) & ~DCACHE_LINEMASK; @@ -4095,30 +4221,31 @@ static int lpc31_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer return *buffer ? OK : -ENOMEM; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kumm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { DEBUGASSERT(drvr && buffer); @@ -4133,30 +4260,30 @@ static int lpc31_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer - * may be queued; Neither these methods nor the transfer() method can be - * called again until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The control endpoint to send/receive the control request. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any - * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using - * DRVR_ALLOC. + * responses. This buffer must be large enough to hold the + * length value in the request description. buffer must have been + * allocated using DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4183,14 +4310,19 @@ static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, #ifdef CONFIG_USBHOST_TRACE usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, RHPORT(rhport), req->req); #else - uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %04x\n", + uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x " + "len: %04x\n", RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], len); #endif /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc31_takesem(&g_ehci.exclsem); + ret = lpc31_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4227,8 +4359,8 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer) { - /* lpc31_ctrlin can handle both directions. We just need to work around the - * differences in the function signatures. + /* lpc31_ctrlin can handle both directions. We just need to work around + * the differences in the function signatures. */ return lpc31_ctrlin(drvr, ep0, req, (uint8_t *)buffer); @@ -4239,26 +4371,27 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4272,8 +4405,9 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)ep; @@ -4284,7 +4418,11 @@ static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc31_takesem(&g_ehci.exclsem); + ret = lpc31_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4354,20 +4492,21 @@ errout_with_sem: * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC - * buflen - The length of the data to be sent or received. + * drvr - The USB host driver instance obtained as a parameter from + * the call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated + * using DRVR_ALLOC + * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4388,7 +4527,11 @@ static int lpc31_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc31_takesem(&g_ehci.exclsem); + ret = lpc31_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the callback well BEFORE initiating the transfer. */ @@ -4445,24 +4588,24 @@ errout_with_sem: } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: lpc31_cancel * * Description: - * Cancel a pending transfer on an endpoint. Cancelled synchronous or + * Cancel a pending transfer on an endpoint. Canceled synchronous or * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4479,20 +4622,25 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(epinfo); - /* We must have exclusive access to the EHCI hardware and data structures. This - * will prevent servicing any transfer completion events while we perform the - * the cancellation, but will not prevent DMA-related race conditions. + /* We must have exclusive access to the EHCI hardware and data structures. + * This will prevent servicing any transfer completion events while we + * perform the cancellation, but will not prevent DMA-related race + * conditions. * - * REVISIT: This won't work. This function must be callable from the interrupt - * level. + * REVISIT: This won't work. This function must be callable from the + * interrupt level. */ - lpc31_takesem(&g_ehci.exclsem); + ret = lpc31_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } - /* Sample and reset all transfer termination information. This will prevent any - * callbacks from occurring while are performing the cancellation. The transfer - * may still be in progress, however, so this does not eliminate other DMA- - * related race conditions. + /* Sample and reset all transfer termination information. This will + * prevent any callbacks from occurring while are performing the + * cancellation. The transfer may still be in progress, however, so this + * does not eliminate other DMA-related race conditions. */ flags = enter_critical_section(); @@ -4541,7 +4689,8 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc31_qh_s *) + lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); /* If the asynchronous queue is empty, then the forward point in * the asynchronous queue head will point back to the queue @@ -4566,7 +4715,8 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc31_qh_s *) + lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); if (qh) { /* if the queue is empty, then just claim that we successfully @@ -4592,13 +4742,13 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Find and remove the QH. There are four possibilities: * - * 1) The transfer has already completed and the QH is no longer in the list. In - * this case, lpc31_hq_foreach will return zero - * 2a) The transfer is not active and still pending. It was removed from the list - * and lpc31_hq_foreach will return one. - * 2b) The is active but not yet complete. This is currently handled the same as - * 2a). REVISIT: This needs to be fixed. - * 3) Some bad happened and lpc31_hq_foreach returned an error code < 0. + * 1) The transfer has already completed and the QH is no longer in the + * list. In this case, sam_hq_foreach will return zero + * 2a) The transfer is not active and still pending. It was removed from + * the list and sam_hq_foreach will return one. + * 2b) The is active but not yet complete. This is currently handled the + * same as 2a). REVISIT: This needs to be fixed. + * 3) Some bad happened and sam_hq_foreach returned an error code < 0. */ ret = lpc31_qh_foreach(qh, &bp, lpc31_qh_cancel, epinfo); @@ -4640,7 +4790,7 @@ errout_with_sem: return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc31_connect * * Description: @@ -4649,17 +4799,17 @@ errout_with_sem: * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int lpc31_connect(FAR struct usbhost_driver_s *drvr, @@ -4671,7 +4821,8 @@ static int lpc31_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4694,17 +4845,18 @@ static int lpc31_connect(FAR struct usbhost_driver_s *drvr, * Name: lpc31_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4722,9 +4874,6 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: lpc31_reset * @@ -4733,9 +4882,9 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr, * * Table 2-9. USBCMD - USB Command Register Bit Definitions * - * "Host Controller Reset (HCRESET) ... This control bit is used by software - * to reset the host controller. The effects of this on Root Hub registers - * are similar to a Chip Hardware Reset. + * "Host Controller Reset (HCRESET) ... This control bit is used by + * software to reset the host controller. The effects of this on Root + * Hub registers are similar to a Chip Hardware Reset. * * "When software writes a one to this bit, the Host Controller resets its * internal pipelines, timers, counters, state machines, etc. to their @@ -4744,16 +4893,18 @@ static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr, * ports. * * "PCI Configuration registers are not affected by this reset. All - * operational registers, including port registers and port state machines - * are set to their initial values. Port ownership reverts to the companion - * host controller(s)... Software must reinitialize the host controller ... - * in order to return the host controller to an operational state. + * operational registers, including port registers and port state + * machines are set to their initial values. Port ownership reverts + * to the companion host controller(s)... Software must reinitialize + * the host controller ... in order to return the host controller to + * an operational state. * - * "This bit is set to zero by the Host Controller when the reset process is - * complete. Software cannot terminate the reset process early by writing a - * zero to this register. Software should not set this bit to a one when - * the HCHalted bit in the USBSTS register is a zero. Attempting to reset - * an actively running host controller will result in undefined behavior." + * "This bit is set to zero by the Host Controller when the reset process + * is complete. Software cannot terminate the reset process early by + * writing a zero to this register. Software should not set this bit to + * a one when the HCHalted bit in the USBSTS register is a zero. + * Attempting to reset an actively running host controller will result + * in undefined behavior." * * Input Parameters: * None. @@ -4772,10 +4923,11 @@ static int lpc31_reset(void) uint32_t regval; unsigned int timeout; - /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to 0, - * the Host Controller completes the current transaction on the USB and then - * halts. The HC Halted bit in the status register indicates when the Hos - * Controller has finished the transaction and has entered the stopped state..." + /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to + * 0, the Host Controller completes the current transaction on the USB and + * then halts. The HC Halted bit in the status register indicates when the + * Host Controller has finished the transaction and has entered the + * stopped state..." */ lpc31_putreg(0, &HCOR->usbcmd); @@ -4793,9 +4945,9 @@ static int lpc31_reset(void) up_udelay(1); timeout++; - /* Get the current value of the USBSTS register. This loop will terminate - * when either the timeout exceeds one millisecond or when the HCHalted - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBSTS register. This loop will + * terminate when either the timeout exceeds one millisecond or when + * the HCHalted bit is no longer set in the USBSTS register. */ regval = lpc31_getreg(&HCOR->usbsts); @@ -4825,9 +4977,9 @@ static int lpc31_reset(void) up_udelay(5); timeout += 5; - /* Get the current value of the USBCMD register. This loop will terminate - * when either the timeout exceeds one second or when the HCReset - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBCMD register. This loop will + * terminate when either the timeout exceeds one second or when the + * HCReset bit is no longer set in the USBSTS register. */ regval = lpc31_getreg(&HCOR->usbcmd); @@ -4842,6 +4994,7 @@ static int lpc31_reset(void) /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: lpc31_ehci_initialize * @@ -4898,7 +5051,7 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) #endif #endif /* CONFIG_USBHOST_INT_DISABLE */ - /* Software Configuration ****************************************************/ + /* Software Configuration *************************************************/ usbhost_vtrace1(EHCI_VTRACE1_INITIALIZING, 0); @@ -5030,7 +5183,8 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) lpc31_qtd_free(&g_qtdpool[i]); } - /* EHCI Hardware Configuration ***********************************************/ + /* EHCI Hardware Configuration ********************************************/ + /* Enable USB to AHB clock and to Event router */ lpc31_enableclock(CLKID_USBOTGAHBCLK); @@ -5076,13 +5230,16 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) */ #ifdef CONFIG_LPC31_EHCI_SDIS - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | USBHOST_USBMODE_VBPS, + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | + USBHOST_USBMODE_VBPS, LPC31_USBDEV_USBMODE); #else - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, LPC31_USBDEV_USBMODE); + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, + LPC31_USBDEV_USBMODE); #endif /* Host Controller Initialization. Paragraph 4.1 */ + /* Reset the EHCI hardware */ ret = lpc31_reset(); @@ -5097,33 +5254,35 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) * host configuration in the reset. */ - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | USBHOST_USBMODE_VBPS, + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | + USBHOST_USBMODE_VBPS, LPC31_USBDEV_USBMODE); - /* "In order to initialize the host controller, software should perform the - * following steps: + /* "In order to initialize the host controller, software should perform + * the following steps: * - * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where all - * of the interface data structures are allocated. [64-bit mode] + * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where + * all of the interface data structures are allocated. [64-bit mode] * - "Write the appropriate value to the USBINTR register to enable the * appropriate interrupts. - * - "Write the base address of the Periodic Frame List to the PERIODICLIST - * BASE register. If there are no work items in the periodic schedule, - * all elements of the Periodic Frame List should have their T-Bits set - * to a one. + * - "Write the base address of the Periodic Frame List to the + * PERIODICLIST BASE register. If there are no work items in the + * periodic schedule, all elements of the Periodic Frame List should + * have their T-Bits set to a one. * - "Write the USBCMD register to set the desired interrupt threshold, * frame list size (if applicable) and turn the host controller ON via * setting the Run/Stop bit. - * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI controller + * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI + * controller * ... * - * "At this point, the host controller is up and running and the port registers - * will begin reporting device connects, etc. System software can enumerate a - * port through the reset process (where the port is in the enabled state). At - * this point, the port is active with SOFs occurring down the enabled por - * enabled Highspeed ports, but the schedules have not yet been enabled. The - * EHCI Host controller will not transmit SOFs to enabled Full- or Low-speed - * ports. + * "At this point, the host controller is up and running and the port + * registers will begin reporting device connects, etc. System software + * can enumerate a port through the reset process (where the port is in + * the enabled state). At this point, the port is active with SOFs + * occurring down the enabled port enabled Highspeed ports, but the + * schedules have not yet been enabled. The EHCI Host controller will not + * transmit SOFs to enabled Full- or Low-speed ports." */ /* Disable all interrupts */ @@ -5145,7 +5304,8 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) /* Verify that the correct number of ports is reported */ regval = lpc31_getreg(&HCCR->hcsparams); - nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT; + nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> + EHCI_HCSPARAMS_NPORTS_SHIFT; usbhost_vtrace2(EHCI_VTRACE2_HCSPARAMS, nports, regval); DEBUGASSERT(nports == LPC31_EHCI_NRHPORT); @@ -5172,7 +5332,8 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) memset(&g_asynchead, 0, sizeof(struct lpc31_qh_s)); physaddr = lpc31_physramaddr((uintptr_t)&g_asynchead); g_asynchead.hw.hlp = lpc31_swap32(physaddr | QH_HLP_TYP_QH); - g_asynchead.hw.epchar = lpc31_swap32(QH_EPCHAR_H | QH_EPCHAR_EPS_FULL); + g_asynchead.hw.epchar = lpc31_swap32(QH_EPCHAR_H | + QH_EPCHAR_EPS_FULL); g_asynchead.hw.overlay.nqp = lpc31_swap32(QH_NQP_T); g_asynchead.hw.overlay.alt = lpc31_swap32(QH_NQP_T); g_asynchead.hw.overlay.token = lpc31_swap32(QH_TOKEN_HALTED); @@ -5210,9 +5371,11 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) /* Set the Periodic Frame List Base Address. */ up_clean_dcache((uintptr_t)&g_intrhead.hw, - (uintptr_t)&g_intrhead.hw + sizeof(struct ehci_qh_s)); + (uintptr_t)&g_intrhead.hw + + sizeof(struct ehci_qh_s)); up_clean_dcache((uintptr_t)g_framelist, - (uintptr_t)g_framelist + FRAME_LIST_SIZE * sizeof(uint32_t)); + (uintptr_t)g_framelist + + FRAME_LIST_SIZE * sizeof(uint32_t)); physaddr = lpc31_physramaddr((uintptr_t)g_framelist); lpc31_putreg(lpc31_swap32(physaddr), &HCOR->periodiclistbase); @@ -5257,14 +5420,14 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) /* Wait for the EHCI to run (i.e., no longer report halted) */ - ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100*1000); + ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100 * 1000); if (ret < 0) { usbhost_trace1(EHCI_TRACE1_RUN_FAILED, lpc31_getreg(&HCOR->usbsts)); return NULL; } - /* Interrupt Configuration ***************************************************/ + /* Interrupt Configuration ************************************************/ ret = irq_attach(LPC31_IRQ_USBOTG, lpc31_ehci_interrupt, NULL); if (ret != 0) @@ -5332,7 +5495,7 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) return &g_ehciconn; } -/******************************************************************************************** +/**************************************************************************** * Name: usbhost_trformat1 and usbhost_trformat2 * * Description: @@ -5343,7 +5506,7 @@ FAR struct usbhost_connection_s *lpc31_ehci_initialize(int controller) * printf. The returned format is expected to handle two unsigned integer * values. * - ********************************************************************************************/ + ****************************************************************************/ #ifdef HAVE_USBHOST_TRACE FAR const char *usbhost_trformat1(uint16_t id) diff --git a/arch/arm/src/lpc43xx/lpc43_ehci.c b/arch/arm/src/lpc43xx/lpc43_ehci.c index 65abe2b6f0..a267e7ddba 100644 --- a/arch/arm/src/lpc43xx/lpc43_ehci.c +++ b/arch/arm/src/lpc43xx/lpc43_ehci.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/lpc43xx/lpc43_ehci.c * - * Copyright (C) 2013-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -73,7 +58,9 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ + /* Pre-requisites */ #if !defined(CONFIG_SCHED_WORKQUEUE) @@ -90,8 +77,8 @@ # define CONFIG_LPC43_EHCI_NQHS (LPC43_EHCI_NRHPORT + 1) #endif -/* Configurable number of Queue Element Transfer Descriptor (qTDs). The default - * is one per root hub plus three from EP0. +/* Configurable number of Queue Element Transfer Descriptor (qTDs). The + * default is one per root hub plus three from EP0. */ #ifndef CONFIG_LPC43_EHCI_NQTDS @@ -122,7 +109,8 @@ # undef CONFIG_DEBUG_USB #endif -/* Registers *******************************************************************/ +/* Registers ****************************************************************/ + /* Traditionally, NuttX specifies register locations using individual * register offsets from a base address. That tradition is broken here and, * instead, register blocks are represented as structures. This is done here @@ -142,7 +130,8 @@ #define HCOR ((volatile struct ehci_hcor_s *)LPC43_USBOTG_HCOR_BASE) -/* Interrupts ******************************************************************/ +/* Interrupts ***************************************************************/ + /* This is the set of interrupts handled by this driver */ #define EHCI_HANDLED_INTS (EHCI_INT_USBINT | EHCI_INT_USBERRINT | \ @@ -150,16 +139,17 @@ EHCI_INT_AAINT) /* The periodic frame list is a 4K-page aligned array of Frame List Link - * pointers. The length of the frame list may be programmable. The programmability - * of the periodic frame list is exported to system software via the HCCPARAMS - * register. If non-programmable, the length is 1024 elements. If programmable, - * the length can be selected by system software as one of 256, 512, or 1024 - * elements. + * pointers. The length of the frame list may be programmable. The + * programmability of the periodic frame list is exported to system software + * via the HCCPARAMS register. If non-programmable, the length is 1024 + * elements. If programmable, the length can be selected by system software + * as one of 256, 512, or 1024 elements. */ #define FRAME_LIST_SIZE 1024 -/* DMA *************************************************************************/ +/* DMA **********************************************************************/ + /* For now, we are assuming an identity mapping between physical and virtual * address spaces. */ @@ -167,7 +157,7 @@ #define lpc43_physramaddr(a) (a) #define lpc43_virtramaddr(a) (a) -/* USB trace *******************************************************************/ +/* USB trace ****************************************************************/ #ifdef HAVE_USBHOST_TRACE # define TR_FMT1 false @@ -192,6 +182,7 @@ /**************************************************************************** * Private Types ****************************************************************************/ + /* Internal representation of the EHCI Queue Head (QH) */ struct lpc43_epinfo_s; @@ -230,7 +221,8 @@ struct lpc43_list_s /* List traversal callout functions */ typedef int (*foreach_qh_t)(struct lpc43_qh_s *qh, uint32_t **bp, void *arg); -typedef int (*foreach_qtd_t)(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg); +typedef int (*foreach_qtd_t)(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg); /* This structure describes one endpoint. */ @@ -283,15 +275,15 @@ struct lpc43_rhport_s struct lpc43_ehci_s { - volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */ + volatile bool pscwait; /* TRUE: Thread is waiting for port status change event */ - sem_t exclsem; /* Support mutually exclusive access */ - sem_t pscsem; /* Semaphore to wait for port status change events */ + sem_t exclsem; /* Support mutually exclusive access */ + sem_t pscsem; /* Semaphore to wait for port status change events */ - struct lpc43_epinfo_s ep0; /* Endpoint 0 */ - struct lpc43_list_s *qhfree; /* List of free Queue Head (QH) structures */ - struct lpc43_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ - struct work_s work; /* Supports interrupt bottom half */ + struct lpc43_epinfo_s ep0; /* Endpoint 0 */ + struct lpc43_list_s *qhfree; /* List of free Queue Head (QH) structures */ + struct lpc43_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ + struct work_s work; /* Supports interrupt bottom half */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -395,7 +387,7 @@ struct lpc43_ehci_trace_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ static uint16_t lpc43_read16(const uint8_t *addr); static uint32_t lpc43_read32(const uint8_t *addr); @@ -426,29 +418,30 @@ static inline void lpc43_putreg(uint32_t regval, volatile uint32_t *regaddr); static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, unsigned int delay); -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void lpc43_takesem(sem_t *sem); +static int lpc43_takesem(sem_t *sem); +static int lpc43_takesem_uninterruptible(sem_t *sem); #define lpc43_givesem(s) nxsem_post(s); -/* Allocators ******************************************************************/ +/* Allocators ***************************************************************/ static struct lpc43_qh_s *lpc43_qh_alloc(void); static void lpc43_qh_free(struct lpc43_qh_s *qh); static struct lpc43_qtd_s *lpc43_qtd_alloc(void); static void lpc43_qtd_free(struct lpc43_qtd_s *qtd); -/* List Management *************************************************************/ +/* List Management **********************************************************/ static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t handler, void *arg); static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, void *arg); -static int lpc43_qtd_discard(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc43_qtd_discard(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc43_qh_discard(struct lpc43_qh_s *qh); - -/* Endpoint Transfer Handling **************************************************/ +/* Endpoint Transfer Handling ***********************************************/ #ifdef CONFIG_LPC43_EHCI_REGDEBUG static void lpc43_qtd_print(struct lpc43_qtd_s *qtd); @@ -472,8 +465,8 @@ static struct lpc43_qh_s *lpc43_qh_create(struct lpc43_rhport_s *rhport, struct lpc43_epinfo_s *epinfo); static int lpc43_qtd_addbpl(struct lpc43_qtd_s *qtd, const void *buffer, size_t buflen); -static struct lpc43_qtd_s *lpc43_qtd_setupphase(struct lpc43_epinfo_s *epinfo, - const struct usb_ctrlreq_s *req); +static struct lpc43_qtd_s *lpc43_qtd_setupphase( + struct lpc43_epinfo_s *epinfo, const struct usb_ctrlreq_s *req); static struct lpc43_qtd_s *lpc43_qtd_dataphase(struct lpc43_epinfo_s *epinfo, void *buffer, int buflen, uint32_t tokenbits); static struct lpc43_qtd_s *lpc43_qtd_statusphase(uint32_t tokenbits); @@ -492,12 +485,15 @@ static inline int lpc43_ioc_async_setup(struct lpc43_rhport_s *rhport, static void lpc43_asynch_completion(struct lpc43_epinfo_s *epinfo); #endif -/* Interrupt Handling **********************************************************/ +/* Interrupt Handling *******************************************************/ -static int lpc43_qtd_ioccheck(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg); -static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg); +static int lpc43_qtd_ioccheck(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg); +static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, + void *arg); #ifdef CONFIG_USBHOST_ASYNCH -static int lpc43_qtd_cancel(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg); +static int lpc43_qtd_cancel(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg); static int lpc43_qh_cancel(struct lpc43_qh_s *qh, uint32_t **bp, void *arg); #endif static inline void lpc43_ioc_bottomhalf(void); @@ -507,7 +503,7 @@ static inline void lpc43_async_advance_bottomhalf(void); static void lpc43_ehci_bottomhalf(FAR void *arg); static int lpc43_ehci_interrupt(int irq, FAR void *context, FAR void *arg); -/* USB Host Controller Operations **********************************************/ +/* USB Host Controller Operations *******************************************/ static int lpc43_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -516,23 +512,26 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, static int lpc43_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); -static int lpc43_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize); +static int lpc43_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize); static int lpc43_epalloc(FAR struct usbhost_driver_s *drvr, const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); static int lpc43_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int lpc43_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int lpc43_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int lpc43_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int lpc43_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int lpc43_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int lpc43_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int lpc43_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int lpc43_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t lpc43_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t lpc43_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int lpc43_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, @@ -546,16 +545,17 @@ static int lpc43_connect(FAR struct usbhost_driver_s *drvr, static void lpc43_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static int lpc43_reset(void); /**************************************************************************** * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. + +/* In this driver implementation, support is provided for only a single + * USB device. All status information can be simply retained in a single + * global instance. */ static struct lpc43_ehci_s g_ehci; @@ -624,69 +624,119 @@ static struct lpc43_qtd_s *g_qtdpool; static const struct lpc43_ehci_trace_s g_trace1[TRACE1_NSTRINGS] = { - TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, "EHCI ERROR: System error: %06x\n"), - TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qtd_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate a QH\n"), - TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, "EHCI ERROR: Buffer too big. Remaining %d\n"), - TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate request qTD"), - TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qtd_addbpl failed: %d\n"), - TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate data buffer qTD, 0"), - TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, "EHCI ERROR: Device disconnected %d\n"), - TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qh_create failed\n"), - TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qtd_setupphase failed\n"), + TRENTRY(EHCI_TRACE1_SYSTEMERROR, TR_FMT1, + "EHCI ERROR: System error: %06x\n"), + TRENTRY(EHCI_TRACE1_QTDFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qtd_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_QHALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate a QH\n"), + TRENTRY(EHCI_TRACE1_BUFTOOBIG, TR_FMT1, + "EHCI ERROR: Buffer too big. Remaining %d\n"), + TRENTRY(EHCI_TRACE1_REQQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate request qTD"), + TRENTRY(EHCI_TRACE1_ADDBPL_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qtd_addbpl failed: %d\n"), + TRENTRY(EHCI_TRACE1_DATAQTDALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate data buffer qTD, 0"), + TRENTRY(EHCI_TRACE1_DEVDISCONNECTED, TR_FMT1, + "EHCI ERROR: Device disconnected %d\n"), + TRENTRY(EHCI_TRACE1_QHCREATE_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qh_create failed\n"), + TRENTRY(EHCI_TRACE1_QTDSETUP_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qtd_setupphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qtd_dataphase failed\n"), - TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qtd_statusphase failed\n"), - TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, "EHCI ERROR: Transfer failed %d\n"), - TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, "EHCI ERROR: lpc43_qh_foreach failed: %d\n"), - TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, "EHCI: Host System Error Interrupt\n"), - TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), - TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate EP info structure\n"), - TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, "EHCI ERROR: Support for transfer type %d not implemented\n"), - TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), - TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the QH pool\n"), + TRENTRY(EHCI_TRACE1_QTDDATA_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qtd_dataphase failed\n"), + TRENTRY(EHCI_TRACE1_QTDSTATUS_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qtd_statusphase failed\n"), + TRENTRY(EHCI_TRACE1_TRANSFER_FAILED, TR_FMT1, + "EHCI ERROR: Transfer failed %d\n"), + TRENTRY(EHCI_TRACE1_QHFOREACH_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_qh_foreach failed: %d\n"), + TRENTRY(EHCI_TRACE1_SYSERR_INTR, TR_FMT1, + "EHCI: Host System Error Interrupt\n"), + TRENTRY(EHCI_TRACE1_USBERR_INTR, TR_FMT1, + "EHCI: USB Error Interrupt (USBERRINT) Interrupt: %06x\n"), + TRENTRY(EHCI_TRACE1_EPALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate EP info structure\n"), + TRENTRY(EHCI_TRACE1_BADXFRTYPE, TR_FMT1, + "EHCI ERROR: Support for transfer type %d not implemented\n"), + TRENTRY(EHCI_TRACE1_HCHALTED_TIMEOUT, TR_FMT1, + "EHCI ERROR: Timed out waiting for HCHalted. USBSTS: %06x\n"), + TRENTRY(EHCI_TRACE1_QHPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the QH pool\n"), - TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the qTD pool\n"), - TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, "EHCI ERROR: Failed to allocate the periodic frame list\n"), - TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, "EHCI ERROR: lpc43_reset failed: %d\n"), - TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), - TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, "EHCI ERROR: Failed to attach IRQ%d\n"), + TRENTRY(EHCI_TRACE1_QTDPOOLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the qTD pool\n"), + TRENTRY(EHCI_TRACE1_PERFLALLOC_FAILED, TR_FMT1, + "EHCI ERROR: Failed to allocate the periodic frame list\n"), + TRENTRY(EHCI_TRACE1_RESET_FAILED, TR_FMT1, + "EHCI ERROR: lpc43_reset failed: %d\n"), + TRENTRY(EHCI_TRACE1_RUN_FAILED, TR_FMT1, + "EHCI ERROR: EHCI Failed to run: USBSTS=%06x\n"), + TRENTRY(EHCI_TRACE1_IRQATTACH_FAILED, TR_FMT1, + "EHCI ERROR: Failed to attach IRQ%d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, "EHCI Connect Status Change: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, "EHCI Already connected: %06x\n"), - TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, "EHCI Already disconnected: %06x\n"), - TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, "EHCI Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, "EHCI Async Advance Interrupt\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CSC, TR_FMT1, + "EHCI Connect Status Change: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_CONNALREADY, TR_FMT1, + "EHCI Already connected: %06x\n"), + TRENTRY(EHCI_VTRACE1_PORTSC_DISCALREADY, TR_FMT1, + "EHCI Already disconnected: %06x\n"), + TRENTRY(EHCI_VTRACE1_TOPHALF, TR_FMT1, + "EHCI Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_AAINTR, TR_FMT1, + "EHCI Async Advance Interrupt\n"), - TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, "EHCI Hub port %d: Enumerate the device\n"), - TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), - TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, "EHCI Enumeration not connected\n"), - TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, "EHCI Initializing EHCI Stack\n"), - TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, "EHCI HCCPARAMS=%06x\n"), - TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, "EHCI USB EHCI Initialized\n"), + TRENTRY(EHCI_VTRACE1_CLASSENUM, TR_FMT1, + "EHCI Hub port %d: Enumerate the device\n"), + TRENTRY(EHCI_VTRACE1_USBINTR, TR_FMT1, + "EHCI USB Interrupt (USBINT) Interrupt: %06x\n"), + TRENTRY(EHCI_VTRACE1_ENUM_DISCONN, TR_FMT1, + "EHCI Enumeration not connected\n"), + TRENTRY(EHCI_VTRACE1_INITIALIZING, TR_FMT1, + "EHCI Initializing EHCI Stack\n"), + TRENTRY(EHCI_VTRACE1_HCCPARAMS, TR_FMT1, + "EHCI HCCPARAMS=%06x\n"), + TRENTRY(EHCI_VTRACE1_INIITIALIZED, TR_FMT1, + "EHCI USB EHCI Initialized\n"), #endif }; static const struct lpc43_ehci_trace_s g_trace2[TRACE2_NSTRINGS] = { - TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, "EHCI EP%d Stalled: TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, "EHCI ERROR: EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), + TRENTRY(EHCI_TRACE2_EPSTALLED, TR_FMT2, + "EHCI EP%d Stalled: TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_EPIOERROR, TR_FMT2, + "EHCI ERROR: EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_TRACE2_CLASSENUM_FAILED, TR_FMT2, + "EHCI Hub port %d usbhost_enumerate() failed: %d\n"), #ifdef HAVE_USBHOST_TRACE_VERBOSE - TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, "EHCI Async transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, "EHCI Intr Transfer EP%d buflen=%d\n"), - TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, "EHCI IOC EP%d TOKEN=%04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, "EHCI PORTSC%d: %04x\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, "EHCI RHPort%d connected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, "EHCI RHport%d disconnected, pscwait: %d\n"), - TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, "EHCI RHPort%d connected: %d\n"), + TRENTRY(EHCI_VTRACE2_ASYNCXFR, TR_FMT2, + "EHCI Async transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_INTRXFR, TR_FMT2, + "EHCI Intr Transfer EP%d buflen=%d\n"), + TRENTRY(EHCI_VTRACE2_IOCCHECK, TR_FMT2, + "EHCI IOC EP%d TOKEN=%04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC, TR_FMT2, + "EHCI PORTSC%d: %04x\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_CONNECTED, TR_FMT2, + "EHCI RHPort%d connected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_PORTSC_DISCONND, TR_FMT2, + "EHCI RHport%d disconnected, pscwait: %d\n"), + TRENTRY(EHCI_VTRACE2_MONWAKEUP, TR_FMT2, + "EHCI RHPort%d connected: %d\n"), - TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, "EHCI EPALLOC: EP%d TYPE=%d\n"), - TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), - TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, "EHCI HCIVERSION %x.%02x\n"), - TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, "EHCI nports=%d, HCSPARAMS=%04x\n"), + TRENTRY(EHCI_VTRACE2_EPALLOC, TR_FMT2, + "EHCI EPALLOC: EP%d TYPE=%d\n"), + TRENTRY(EHCI_VTRACE2_CTRLINOUT, TR_FMT2, + "EHCI CTRLIN/OUT: RHPort%d req: %02x\n"), + TRENTRY(EHCI_VTRACE2_HCIVERSION, TR_FMT2, + "EHCI HCIVERSION %x.%02x\n"), + TRENTRY(EHCI_VTRACE2_HCSPARAMS, TR_FMT2, + "EHCI nports=%d, HCSPARAMS=%04x\n"), #endif }; #endif /* HAVE_USBHOST_TRACE */ @@ -694,9 +744,7 @@ static const struct lpc43_ehci_trace_s g_trace2[TRACE2_NSTRINGS] = /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Register Operations - ****************************************************************************/ + /**************************************************************************** * Name: lpc43_read16 * @@ -832,15 +880,16 @@ static void lpc43_printreg(volatile uint32_t *regaddr, uint32_t regval, ****************************************************************************/ #ifdef CONFIG_LPC43_EHCI_REGDEBUG -static void lpc43_checkreg(volatile uint32_t *regaddr, uint32_t regval, bool iswrite) +static void lpc43_checkreg(volatile uint32_t *regaddr, uint32_t regval, + bool iswrite) { static uint32_t *prevaddr = NULL; static uint32_t preval = 0; static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (regaddr == prevaddr && regval == preval && prevwrite == iswrite) @@ -990,9 +1039,6 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, return (regval == donebits) ? OK : -ETIMEDOUT; } -/**************************************************************************** - * Semaphores - ****************************************************************************/ /**************************************************************************** * Name: lpc43_takesem * @@ -1002,14 +1048,45 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, * ****************************************************************************/ -static void lpc43_takesem(sem_t *sem) +static int lpc43_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** - * Allocators + * Name: lpc43_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * ****************************************************************************/ + +static int lpc43_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; +} + /**************************************************************************** * Name: lpc43_qh_alloc * @@ -1060,8 +1137,8 @@ static void lpc43_qh_free(struct lpc43_qh_s *qh) * Name: lpc43_qtd_alloc * * Description: - * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from the - * free list + * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from + * the free list * * Assumption: Caller holds the exclsem * @@ -1087,8 +1164,8 @@ static struct lpc43_qtd_s *lpc43_qtd_alloc(void) * Name: lpc43_qtd_free * * Description: - * Free a Queue Element Transfer Descriptor (qTD) by returning it to the free - * list + * Free a Queue Element Transfer Descriptor (qTD) by returning it to the + * free list * * Assumption: Caller holds the exclsem * @@ -1104,10 +1181,6 @@ static void lpc43_qtd_free(struct lpc43_qtd_s *qtd) g_ehci.qtdfree = entry; } -/**************************************************************************** - * List Management - ****************************************************************************/ - /**************************************************************************** * Name: lpc43_qh_foreach * @@ -1118,8 +1191,8 @@ static void lpc43_qtd_free(struct lpc43_qtd_s *qtd) * ****************************************************************************/ -static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t handler, - void *arg) +static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, + foreach_qh_t handler, void *arg) { struct lpc43_qh_s *next; uintptr_t physaddr; @@ -1128,8 +1201,9 @@ static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t h DEBUGASSERT(qh && handler); while (qh) { - /* Is this the end of the list? Check the horizontal link pointer (HLP) - * terminate (T) bit. If T==1, then the HLP address is not valid. + /* Is this the end of the list? Check the horizontal link pointer + * (HLP) terminate (T) bit. If T==1, then the HLP address is not + * valid. */ physaddr = lpc43_swap32(qh->hw.hlp); @@ -1144,7 +1218,8 @@ static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t h * the end of the asynchronous queue? */ - else if (lpc43_virtramaddr(physaddr & QH_HLP_MASK) == (uintptr_t)&g_asynchead) + else if (lpc43_virtramaddr(physaddr & QH_HLP_MASK) == + (uintptr_t)&g_asynchead) { /* That will also terminate the loop */ @@ -1171,8 +1246,8 @@ static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t h ret = handler(qh, bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1197,7 +1272,8 @@ static int lpc43_qh_foreach(struct lpc43_qh_s *qh, uint32_t **bp, foreach_qh_t h * ****************************************************************************/ -static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, void *arg) +static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, + void *arg) { struct lpc43_qtd_s *qtd; struct lpc43_qtd_s *next; @@ -1209,7 +1285,7 @@ static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, void /* Handle the special case where the queue is empty */ - bp = &qh->fqp; /* Start of qTDs in original list */ + bp = &qh->fqp; /* Start of qTDs in original list */ physaddr = lpc43_swap32(*bp); /* Physical address of first qTD in CPU order */ if ((physaddr & QTD_NQP_T) != 0) @@ -1246,14 +1322,14 @@ static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, void * unlinking the entry! But that is okay because we already have the * next qTD pointer. * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qtd, &bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1273,12 +1349,13 @@ static int lpc43_qtd_foreach(struct lpc43_qh_s *qh, foreach_qtd_t handler, void * Name: lpc43_qtd_discard * * Description: - * This is a lpc43_qtd_foreach callback. It simply unlinks the QTD, updates - * the back pointer, and frees the QTD structure. + * This is a lpc43_qtd_foreach callback. It simply unlinks the QTD, + * updates the back pointer, and frees the QTD structure. * ****************************************************************************/ -static int lpc43_qtd_discard(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc43_qtd_discard(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg) { DEBUGASSERT(qtd && bp && *bp); @@ -1327,10 +1404,6 @@ static int lpc43_qh_discard(struct lpc43_qh_s *qh) return ret; } -/**************************************************************************** - * Endpoint Transfer Handling - ****************************************************************************/ - /**************************************************************************** * Name: lpc43_qtd_print * @@ -1398,8 +1471,8 @@ static void lpc43_qh_print(struct lpc43_qh_s *qh) * Name: lpc43_qtd_dump * * Description: - * This is a lpc43_qtd_foreach callout function. It dumps the context of one - * qTD + * This is a lpc43_qtd_foreach call-out function. It dumps the context of + * one qTD * ****************************************************************************/ @@ -1415,8 +1488,8 @@ static int lpc43_qtd_dump(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc43_qh_dump * * Description: - * This is a lpc43_qh_foreach callout function. It dumps a QH structure and - * all of the qTD structures linked to the QH. + * This is a lpc43_qh_foreach callout function. It dumps a QH structure + * and all of the qTD structures linked to the QH. * ****************************************************************************/ @@ -1432,8 +1505,8 @@ static int lpc43_qh_dump(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) * Name: lpc43_ehci_speed * * Description: - * Map a speed enumeration value per Chapter 9 of the USB specification to the - * speed enumeration required in the EHCI queue head. + * Map a speed enumeration value per Chapter 9 of the USB specification to + * the speed enumeration required in the EHCI queue head. * ****************************************************************************/ @@ -1448,15 +1521,16 @@ static inline uint8_t lpc43_ehci_speed(uint8_t usbspeed) * * Description: * Set the request for the IOC event well BEFORE enabling the transfer (as - * soon as we are absolutely committed to the to avoid transfer). We do this - * to minimize race conditions. This logic would have to be expanded if we - * want to have more than one packet in flight at a time! + * soon as we are absolutely committed to the to avoid transfer). We do + * this to minimize race conditions. This logic would have to be expanded + * if we want to have more than one packet in flight at a time! * * Assumption: The caller holds tex EHCI exclsem * ****************************************************************************/ -static int lpc43_ioc_setup(struct lpc43_rhport_s *rhport, struct lpc43_epinfo_s *epinfo) +static int lpc43_ioc_setup(struct lpc43_rhport_s *rhport, + struct lpc43_epinfo_s *epinfo) { irqstate_t flags; int ret = -ENODEV; @@ -1497,21 +1571,30 @@ static int lpc43_ioc_setup(struct lpc43_rhport_s *rhport, struct lpc43_epinfo_s * Description: * Wait for the IOC event. * - * Assumption: The caller does *NOT* hold the EHCI exclsem. That would cause - * a deadlock when the bottom-half, worker thread needs to take the semaphore. + * Assumption: The caller does *NOT* hold the EHCI exclsem. That would + * cause a deadlock when the bottom-half, worker thread needs to take the + * semaphore. * ****************************************************************************/ static int lpc43_ioc_wait(struct lpc43_epinfo_s *epinfo) { - /* Wait for the IOC event. Loop to handle any false alarm semaphore counts. */ + int ret = OK; + + /* Wait for the IOC event. Loop to handle any false alarm semaphore + * counts. Return an error if the task is canceled. + */ while (epinfo->iocwait) { - lpc43_takesem(&epinfo->iocsem); + ret = lpc43_takesem(&epinfo->iocsem); + if (ret < 0) + { + break; + } } - return epinfo->result; + return ret < 0 ? ret : epinfo->result; } /**************************************************************************** @@ -1538,15 +1621,13 @@ static void lpc43_qh_enqueue(struct lpc43_qh_s *qhead, struct lpc43_qh_s *qh) /* Add the new QH to the head of the asynchronous queue list. * - * First, attach the old head as the new QH HLP and flush the new QH and its - * attached qTDs to RAM. + * First, attach the old head as the new QH HLP and flush the new QH and + * its attached qTDs to RAM. */ qh->hw.hlp = qhead->hw.hlp; - /* Then set the new QH as the first QH in the asychronous queue and flush the - * modified head to RAM. - */ + /* Then set the new QH as the first QH in the asynchronous queue */ physaddr = (uintptr_t)lpc43_physramaddr((uintptr_t)qh); qhead->hw.hlp = lpc43_swap32(physaddr | QH_HLP_TYP_QH); @@ -1598,7 +1679,8 @@ static struct lpc43_qh_s *lpc43_qh_create(struct lpc43_rhport_s *rhport, regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | ((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | - ((uint32_t)lpc43_ehci_speed(epinfo->speed) << QH_EPCHAR_EPS_SHIFT) | + ((uint32_t)lpc43_ehci_speed(epinfo->speed) << + QH_EPCHAR_EPS_SHIFT) | QH_EPCHAR_DTC | ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((uint32_t)8 << QH_EPCHAR_RL_SHIFT); @@ -1697,32 +1779,33 @@ static struct lpc43_qh_s *lpc43_qh_create(struct lpc43_rhport_s *rhport, * ****************************************************************************/ -static int lpc43_qtd_addbpl(struct lpc43_qtd_s *qtd, const void *buffer, size_t buflen) +static int lpc43_qtd_addbpl(struct lpc43_qtd_s *qtd, const void *buffer, + size_t buflen) { uint32_t physaddr; uint32_t nbytes; uint32_t next; int ndx; - /* Loop, adding the aligned physical addresses of the buffer to the buffer page - * list. Only the first entry need not be aligned (because only the first - * entry has the offset field). The subsequent entries must begin on 4KB - * address boundaries. + /* Loop, adding the aligned physical addresses of the buffer to the buffer + * page list. Only the first entry need not be aligned (because only the + * first entry has the offset field). The subsequent entries must begin on + * 4KB address boundaries. */ physaddr = (uint32_t)lpc43_physramaddr((uintptr_t)buffer); for (ndx = 0; ndx < 5; ndx++) { - /* Write the physical address of the buffer into the qTD buffer pointer - * list. + /* Write the physical address of the buffer into the qTD buffer + * pointer list. */ qtd->hw.bpl[ndx] = lpc43_swap32(physaddr); - /* Get the next buffer pointer (in the case where we will have to transfer - * more then one chunk). This buffer must be aligned to a 4KB address - * boundary. + /* Get the next buffer pointer (in the case where we will have to + * transfer more then one chunk). This buffer must be aligned to a + * 4KB address boundary. */ next = (physaddr + 4096) & ~4095; @@ -1766,8 +1849,9 @@ static int lpc43_qtd_addbpl(struct lpc43_qtd_s *qtd, const void *buffer, size_t * ****************************************************************************/ -static struct lpc43_qtd_s *lpc43_qtd_setupphase(struct lpc43_epinfo_s *epinfo, - const struct usb_ctrlreq_s *req) +static struct lpc43_qtd_s * + lpc43_qtd_setupphase(struct lpc43_epinfo_s *epinfo, + const struct usb_ctrlreq_s *req) { struct lpc43_qtd_s *qtd; uint32_t regval; @@ -1946,13 +2030,13 @@ static struct lpc43_qtd_s *lpc43_qtd_statusphase(uint32_t tokenbits) * Name: lpc43_async_setup * * Description: - * Process a IN or OUT request on any asynchronous endpoint (bulk or control). - * This function will enqueue the request and wait for it to complete. Bulk - * data transfers differ in that req == NULL and there are not SETUP or STATUS - * phases. + * Process a IN or OUT request on any asynchronous endpoint (bulk or + * control). This function will enqueue the request and wait for it to + * complete. Bulk data transfers differ in that req == NULL and there are + * not SETUP or STATUS phases. * - * This is a blocking function; it will not return until the control transfer - * has completed. + * This is a blocking function; it will not return until the control + * transfer has completed. * * Assumption: The caller holds the EHCI exclsem. * @@ -1987,8 +2071,8 @@ static int lpc43_async_setup(struct lpc43_rhport_s *rhport, DEBUGASSERT(rhport && epinfo); - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ DEBUGASSERT(req || (buffer && buflen > 0)); @@ -2045,8 +2129,8 @@ static int lpc43_async_setup(struct lpc43_rhport_s *rhport, toggle = QTD_TOKEN_TOGGLE; } - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ alt = NULL; @@ -2202,19 +2286,20 @@ errout_with_qh: * into the periodic frame list. * * Paragraph 4.10.7 "Adding Interrupt Queue Heads to the Periodic Schedule" - * "The link path(s) from the periodic frame list to a queue head establishes - * in which frames a transaction can be executed for the queue head. Queue - * heads are linked into the periodic schedule so they are polled at - * the appropriate rate. System software sets a bit in a queue head's - * S-Mask to indicate which micro-frame with-in a 1 millisecond period a - * transaction should be executed for the queue head. Software must ensure - * that all queue heads in the periodic schedule have S-Mask set to a non- - * zero value. An S-mask with a zero value in the context of the periodic - * schedule yields undefined results. + * "The link path(s) from the periodic frame list to a queue head + * establishes in which frames a transaction can be executed for the + * queue head. Queue heads are linked into the periodic schedule so they + * are polled at the appropriate rate. System software sets a bit in a + * queue head's S-Mask to indicate which micro-frame with-in a 1 + * millisecond period a transaction should be executed for the queue + * head. Software must ensure that all queue heads in the periodic + * schedule have S-Mask set to a non-zero value. An S-mask with a zero + * value in the context of the periodic schedule yields undefined + * results. * - * "If the desired poll rate is greater than one frame, system software can - * use a combination of queue head linking and S-Mask values to spread - * interrupts of equal poll rates through the schedule so that the + * "If the desired poll rate is greater than one frame, system software + * can use a combination of queue head linking and S-Mask values to + * spread interrupts of equal poll rates through the schedule so that the * periodic bandwidth is allocated and managed in the most efficient * manner possible." * @@ -2344,16 +2429,18 @@ errout_with_qh: * EHCI resources could be very different upon return. * * Returned Value: - * On success, this function returns the number of bytes actually transferred. - * For control transfers, this size includes the size of the control request - * plus the size of the data (which could be short); For bulk transfers, this - * will be the number of data bytes transfers (which could be short). + * On success, this function returns the number of bytes actually + * transferred. For control transfers, this size includes the size of the + * control request plus the size of the data (which could be short); for + * bulk transfers, this will be the number of data bytes transfers (which + * could be short). * ****************************************************************************/ static ssize_t lpc43_transfer_wait(struct lpc43_epinfo_s *epinfo) { int ret; + int ret2; /* Release the EHCI semaphore while we wait. Other threads need the * opportunity to access the EHCI resources while we wait. @@ -2375,9 +2462,15 @@ static ssize_t lpc43_transfer_wait(struct lpc43_epinfo_s *epinfo) * this upon return. */ - lpc43_takesem(&g_ehci.exclsem); + ret2 = lpc43_takesem_uninterruptible(&g_ehci.exclsem); + if (ret2 < 0) + { + ret = ret2; + } - /* Did lpc43_ioc_wait() report an error? */ + /* Did lpc43_ioc_wait() or lpc43_takesem_uninterruptible()report an + * error? + */ if (ret < 0) { @@ -2415,8 +2508,9 @@ static ssize_t lpc43_transfer_wait(struct lpc43_epinfo_s *epinfo) #ifdef CONFIG_USBHOST_ASYNCH static inline int lpc43_ioc_async_setup(struct lpc43_rhport_s *rhport, - struct lpc43_epinfo_s *epinfo, - usbhost_asynch_t callback, FAR void *arg) + struct lpc43_epinfo_s *epinfo, + usbhost_asynch_t callback, + FAR void *arg) { irqstate_t flags; int ret = -ENODEV; @@ -2502,21 +2596,18 @@ static void lpc43_asynch_completion(struct lpc43_epinfo_s *epinfo) } #endif -/**************************************************************************** - * EHCI Interrupt Handling - ****************************************************************************/ - /**************************************************************************** * Name: lpc43_qtd_ioccheck * * Description: - * This function is a lpc43_qtd_foreach() callback function. It services one - * qTD in the asynchronous queue. It removes all of the qTD structures that - * are no longer active. + * This function is a lpc43_qtd_foreach() callback function. It services + * one qTD in the asynchronous queue. It removes all of the qTD + * structures that are no longer active. * ****************************************************************************/ -static int lpc43_qtd_ioccheck(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc43_qtd_ioccheck(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg) { struct lpc43_epinfo_s *epinfo = (struct lpc43_epinfo_s *)arg; DEBUGASSERT(qtd && epinfo); @@ -2553,10 +2644,10 @@ static int lpc43_qtd_ioccheck(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc43_qh_ioccheck * * Description: - * This function is a lpc43_qh_foreach() callback function. It services one - * QH in the asynchronous queue. It check all attached qTD structures and - * remove all of the structures that are no longer active. if all of the - * qTD structures are removed, then QH itself will also be removed. + * This function is a lpc43_qh_foreach() callback function. It services + * one QH in the asynchronous queue. It check all attached qTD structures + * and remove all of the structures that are no longer active. if all of + * the qTD structures are removed, then QH itself will also be removed. * ****************************************************************************/ @@ -2577,14 +2668,15 @@ static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) epinfo = qh->epinfo; DEBUGASSERT(epinfo); - /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area represent - * a transaction working space for the host controller. The general - * operational model is that the host controller can detect whether the - * overlay area contains a description of an active transfer. If it does - * not contain an active transfer, then it follows the Queue Head Horizontal - * Link Pointer to the next queue head. The host controller will never follow - * the Next Transfer Queue Element or Alternate Queue Element pointers unless - * it is actively attempting to advance the queue ..." + /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area + * represent a transaction working space for the host controller. The + * general operational model is that the host controller can detect + * whether the overlay area contains a description of an active transfer. + * If it does not contain an active transfer, then it follows the Queue + * Head Horizontal Link Pointer to the next queue head. The host + * controller will never follow the Next Transfer Queue Element or + * Alternate Queue Element pointers unless it is actively attempting to + * advance the queue ..." */ /* Is the qTD still active? */ @@ -2597,6 +2689,7 @@ static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) /* Yes... we cannot process the QH while it is still active. Return * zero to visit the next QH in the list. */ + *bp = &qh->hw.hlp; return OK; } @@ -2638,16 +2731,18 @@ static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) { /* An error occurred */ - epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> QH_TOKEN_STATUS_SHIFT; + epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> + QH_TOKEN_STATUS_SHIFT; - /* The HALT condition is set on a variety of conditions: babble, error - * counter countdown to zero, or a STALL. If we can rule out babble - * (babble bit not set) and if the error counter is non-zero, then we can - * assume a STALL. In this case, we return -PERM to inform the class - * driver of the stall condition. + /* The HALT condition is set on a variety of conditions: babble, + * error counter countdown to zero, or a STALL. If we can rule + * out babble (babble bit not set) and if the error counter is + * non-zero, then we can assume a STALL. In this case, we return + * -PERM to inform the class driver of the stall condition. */ - if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == QH_TOKEN_HALTED && + if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == + QH_TOKEN_HALTED && (token & QH_TOKEN_CERR_MASK) != 0) { /* It is a stall, Note that the data toggle is reset @@ -2694,7 +2789,8 @@ static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) } else { - /* Otherwise, the horizontal link pointer of this QH will become the next back pointer. + /* Otherwise, the horizontal link pointer of this QH will become the + * next back pointer. */ *bp = &qh->hw.hlp; @@ -2707,13 +2803,14 @@ static int lpc43_qh_ioccheck(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) * Name: lpc43_qtd_cancel * * Description: - * This function is a lpc43_qtd_foreach() callback function. It removes each - * qTD attached to a QH. + * This function is a lpc43_qtd_foreach() callback function. It removes + * each qTD attached to a QH. * ****************************************************************************/ #ifdef CONFIG_USBHOST_ASYNCH -static int lpc43_qtd_cancel(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) +static int lpc43_qtd_cancel(struct lpc43_qtd_s *qtd, uint32_t **bp, + void *arg) { DEBUGASSERT(qtd != NULL && bp != NULL); @@ -2742,10 +2839,10 @@ static int lpc43_qtd_cancel(struct lpc43_qtd_s *qtd, uint32_t **bp, void *arg) * Name: lpc43_qh_cancel * * Description: - * This function is a lpc43_qh_foreach() callback function. It cancels one - * QH in the asynchronous queue. It will remove all attached qTD structures - * and remove all of the structures that are no longer active. Then QH - * itself will also be removed. + * This function is a imxrt_qh_foreach() callback function. It cancels + * one QH in the asynchronous queue. It will remove all attached qTD + * structures and remove all of the structures that are no longer active. + * Then QH itself will also be removed. * ****************************************************************************/ @@ -2814,13 +2911,13 @@ static int lpc43_qh_cancel(struct lpc43_qh_s *qh, uint32_t **bp, void *arg) * Description: * EHCI USB Interrupt (USBINT) "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 on the completion of a USB - * transaction, which results in the retirement of a Transfer Descriptor that - * had its IOC bit set. + * "The Host Controller sets this bit to 1 on the completion of a USB + * transaction, which results in the retirement of a Transfer Descriptor + * that had its IOC bit set. * - * "The Host Controller also sets this bit to 1 when a short packet is detected - * (actual number of bytes received was less than the expected number of - * bytes)." + * "The Host Controller also sets this bit to 1 when a short packet is + * detected (actual number of bytes received was less than the expected + * number of bytes)." * * Assumptions: The caller holds the EHCI exclsem * @@ -2837,7 +2934,8 @@ static inline void lpc43_ioc_bottomhalf(void) */ bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct lpc43_qh_s *)lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc43_qh_s *) + lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); /* If the asynchronous queue is empty, then the forward point in the * asynchronous queue head will point back to the queue head. @@ -2864,7 +2962,8 @@ static inline void lpc43_ioc_bottomhalf(void) */ bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct lpc43_qh_s *)lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc43_qh_s *) + lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); if (qh) { /* Then traverse and operate on every QH and qTD in the asynchronous @@ -2886,19 +2985,19 @@ static inline void lpc43_ioc_bottomhalf(void) * Description: * EHCI Port Change Detect "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to a one when any port for which the Port - * Owner bit is set to zero ... has a change bit transition from a zero to a - * one or a Force Port Resume bit transition from a zero to a one as a result - * of a J-K transition detected on a suspended port. This bit will also be set - * as a result of the Connect Status Change being set to a one after system - * software has relinquished ownership of a connected port by writing a one - * to a port's Port Owner bit... + * "The Host Controller sets this bit to a one when any port for which the + * Port Owner bit is set to zero ... has a change bit transition from a + * zero to a one or a Force Port Resume bit transition from a zero to a + * one as a result of a J-K transition detected on a suspended port. + * This bit will also be set as a result of the Connect Status Change + * being set to a one after system software has relinquished ownership of + * a connected port by writing a one to a port's Port Owner bit... * * "This bit is allowed to be maintained in the Auxiliary power well. - * Alternatively, it is also acceptable that on a D3 to D0 transition of the - * EHCI HC device, this bit is loaded with the OR of all of the PORTSC change - * bits (including: Force port resume, over-current change, enable/disable - * change and connect status change)." + * Alternatively, it is also acceptable that on a D3 to D0 transition of + * the EHCI HC device, this bit is loaded with the OR of all of the PORTSC + * change bits (including: Force port resume, over-current change, + * enable/disable change and connect status change)." * ****************************************************************************/ @@ -2961,7 +3060,7 @@ static inline void lpc43_portsc_bottomhalf(void) /* Yes.. disconnect the device */ usbhost_vtrace2(EHCI_VTRACE2_PORTSC_DISCONND, - rhpndx+1, g_ehci.pscwait); + rhpndx + 1, g_ehci.pscwait); rhport->connected = false; rhport->lowspeed = false; @@ -3009,10 +3108,11 @@ static inline void lpc43_portsc_bottomhalf(void) * Description: * EHCI Host System Error "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 when a serious error occurs during a - * host system access involving the Host Controller module. ... When this - * error occurs, the Host Controller clears the Run/Stop bit in the Command - * register to prevent further execution of the scheduled TDs." + * "The Host Controller sets this bit to 1 when a serious error occurs + * during a host system access involving the Host Controller module. ... + * When this error occurs, the Host Controller clears the Run/Stop bit + * in the Command register to prevent further execution of the scheduled + * TDs." * ****************************************************************************/ @@ -3029,10 +3129,10 @@ static inline void lpc43_syserr_bottomhalf(void) * EHCI Async Advance "Bottom Half" interrupt handler * * "System software can force the host controller to issue an interrupt the - * next time the host controller advances the asynchronous schedule by writing - * a one to the Interrupt on Async Advance Doorbell bit in the USBCMD - * register. This status bit indicates the assertion of that interrupt - * source." + * next time the host controller advances the asynchronous schedule by + * writing a one to the Interrupt on Async Advance Doorbell bit in the + * USBCMD register. This status bit indicates the assertion of that + * interrupt source." * ****************************************************************************/ @@ -3055,14 +3155,15 @@ static void lpc43_ehci_bottomhalf(FAR void *arg) { uint32_t pending = (uint32_t)arg; - /* We need to have exclusive access to the EHCI data structures. Waiting here - * is not a good thing to do on the worker thread, but there is no real option - * (other than to reschedule and delay). + /* We need to have exclusive access to the EHCI data structures. Waiting + * here is not a good thing to do on the worker thread, but there is no + * real option (other than to reschedule and delay). */ - lpc43_takesem(&g_ehci.exclsem); + lpc43_takesem_uninterruptible(&g_ehci.exclsem); /* Handle all unmasked interrupt sources */ + /* USB Interrupt (USBINT) * * "The Host Controller sets this bit to 1 on the completion of a USB @@ -3122,13 +3223,14 @@ static void lpc43_ehci_bottomhalf(FAR void *arg) /* Frame List Rollover * - * "The Host Controller sets this bit to a one when the Frame List Index ... - * rolls over from its maximum value to zero. The exact value at which - * the rollover occurs depends on the frame list size. For example, if - * the frame list size (as programmed in the Frame List Size field of the - * USBCMD register) is 1024, the Frame Index Register rolls over every - * time FRINDEX[13] toggles. Similarly, if the size is 512, the Host - * Controller sets this bit to a one every time FRINDEX[12] toggles." + * "The Host Controller sets this bit to a one when the Frame List Index + * ... rolls over from its maximum value to zero. The exact value at + * which the rollover occurs depends on the frame list size. For example, + * if the frame list size (as programmed in the Frame List Size field of + * the USBCMD register) is 1024, the Frame Index Register rolls over + * every time FRINDEX[13] toggles. Similarly, if the size is 512, the + * Host Controller sets this bit to a one every time FRINDEX[12] + * toggles." */ #if 0 /* Not used */ @@ -3207,9 +3309,9 @@ static int lpc43_ehci_interrupt(int irq, FAR void *context, FAR void *arg) pending = usbsts & regval; if (pending != 0) { - /* Schedule interrupt handling work for the high priority worker thread - * so that we are not pressed for time and so that we can interrupt with - * other USB threads gracefully. + /* Schedule interrupt handling work for the high priority worker + * thread so that we are not pressed for time and so that we can + * interrupt with other USB threads gracefully. * * The worker should be available now because we implement a handshake * by controlling the EHCI interrupts. @@ -3235,9 +3337,6 @@ static int lpc43_ehci_interrupt(int irq, FAR void *context, FAR void *arg) return OK; } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ /**************************************************************************** * Name: lpc43_wait * @@ -3245,8 +3344,8 @@ static int lpc43_ehci_interrupt(int irq, FAR void *context, FAR void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from the + * call to the USB driver initialization logic. * hport - The location to return the hub port descriptor that detected the * connection related event. * @@ -3268,9 +3367,10 @@ static int lpc43_wait(FAR struct usbhost_connection_s *conn, { irqstate_t flags; int rhpndx; + int ret; - /* Loop until a change in the connection state changes on one of the root hub - * ports or until an error occurs. + /* Loop until the connection state changes on one of the root hub ports or + * until an error occurs. */ flags = enter_critical_section(); @@ -3329,7 +3429,11 @@ static int lpc43_wait(FAR struct usbhost_connection_s *conn, */ g_ehci.pscwait = true; - lpc43_takesem(&g_ehci.pscsem); + ret = lpc43_takesem(&g_ehci.pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3347,14 +3451,14 @@ static int lpc43_wait(FAR struct usbhost_connection_s *conn, * charge of the sequence of operations. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from - * the call to the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. * hport - The descriptor of the hub port that has the newly connected - * device. + * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3392,7 +3496,7 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, * reset for 50Msec, not wait 50Msec before resetting. */ - nxsig_usleep(100*1000); + nxsig_usleep(100 * 1000); /* Paragraph 2.3.9: * @@ -3409,8 +3513,8 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, * 01b K-state Low-speed device, release ownership of port * * NOTE: Low-speed devices could be detected by examining the PORTSC PSPD - * field after resetting the device. The more conventional way here, however, - * also appears to work. + * field after resetting the device. The more conventional way here, + * however, also appears to work. */ regval = lpc43_getreg(&HCOR->portsc[rhpndx]); @@ -3465,7 +3569,7 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, /* Put the root hub port in reset. * - * Paragraph 2.3.9: + * EHCI Paragraph 2.3.9: * * "The HCHalted bit in the USBSTS register should be a zero before * software attempts to use [the Port Reset] bit. The host controller @@ -3474,15 +3578,15 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, DEBUGASSERT((lpc43_getreg(&HCOR->usbsts) & EHCI_USBSTS_HALTED) == 0); - /* EHCI paragraph 2.3.9: + /* EHCI Paragraph 2.3.9: * * "When software writes a one to [the Port Reset] bit (from a zero), the - * bus reset sequence as defined in the USB Specification Revision 2.0 is - * started. Software writes a zero to this bit to terminate the bus reset - * sequence. Software must keep this bit at a one long enough to ensure - * the reset sequence, as specified in the USB Specification Revision 2.0, - * completes. Note: when software writes this bit to a one, it must also - * write a zero to the Port Enable bit." + * bus reset sequence as defined in the USB Specification Revision 2.0 + * is started. Software writes a zero to this bit to terminate the bus + * reset sequence. Software must keep this bit at a one long enough to + * ensure the reset sequence, as specified in the USB Specification + * Revision 2.0, completes. Note: when software writes this bit to a + * one, it must also write a zero to the Port Enable bit." */ regaddr = &HCOR->portsc[RHPNDX(rhport)]; @@ -3495,7 +3599,7 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, * 50 ms." */ - nxsig_usleep(50*1000); + nxsig_usleep(50 * 1000); regval = lpc43_getreg(regaddr); regval &= ~EHCI_PORTSC_RESET; @@ -3516,35 +3620,36 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, */ while ((lpc43_getreg(regaddr) & EHCI_PORTSC_RESET) != 0); - nxsig_usleep(200*1000); + nxsig_usleep(200 * 1000); - /* EHCI Paragraph 4.2.2: + /* Paragraph 4.2.2: * * "... The reset process is actually complete when software reads a zero - * in the PortReset bit. The EHCI Driver checks the PortEnable bit in the - * PORTSC register. If set to a one, the connected device is a high-speed - * device and EHCI Driver (root hub emulator) issues a change report to the - * hub driver and the hub driver continues to enumerate the attached device." + * in the PortReset bit. The EHCI Driver checks the PortEnable bit in + * the PORTSC register. If set to a one, the connected device is a high- + * speed device and EHCI Driver (root hub emulator) issues a change + * report to the hub driver and the hub driver continues to enumerate + * the attached device." * - * "At the time the EHCI Driver receives the port reset and enable request - * the LineStatus bits might indicate a low-speed device. Additionally, - * when the port reset process is complete, the PortEnable field may - * indicate that a full-speed device is attached. In either case the EHCI - * driver sets the PortOwner bit in the PORTSC register to a one to - * release port ownership to a companion host controller." + * "At the time the EHCI Driver receives the port reset and enable + * request the LineStatus bits might indicate a low-speed device. + * Additionally, when the port reset process is complete, the PortEnable + * field may indicate that a full-speed device is attached. In either + * case the EHCI driver sets the PortOwner bit in the PORTSC register to + * a one to release port ownership to a companion host controller." * * LPC43xx User Manual Paragraph 6.1.3: * * "In a standard EHCI controller design, the EHCI host controller driver * detects a Full speed (FS) or Low speed (LS) device by noting if the - * port enable bit is set after the port reset operation. The port enable - * will only be set in a standard EHCI controller implementation after the - * port reset operation and when the host and device negotiate a High-Speed - * connection (i.e. Chirp completes successfully). Since this controller has - * an embedded Transaction Translator, the port enable will always be set - * after the port reset operation regardless of the result of the host device - * chirp result and the resulting port speed will be indicated by the PSPD - * field in PORTSC1. + * port enable bit is set after the port reset operation. The port + * enable will only be set in a standard EHCI controller implementation + * after the port reset operation and when the host and device negotiate + * a High-Speed connection (i.e. Chirp completes successfully). Since + * this controller has an embedded Transaction Translator, the port + * enable will always be set after the port reset operation regardless + * of the result of the host device chirp result and the resulting port + * speed will be indicated by the PSPD field in PORTSC1." */ regval = lpc43_getreg(&HCOR->portsc[rhpndx]); @@ -3595,7 +3700,8 @@ static int lpc43_rh_enumerate(FAR struct usbhost_connection_s *conn, else { DEBUGASSERT(hport->speed == USB_SPEED_LOW); - DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == USBDEV_PRTSC1_PSPD_LS); + DEBUGASSERT((regval & USBDEV_PRTSC1_PSPD_MASK) == + USBDEV_PRTSC1_PSPD_LS); } return OK; @@ -3633,8 +3739,9 @@ static int lpc43_enumerate(FAR struct usbhost_connection_s *conn, usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, hport->port + 1, -ret); - /* If this is a root hub port, then marking the hub port not connected will - * cause lpc43_wait() to return and we will try the connection again. + /* If this is a root hub port, then marking the hub port not connected + * will cause sam_wait() to return and we will try the connection + * again. */ hport->connected = false; @@ -3643,7 +3750,7 @@ static int lpc43_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_ep0configure * * Description: @@ -3652,78 +3759,85 @@ static int lpc43_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * 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. A funcaddr of zero will be received if no address is yet assigned - * to the device. + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc43_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) +static int lpc43_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { struct lpc43_epinfo_s *epinfo = (struct lpc43_epinfo_s *)ep0; + int ret; DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048); /* We must have exclusive access to the EHCI data structures. */ - lpc43_takesem(&g_ehci.exclsem); + ret = lpc43_takesem(&g_ehci.exclsem); + if (ret >= 0) + { + /* Remember the new device address and max packet size */ - /* Remember the new device address and max packet size */ + epinfo->devaddr = funcaddr; + epinfo->speed = speed; + epinfo->maxpacket = maxpacketsize; - epinfo->devaddr = funcaddr; - epinfo->speed = speed; - epinfo->maxpacket = maxpacketsize; + lpc43_givesem(&g_ehci.exclsem); + } - lpc43_givesem(&g_ehci.exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc43_epalloc(FAR struct usbhost_driver_s *drvr, - const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const FAR struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct lpc43_epinfo_s *epinfo; struct usbhost_hubport_s *hport; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ - DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && ep != NULL); + DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && + ep != NULL); hport = epdesc->hport; /* Terse output only if we are tracing */ @@ -3738,7 +3852,8 @@ static int lpc43_epalloc(FAR struct usbhost_driver_s *drvr, /* Allocate a endpoint information structure */ - epinfo = (struct lpc43_epinfo_s *)kmm_zalloc(sizeof(struct lpc43_epinfo_s)); + epinfo = (struct lpc43_epinfo_s *) + kmm_zalloc(sizeof(struct lpc43_epinfo_s)); if (!epinfo) { usbhost_trace1(EHCI_TRACE1_EPALLOC_FAILED, 0); @@ -3768,33 +3883,33 @@ static int lpc43_epalloc(FAR struct usbhost_driver_s *drvr, nxsem_init(&epinfo->iocsem, 0, 0); nxsem_setprotocol(&epinfo->iocsem, SEM_PRIO_NONE); - /* Success.. return an opaque reference to the endpoint information structure - * instance + /* Success.. return an opaque reference to the endpoint information + * structure instance */ *ep = (usbhost_ep_t)epinfo; return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The endpint to be freed. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The endpint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc43_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -3814,10 +3929,11 @@ static int lpc43_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: lpc43_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * allocate the request/descriptor memory. If the underlying hardware does - * not support such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc(). * * This interface was optimized under a particular assumption. It was * assumed that the driver maintains a pool of small, pre-allocated buffers @@ -3825,16 +3941,16 @@ static int lpc43_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. - * buffer - The address of a memory location provided by the caller in which - * to return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which - * to return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3864,19 +3980,20 @@ static int lpc43_alloc(FAR struct usbhost_driver_s *drvr, * Name: lpc43_free * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * free that request/descriptor memory. If the underlying hardware does not - * support such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -3893,70 +4010,74 @@ static int lpc43_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kumm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kumm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are variable- + * sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc43_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, - size_t buflen) +static int lpc43_ioalloc(FAR struct usbhost_driver_s *drvr, + FAR uint8_t **buffer, size_t buflen) { DEBUGASSERT(drvr && buffer && buflen > 0); - /* The only special requirements for I/O buffers are they might need to be user - * accessible (depending on how the class driver implements its buffering). + /* The only special requirements for I/O buffers are they might need to be + * user accessible (depending on how the class driver implements its + * buffering). */ *buffer = (FAR uint8_t *)kumm_malloc(buflen); return *buffer ? OK : -ENOMEM; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kumm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc43_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int lpc43_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { DEBUGASSERT(drvr && buffer); @@ -3971,30 +4092,30 @@ static int lpc43_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer - * may be queued; Neither these methods nor the transfer() method can be - * called again until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The control endpoint to send/receive the control request. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any - * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using - * DRVR_ALLOC. + * responses. This buffer must be large enough to hold the + * length value in the request description. buffer must have been + * allocated using DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4021,14 +4142,19 @@ static int lpc43_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, #ifdef CONFIG_USBHOST_TRACE usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, RHPORT(rhport), req->req); #else - uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %04x\n", + uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x " + "len: %04x\n", RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], len); #endif /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc43_takesem(&g_ehci.exclsem); + ret = lpc43_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4065,8 +4191,8 @@ static int lpc43_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer) { - /* lpc43_ctrlin can handle both directions. We just need to work around the - * differences in the function signatures. + /* lpc43_ctrlin can handle both directions. We just need to work around + * the differences in the function signatures. */ return lpc43_ctrlin(drvr, ep0, req, (uint8_t *)buffer); @@ -4077,26 +4203,27 @@ static int lpc43_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4110,8 +4237,9 @@ static int lpc43_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t lpc43_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t lpc43_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { struct lpc43_rhport_s *rhport = (struct lpc43_rhport_s *)drvr; struct lpc43_epinfo_s *epinfo = (struct lpc43_epinfo_s *)ep; @@ -4122,7 +4250,11 @@ static ssize_t lpc43_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc43_takesem(&g_ehci.exclsem); + ret = lpc43_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4192,20 +4324,21 @@ errout_with_sem: * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC - * buflen - The length of the data to be sent or received. + * drvr - The USB host driver instance obtained as a parameter from + * the call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated + * using DRVR_ALLOC + * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4226,7 +4359,11 @@ static int lpc43_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the EHCI hardware and data structures. */ - lpc43_takesem(&g_ehci.exclsem); + ret = lpc43_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the callback well BEFORE initiating the transfer. */ @@ -4283,24 +4420,24 @@ errout_with_sem: } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: lpc43_cancel * * Description: - * Cancel a pending transfer on an endpoint. Cancelled synchronous or + * Cancel a pending transfer on an endpoint. Canceled synchronous or * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int lpc43_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4317,20 +4454,25 @@ static int lpc43_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(epinfo); - /* We must have exclusive access to the EHCI hardware and data structures. This - * will prevent servicing any transfer completion events while we perform the - * the cancellation, but will not prevent DMA-related race conditions. + /* We must have exclusive access to the EHCI hardware and data structures. + * This will prevent servicing any transfer completion events while we + * perform the cancellation, but will not prevent DMA-related race + * conditions. * - * REVISIT: This won't work. This function must be callable from the interrupt - * level. + * REVISIT: This won't work. This function must be callable from the + * interrupt level. */ - lpc43_takesem(&g_ehci.exclsem); + ret = lpc43_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } - /* Sample and reset all transfer termination information. This will prevent any - * callbacks from occurring while are performing the cancellation. The transfer - * may still be in progress, however, so this does not eliminate other DMA- - * related race conditions. + /* Sample and reset all transfer termination information. This will + * prevent any callbacks from occurring while are performing the + * cancellation. The transfer may still be in progress, however, so this + * does not eliminate other DMA-related race conditions. */ flags = enter_critical_section(); @@ -4379,7 +4521,8 @@ static int lpc43_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct lpc43_qh_s *)lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc43_qh_s *) + lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); /* If the asynchronous queue is empty, then the forward point in * the asynchronous queue head will point back to the queue @@ -4404,7 +4547,8 @@ static int lpc43_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct lpc43_qh_s *)lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); + qh = (struct lpc43_qh_s *) + lpc43_virtramaddr(lpc43_swap32(*bp) & QH_HLP_MASK); if (qh) { /* if the queue is empty, then just claim that we successfully @@ -4430,13 +4574,13 @@ static int lpc43_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Find and remove the QH. There are four possibilities: * - * 1) The transfer has already completed and the QH is no longer in the list. In - * this case, lpc43_hq_foreach will return zero - * 2a) The transfer is not active and still pending. It was removed from the list - * and lpc43_hq_foreach will return one. - * 2b) The is active but not yet complete. This is currently handled the same as - * 2a). REVISIT: This needs to be fixed. - * 3) Some bad happened and lpc43_hq_foreach returned an error code < 0. + * 1) The transfer has already completed and the QH is no longer in the + * list. In this case, sam_hq_foreach will return zero + * 2a) The transfer is not active and still pending. It was removed from + * the list and sam_hq_foreach will return one. + * 2b) The is active but not yet complete. This is currently handled the + * same as 2a). REVISIT: This needs to be fixed. + * 3) Some bad happened and sam_hq_foreach returned an error code < 0. */ ret = lpc43_qh_foreach(qh, &bp, lpc43_qh_cancel, epinfo); @@ -4478,7 +4622,7 @@ errout_with_sem: return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc43_connect * * Description: @@ -4487,17 +4631,17 @@ errout_with_sem: * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int lpc43_connect(FAR struct usbhost_driver_s *drvr, @@ -4509,7 +4653,8 @@ static int lpc43_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4532,17 +4677,18 @@ static int lpc43_connect(FAR struct usbhost_driver_s *drvr, * Name: lpc43_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4560,9 +4706,6 @@ static void lpc43_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: lpc43_reset * @@ -4571,9 +4714,9 @@ static void lpc43_disconnect(FAR struct usbhost_driver_s *drvr, * * Table 2-9. USBCMD - USB Command Register Bit Definitions * - * "Host Controller Reset (HCRESET) ... This control bit is used by software - * to reset the host controller. The effects of this on Root Hub registers - * are similar to a Chip Hardware Reset. + * "Host Controller Reset (HCRESET) ... This control bit is used by + * software to reset the host controller. The effects of this on Root + * Hub registers are similar to a Chip Hardware Reset. * * "When software writes a one to this bit, the Host Controller resets its * internal pipelines, timers, counters, state machines, etc. to their @@ -4582,16 +4725,18 @@ static void lpc43_disconnect(FAR struct usbhost_driver_s *drvr, * ports. * * "PCI Configuration registers are not affected by this reset. All - * operational registers, including port registers and port state machines - * are set to their initial values. Port ownership reverts to the companion - * host controller(s)... Software must reinitialize the host controller ... - * in order to return the host controller to an operational state. + * operational registers, including port registers and port state + * machines are set to their initial values. Port ownership reverts + * to the companion host controller(s)... Software must reinitialize + * the host controller ... in order to return the host controller to + * an operational state. * - * "This bit is set to zero by the Host Controller when the reset process is - * complete. Software cannot terminate the reset process early by writing a - * zero to this register. Software should not set this bit to a one when - * the HCHalted bit in the USBSTS register is a zero. Attempting to reset - * an actively running host controller will result in undefined behavior." + * "This bit is set to zero by the Host Controller when the reset process + * is complete. Software cannot terminate the reset process early by + * writing a zero to this register. Software should not set this bit to + * a one when the HCHalted bit in the USBSTS register is a zero. + * Attempting to reset an actively running host controller will result + * in undefined behavior." * * Input Parameters: * None. @@ -4610,10 +4755,11 @@ static int lpc43_reset(void) uint32_t regval; unsigned int timeout; - /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to 0, - * the Host Controller completes the current transaction on the USB and then - * halts. The HC Halted bit in the status register indicates when the Hos - * Controller has finished the transaction and has entered the stopped state..." + /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to + * 0, the Host Controller completes the current transaction on the USB and + * then halts. The HC Halted bit in the status register indicates when the + * Host Controller has finished the transaction and has entered the + * stopped state..." */ lpc43_putreg(0, &HCOR->usbcmd); @@ -4631,9 +4777,9 @@ static int lpc43_reset(void) up_udelay(1); timeout++; - /* Get the current value of the USBSTS register. This loop will terminate - * when either the timeout exceeds one millisecond or when the HCHalted - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBSTS register. This loop will + * terminate when either the timeout exceeds one millisecond or when + * the HCHalted bit is no longer set in the USBSTS register. */ regval = lpc43_getreg(&HCOR->usbsts); @@ -4663,9 +4809,9 @@ static int lpc43_reset(void) up_udelay(5); timeout += 5; - /* Get the current value of the USBCMD register. This loop will terminate - * when either the timeout exceeds one second or when the HCReset - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBCMD register. This loop will + * terminate when either the timeout exceeds one second or when the + * HCReset bit is no longer set in the USBSTS register. */ regval = lpc43_getreg(&HCOR->usbcmd); @@ -4680,6 +4826,7 @@ static int lpc43_reset(void) /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: lpc43_ehci_initialize * @@ -4736,7 +4883,7 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) #endif #endif /* CONFIG_USBHOST_INT_DISABLE */ - /* Software Configuration ****************************************************/ + /* Software Configuration *************************************************/ usbhost_vtrace1(EHCI_VTRACE1_INITIALIZING, 0); @@ -4868,7 +5015,8 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) lpc43_qtd_free(&g_qtdpool[i]); } - /* EHCI Hardware Configuration ***********************************************/ + /* EHCI Hardware Configuration ********************************************/ + /* Enable USB to AHB clock and to Event router */ lpc43_pll0usbconfig(); @@ -4890,13 +5038,16 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) */ #ifdef CONFIG_LPC43_EHCI_SDIS - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | USBHOST_USBMODE_VBPS, + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | + USBHOST_USBMODE_VBPS, LPC43_USBDEV_USBMODE); #else - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, LPC43_USBDEV_USBMODE); + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, + LPC43_USBDEV_USBMODE); #endif /* Host Controller Initialization. Paragraph 4.1 */ + /* Reset the EHCI hardware */ ret = lpc43_reset(); @@ -4912,36 +5063,39 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) */ #ifdef CONFIG_LPC43_EHCI_SDIS - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | USBHOST_USBMODE_VBPS, + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_SDIS | + USBHOST_USBMODE_VBPS, LPC43_USBDEV_USBMODE); #else - putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, LPC43_USBDEV_USBMODE); + putreg32(USBHOST_USBMODE_CM_HOST | USBHOST_USBMODE_VBPS, + LPC43_USBDEV_USBMODE); #endif - /* "In order to initialize the host controller, software should perform the - * following steps: + /* "In order to initialize the host controller, software should perform + * the following steps: * - * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where all - * of the interface data structures are allocated. [64-bit mode] + * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where + * all of the interface data structures are allocated. [64-bit mode] * - "Write the appropriate value to the USBINTR register to enable the * appropriate interrupts. - * - "Write the base address of the Periodic Frame List to the PERIODICLIST - * BASE register. If there are no work items in the periodic schedule, - * all elements of the Periodic Frame List should have their T-Bits set - * to a one. + * - "Write the base address of the Periodic Frame List to the + * PERIODICLIST BASE register. If there are no work items in the + * periodic schedule, all elements of the Periodic Frame List should + * have their T-Bits set to a one. * - "Write the USBCMD register to set the desired interrupt threshold, * frame list size (if applicable) and turn the host controller ON via * setting the Run/Stop bit. - * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI controller + * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI + * controller * ... * - * "At this point, the host controller is up and running and the port registers - * will begin reporting device connects, etc. System software can enumerate a - * port through the reset process (where the port is in the enabled state). At - * this point, the port is active with SOFs occurring down the enabled por - * enabled Highspeed ports, but the schedules have not yet been enabled. The - * EHCI Host controller will not transmit SOFs to enabled Full- or Low-speed - * ports. + * "At this point, the host controller is up and running and the port + * registers will begin reporting device connects, etc. System software + * can enumerate a port through the reset process (where the port is in + * the enabled state). At this point, the port is active with SOFs + * occurring down the enabled port enabled Highspeed ports, but the + * schedules have not yet been enabled. The EHCI Host controller will not + * transmit SOFs to enabled Full- or Low-speed ports." */ regval = getreg32(LPC43_CREG0); @@ -4967,7 +5121,8 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) /* Verify that the correct number of ports is reported */ regval = lpc43_getreg(&HCCR->hcsparams); - nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT; + nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> + EHCI_HCSPARAMS_NPORTS_SHIFT; usbhost_vtrace2(EHCI_VTRACE2_HCSPARAMS, nports, regval); DEBUGASSERT(nports == LPC43_EHCI_NRHPORT); @@ -4994,7 +5149,8 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) memset(&g_asynchead, 0, sizeof(struct lpc43_qh_s)); physaddr = lpc43_physramaddr((uintptr_t)&g_asynchead); g_asynchead.hw.hlp = lpc43_swap32(physaddr | QH_HLP_TYP_QH); - g_asynchead.hw.epchar = lpc43_swap32(QH_EPCHAR_H | QH_EPCHAR_EPS_FULL); + g_asynchead.hw.epchar = lpc43_swap32(QH_EPCHAR_H | + QH_EPCHAR_EPS_FULL); g_asynchead.hw.overlay.nqp = lpc43_swap32(QH_NQP_T); g_asynchead.hw.overlay.alt = lpc43_swap32(QH_NQP_T); g_asynchead.hw.overlay.token = lpc43_swap32(QH_TOKEN_HALTED); @@ -5071,14 +5227,14 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) /* Wait for the EHCI to run (i.e., no longer report halted) */ - ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100*1000); + ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100 * 1000); if (ret < 0) { usbhost_trace1(EHCI_TRACE1_RUN_FAILED, lpc43_getreg(&HCOR->usbsts)); return NULL; } - /* Interrupt Configuration ***************************************************/ + /* Interrupt Configuration ************************************************/ ret = irq_attach(LPC43M4_IRQ_USB0, lpc43_ehci_interrupt, NULL); if (ret != 0) @@ -5108,12 +5264,14 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) for (i = 0; i < LPC43_EHCI_NRHPORT; i++) { +#if 0 /* Enable VBUS power for the port */ - //lpc43_usbhost_vbusdrive(i, true); + lpc43_usbhost_vbusdrive(i, true); +#endif up_mdelay(25); - /* Power up the power. REVISIT: Is this necessary? The PP bit never + /* Power up the hub. REVISIT: Is this necessary? The PP bit never * gets set unless I explicitly set it here. */ @@ -5146,7 +5304,7 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) return &g_ehciconn; } -/******************************************************************************************** +/**************************************************************************** * Name: usbhost_trformat1 and usbhost_trformat2 * * Description: @@ -5157,7 +5315,7 @@ FAR struct usbhost_connection_s *lpc43_ehci_initialize(int controller) * printf. The returned format is expected to handle two unsigned integer * values. * - ********************************************************************************************/ + ****************************************************************************/ #ifdef HAVE_USBHOST_TRACE FAR const char *usbhost_trformat1(uint16_t id) diff --git a/arch/arm/src/lpc54xx/lpc54_usb0_ohci.c b/arch/arm/src/lpc54xx/lpc54_usb0_ohci.c index e5ffdc9bc4..3e239d6a95 100644 --- a/arch/arm/src/lpc54xx/lpc54_usb0_ohci.c +++ b/arch/arm/src/lpc54xx/lpc54_usb0_ohci.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/lpc54xx/lpc54_usb0_ohci.c * - * Copyright (C) 2019 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -73,11 +58,11 @@ * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ +/* Configuration ************************************************************/ /* All I/O buffers must lie in AHB SRAM because of the OHCI DMA. It might be - * okay if no I/O buffers are used *IF* the application can guarantee that all - * end-user I/O buffers reside in AHB SRAM. + * okay if no I/O buffers are used *IF* the application can guarantee that + * all end-user I/O buffers reside in AHB SRAM. */ #if LPC54_IOBUFFERS < 1 @@ -92,7 +77,7 @@ # undef CONFIG_LPC54_OHCI_REGDEBUG #endif -/* OHCI Setup ******************************************************************/ +/* OHCI Setup ***************************************************************/ /* Frame Interval / Periodic Start */ @@ -129,22 +114,22 @@ # define usbhost_dumpgpio() #endif -/* Numbers and Sizes of Things *************************************************/ +/* Numbers and Sizes of Things **********************************************/ /* Fixed size of the OHCI control area */ #define LPC54_HCCA_SIZE 256 -/* Fixed endpoint descriptor size. The actual size required by the hardware is only - * 16 bytes, however, we set aside an additional 16 bytes for for internal use by - * the OHCI host driver. 16-bytes is set aside because the EDs must still be - * aligned to 16-byte boundaries. +/* Fixed endpoint descriptor size. The actual size required by the hardware + * is only 16 bytes, however, we set aside an additional 16 bytes for + * internal use by the OHCI host driver. 16-bytes is set aside because the + * EDs must still be aligned to 16-byte boundaries. */ #define LPC54_ED_SIZE 32 -/* Configurable number of user endpoint descriptors (EDs). This number excludes - * the control endpoint that is always allocated. +/* Configurable number of user endpoint descriptors (EDs). This number + * excludes the control endpoint that is always allocated. */ #ifndef CONFIG_LP17_OHCI_NEDS @@ -155,10 +140,10 @@ #define LPC54_EDFREE_SIZE (CONFIG_LP17_OHCI_NEDS * LPC54_ED_SIZE) -/* Fixed transfer descriptor size. The actual size required by the hardware is only - * 16 bytes, however, we set aside an additional 16 bytes for for internal use by - * the OHCI host driver. 16-bytes is set aside because the TDs must still be - * aligned to 16-byte boundaries. +/* Fixed transfer descriptor size. The actual size required by the hardware + * is only 16 bytes, however, we set aside an additional 16 bytes for for + * internal use by the OHCI host driver. 16-bytes is set aside because the + * TDs must still be aligned to 16-byte boundaries. */ #define LPC54_TD_SIZE 32 @@ -199,8 +184,9 @@ #define LPC54_TBFREE_SIZE (CONFIG_LPC54_OHCI_TDBUFFERS * CONFIG_LPC54_OHCI_TDBUFSIZE) -/* Configurable size of an IO buffer. The number of IO buffers will be determined - * by what is left at the end of the BANK1 memory setup aside of OHCI RAM. +/* Configurable size of an IO buffer. The number of IO buffers will be + * determined by what is left at the end of the BANK1 memory setup aside of + * OHCI RAM. */ #ifndef CONFIG_LPC54_OHCI_IOBUFSIZE @@ -211,7 +197,7 @@ # error "IO buffer size must be an even number of 32-bit words" #endif -/* USB Host Memory *************************************************************/ +/* USB Host Memory **********************************************************/ /* Required Alignment */ @@ -239,7 +225,7 @@ #define MIN_PERINTERVAL 2 #define MAX_PERINTERVAL 32 -/* Descriptors *****************************************************************/ +/* Descriptors **************************************************************/ /* TD delay interrupt value */ @@ -329,8 +315,11 @@ struct lpc54_ed_s uint8_t xfrtype; /* 16: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */ uint8_t interval; /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */ - sem_t wdhsem; /* 18: Semaphore used to wait for Writeback Done Head event */ - /* Unused bytes may follow, depending on the size of sem_t */ + sem_t wdhsem; /* 18: Semaphore used to wait for Writeback + * Done Head event */ + + /* Unused bytes may follow, depending on the size of sem_t */ + /* Pointer to structure that manages asynchronous transfers on this pipe */ struct lpc54_xfrinfo_s *xfrinfo; @@ -366,7 +355,7 @@ struct lpc54_list_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_LPC54_OHCI_REGDEBUG static void lpc54_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -378,19 +367,20 @@ static void lpc54_putreg(uint32_t val, uint32_t addr); # define lpc54_putreg(val,addr) putreg32(val,addr) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void lpc54_takesem(sem_t *sem); +static int lpc54_takesem(sem_t *sem); +static int lpc54_takesem_uninterruptible(sem_t *sem); #define lpc54_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t lpc54_getle16(const uint8_t *val); #if 0 /* Not used */ static void lpc54_putle16(uint8_t *dest, uint16_t val); #endif -/* OHCI memory pool helper functions *******************************************/ +/* OHCI memory pool helper functions ****************************************/ static inline void lpc54_edfree(struct lpc54_ed_s *ed); static struct lpc54_gtd_s *lpc54_tdalloc(void); @@ -404,7 +394,7 @@ static void lpc54_freeio(uint8_t *buffer); static struct lpc54_xfrinfo_s *lpc54_alloc_xfrinfo(void); static void lpc54_free_xfrinfo(struct lpc54_xfrinfo_s *xfrinfo); -/* ED list helper functions ****************************************************/ +/* ED list helper functions *************************************************/ static inline int lpc54_addctrled(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed); @@ -418,7 +408,8 @@ static inline int lpc54_rembulked(struct lpc54_usbhost_s *priv, #if !defined(CONFIG_OHCI_INT_DISABLE) || !defined(CONFIG_OHCI_ISOC_DISABLE) static unsigned int lpc54_getinterval(uint8_t interval); -static void lpc54_setinttab(uint32_t value, unsigned int interval, unsigned int offset); +static void lpc54_setinttab(uint32_t value, unsigned int interval, + unsigned int offset); #endif static inline int lpc54_addinted(struct lpc54_usbhost_s *priv, @@ -433,7 +424,7 @@ static inline int lpc54_addisoced(struct lpc54_usbhost_s *priv, static inline int lpc54_remisoced(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed); -/* Descriptor helper functions *************************************************/ +/* Descriptor helper functions **********************************************/ static int lpc54_enqueuetd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, uint32_t dirpid, @@ -442,11 +433,11 @@ static int lpc54_enqueuetd(struct lpc54_usbhost_s *priv, static int lpc54_ctrltd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, uint32_t dirpid, uint8_t *buffer, size_t buflen); -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int lpc54_wait(struct usbhost_connection_s *conn, struct usbhost_hubport_s **hport); @@ -456,10 +447,11 @@ static int lpc54_enumerate(struct usbhost_connection_s *conn, struct usbhost_hubport_s *hport); static int lpc54_ep0configure(struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int lpc54_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); static int lpc54_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int lpc54_alloc(struct usbhost_driver_s *drvr, uint8_t **buffer, size_t *maxlen); @@ -502,7 +494,7 @@ static int lpc54_connect(FAR struct usbhost_driver_s *drvr, static void lpc54_disconnect(struct usbhost_driver_s *drvr, struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static inline void lpc54_ep0init(struct lpc54_usbhost_s *priv); @@ -510,9 +502,9 @@ static inline void lpc54_ep0init(struct lpc54_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct lpc54_usbhost_s g_usbhost; @@ -559,10 +551,6 @@ static struct lpc54_list_s *g_iofree; /* List of unused I/O buffers */ static struct lpc54_list_s *g_xfrfree; static struct lpc54_xfrinfo_s g_xfrbuffers[CONFIG_LPC54_OHCI_NPREALLOC]; -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -598,8 +586,8 @@ static void lpc54_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -698,9 +686,43 @@ static void lpc54_putreg(uint32_t val, uint32_t addr) * ****************************************************************************/ -static void lpc54_takesem(sem_t *sem) +static int lpc54_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: lpc54_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int lpc54_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -769,8 +791,8 @@ static struct lpc54_gtd_s *lpc54_tdalloc(void) struct lpc54_gtd_s *ret; irqstate_t flags; - /* Disable interrupts momentarily so that lpc54_tdfree is not called from the - * interrupt handler. + /* Disable interrupts momentarily so that lpc54_tdfree is not called from + * the interrupt handler. */ flags = enter_critical_section(); @@ -791,7 +813,8 @@ static struct lpc54_gtd_s *lpc54_tdalloc(void) * Return an transfer descriptor to the free list * * Assumptions: - * - Only called from the WDH interrupt handler (and during initialization). + * - Only called from the WDH interrupt handler (and during + * initialization). * - Interrupts are disabled in any case. * ****************************************************************************/ @@ -830,6 +853,7 @@ static uint8_t *lpc54_tballoc(void) { g_tbfree = ((struct lpc54_list_s *)ret)->flink; } + return ret; } @@ -1213,9 +1237,10 @@ static inline int lpc54_rembulked(struct lpc54_usbhost_s *priv, #if !defined(CONFIG_OHCI_INT_DISABLE) || !defined(CONFIG_OHCI_ISOC_DISABLE) static unsigned int lpc54_getinterval(uint8_t interval) { - /* The bInterval field of the endpoint descriptor contains the polling interval - * for interrupt and isochronous endpoints. For other types of endpoint, this - * value should be ignored. bInterval is provided in units of 1MS frames. + /* The bInterval field of the endpoint descriptor contains the polling + * interval for interrupt and isochronous endpoints. For other types of + * endpoint, this value should be ignored. bInterval is provided in units + * of 1MS frames. */ if (interval < 3) @@ -1245,13 +1270,14 @@ static unsigned int lpc54_getinterval(uint8_t interval) * Name: lpc54_setinttab * * Description: - * Set the interrupt table to the selected value using the provided interval - * and offset. + * Set the interrupt table to the selected value using the provided + * interval and offset. * ****************************************************************************/ #if !defined(CONFIG_OHCI_INT_DISABLE) || !defined(CONFIG_OHCI_ISOC_DISABLE) -static void lpc54_setinttab(uint32_t value, unsigned int interval, unsigned int offset) +static void lpc54_setinttab(uint32_t value, unsigned int interval, + unsigned int offset) { unsigned int i; for (i = offset; i < HCCA_INTTBL_WSIZE; i += interval) @@ -1267,17 +1293,18 @@ static void lpc54_setinttab(uint32_t value, unsigned int interval, unsigned int * Description: * Helper function to add an ED to the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ @@ -1291,8 +1318,8 @@ static inline int lpc54_addinted(struct lpc54_usbhost_s *priv, uint32_t head; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ regval = lpc54_getreg(LPC54_OHCI_CTRL); @@ -1338,6 +1365,7 @@ static inline int lpc54_addinted(struct lpc54_usbhost_s *priv, interval = priv->outinterval; } } + uinfo("min interval: %d offset: %d\n", interval, offset); /* Get the head of the first of the duplicated entries. The first offset @@ -1376,17 +1404,18 @@ static inline int lpc54_addinted(struct lpc54_usbhost_s *priv, * Description: * Helper function to remove an ED from the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ @@ -1401,8 +1430,8 @@ static inline int lpc54_reminted(struct lpc54_usbhost_s *priv, unsigned int offset; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ regval = lpc54_getreg(LPC54_OHCI_CTRL); @@ -1489,8 +1518,8 @@ static inline int lpc54_reminted(struct lpc54_usbhost_s *priv, priv->outinterval = interval; } - /* Set the head ED in all of the appropriate entries of the HCCA interrupt - * table (head might be NULL). + /* Set the head ED in all of the appropriate entries of the HCCA + * interrupt table (head might be NULL). */ lpc54_setinttab((uint32_t)head, interval, offset); @@ -1557,7 +1586,8 @@ static inline int lpc54_remisoced(struct lpc54_usbhost_s *priv, static int lpc54_enqueuetd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, uint32_t dirpid, - uint32_t toggle, volatile uint8_t *buffer, size_t buflen) + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen) { struct lpc54_gtd_s *td; int ret = -ENOMEM; @@ -1569,7 +1599,8 @@ static int lpc54_enqueuetd(struct lpc54_usbhost_s *priv, { /* Initialize the allocated TD and link it before the common tail TD. */ - td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK); + td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | + GTD_STATUS_CC_MASK); TDTAIL->hw.ctrl = 0; td->hw.cbp = (uint32_t)buffer; TDTAIL->hw.cbp = 0; @@ -1597,10 +1628,11 @@ static int lpc54_enqueuetd(struct lpc54_usbhost_s *priv, * Name: lpc54_wdhwait * * Description: - * Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * ****************************************************************************/ @@ -1617,8 +1649,9 @@ static int lpc54_wdhwait(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed) if (priv->connected) { - /* Yes.. then set wdhwait to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set wdhwait to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ xfrinfo->wdhwait = true; @@ -1672,8 +1705,8 @@ static int lpc54_ctrltd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, ed->xfrinfo = xfrinfo; - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ ret = lpc54_wdhwait(priv, ed); @@ -1700,8 +1733,8 @@ static int lpc54_ctrltd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, ret = lpc54_enqueuetd(priv, ed, dirpid, toggle, buffer, buflen); if (ret == OK) { - /* Set ControlListFilled. This bit is used to indicate whether there are - * TDs on the Control list. + /* Set ControlListFilled. This bit is used to indicate whether there + * are TDs on the Control list. */ regval = lpc54_getreg(LPC54_OHCI_CMDST); @@ -1710,11 +1743,15 @@ static int lpc54_ctrltd(struct lpc54_usbhost_s *priv, struct lpc54_ed_s *ed, /* Wait for the Writeback Done Head interrupt */ - lpc54_takesem(&ed->wdhsem); + ret = lpc54_takesem(&ed->wdhsem); + if (ret < 0) + { + /* Task has been canceled */ + } /* Check the TD completion status bits */ - if (xfrinfo->tdstatus == TD_CC_NOERROR) + else if (xfrinfo->tdstatus == TD_CC_NOERROR) { ret = OK; } @@ -1772,7 +1809,9 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) uint32_t rhstatus = lpc54_getreg(LPC54_OHCI_RHSTATUS); uinfo("Connect Status Change, RHSTATUS: %08x\n", rhstatus); - /* If DRWE is set, Connect Status Change indicates a remote wake-up event */ + /* If DRWE is set, Connect Status Change indicates a remote + * wake-up event. + */ if (rhstatus & OHCI_RHSTATUS_DRWE) { @@ -1807,7 +1846,8 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) } else { - uwarn("WARNING: Spurious status change (connected)\n"); + uwarn("WARNING: Spurious status change " + "(connected)\n"); } /* The LSDA (Low speed device attached) bit is valid @@ -1863,7 +1903,8 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) } else { - uwarn("WARNING: Spurious status change (disconnected)\n"); + uwarn("WARNING: Spurious status change " + "(disconnected)\n"); } } @@ -1889,14 +1930,14 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) struct lpc54_gtd_s *td; struct lpc54_gtd_s *next; - /* The host controller just wrote the list of finished TDs into the HCCA - * done head. This may include multiple packets that were transferred - * in the preceding frame. + /* The host controller just wrote the list of finished TDs into + * the HCCA done head. This may include multiple packets that + * were transferred in the preceding frame. * - * Remove the TD(s) from the Writeback Done Head in the HCCA and return - * them to the free list. Note that this is safe because the hardware - * will not modify the writeback done head again until the WDH bit is - * cleared in the interrupt status register. + * Remove the TD(s) from the Writeback Done Head in the HCCA and + * return them to the free list. Note that this is safe because + * the hardware will not modify the writeback done head again + * until the WDH bit is cleared in the interrupt status register. */ td = (struct lpc54_gtd_s *)(HCCA->donehead & HCCA_DONEHEAD_MASK); @@ -1909,12 +1950,13 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) { /* REVISIT: I have encountered bad TDs in the done list linked * after at least one good TD. This is some consequence of how - * transfers are being cancelled. But for now, I have only + * transfers are being canceled. But for now, I have only * this work-around. */ if ((uintptr_t)td < LPC54_TDFREE_BASE || - (uintptr_t)td >= (LPC54_TDFREE_BASE + LPC54_TD_SIZE*CONFIG_LP17_OHCI_NTDS)) + (uintptr_t)td >= (LPC54_TDFREE_BASE + + LPC54_TD_SIZE * CONFIG_LP17_OHCI_NTDS)) { break; } @@ -1924,26 +1966,31 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) ed = td->ed; DEBUGASSERT(ed != NULL); - /* If there is a transfer in progress, then the xfrinfo pointer will be - * non-NULL. But it appears that a NULL pointer may be received with a - * spurious interrupt such as may occur after a transfer is cancelled. + /* If there is a transfer in progress, then the xfrinfo + * pointer will be non-NULL. But it appears that a NULL + * pointer may be received with a spurious interrupt such as + * may occur after a transfer is canceled. */ xfrinfo = ed->xfrinfo; if (xfrinfo) { - /* Save the condition code from the (single) TD status/control - * word. + /* Save the condition code from the (single) TD status/ + * control word. */ - xfrinfo->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + xfrinfo->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> + GTD_STATUS_CC_SHIFT; #ifdef CONFIG_DEBUG_USB if (xfrinfo->tdstatus != TD_CC_NOERROR) { - /* The transfer failed for some reason... dump some diagnostic info. */ + /* The transfer failed for some reason... dump some + * diagnostic info. + */ - uerr("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d RHPORTST1:%08x\n", + uerr("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d " + "RHPORTST1:%08x\n", ed->xfrtype, td->hw.ctrl, xfrinfo->tdstatus, lpc54_getreg(LPC54_OHCI_RHPORTST1)); } @@ -2019,10 +2066,6 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) return OK; } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ - /**************************************************************************** * Name: lpc54_wait * @@ -2030,17 +2073,17 @@ static int lpc54_usbinterrupt(int irq, void *context, FAR void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or - * disconnected. This function will not return until either (1) a device is - * connected or disconnect to/from any hub port or until (2) some failure - * occurs. On a failure, a negated errno value is returned indicating the - * nature of the failure + * disconnected. This function will not return until either (1) a device + * is connected or disconnect to/from any hub port or until (2) some + * failure occurs. On a failure, a negated errno value is returned + * indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2054,6 +2097,11 @@ static int lpc54_wait(struct usbhost_connection_s *conn, struct lpc54_usbhost_s *priv = (struct lpc54_usbhost_s *)&g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; + + /* Loop until a change in the connection state changes on one of the root + * hub ports or until an error occurs. + */ flags = enter_critical_section(); for (; ; ) @@ -2100,7 +2148,8 @@ static int lpc54_wait(struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -2108,7 +2157,11 @@ static int lpc54_wait(struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - lpc54_takesem(&priv->pscsem); + ret = lpc54_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -2132,8 +2185,8 @@ static int lpc54_wait(struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -2160,7 +2213,7 @@ static int lpc54_rh_enumerate(struct usbhost_connection_s *conn, /* USB 2.0 spec says at least 50ms delay before port reset */ - nxsig_usleep(100*1000); + nxsig_usleep(100 * 1000); /* Put RH port 1 in reset (the LPC546x supports only a single downstream port) */ @@ -2173,7 +2226,7 @@ static int lpc54_rh_enumerate(struct usbhost_connection_s *conn, /* Release RH port 1 from reset and wait a bit */ lpc54_putreg(OHCI_RHPORTST_PRSC, LPC54_OHCI_RHPORTST1); - nxsig_usleep(200*1000); + nxsig_usleep(200 * 1000); return OK; } @@ -2212,7 +2265,7 @@ static int lpc54_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_ep0configure * * Description: @@ -2221,37 +2274,45 @@ static int lpc54_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * mps (maxpacketsize) - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc54_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) +static int lpc54_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { struct lpc54_usbhost_s *priv = (struct lpc54_usbhost_s *)drvr; struct lpc54_ed_s *ed; uint32_t hwctrl; + int ret; - DEBUGASSERT(drvr != NULL && ep0 != NULL && funcaddr < 128 && maxpacketsize < 2048); + DEBUGASSERT(drvr != NULL && ep0 != NULL && funcaddr < 128 && + maxpacketsize < 2048); ed = (struct lpc54_ed_s *)ep0; /* We must have exclusive access to EP0 and the control list */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Set the EP0 ED control word */ @@ -2272,47 +2333,54 @@ static int lpc54_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc54_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct lpc54_usbhost_s *priv = (struct lpc54_usbhost_s *)drvr; struct usbhost_hubport_s *hport; struct lpc54_ed_s *ed; - int ret = -ENOMEM; + int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(priv && epdesc && ep && priv->connected); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list, and the interrupt table. */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + ret = -ENOMEM; /* Take the next ED from the beginning of the free list */ @@ -2368,6 +2436,7 @@ static int lpc54_epalloc(struct usbhost_driver_s *drvr, ed->hw.ctrl |= ED_CONTROL_F; } #endif + uinfo("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl); /* Initialize the semaphore that is used to wait for the endpoint @@ -2414,7 +2483,9 @@ static int lpc54_epalloc(struct usbhost_driver_s *drvr, { /* No.. destroy it and report the error */ - uerr("ERROR: Failed to queue ED for transfer type: %d\n", ed->xfrtype); + uerr("ERROR: Failed to queue ED for transfer type: %d\n", + ed->xfrtype); + nxsem_destroy(&ed->wdhsem); lpc54_edfree(ed); } @@ -2430,25 +2501,25 @@ static int lpc54_epalloc(struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc54_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -2458,13 +2529,18 @@ static int lpc54_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* There should not be any pending, real TDs linked to this ED */ - DEBUGASSERT(ed && (ed->hw.headp & ED_HEADP_ADDR_MASK) == LPC54_TDTAIL_ADDR); + DEBUGASSERT(ed && (ed->hw.headp & ED_HEADP_ADDR_MASK) == + LPC54_TDTAIL_ADDR); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list and the interrupt table. */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Remove the ED to the correct list depending on the transfer type */ @@ -2506,27 +2582,28 @@ static int lpc54_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: lpc54_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2539,11 +2616,17 @@ static int lpc54_alloc(struct usbhost_driver_s *drvr, { struct lpc54_usbhost_s *priv = (struct lpc54_usbhost_s *)drvr; DEBUGASSERT(priv && buffer && maxlen); - int ret = -ENOMEM; + int ret; /* We must have exclusive access to the transfer buffer pool */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } + + ret = -ENOMEM; *buffer = lpc54_tballoc(); if (*buffer) @@ -2560,19 +2643,20 @@ static int lpc54_alloc(struct usbhost_driver_s *drvr, * Name: lpc54_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Never called from an interrupt handler. @@ -2582,42 +2666,46 @@ static int lpc54_alloc(struct usbhost_driver_s *drvr, static int lpc54_free(struct usbhost_driver_s *drvr, uint8_t *buffer) { struct lpc54_usbhost_s *priv = (struct lpc54_usbhost_s *)drvr; + int ret; + DEBUGASSERT(buffer); /* We must have exclusive access to the transfer buffer pool */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem_uninterruptible(&priv->exclsem); lpc54_tbfree(buffer); lpc54_givesem(&priv->exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kumm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc54_ioalloc(struct usbhost_driver_s *drvr, uint8_t **buffer, size_t buflen) @@ -2641,28 +2729,28 @@ static int lpc54_ioalloc(struct usbhost_driver_s *drvr, #endif } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int lpc54_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) { @@ -2680,31 +2768,31 @@ static int lpc54_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) * Name: lpc54_ctrlin and lpc54_ctrlout * * Description: - * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2729,10 +2817,15 @@ static int lpc54_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } len = lpc54_getle16(req->len); - ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, USB_SIZEOF_CTRLREQ); + ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, + USB_SIZEOF_CTRLREQ); if (ret == OK) { if (len) @@ -2767,15 +2860,21 @@ static int lpc54_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } len = lpc54_getle16(req->len); - ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, USB_SIZEOF_CTRLREQ); + ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, (uint8_t *)req, + USB_SIZEOF_CTRLREQ); if (ret == OK) { if (len) { - ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_OUT, (uint8_t *)buffer, len); + ret = lpc54_ctrltd(priv, ed, GTD_STATUS_DP_OUT, (uint8_t *)buffer, + len); } if (ret == OK) @@ -2797,16 +2896,16 @@ static int lpc54_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. - * + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2848,7 +2947,8 @@ static int lpc54_transfer_common(struct lpc54_usbhost_s *priv, /* Then enqueue the transfer */ xfrinfo->tdstatus = TD_CC_NOERROR; - ret = lpc54_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); + ret = lpc54_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, + buflen); if (ret == OK) { /* BulkListFilled. This bit is used to indicate whether there are any @@ -2870,20 +2970,21 @@ static int lpc54_transfer_common(struct lpc54_usbhost_s *priv, * Name: lpc54_dma_alloc * * Description: - * Allocate DMA memory to perform a transfer, copying user data as necessary + * Allocate DMA memory to perform a transfer, copying user data as + * necessary * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * userbuffer - The user buffer containing the data to be sent (OUT endpoint) - * or received (IN endpoint). + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * userbuffer - The user buffer containing the data to be sent (OUT + * endpoint) or received (IN endpoint). * buflen - The length of the data to be sent or received. * alloc - The location to return the allocated DMA buffer. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2899,7 +3000,8 @@ static int lpc54_dma_alloc(struct lpc54_usbhost_s *priv, uint8_t *newbuffer; if ((uintptr_t)userbuffer < LPC54_SRAM_BANK0 || - (uintptr_t)userbuffer >= (LPC54_SRAM_BANK0 + LPC54_BANK0_SIZE + LPC54_BANK1_SIZE)) + (uintptr_t)userbuffer >= (LPC54_SRAM_BANK0 + LPC54_BANK0_SIZE + + LPC54_BANK1_SIZE)) { /* Will the transfer fit in an IO buffer? */ @@ -2946,16 +3048,16 @@ static int lpc54_dma_alloc(struct lpc54_usbhost_s *priv, * * Input Parameters: * priv - Internal driver state structure. - * ed - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * userbuffer - The user buffer containing the data to be sent (OUT endpoint) - * or received (IN endpoint). + * ed - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * userbuffer - The user buffer containing the data to be sent (OUT + * endpoint) or received (IN endpoint). * buflen - The length of the data to be sent or received. * alloc - The allocated DMA buffer to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2999,26 +3101,27 @@ static void lpc54_dma_free(struct lpc54_usbhost_s *priv, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -3047,11 +3150,16 @@ static ssize_t lpc54_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, DEBUGASSERT(priv && ed && buffer && buflen > 0); - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. */ - lpc54_takesem(&priv->exclsem); + ret = lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Allocate a structure to retain the information needed when the transfer * completes. @@ -3095,8 +3203,8 @@ static ssize_t lpc54_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ ret = lpc54_wdhwait(priv, ed); @@ -3119,7 +3227,12 @@ static ssize_t lpc54_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* Wait for the Writeback Done Head interrupt */ - lpc54_takesem(&ed->wdhsem); + ret = lpc54_takesem(&ed->wdhsem); + if (ret < 0) + { + nbytes = (ssize_t)ret; + goto errout_with_wdhwait; + } /* Check the TD completion status bits */ @@ -3155,6 +3268,7 @@ static ssize_t lpc54_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, } errout_with_wdhwait: + /* Make sure that there is no outstanding request on this endpoint */ xfrinfo->wdhwait = false; @@ -3167,6 +3281,7 @@ errout_with_buffers: #endif errout_with_xfrinfo: + /* Make sure that there is no outstanding request on this endpoint */ lpc54_free_xfrinfo(xfrinfo); @@ -3186,8 +3301,8 @@ errout_with_sem: * * Input Parameters: * priv - Internal driver state structure. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which the - * transfer was performed. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which the transfer was performed. * * Returned Value: * None @@ -3280,20 +3395,21 @@ static void lpc54_asynch_completion(struct lpc54_usbhost_s *priv, * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3311,16 +3427,22 @@ static int lpc54_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, struct lpc54_xfrinfo_s *xfrinfo; int ret; - DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && buffer && buflen > 0 && callback); + DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && buffer && buflen > 0 && + callback); - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. */ - lpc54_takesem(&priv->exclsem); + ret lpc54_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } - /* Allocate a structure to retain the information needed when the asynchronous - * transfer completes. + /* Allocate a structure to retain the information needed when the + * asynchronous transfer completes. */ DEBUGASSERT(ed->xfrinfo == NULL); @@ -3395,7 +3517,7 @@ errout_with_sem: } #endif /* CONFIG_OHCI_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: lpc54_cancel * * Description: @@ -3403,16 +3525,16 @@ errout_with_sem: * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -3437,8 +3559,8 @@ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) xfrinfo = ed->xfrinfo; if (xfrinfo) { - /* It might be possible for no transfer to be in progress (callback == NULL - * and wdhwait == false) + /* It might be possible for no transfer to be in progress (callback == + * NULL and wdhwait == false) */ #ifdef CONFIG_OHCI_ASYNCH @@ -3461,7 +3583,8 @@ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Remove the TDs attached to the ED, keeping the ED in the list */ - td = (struct lpc54_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); + td = (struct lpc54_gtd_s *) + (ed->hw.headp & ED_HEADP_ADDR_MASK); ed->hw.headp = LPC54_TDTAIL_ADDR; ed->xfrinfo = NULL; @@ -3474,7 +3597,8 @@ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Remove the TDs attached to the ED, keeping the Ed in the list */ - td = (struct lpc54_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); + td = (struct lpc54_gtd_s *) + (ed->hw.headp & ED_HEADP_ADDR_MASK); ed->hw.headp = LPC54_TDTAIL_ADDR; ed->xfrinfo = NULL; } @@ -3538,7 +3662,7 @@ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: lpc54_connect * * Description: @@ -3547,17 +3671,17 @@ static int lpc54_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_OHCI_HUB static int lpc54_connect(FAR struct usbhost_driver_s *drvr, @@ -3571,7 +3695,8 @@ static int lpc54_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -3592,17 +3717,18 @@ static int lpc54_connect(FAR struct usbhost_driver_s *drvr, * Name: lpc54_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -3620,9 +3746,6 @@ static void lpc54_disconnect(struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: lpc54_ep0init * @@ -3710,6 +3833,7 @@ struct usbhost_connection_s *lpc54_usbhost_initialize(int controller) DEBUGASSERT(sizeof(struct lpc54_gtd_s) <= LPC54_TD_SIZE); /* Initialize the state data structure */ + /* Initialize the device operations */ drvr = &priv->drvr; @@ -3799,7 +3923,8 @@ struct usbhost_connection_s *lpc54_usbhost_initialize(int controller) /* Now we can turn off the PORTSEL clock */ - lpc54_putreg((LPC54_CLKCTRL_ENABLES & ~USBOTG_CLK_PORTSELCLK), LPC54_USBOTG_CLKCTRL); + lpc54_putreg((LPC54_CLKCTRL_ENABLES & ~USBOTG_CLK_PORTSELCLK), + LPC54_USBOTG_CLKCTRL); /* Configure I/O pins */ @@ -3818,13 +3943,20 @@ struct usbhost_connection_s *lpc54_usbhost_initialize(int controller) #if 0 /* Useful if you have doubts about the layout */ uinfo("AHB SRAM:\n"); - uinfo(" HCCA: %08x %d\n", LPC54_HCCA_BASE, LPC54_HCCA_SIZE); - uinfo(" TDTAIL: %08x %d\n", LPC54_TDTAIL_ADDR, LPC54_TD_SIZE); - uinfo(" EDCTRL: %08x %d\n", LPC54_EDCTRL_ADDR, LPC54_ED_SIZE); - uinfo(" EDFREE: %08x %d\n", LPC54_EDFREE_BASE, LPC54_ED_SIZE); - uinfo(" TDFREE: %08x %d\n", LPC54_TDFREE_BASE, LPC54_EDFREE_SIZE); - uinfo(" TBFREE: %08x %d\n", LPC54_TBFREE_BASE, LPC54_TBFREE_SIZE); - uinfo(" IOFREE: %08x %d\n", LPC54_IOFREE_BASE, LPC54_IOBUFFERS * CONFIG_LPC54_OHCI_IOBUFSIZE); + uinfo(" HCCA: %08x %d\n", + LPC54_HCCA_BASE, LPC54_HCCA_SIZE); + uinfo(" TDTAIL: %08x %d\n", + LPC54_TDTAIL_ADDR, LPC54_TD_SIZE); + uinfo(" EDCTRL: %08x %d\n", + LPC54_EDCTRL_ADDR, LPC54_ED_SIZE); + uinfo(" EDFREE: %08x %d\n", + LPC54_EDFREE_BASE, LPC54_ED_SIZE); + uinfo(" TDFREE: %08x %d\n", + LPC54_TDFREE_BASE, LPC54_EDFREE_SIZE); + uinfo(" TBFREE: %08x %d\n", + LPC54_TBFREE_BASE, LPC54_TBFREE_SIZE); + uinfo(" IOFREE: %08x %d\n", + LPC54_IOFREE_BASE, LPC54_IOBUFFERS * CONFIG_LPC54_OHCI_IOBUFSIZE); #endif /* Initialize all the TDs, EDs and HCCA to 0 */ diff --git a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c index b8b8398e02..2dbb74ec6b 100644 --- a/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c +++ b/arch/arm/src/s32k1xx/s32k1xx_lpi2c.c @@ -245,9 +245,6 @@ static inline void uint32_t setbits); static inline int s32k1xx_lpi2c_sem_wait(FAR struct s32k1xx_lpi2c_priv_s *priv); -static int - s32k1xx_lpi2c_sem_wait_uninterruptible( - FAR struct s32k1xx_lpi2c_priv_s *priv); #ifdef CONFIG_S32K1XX_I2C_DYNTIMEO static useconds_t @@ -465,21 +462,6 @@ static inline int return nxsem_wait(&priv->sem_excl); } -/**************************************************************************** - * Name: s32k1xx_lpi2c_sem_wait_uninterruptible - * - * Description: - * Take the exclusive access, waiting as necessary - * - ****************************************************************************/ - -static int - s32k1xx_lpi2c_sem_wait_uninterruptible( - FAR struct s32k1xx_lpi2c_priv_s *priv) -{ - return nxsem_wait_uninterruptible(&priv->sem_excl); -} - /**************************************************************************** * Name: s32k1xx_lpi2c_tousecs * @@ -1705,7 +1687,7 @@ static int s32k1xx_lpi2c_reset(FAR struct i2c_master_s *dev) /* Lock out other clients */ - ret = s32k1xx_lpi2c_sem_wait_uninterruptible(priv); + ret = s32k1xx_lpi2c_sem_wait(priv); if (ret < 0) { return ret; diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index d2f2cd278a..c35e3bf4e8 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/sama5/sam_ehci.c * - * Copyright (C) 2013, 2016-2017, 2019 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -91,8 +76,8 @@ # define CONFIG_SAMA5_EHCI_NQHS (SAM_EHCI_NRHPORT + 1) #endif -/* Configurable number of Queue Element Transfer Descriptor (qTDs). The default - * is one per root hub plus three from EP0. +/* Configurable number of Queue Element Transfer Descriptor (qTDs). The + * default is one per root hub plus three from EP0. */ #ifndef CONFIG_SAMA5_EHCI_NQTDS @@ -135,7 +120,7 @@ #undef CONFIG_SAMA5_UHPHS_RHPORT1 -/* Driver-private Definitions ************************************************/ +/* Driver-private Definitions ***********************************************/ /* This is the set of interrupts handled by this driver */ @@ -144,11 +129,11 @@ EHCI_INT_AAINT) /* The periodic frame list is a 4K-page aligned array of Frame List Link - * pointers. The length of the frame list may be programmable. The programmability - * of the periodic frame list is exported to system software via the HCCPARAMS - * register. If non-programmable, the length is 1024 elements. If programmable, - * the length can be selected by system software as one of 256, 512, or 1024 - * elements. + * pointers. The length of the frame list may be programmable. The + * programmability of the periodic frame list is exported to system software + * via the HCCPARAMS register. If non-programmable, the length is 1024 + * elements. If programmable, the length can be selected by system software + * as one of 256, 512, or 1024 elements. */ #define FRAME_LIST_SIZE 1024 @@ -161,6 +146,7 @@ /**************************************************************************** * Private Types ****************************************************************************/ + /* Internal representation of the EHCI Queue Head (QH) */ struct sam_epinfo_s; @@ -199,7 +185,8 @@ struct sam_list_s /* List traversal callout functions */ typedef int (*foreach_qh_t)(struct sam_qh_s *qh, uint32_t **bp, void *arg); -typedef int (*foreach_qtd_t)(struct sam_qtd_s *qtd, uint32_t **bp, void *arg); +typedef int (*foreach_qtd_t)(struct sam_qtd_s *qtd, uint32_t **bp, + void *arg); /* This structure describes one endpoint. */ @@ -276,7 +263,7 @@ struct sam_ehci_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ static uint16_t sam_read16(const uint8_t *addr); static uint32_t sam_read32(const uint8_t *addr); @@ -307,19 +294,20 @@ static inline void sam_putreg(uint32_t regval, volatile uint32_t *regaddr); static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, unsigned int delay); -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void sam_takesem(sem_t *sem); +static int sam_takesem(sem_t *sem); +static int sam_takesem_uninterruptible(sem_t *sem); #define sam_givesem(s) nxsem_post(s); -/* Allocators ******************************************************************/ +/* Allocators ***************************************************************/ static struct sam_qh_s *sam_qh_alloc(void); static void sam_qh_free(struct sam_qh_s *qh); static struct sam_qtd_s *sam_qtd_alloc(void); static void sam_qtd_free(struct sam_qtd_s *qtd); -/* List Management *************************************************************/ +/* List Management **********************************************************/ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handler, void *arg); @@ -328,16 +316,17 @@ static int sam_qtd_foreach(struct sam_qh_s *qh, foreach_qtd_t handler, static int sam_qtd_discard(struct sam_qtd_s *qtd, uint32_t **bp, void *arg); static int sam_qh_discard(struct sam_qh_s *qh); -/* Cache Operations ************************************************************/ +/* Cache Operations *********************************************************/ #if 0 /* Not used */ -static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, void *arg); +static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, + void *arg); static int sam_qh_invalidate(struct sam_qh_s *qh); #endif static int sam_qtd_flush(struct sam_qtd_s *qtd, uint32_t **bp, void *arg); static int sam_qh_flush(struct sam_qh_s *qh); -/* Endpoint Transfer Handling **************************************************/ +/* Endpoint Transfer Handling ***********************************************/ #ifdef CONFIG_SAMA5_EHCI_REGDEBUG static void sam_qtd_print(struct sam_qtd_s *qtd); @@ -352,12 +341,14 @@ static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg); #endif static inline uint8_t sam_ehci_speed(uint8_t usbspeed); -static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo); +static int sam_ioc_setup(struct sam_rhport_s *rhport, + struct sam_epinfo_s *epinfo); static int sam_ioc_wait(struct sam_epinfo_s *epinfo); static void sam_qh_enqueue(struct sam_qh_s *qhead, struct sam_qh_s *qh); static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo); -static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, size_t buflen); +static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, + size_t buflen); static struct sam_qtd_s *sam_qtd_setupphase(struct sam_epinfo_s *epinfo, const struct usb_ctrlreq_s *req); static struct sam_qtd_s *sam_qtd_dataphase(struct sam_epinfo_s *epinfo, @@ -378,7 +369,7 @@ static inline int sam_ioc_async_setup(struct sam_rhport_s *rhport, static void sam_asynch_completion(struct sam_epinfo_s *epinfo); #endif -/* Interrupt Handling **********************************************************/ +/* Interrupt Handling *******************************************************/ static int sam_qtd_ioccheck(struct sam_qtd_s *qtd, uint32_t **bp, void *arg); static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg); @@ -391,7 +382,7 @@ static inline void sam_async_advance_bottomhalf(void); static void sam_ehci_bottomhalf(FAR void *arg); static int sam_ehci_tophalf(int irq, FAR void *context, FAR void *arg); -/* USB Host Controller Operations **********************************************/ +/* USB Host Controller Operations *******************************************/ static int sam_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -400,8 +391,9 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, static int sam_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); -static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize); +static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize); static int sam_epalloc(FAR struct usbhost_driver_s *drvr, const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); @@ -410,13 +402,14 @@ static int sam_alloc(FAR struct usbhost_driver_s *drvr, static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); static int sam_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int sam_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, @@ -430,16 +423,17 @@ static int sam_connect(FAR struct usbhost_driver_s *drvr, static void sam_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static int sam_reset(void); /**************************************************************************** * Private Data ****************************************************************************/ + /* In this driver implementation, support is provided for only a single - * USB device. All status information can be simply retained in a single global - * instance. + * USB device. All status information can be simply retained in a single + * global instance. */ static struct sam_ehci_s g_ehci; @@ -506,9 +500,7 @@ static struct sam_qtd_s *g_qtdpool; /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Register Operations - ****************************************************************************/ + /**************************************************************************** * Name: sam_read16 * @@ -644,15 +636,16 @@ static void sam_printreg(volatile uint32_t *regaddr, uint32_t regval, ****************************************************************************/ #ifdef CONFIG_SAMA5_EHCI_REGDEBUG -static void sam_checkreg(volatile uint32_t *regaddr, uint32_t regval, bool iswrite) +static void sam_checkreg(volatile uint32_t *regaddr, uint32_t regval, + bool iswrite) { static uint32_t *prevaddr = NULL; static uint32_t preval = 0; static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (regaddr == prevaddr && regval == preval && prevwrite == iswrite) @@ -802,9 +795,6 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, return (regval == donebits) ? OK : -ETIMEDOUT; } -/**************************************************************************** - * Semaphores - ****************************************************************************/ /**************************************************************************** * Name: sam_takesem * @@ -814,14 +804,45 @@ static int ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, * ****************************************************************************/ -static void sam_takesem(sem_t *sem) +static int sam_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); } /**************************************************************************** - * Allocators + * Name: sam_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * ****************************************************************************/ + +static int sam_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; +} + /**************************************************************************** * Name: sam_qh_alloc * @@ -872,8 +893,8 @@ static void sam_qh_free(struct sam_qh_s *qh) * Name: sam_qtd_alloc * * Description: - * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from the - * free list + * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from + * the free list * * Assumption: Caller holds the exclsem * @@ -899,8 +920,8 @@ static struct sam_qtd_s *sam_qtd_alloc(void) * Name: sam_qtd_free * * Description: - * Free a Queue Element Transfer Descriptor (qTD) by returning it to the free - * list + * Free a Queue Element Transfer Descriptor (qTD) by returning it to the + * free list * * Assumption: Caller holds the exclsem * @@ -916,10 +937,6 @@ static void sam_qtd_free(struct sam_qtd_s *qtd) g_ehci.qtdfree = entry; } -/**************************************************************************** - * List Management - ****************************************************************************/ - /**************************************************************************** * Name: sam_qh_foreach * @@ -930,8 +947,8 @@ static void sam_qtd_free(struct sam_qtd_s *qtd) * ****************************************************************************/ -static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handler, - void *arg) +static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, + foreach_qh_t handler, void *arg) { struct sam_qh_s *next; uintptr_t physaddr; @@ -940,8 +957,9 @@ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handl DEBUGASSERT(qh && handler); while (qh) { - /* Is this the end of the list? Check the horizontal link pointer (HLP) - * terminate (T) bit. If T==1, then the HLP address is not valid. + /* Is this the end of the list? Check the horizontal link pointer + * (HLP) terminate (T) bit. If T==1, then the HLP address is not + * valid. */ physaddr = sam_swap32(qh->hw.hlp); @@ -956,7 +974,8 @@ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handl * the end of the asynchronous queue? */ - else if (sam_virtramaddr(physaddr & QH_HLP_MASK) == (uintptr_t)&g_asynchead) + else if (sam_virtramaddr(physaddr & QH_HLP_MASK) == + (uintptr_t)&g_asynchead) { /* That will also terminate the loop */ @@ -977,14 +996,14 @@ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handl * unlinking the entry! But that is okay because we already have the * next QH pointer. * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qh, bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1009,7 +1028,8 @@ static int sam_qh_foreach(struct sam_qh_s *qh, uint32_t **bp, foreach_qh_t handl * ****************************************************************************/ -static int sam_qtd_foreach(struct sam_qh_s *qh, foreach_qtd_t handler, void *arg) +static int sam_qtd_foreach(struct sam_qh_s *qh, foreach_qtd_t handler, + void *arg) { struct sam_qtd_s *qtd; struct sam_qtd_s *next; @@ -1056,16 +1076,16 @@ static int sam_qtd_foreach(struct sam_qh_s *qh, foreach_qtd_t handler, void *arg /* Perform the user action on this entry. The action might result in * unlinking the entry! But that is okay because we already have the - * next qTD pointer. + * next QH pointer. * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. + * Notice that we do not manage the back pointer (bp). If the call- + * out uses it, it must update it as necessary. */ ret = handler(qtd, &bp, arg); - /* If the handler returns any non-zero value, then terminate the traversal - * early. + /* If the handler returns any non-zero value, then terminate the + * traversal early. */ if (ret != 0) @@ -1139,21 +1159,18 @@ static int sam_qh_discard(struct sam_qh_s *qh) return ret; } -/**************************************************************************** - * Cache Operations - ****************************************************************************/ - /**************************************************************************** * Name: sam_qtd_invalidate * * Description: - * This is a callback from sam_qtd_foreach. It simply invalidates D-cache for - * address range of the qTD entry. + * This is a callback from sam_qtd_foreach. It simply invalidates D-cache + * for address range of the qTD entry. * ****************************************************************************/ #if 0 /* Not used */ -static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, void *arg) +static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, + void *arg) { /* Invalidate the D-Cache, i.e., force reloading of the D-Cache from memory * memory over the specified address range. @@ -1198,9 +1215,10 @@ static int sam_qh_invalidate(struct sam_qh_s *qh) static int sam_qtd_flush(struct sam_qtd_s *qtd, uint32_t **bp, void *arg) { - /* Flush the D-Cache, i.e., make the contents of the memory match the contents - * of the D-Cache in the specified address range and invalidate the D-Cache - * to force re-loading of the data from memory when next accessed. + /* Flush the D-Cache, i.e., make the contents of the memory match the + * contents of the D-Cache in the specified address range and invalidate + * the D-Cache to force re-loading of the data from memory when next + * accessed. */ #if 0 /* Didn't behave as expected */ @@ -1226,9 +1244,9 @@ static int sam_qtd_flush(struct sam_qtd_s *qtd, uint32_t **bp, void *arg) static int sam_qh_flush(struct sam_qh_s *qh) { - /* Flush the QH first. This will write the contents of the D-cache to RAM and - * invalidate the contents of the D-cache so that the next access will be - * reloaded from D-Cache. + /* Flush the QH first. This will write the contents of the D-cache to RAM + * and invalidate the contents of the D-cache so that the next access will + * be reloaded from D-Cache. */ #if 0 /* Didn't behave as expected */ @@ -1246,10 +1264,6 @@ static int sam_qh_flush(struct sam_qh_s *qh) return sam_qtd_foreach(qh, sam_qtd_flush, NULL); } -/**************************************************************************** - * Endpoint Transfer Handling - ****************************************************************************/ - /**************************************************************************** * Name: sam_qtd_print * @@ -1351,8 +1365,8 @@ static int sam_qh_dump(struct sam_qh_s *qh, uint32_t **bp, void *arg) * Name: sam_ehci_speed * * Description: - * Map a speed enumeration value per Chapter 9 of the USB specification to the - * speed enumeration required in the EHCI queue head. + * Map a speed enumeration value per Chapter 9 of the USB specification to + * the speed enumeration required in the EHCI queue head. * ****************************************************************************/ @@ -1367,15 +1381,16 @@ static inline uint8_t sam_ehci_speed(uint8_t usbspeed) * * Description: * Set the request for the IOC event well BEFORE enabling the transfer (as - * soon as we are absolutely committed to the to avoid transfer). We do this - * to minimize race conditions. This logic would have to be expanded if we - * want to have more than one packet in flight at a time! + * soon as we are absolutely committed to the to avoid transfer). We do + * this to minimize race conditions. This logic would have to be expanded + * if we want to have more than one packet in flight at a time! * * Assumption: The caller holds tex EHCI exclsem * ****************************************************************************/ -static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinfo) +static int sam_ioc_setup(struct sam_rhport_s *rhport, + struct sam_epinfo_s *epinfo) { irqstate_t flags; int ret = -ENODEV; @@ -1416,21 +1431,30 @@ static int sam_ioc_setup(struct sam_rhport_s *rhport, struct sam_epinfo_s *epinf * Description: * Wait for the IOC event. * - * Assumption: The caller does *NOT* hold the EHCI exclsem. That would cause - * a deadlock when the bottom-half, worker thread needs to take the semaphore. + * Assumption: The caller does *NOT* hold the EHCI exclsem. That would + * cause a deadlock when the bottom-half, worker thread needs to take the + * semaphore. * ****************************************************************************/ static int sam_ioc_wait(struct sam_epinfo_s *epinfo) { - /* Wait for the IOC event. Loop to handle any false alarm semaphore counts. */ + int ret = OK; + + /* Wait for the IOC event. Loop to handle any false alarm semaphore + * counts. Return an error if the task is canceled. + */ while (epinfo->iocwait) { - sam_takesem(&epinfo->iocsem); + ret = sam_takesem(&epinfo->iocsem); + if (ret < 0) + { + break; + } } - return epinfo->result; + return ret < 0 ? ret : epinfo->result; } /**************************************************************************** @@ -1457,15 +1481,15 @@ static void sam_qh_enqueue(struct sam_qh_s *qhead, struct sam_qh_s *qh) /* Add the new QH to the head of the asynchronous queue list. * - * First, attach the old head as the new QH HLP and flush the new QH and its - * attached qTDs to RAM. + * First, attach the old head as the new QH HLP and flush the new QH and + * its attached qTDs to RAM. */ qh->hw.hlp = qhead->hw.hlp; sam_qh_flush(qh); - /* Then set the new QH as the first QH in the asychronous queue and flush the - * modified head to RAM. + /* Then set the new QH as the first QH in the asynchronous queue and flush + * the modified head to RAM. */ physaddr = (uintptr_t)sam_physramaddr((uintptr_t)qh); @@ -1619,15 +1643,16 @@ static struct sam_qh_s *sam_qh_create(struct sam_rhport_s *rhport, * ****************************************************************************/ -static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, size_t buflen) +static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, + size_t buflen) { uint32_t physaddr; uint32_t nbytes; uint32_t next; int ndx; - /* Flush the contents of the data buffer to RAM so that the correct contents - * will be accessed for an OUT DMA. + /* Flush the contents of the data buffer to RAM so that the correct + * contents will be accessed for an OUT DMA. */ #if 0 /* Didn't behave as expected */ @@ -1637,25 +1662,25 @@ static int sam_qtd_addbpl(struct sam_qtd_s *qtd, const void *buffer, size_t bufl up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)buffer + buflen); #endif - /* Loop, adding the aligned physical addresses of the buffer to the buffer page - * list. Only the first entry need not be aligned (because only the first - * entry has the offset field). The subsequent entries must begin on 4KB - * address boundaries. + /* Loop, adding the aligned physical addresses of the buffer to the buffer + * page list. Only the first entry need not be aligned (because only the + * first entry has the offset field). The subsequent entries must begin on + * 4KB address boundaries. */ physaddr = (uint32_t)sam_physramaddr((uintptr_t)buffer); for (ndx = 0; ndx < 5; ndx++) { - /* Write the physical address of the buffer into the qTD buffer pointer - * list. + /* Write the physical address of the buffer into the qTD buffer + * pointer list. */ qtd->hw.bpl[ndx] = sam_swap32(physaddr); - /* Get the next buffer pointer (in the case where we will have to transfer - * more then one chunk). This buffer must be aligned to a 4KB address - * boundary. + /* Get the next buffer pointer (in the case where we will have to + * transfer more then one chunk). This buffer must be aligned to a + * 4KB address boundary. */ next = (physaddr + 4096) & ~4095; @@ -1879,13 +1904,13 @@ static struct sam_qtd_s *sam_qtd_statusphase(uint32_t tokenbits) * Name: sam_async_setup * * Description: - * Process a IN or OUT request on any asynchronous endpoint (bulk or control). - * This function will enqueue the request and wait for it to complete. Bulk - * data transfers differ in that req == NULL and there are not SETUP or STATUS - * phases. + * Process a IN or OUT request on any asynchronous endpoint (bulk or + * control). This function will enqueue the request and wait for it to + * complete. Bulk data transfers differ in that req == NULL and there are + * not SETUP or STATUS phases. * - * This is a blocking function; it will not return until the control transfer - * has completed. + * This is a blocking function; it will not return until the control + * transfer has completed. * * Assumption: The caller holds the EHCI exclsem. * @@ -1920,8 +1945,8 @@ static int sam_async_setup(struct sam_rhport_s *rhport, DEBUGASSERT(rhport && epinfo); - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ DEBUGASSERT(req || (buffer && buflen > 0)); @@ -1978,8 +2003,8 @@ static int sam_async_setup(struct sam_rhport_s *rhport, toggle = QTD_TOKEN_TOGGLE; } - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer will - * always be present for normal endpoint data transfers. + /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer + * will always be present for normal endpoint data transfers. */ alt = NULL; @@ -2135,19 +2160,20 @@ errout_with_qh: * into the periodic frame list. * * Paragraph 4.10.7 "Adding Interrupt Queue Heads to the Periodic Schedule" - * "The link path(s) from the periodic frame list to a queue head establishes - * in which frames a transaction can be executed for the queue head. Queue - * heads are linked into the periodic schedule so they are polled at - * the appropriate rate. System software sets a bit in a queue head's - * S-Mask to indicate which micro-frame with-in a 1 millisecond period a - * transaction should be executed for the queue head. Software must ensure - * that all queue heads in the periodic schedule have S-Mask set to a non- - * zero value. An S-mask with a zero value in the context of the periodic - * schedule yields undefined results. + * "The link path(s) from the periodic frame list to a queue head + * establishes in which frames a transaction can be executed for the + * queue head. Queue heads are linked into the periodic schedule so they + * are polled at the appropriate rate. System software sets a bit in a + * queue head's S-Mask to indicate which micro-frame with-in a 1 + * millisecond period a transaction should be executed for the queue + * head. Software must ensure that all queue heads in the periodic + * schedule have S-Mask set to a non-zero value. An S-mask with a zero + * value in the context of the periodic schedule yields undefined + * results. * - * "If the desired poll rate is greater than one frame, system software can - * use a combination of queue head linking and S-Mask values to spread - * interrupts of equal poll rates through the schedule so that the + * "If the desired poll rate is greater than one frame, system software + * can use a combination of queue head linking and S-Mask values to + * spread interrupts of equal poll rates through the schedule so that the * periodic bandwidth is allocated and managed in the most efficient * manner possible." * @@ -2277,16 +2303,18 @@ errout_with_qh: * EHCI resources could be very different upon return. * * Returned Value: - * On success, this function returns the number of bytes actually transferred. - * For control transfers, this size includes the size of the control request - * plus the size of the data (which could be short); For bulk transfers, this - * will be the number of data bytes transfers (which could be short). + * On success, this function returns the number of bytes actually + * transferred. For control transfers, this size includes the size of the + * control request plus the size of the data (which could be short); for + * bulk transfers, this will be the number of data bytes transfers (which + * could be short). * ****************************************************************************/ static ssize_t sam_transfer_wait(struct sam_epinfo_s *epinfo) { int ret; + int ret2; /* Release the EHCI semaphore while we wait. Other threads need the * opportunity to access the EHCI resources while we wait. @@ -2308,7 +2336,11 @@ static ssize_t sam_transfer_wait(struct sam_epinfo_s *epinfo) * this upon return. */ - sam_takesem(&g_ehci.exclsem); + ret2 = sam_takesem_uninterruptible(&g_ehci.exclsem); + if (ret2 < 0) + { + ret = ret2; + } #if 0 /* Does not seem to be needed */ /* Was there a data buffer? Was this an OUT transfer? */ @@ -2328,7 +2360,7 @@ static ssize_t sam_transfer_wait(struct sam_epinfo_s *epinfo) } #endif - /* Did sam_ioc_wait() report an error? */ + /* Did sam_ioc_wait() or sam_takesem_uninterruptible() report an error? */ if (ret < 0) { @@ -2453,17 +2485,13 @@ static void sam_asynch_completion(struct sam_epinfo_s *epinfo) } #endif -/**************************************************************************** - * EHCI Interrupt Handling - ****************************************************************************/ - /**************************************************************************** * Name: sam_qtd_ioccheck * * Description: - * This function is a sam_qtd_foreach() callback function. It services one - * qTD in the asynchronous queue. It removes all of the qTD structures that - * are no longer active. + * This function is a sam_qtd_foreach() callback function. It services + * one qTD in the asynchronous queue. It removes all of the qTD + * structures that are no longer active. * ****************************************************************************/ @@ -2536,14 +2564,15 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg) epinfo = qh->epinfo; DEBUGASSERT(epinfo); - /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area represent - * a transaction working space for the host controller. The general - * operational model is that the host controller can detect whether the - * overlay area contains a description of an active transfer. If it does - * not contain an active transfer, then it follows the Queue Head Horizontal - * Link Pointer to the next queue head. The host controller will never follow - * the Next Transfer Queue Element or Alternate Queue Element pointers unless - * it is actively attempting to advance the queue ..." + /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area + * represent a transaction working space for the host controller. The + * general operational model is that the host controller can detect + * whether the overlay area contains a description of an active transfer. + * If it does not contain an active transfer, then it follows the Queue + * Head Horizontal Link Pointer to the next queue head. The host + * controller will never follow the Next Transfer Queue Element or + * Alternate Queue Element pointers unless it is actively attempting to + * advance the queue ..." */ /* Is the qTD still active? */ @@ -2556,6 +2585,7 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg) /* Yes... we cannot process the QH while it is still active. Return * zero to visit the next QH in the list. */ + *bp = &qh->hw.hlp; return OK; } @@ -2598,16 +2628,18 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg) { /* An error occurred */ - epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> QH_TOKEN_STATUS_SHIFT; + epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> + QH_TOKEN_STATUS_SHIFT; - /* The HALT condition is set on a variety of conditions: babble, error - * counter countdown to zero, or a STALL. If we can rule out babble - * (babble bit not set) and if the error counter is non-zero, then we can - * assume a STALL. In this case, we return -PERM to inform the class - * driver of the stall condition. + /* The HALT condition is set on a variety of conditions: babble, + * error counter countdown to zero, or a STALL. If we can rule + * out babble (babble bit not set) and if the error counter is + * non-zero, then we can assume a STALL. In this case, we return + * -PERM to inform the class driver of the stall condition. */ - if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == QH_TOKEN_HALTED && + if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == + QH_TOKEN_HALTED && (token & QH_TOKEN_CERR_MASK) != 0) { /* It is a stall, Note that the data toggle is reset @@ -2654,7 +2686,8 @@ static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg) } else { - /* Otherwise, the horizontal link pointer of this QH will become the next back pointer. + /* Otherwise, the horizontal link pointer of this QH will become the + * next back pointer. */ *bp = &qh->hw.hlp; @@ -2704,10 +2737,10 @@ static int sam_qtd_cancel(struct sam_qtd_s *qtd, uint32_t **bp, void *arg) * Name: sam_qh_cancel * * Description: - * This function is a sam_qh_foreach() callback function. It cancels one - * QH in the asynchronous queue. It will remove all attached qTD structures - * and remove all of the structures that are no longer active. Then QH - * itself will also be removed. + * This function is a imxrt_qh_foreach() callback function. It cancels + * one QH in the asynchronous queue. It will remove all attached qTD + * structures and remove all of the structures that are no longer active. + * Then QH itself will also be removed. * ****************************************************************************/ @@ -2779,13 +2812,13 @@ static int sam_qh_cancel(struct sam_qh_s *qh, uint32_t **bp, void *arg) * Description: * EHCI USB Interrupt (USBINT) "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 on the completion of a USB - * transaction, which results in the retirement of a Transfer Descriptor that - * had its IOC bit set. + * "The Host Controller sets this bit to 1 on the completion of a USB + * transaction, which results in the retirement of a Transfer Descriptor + * that had its IOC bit set. * - * "The Host Controller also sets this bit to 1 when a short packet is detected - * (actual number of bytes received was less than the expected number of - * bytes)." + * "The Host Controller also sets this bit to 1 when a short packet is + * detected (actual number of bytes received was less than the expected + * number of bytes)." * * Assumptions: The caller holds the EHCI exclsem * @@ -2798,10 +2831,12 @@ static inline void sam_ioc_bottomhalf(void) int ret; /* Check the Asynchronous Queue */ + /* Make sure that the head of the asynchronous queue is invalidated */ up_invalidate_dcache((uintptr_t)&g_asynchead.hw, - (uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s)); + (uintptr_t)&g_asynchead.hw + + sizeof(struct ehci_qh_s)); /* Set the back pointer to the forward QH pointer of the asynchronous * queue head. @@ -2829,6 +2864,7 @@ static inline void sam_ioc_bottomhalf(void) #ifndef CONFIG_USBHOST_INT_DISABLE /* Check the Interrupt Queue */ + /* Make sure that the head of the interrupt queue is invalidated */ up_invalidate_dcache((uintptr_t)&g_intrhead.hw, @@ -2861,19 +2897,19 @@ static inline void sam_ioc_bottomhalf(void) * Description: * EHCI Port Change Detect "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to a one when any port for which the Port - * Owner bit is set to zero ... has a change bit transition from a zero to a - * one or a Force Port Resume bit transition from a zero to a one as a result - * of a J-K transition detected on a suspended port. This bit will also be set - * as a result of the Connect Status Change being set to a one after system - * software has relinquished ownership of a connected port by writing a one - * to a port's Port Owner bit... + * "The Host Controller sets this bit to a one when any port for which the + * Port Owner bit is set to zero ... has a change bit transition from a + * zero to a one or a Force Port Resume bit transition from a zero to a + * one as a result of a J-K transition detected on a suspended port. + * This bit will also be set as a result of the Connect Status Change + * being set to a one after system software has relinquished ownership of + * a connected port by writing a one to a port's Port Owner bit... * * "This bit is allowed to be maintained in the Auxiliary power well. - * Alternatively, it is also acceptable that on a D3 to D0 transition of the - * EHCI HC device, this bit is loaded with the OR of all of the PORTSC change - * bits (including: Force port resume, over-current change, enable/disable - * change and connect status change)." + * Alternatively, it is also acceptable that on a D3 to D0 transition of + * the EHCI HC device, this bit is loaded with the OR of all of the PORTSC + * change bits (including: Force port resume, over-current change, + * enable/disable change and connect status change)." * ****************************************************************************/ @@ -2936,7 +2972,7 @@ static inline void sam_portsc_bottomhalf(void) /* Yes.. disconnect the device */ usbhost_vtrace2(EHCI_VTRACE2_PORTSC_DISCONND, - rhpndx+1, g_ehci.pscwait); + rhpndx + 1, g_ehci.pscwait); rhport->connected = false; @@ -2983,10 +3019,10 @@ static inline void sam_portsc_bottomhalf(void) * Description: * EHCI Host System Error "Bottom Half" interrupt handler * - * "The Host Controller sets this bit to 1 when a serious error occurs during a - * host system access involving the Host Controller module. ... When this - * error occurs, the Host Controller clears the Run/Stop bit in the Command - * register to prevent further execution of the scheduled TDs." + * "The Host Controller sets this bit to 1 when a serious error occurs + * during a host system access involving the Host Controller module. ... + * When this error occurs, the Host Controller clears the Run/Stop bit in + * the Command register to prevent further execution of the scheduled TDs." * ****************************************************************************/ @@ -3003,10 +3039,10 @@ static inline void sam_syserr_bottomhalf(void) * EHCI Async Advance "Bottom Half" interrupt handler * * "System software can force the host controller to issue an interrupt the - * next time the host controller advances the asynchronous schedule by writing - * a one to the Interrupt on Async Advance Doorbell bit in the USBCMD - * register. This status bit indicates the assertion of that interrupt - * source." + * next time the host controller advances the asynchronous schedule by + * writing a one to the Interrupt on Async Advance Doorbell bit in the + * USBCMD register. This status bit indicates the assertion of that + * interrupt source." * ****************************************************************************/ @@ -3029,14 +3065,15 @@ static void sam_ehci_bottomhalf(FAR void *arg) { uint32_t pending = (uint32_t)arg; - /* We need to have exclusive access to the EHCI data structures. Waiting here - * is not a good thing to do on the worker thread, but there is no real option - * (other than to reschedule and delay). + /* We need to have exclusive access to the EHCI data structures. Waiting + * here is not a good thing to do on the worker thread, but there is no + * real option (other than to reschedule and delay). */ - sam_takesem(&g_ehci.exclsem); + sam_takesem_uninterruptible(&g_ehci.exclsem); /* Handle all unmasked interrupt sources */ + /* USB Interrupt (USBINT) * * "The Host Controller sets this bit to 1 on the completion of a USB @@ -3096,13 +3133,14 @@ static void sam_ehci_bottomhalf(FAR void *arg) /* Frame List Rollover * - * "The Host Controller sets this bit to a one when the Frame List Index ... - * rolls over from its maximum value to zero. The exact value at which - * the rollover occurs depends on the frame list size. For example, if - * the frame list size (as programmed in the Frame List Size field of the - * USBCMD register) is 1024, the Frame Index Register rolls over every - * time FRINDEX[13] toggles. Similarly, if the size is 512, the Host - * Controller sets this bit to a one every time FRINDEX[12] toggles." + * "The Host Controller sets this bit to a one when the Frame List Index + * ... rolls over from its maximum value to zero. The exact value at + * which the rollover occurs depends on the frame list size. For example, + * if the frame list size (as programmed in the Frame List Size field of + * the USBCMD register) is 1024, the Frame Index Register rolls over + * every time FRINDEX[13] toggles. Similarly, if the size is 512, the + * Host Controller sets this bit to a one every time FRINDEX[12] + * toggles." */ #if 0 /* Not used */ @@ -3181,9 +3219,9 @@ static int sam_ehci_tophalf(int irq, FAR void *context, FAR void *arg) pending = usbsts & regval; if (pending != 0) { - /* Schedule interrupt handling work for the high priority worker thread - * so that we are not pressed for time and so that we can interrupt with - * other USB threads gracefully. + /* Schedule interrupt handling work for the high priority worker + * thread so that we are not pressed for time and so that we can + * interrupt with other USB threads gracefully. * * The worker should be available now because we implement a handshake * by controlling the EHCI interrupts. @@ -3213,9 +3251,9 @@ static int sam_ehci_tophalf(int irq, FAR void *context, FAR void *arg) * Name: sam_uhphs_interrupt * * Description: - * Common UHPHS interrupt handler. When both OHCI and EHCI are enabled, EHCI - * owns the interrupt and provides the interrupting event to both the OHCI and - * EHCI controllers. + * Common UHPHS interrupt handler. When both OHCI and EHCI are enabled, + * EHCI owns the interrupt and provides the interrupting event to both the + * OHCI and EHCI controllers. * ****************************************************************************/ @@ -3236,9 +3274,6 @@ static int sam_uhphs_interrupt(int irq, FAR void *context, FAR void *arg) } #endif -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ /**************************************************************************** * Name: sam_wait * @@ -3246,8 +3281,8 @@ static int sam_uhphs_interrupt(int irq, FAR void *context, FAR void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from the + * call to the USB driver initialization logic. * hport - The location to return the hub port descriptor that detected the * connection related event. * @@ -3269,9 +3304,10 @@ static int sam_wait(FAR struct usbhost_connection_s *conn, { irqstate_t flags; int rhpndx; + int ret; - /* Loop until a change in the connection state changes on one of the root hub - * ports or until an error occurs. + /* Loop until the connection state changes on one of the root hub ports or + * until an error occurs. */ flags = enter_critical_section(); @@ -3330,7 +3366,11 @@ static int sam_wait(FAR struct usbhost_connection_s *conn, */ g_ehci.pscwait = true; - sam_takesem(&g_ehci.pscsem); + ret = sam_takesem(&g_ehci.pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3348,14 +3388,14 @@ static int sam_wait(FAR struct usbhost_connection_s *conn, * charge of the sequence of operations. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from - * the call to the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. * hport - The descriptor of the hub port that has the newly connected - * device. + * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3393,7 +3433,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, * reset for 50Msec, not wait 50Msec before resetting. */ - nxsig_usleep(100*1000); + nxsig_usleep(100 * 1000); /* Paragraph 2.3.9: * @@ -3469,7 +3509,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, /* Put the root hub port in reset. * - * Paragraph 2.3.9: + * EHCI Paragraph 2.3.9: * * "The HCHalted bit in the USBSTS register should be a zero before * software attempts to use [the Port Reset] bit. The host controller @@ -3478,15 +3518,15 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, DEBUGASSERT((sam_getreg(&HCOR->usbsts) & EHCI_USBSTS_HALTED) == 0); - /* paragraph 2.3.9: + /* EHCI Paragraph 2.3.9: * * "When software writes a one to [the Port Reset] bit (from a zero), the - * bus reset sequence as defined in the USB Specification Revision 2.0 is - * started. Software writes a zero to this bit to terminate the bus reset - * sequence. Software must keep this bit at a one long enough to ensure - * the reset sequence, as specified in the USB Specification Revision 2.0, - * completes. Note: when software writes this bit to a one, it must also - * write a zero to the Port Enable bit." + * bus reset sequence as defined in the USB Specification Revision 2.0 + * is started. Software writes a zero to this bit to terminate the bus + * reset sequence. Software must keep this bit at a one long enough to + * ensure the reset sequence, as specified in the USB Specification + * Revision 2.0, completes. Note: when software writes this bit to a + * one, it must also write a zero to the Port Enable bit." */ regaddr = &HCOR->portsc[RHPNDX(rhport)]; @@ -3499,7 +3539,7 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, * 50 ms." */ - nxsig_usleep(50*1000); + nxsig_usleep(50 * 1000); regval = sam_getreg(regaddr); regval &= ~EHCI_PORTSC_RESET; @@ -3520,22 +3560,23 @@ static int sam_rh_enumerate(FAR struct usbhost_connection_s *conn, */ while ((sam_getreg(regaddr) & EHCI_PORTSC_RESET) != 0); - nxsig_usleep(200*1000); + nxsig_usleep(200 * 1000); /* Paragraph 4.2.2: * * "... The reset process is actually complete when software reads a zero - * in the PortReset bit. The EHCI Driver checks the PortEnable bit in the - * PORTSC register. If set to a one, the connected device is a high-speed - * device and EHCI Driver (root hub emulator) issues a change report to the - * hub driver and the hub driver continues to enumerate the attached device." + * in the PortReset bit. The EHCI Driver checks the PortEnable bit in + * the PORTSC register. If set to a one, the connected device is a high- + * speed device and EHCI Driver (root hub emulator) issues a change + * report to the hub driver and the hub driver continues to enumerate + * the attached device." * - * "At the time the EHCI Driver receives the port reset and enable request - * the LineStatus bits might indicate a low-speed device. Additionally, - * when the port reset process is complete, the PortEnable field may - * indicate that a full-speed device is attached. In either case the EHCI - * driver sets the PortOwner bit in the PORTSC register to a one to - * release port ownership to a companion host controller." + * "At the time the EHCI Driver receives the port reset and enable + * request the LineStatus bits might indicate a low-speed device. + * Additionally, when the port reset process is complete, the PortEnable + * field may indicate that a full-speed device is attached. In either + * case the EHCI driver sets the PortOwner bit in the PORTSC register to + * a one to release port ownership to a companion host controller." */ regval = sam_getreg(&HCOR->portsc[rhpndx]); @@ -3617,8 +3658,9 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, hport->port + 1, -ret); - /* If this is a root hub port, then marking the hub port not connected will - * cause sam_wait() to return and we will try the connection again. + /* If this is a root hub port, then marking the hub port not connected + * will cause sam_wait() to return and we will try the connection + * again. */ hport->connected = false; @@ -3627,7 +3669,7 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_ep0configure * * Description: @@ -3636,79 +3678,86 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * 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. A funcaddr of zero will be received if no address is yet assigned - * to the device. + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) +static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep0; + int ret; usbhost_vtrace2(EHCI_VTRACE2_EP0CONFIG, speed, funcaddr); DEBUGASSERT(drvr != NULL && epinfo != NULL && maxpacketsize < 2048); /* We must have exclusive access to the EHCI data structures. */ - sam_takesem(&g_ehci.exclsem); + ret = sam_takesem(&g_ehci.exclsem); + if (ret >= 0) + { + /* Remember the new device address and max packet size */ - /* Remember the new device address and max packet size */ + epinfo->devaddr = funcaddr; + epinfo->speed = speed; + epinfo->maxpacket = maxpacketsize; - epinfo->devaddr = funcaddr; - epinfo->speed = speed; - epinfo->maxpacket = maxpacketsize; + sam_givesem(&g_ehci.exclsem); + } - sam_givesem(&g_ehci.exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_epalloc(FAR struct usbhost_driver_s *drvr, - const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const FAR struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct sam_epinfo_s *epinfo; struct usbhost_hubport_s *hport; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ - DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && ep != NULL); + DEBUGASSERT(drvr != 0 && epdesc != NULL && epdesc->hport != NULL && + ep != NULL); hport = epdesc->hport; /* Terse output only if we are tracing */ @@ -3753,33 +3802,33 @@ static int sam_epalloc(FAR struct usbhost_driver_s *drvr, nxsem_init(&epinfo->iocsem, 0, 0); nxsem_setprotocol(&epinfo->iocsem, SEM_PRIO_NONE); - /* Success.. return an opaque reference to the endpoint information structure - * instance + /* Success.. return an opaque reference to the endpoint information + * structure instance */ *ep = (usbhost_ep_t)epinfo; return OK; } -/************************************************************************************ +/**************************************************************************** * Name: sam_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The endpint to be freed. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The endpint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -3799,10 +3848,11 @@ static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: sam_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * allocate the request/descriptor memory. If the underlying hardware does - * not support such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc(). * * This interface was optimized under a particular assumption. It was * assumed that the driver maintains a pool of small, pre-allocated buffers @@ -3810,16 +3860,16 @@ static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. - * buffer - The address of a memory location provided by the caller in which - * to return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which - * to return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3833,12 +3883,13 @@ static int sam_alloc(FAR struct usbhost_driver_s *drvr, int ret = -ENOMEM; DEBUGASSERT(drvr && buffer && maxlen); - /* The only special requirements for transfer/descriptor buffers are that (1) - * they be aligned to a cache line boundary and (2) they are a multiple of the - * cache line size in length. + /* The only special requirements for transfer/descriptor buffers are that + * (1) they be aligned to a cache line boundary and (2) they are a + * multiple of the cache line size in length. */ - *buffer = (FAR uint8_t *)kmm_memalign(ARMV7A_DCACHE_LINESIZE, SAMA5_EHCI_BUFSIZE); + *buffer = (FAR uint8_t *) + kmm_memalign(ARMV7A_DCACHE_LINESIZE, SAMA5_EHCI_BUFSIZE); if (*buffer) { *maxlen = SAMA5_EHCI_BUFSIZE; @@ -3852,19 +3903,20 @@ static int sam_alloc(FAR struct usbhost_driver_s *drvr, * Name: sam_free * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * free that request/descriptor memory. If the underlying hardware does not - * support such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -3881,42 +3933,44 @@ static int sam_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: sam_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kumm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kumm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are variable- + * sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, - size_t buflen) +static int sam_ioalloc(FAR struct usbhost_driver_s *drvr, + FAR uint8_t **buffer, size_t buflen) { DEBUGASSERT(drvr && buffer && buflen > 0); - /* The only special requirements for I/O buffers are that (1) they be aligned to a - * cache line boundary, (2) they are a multiple of the cache line size in length, - * and (3) they might need to be user accessible (depending on how the class driver - * implements its buffering). + /* The only special requirements for I/O buffers are that (1) they be + * aligned to a cache line boundary, (2) they are a multiple of the cache + * line size in length, and (3) they might need to be user accessible + * (depending on how the class driver implements its buffering). */ buflen = (buflen + DCACHE_LINEMASK) & ~DCACHE_LINEMASK; @@ -3924,28 +3978,28 @@ static int sam_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, return *buffer ? OK : -ENOMEM; } -/************************************************************************************ +/**************************************************************************** * Name: sam_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kumm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) { @@ -3962,29 +4016,30 @@ static int sam_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The control endpoint to send/receive the control request. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any - * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * responses. This buffer must be large enough to hold the + * length value in the request description. buffer must have been + * allocated using DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4011,14 +4066,19 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, #ifdef CONFIG_USBHOST_TRACE usbhost_vtrace2(EHCI_VTRACE2_CTRLINOUT, RHPORT(rhport), req->req); #else - uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %04x\n", + uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x " + "len: %04x\n", RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], len); #endif /* We must have exclusive access to the EHCI hardware and data structures. */ - sam_takesem(&g_ehci.exclsem); + ret = sam_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4067,26 +4127,27 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4100,8 +4161,9 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep; @@ -4112,7 +4174,11 @@ static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the EHCI hardware and data structures. */ - sam_takesem(&g_ehci.exclsem); + ret = sam_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Set the request for the IOC event well BEFORE initiating the transfer. */ @@ -4183,20 +4249,21 @@ errout_with_sem: * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC - * buflen - The length of the data to be sent or received. + * drvr - The USB host driver instance obtained as a parameter from + * the call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated + * using DRVR_ALLOC + * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4217,7 +4284,11 @@ static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the EHCI hardware and data structures. */ - sam_takesem(&g_ehci.exclsem); + ret = sam_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the callback well BEFORE initiating the transfer. */ @@ -4274,24 +4345,26 @@ errout_with_sem: } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: sam_cancel * * Description: - * Cancel a pending transfer on an endpoint. Cancelled synchronous or - * asynchronous transfer will complete normally with the error -ESHUTDOWN. + * New connections may be detected by an attached hub. This method is the + * mechanism that is used by the hub class to introduce a new connection + * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The descriptor of the hub port that detected the connection + * related event + * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4308,20 +4381,25 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(epinfo); - /* We must have exclusive access to the EHCI hardware and data structures. This - * will prevent servicing any transfer completion events while we perform the - * the cancellation, but will not prevent DMA-related race conditions. + /* We must have exclusive access to the EHCI hardware and data structures. + * This will prevent servicing any transfer completion events while we + * perform the cancellation, but will not prevent DMA-related race + * conditions. * - * REVISIT: This won't work. This function must be callable from the interrupt - * level. + * REVISIT: This won't work. This function must be callable from the + * interrupt level. */ - sam_takesem(&g_ehci.exclsem); + ret = sam_takesem(&g_ehci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } - /* Sample and reset all transfer termination information. This will prevent any - * callbacks from occurring while are performing the cancellation. The transfer - * may still be in progress, however, so this does not eliminate other DMA- - * related race conditions. + /* Sample and reset all transfer termination information. This will + * prevent any callbacks from occurring while are performing the + * cancellation. The transfer may still be in progress, however, so this + * does not eliminate other DMA-related race conditions. */ flags = enter_critical_section(); @@ -4362,7 +4440,8 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK); + qh = (struct sam_qh_s *) + sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK); /* If the asynchronous queue is empty, then the forward point in * the asynchronous queue head will point back to the queue @@ -4387,7 +4466,8 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) */ bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK); + qh = (struct sam_qh_s *) + sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK); if (qh) { /* if the queue is empty, then just claim that we successfully @@ -4413,12 +4493,12 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* Find and remove the QH. There are four possibilities: * - * 1) The transfer has already completed and the QH is no longer in the list. In - * this case, sam_hq_foreach will return zero - * 2a) The transfer is not active and still pending. It was removed from the list - * and sam_hq_foreach will return one. - * 2b) The is active but not yet complete. This is currently handled the same as - * 2a). REVISIT: This needs to be fixed. + * 1) The transfer has already completed and the QH is no longer in the + * list. In this case, sam_hq_foreach will return zero + * 2a) The transfer is not active and still pending. It was removed from + * the list and sam_hq_foreach will return one. + * 2b) The is active but not yet complete. This is currently handled the + * same as 2a). REVISIT: This needs to be fixed. * 3) Some bad happened and sam_hq_foreach returned an error code < 0. */ @@ -4461,7 +4541,7 @@ errout_with_sem: return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_connect * * Description: @@ -4470,17 +4550,17 @@ errout_with_sem: * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int sam_connect(FAR struct usbhost_driver_s *drvr, @@ -4492,7 +4572,8 @@ static int sam_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4515,17 +4596,18 @@ static int sam_connect(FAR struct usbhost_driver_s *drvr, * Name: sam_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4543,9 +4625,6 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: sam_reset * @@ -4554,9 +4633,9 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr, * * Table 2-9. USBCMD - USB Command Register Bit Definitions * - * "Host Controller Reset (HCRESET) ... This control bit is used by software - * to reset the host controller. The effects of this on Root Hub registers - * are similar to a Chip Hardware Reset. + * "Host Controller Reset (HCRESET) ... This control bit is used by + * software to reset the host controller. The effects of this on Root + * Hub registers are similar to a Chip Hardware Reset. * * "When software writes a one to this bit, the Host Controller resets its * internal pipelines, timers, counters, state machines, etc. to their @@ -4565,16 +4644,18 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr, * ports. * * "PCI Configuration registers are not affected by this reset. All - * operational registers, including port registers and port state machines - * are set to their initial values. Port ownership reverts to the companion - * host controller(s)... Software must reinitialize the host controller ... - * in order to return the host controller to an operational state. + * operational registers, including port registers and port state + * machines are set to their initial values. Port ownership reverts + * to the companion host controller(s)... Software must reinitialize + * the host controller ... in order to return the host controller to + * an operational state. * - * "This bit is set to zero by the Host Controller when the reset process is - * complete. Software cannot terminate the reset process early by writing a - * zero to this register. Software should not set this bit to a one when - * the HCHalted bit in the USBSTS register is a zero. Attempting to reset - * an actively running host controller will result in undefined behavior." + * "This bit is set to zero by the Host Controller when the reset process + * is complete. Software cannot terminate the reset process early by + * writing a zero to this register. Software should not set this bit to + * a one when the HCHalted bit in the USBSTS register is a zero. + * Attempting to reset an actively running host controller will result + * in undefined behavior." * * Input Parameters: * None. @@ -4593,10 +4674,11 @@ static int sam_reset(void) uint32_t regval; unsigned int timeout; - /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to 0, - * the Host Controller completes the current transaction on the USB and then - * halts. The HC Halted bit in the status register indicates when the Hos - * Controller has finished the transaction and has entered the stopped state..." + /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to + * 0, the Host Controller completes the current transaction on the USB and + * then halts. The HC Halted bit in the status register indicates when the + * Host Controller has finished the transaction and has entered the + * stopped state..." */ sam_putreg(0, &HCOR->usbcmd); @@ -4614,9 +4696,9 @@ static int sam_reset(void) up_udelay(1); timeout++; - /* Get the current value of the USBSTS register. This loop will terminate - * when either the timeout exceeds one millisecond or when the HCHalted - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBSTS register. This loop will + * terminate when either the timeout exceeds one millisecond or when + * the HCHalted bit is no longer set in the USBSTS register. */ regval = sam_getreg(&HCOR->usbsts); @@ -4646,9 +4728,9 @@ static int sam_reset(void) up_udelay(5); timeout += 5; - /* Get the current value of the USBCMD register. This loop will terminate - * when either the timeout exceeds one second or when the HCReset - * bit is no longer set in the USBSTS register. + /* Get the current value of the USBCMD register. This loop will + * terminate when either the timeout exceeds one second or when the + * HCReset bit is no longer set in the USBSTS register. */ regval = sam_getreg(&HCOR->usbcmd); @@ -4663,6 +4745,7 @@ static int sam_reset(void) /**************************************************************************** * Public Functions ****************************************************************************/ + /**************************************************************************** * Name: sam_ehci_initialize * @@ -4720,7 +4803,8 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) #endif #endif /* CONFIG_USBHOST_INT_DISABLE */ - /* SAMA5 Configuration *******************************************************/ + /* SAMA5 Configuration ****************************************************/ + /* For High-speed operations, the user has to perform the following: * * 1) Enable UHP peripheral clock, bit (1 << AT91C_ID_UHPHS) in @@ -4777,7 +4861,7 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) * dedicated function */ - /* Software Configuration ****************************************************/ + /* Software Configuration *************************************************/ usbhost_vtrace1(EHCI_VTRACE1_INITIALIZING, 0); @@ -4909,8 +4993,10 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) sam_qtd_free(&g_qtdpool[i]); } - /* EHCI Hardware Configuration ***********************************************/ + /* EHCI Hardware Configuration ********************************************/ + /* Host Controller Initialization. Paragraph 4.1 */ + /* Reset the EHCI hardware */ ret = sam_reset(); @@ -4920,30 +5006,31 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) return NULL; } - /* "In order to initialize the host controller, software should perform the - * following steps: + /* "In order to initialize the host controller, software should perform + * the following steps: * - * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where all - * of the interface data structures are allocated. [64-bit mode] + * - "Program the CTRLDSSEGMENT register with 4-Gigabyte segment where + * all of the interface data structures are allocated. [64-bit mode] * - "Write the appropriate value to the USBINTR register to enable the * appropriate interrupts. - * - "Write the base address of the Periodic Frame List to the PERIODICLIST - * BASE register. If there are no work items in the periodic schedule, - * all elements of the Periodic Frame List should have their T-Bits set - * to a one. + * - "Write the base address of the Periodic Frame List to the + * PERIODICLIST BASE register. If there are no work items in the + * periodic schedule, all elements of the Periodic Frame List should + * have their T-Bits set to a one. * - "Write the USBCMD register to set the desired interrupt threshold, * frame list size (if applicable) and turn the host controller ON via * setting the Run/Stop bit. - * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI controller + * - Write a 1 to CONFIGFLAG register to route all ports to the EHCI + * controller * ... * - * "At this point, the host controller is up and running and the port registers - * will begin reporting device connects, etc. System software can enumerate a - * port through the reset process (where the port is in the enabled state). At - * this point, the port is active with SOFs occurring down the enabled por - * enabled Highspeed ports, but the schedules have not yet been enabled. The - * EHCI Host controller will not transmit SOFs to enabled Full- or Low-speed - * ports. + * "At this point, the host controller is up and running and the port + * registers will begin reporting device connects, etc. System software + * can enumerate a port through the reset process (where the port is in + * the enabled state). At this point, the port is active with SOFs + * occurring down the enabled port enabled Highspeed ports, but the + * schedules have not yet been enabled. The EHCI Host controller will not + * transmit SOFs to enabled Full- or Low-speed ports." */ /* Disable all interrupts */ @@ -4965,7 +5052,8 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) /* Verify that the correct number of ports is reported */ regval = sam_getreg(&HCCR->hcsparams); - nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT; + nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> + EHCI_HCSPARAMS_NPORTS_SHIFT; usbhost_vtrace2(EHCI_VTRACE2_HCSPARAMS, nports, regval); DEBUGASSERT(nports == SAM_EHCI_NRHPORT); @@ -4992,7 +5080,8 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) memset(&g_asynchead, 0, sizeof(struct sam_qh_s)); physaddr = sam_physramaddr((uintptr_t)&g_asynchead); g_asynchead.hw.hlp = sam_swap32(physaddr | QH_HLP_TYP_QH); - g_asynchead.hw.epchar = sam_swap32(QH_EPCHAR_H | QH_EPCHAR_EPS_FULL); + g_asynchead.hw.epchar = sam_swap32(QH_EPCHAR_H | + QH_EPCHAR_EPS_FULL); g_asynchead.hw.overlay.nqp = sam_swap32(QH_NQP_T); g_asynchead.hw.overlay.alt = sam_swap32(QH_NQP_T); g_asynchead.hw.overlay.token = sam_swap32(QH_TOKEN_HALTED); @@ -5030,9 +5119,11 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) /* Set the Periodic Frame List Base Address. */ up_clean_dcache((uintptr_t)&g_intrhead.hw, - (uintptr_t)&g_intrhead.hw + sizeof(struct ehci_qh_s)); + (uintptr_t)&g_intrhead.hw + + sizeof(struct ehci_qh_s)); up_clean_dcache((uintptr_t)g_framelist, - (uintptr_t)g_framelist + FRAME_LIST_SIZE * sizeof(uint32_t)); + (uintptr_t)g_framelist + + FRAME_LIST_SIZE * sizeof(uint32_t)); physaddr = sam_physramaddr((uintptr_t)g_framelist); sam_putreg(sam_swap32(physaddr), &HCOR->periodiclistbase); @@ -5077,14 +5168,15 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller) /* Wait for the EHCI to run (i.e., no longer report halted) */ - ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100*1000); + ret = ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100 * 1000); if (ret < 0) { usbhost_trace1(EHCI_TRACE1_RUN_FAILED, sam_getreg(&HCOR->usbsts)); return NULL; } - /* Interrupt Configuration ***************************************************/ + /* Interrupt Configuration ************************************************/ + /* Attach USB host controller interrupt handler. If OHCI is also enabled, * then we have to use a common UHPHS interrupt handler. */ diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index 5f9dceae40..4e8c0207d7 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/sama5/sam_ohci.c * - * Copyright (C) 2013, 2015-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -77,15 +62,17 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ -/* Configuration ***************************************************************/ + +/* Configuration ************************************************************/ + /* Pre-requisites */ #ifndef CONFIG_SCHED_WORKQUEUE # error Work queue support is required (CONFIG_SCHED_WORKQUEUE) #endif -/* Configurable number of user endpoint descriptors (EDs). This number excludes - * the control endpoint that is always allocated. +/* Configurable number of user endpoint descriptors (EDs). This number + * excludes the control endpoint that is always allocated. */ #ifndef CONFIG_SAMA5_OHCI_NEDS @@ -102,8 +89,8 @@ # error Insufficient number of transfer descriptors (CONFIG_SAMA5_OHCI_NTDS < 2) #endif -/* Minimum alignment for DMA access is 16 bytes, but it is safer to align to the - * cache line size. +/* Minimum alignment for DMA access is 16 bytes, but it is safer to align to + * the cache line size. */ #if ARMV7A_DCACHE_LINESIZE > 16 @@ -154,7 +141,8 @@ # undef CONFIG_SAMA5_OHCI_REGDEBUG #endif -/* OHCI Setup ******************************************************************/ +/* OHCI Setup ***************************************************************/ + /* Frame Interval / Periodic Start. * * At 12Mbps, there are 12000 bit time in each 1Msec frame. @@ -181,13 +169,15 @@ #define SAM_NORMAL_INTS (OHCI_INT_WDH|OHCI_INT_RHSC) #define SAM_ALL_INTS (SAM_NORMAL_INTS|SAM_DEBUG_INTS) -/* Periodic Intervals **********************************************************/ +/* Periodic Intervals *******************************************************/ + /* Periodic intervals 2, 4, 8, 16,and 32 supported */ #define MIN_PERINTERVAL 2 #define MAX_PERINTERVAL 32 -/* Descriptors *****************************************************************/ +/* Descriptors **************************************************************/ + /* Actual number of allocated EDs and TDs will include one for the control ED * and one for the tail ED for each RHPort: */ @@ -209,11 +199,12 @@ /**************************************************************************** * Private Types ****************************************************************************/ -/* This structure contains one endpoint list. The main reason for the existence - * of this structure is to contain the sem_t value associated with the ED. It - * doesn't work well within the ED itself because then the semaphore counter - * is subject to DMA cache operations (invalidate a modified semaphore count - * is fatal!). + +/* This structure contains one endpoint list. The main reason for the + * existence of this structure is to contain the sem_t value associated with + * the ED. It doesn't work well within the ED itself because then the + * semaphore counter is subject to DMA cache operations (invalidate a + * modified semaphore count is fatal!). */ struct sam_eplist_s @@ -284,9 +275,9 @@ struct sam_ohci_s /* The OCHI expects the size of an endpoint descriptor to be 16 bytes. * However, the size allocated for an endpoint descriptor is 32 bytes. This * is necessary first because the Cortex-A5 cache line size is 32 bytes and - * this is the smallest amount of memory that we can perform cache operations - * on. The 16-bytes is also used by the OHCI host driver in order to maintain - * additional endpoint-specific data. + * this is the smallest amount of memory that we can perform cache + * operations on. The 16-bytes is also used by the OHCI host driver in + * order to maintain additional endpoint-specific data. */ struct sam_ed_s @@ -338,7 +329,7 @@ struct sam_list_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_SAMA5_OHCI_REGDEBUG static void sam_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -350,19 +341,20 @@ static void sam_putreg(uint32_t val, uint32_t addr); # define sam_putreg(val,addr) putreg32(val,addr) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void sam_takesem(sem_t *sem); +static int sam_takesem(sem_t *sem); +static int sam_takesem_uninterruptible(sem_t *sem); #define sam_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t sam_getle16(const uint8_t *val); #if 0 /* Not used */ static void sam_putle16(uint8_t *dest, uint16_t val); #endif -/* OHCI memory pool helper functions *******************************************/ +/* OHCI memory pool helper functions ****************************************/ static struct sam_ed_s *sam_edalloc(void); static void sam_edfree(struct sam_ed_s *ed); @@ -371,7 +363,7 @@ static void sam_tdfree(struct sam_gtd_s *buffer); static uint8_t *sam_tballoc(void); static void sam_tbfree(uint8_t *buffer); -/* ED list helper functions ****************************************************/ +/* ED list helper functions *************************************************/ static int sam_addctrled(struct sam_ed_s *ed); static inline int sam_remctrled(struct sam_ed_s *ed); @@ -381,7 +373,8 @@ static inline int sam_rembulked(struct sam_ed_s *ed); #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) static unsigned int sam_getinterval(uint8_t interval); -static void sam_setinttab(uint32_t value, unsigned int interval, unsigned int offset); +static void sam_setinttab(uint32_t value, unsigned int interval, + unsigned int offset); #endif static inline int sam_addinted(const struct usbhost_epdesc_s *epdesc, @@ -392,10 +385,11 @@ static inline int sam_addisoced(const struct usbhost_epdesc_s *epdesc, struct sam_ed_s *ed); static inline int sam_remisoced(struct sam_ed_s *ed); -/* Descriptor helper functions *************************************************/ +/* Descriptor helper functions **********************************************/ -static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, - struct sam_ed_s *ed, uint32_t dirpid, uint32_t toggle, +static int sam_enqueuetd(struct sam_rhport_s *rhport, + struct sam_eplist_s *eplist, struct sam_ed_s *ed, + uint32_t dirpid, uint32_t toggle, volatile uint8_t *buffer, size_t buflen); static int sam_ep0enqueue(struct sam_rhport_s *rhport); static void sam_ep0dequeue(struct sam_eplist_s *ep0); @@ -409,13 +403,13 @@ static int sam_wdhasynch(struct sam_rhport_s *rhport, struct sam_ed_s *ed, static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *ep0, uint32_t dirpid, uint8_t *buffer, size_t buflen); -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ static void sam_rhsc_bottomhalf(void); static void sam_wdh_bottomhalf(void); static void sam_ohci_bottomhalf(void *arg); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int sam_wait(struct usbhost_connection_s *conn, struct usbhost_hubport_s **hport); @@ -425,10 +419,11 @@ static int sam_enumerate(struct usbhost_connection_s *conn, struct usbhost_hubport_s *hport); static int sam_ep0configure(struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int sam_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep); + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); static int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int sam_alloc(struct usbhost_driver_s *drvr, uint8_t **buffer, size_t *maxlen); @@ -466,9 +461,9 @@ static void sam_disconnect(struct usbhost_driver_s *drvr, * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct sam_ohci_s g_ohci; @@ -539,8 +534,8 @@ static void sam_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -639,9 +634,43 @@ static void sam_putreg(uint32_t val, uint32_t addr) * ****************************************************************************/ -static void sam_takesem(sem_t *sem) +static int sam_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: sam_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int sam_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -755,7 +784,8 @@ static struct sam_gtd_s *sam_tdalloc(void) * Free a transfer descriptor by returning it to the free list * * Assumptions: - * - Only called from the WDH interrupt handler (and during initialization). + * - Only called from the WDH interrupt handler (and during + * initialization). * - Interrupts are disabled in any case. * ****************************************************************************/ @@ -1064,9 +1094,10 @@ static inline int sam_rembulked(struct sam_ed_s *ed) #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) static unsigned int sam_getinterval(uint8_t interval) { - /* The bInterval field of the endpoint descriptor contains the polling interval - * for interrupt and isochronous endpoints. For other types of endpoint, this - * value should be ignored. bInterval is provided in units of 1MS frames. + /* The bInterval field of the endpoint descriptor contains the polling + * interval for interrupt and isochronous endpoints. For other types of + * endpoint, this value should be ignored. bInterval is provided in units + * of 1MS frames. */ if (interval < 3) @@ -1096,13 +1127,14 @@ static unsigned int sam_getinterval(uint8_t interval) * Name: sam_setinttab * * Description: - * Set the interrupt table to the selected value using the provided interval - * and offset. + * Set the interrupt table to the selected value using the provided + * interval and offset. * ****************************************************************************/ #if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) -static void sam_setinttab(uint32_t value, unsigned int interval, unsigned int offset) +static void sam_setinttab(uint32_t value, unsigned int interval, + unsigned int offset) { uintptr_t inttbl; unsigned int i; @@ -1127,17 +1159,18 @@ static void sam_setinttab(uint32_t value, unsigned int interval, unsigned int of * Description: * Helper function to add an ED to the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ @@ -1152,8 +1185,8 @@ static inline int sam_addinted(const struct usbhost_epdesc_s *epdesc, uintptr_t physhead; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ flags = enter_critical_section(); @@ -1246,17 +1279,18 @@ static inline int sam_addinted(const struct usbhost_epdesc_s *epdesc, * Description: * Helper function to remove an ED from the HCCA interrupt table. * - * To avoid reshuffling the table so much and to keep life simple in general, - * the following rules are applied: + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: * * 1. IN EDs get the even entries, OUT EDs get the odd entries. - * 2. Add IN/OUT EDs are scheduled together at the minimum interval of all - * IN/OUT EDs. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. * * This has the following consequences: * * 1. The minimum support polling rate is 2MS, and - * 2. Some devices may get polled at a much higher rate than they request. + * 2. Some devices may get polled at a much higher rate than they + * request. * ****************************************************************************/ @@ -1272,8 +1306,8 @@ static inline int sam_reminted(struct sam_ed_s *ed) unsigned int offset; uint32_t regval; - /* Disable periodic list processing. Does this take effect immediately? Or - * at the next SOF... need to check. + /* Disable periodic list processing. Does this take effect immediately? + * Or at the next SOF... need to check. */ flags = enter_critical_section(); @@ -1372,8 +1406,8 @@ static inline int sam_reminted(struct sam_ed_s *ed) g_ohci.outinterval = interval; } - /* Set the head ED in all of the appropriate entries of the HCCA interrupt - * table (head might be NULL). + /* Set the head ED in all of the appropriate entries of the HCCA + * interrupt table (head might be NULL). */ sam_setinttab((uint32_t)physhead, interval, offset); @@ -1410,7 +1444,6 @@ static inline int sam_addisoced(const struct usbhost_epdesc_s *epdesc, # warning "Isochronous endpoints not yet supported" #endif return -ENOSYS; - } /**************************************************************************** @@ -1438,8 +1471,9 @@ static inline int sam_remisoced(struct sam_ed_s *ed) * ****************************************************************************/ -static int sam_enqueuetd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, - struct sam_ed_s *ed, uint32_t dirpid, uint32_t toggle, +static int sam_enqueuetd(struct sam_rhport_s *rhport, + struct sam_eplist_s *eplist, struct sam_ed_s *ed, + uint32_t dirpid, uint32_t toggle, volatile uint8_t *buffer, size_t buflen) { struct sam_gtd_s *td; @@ -1606,12 +1640,12 @@ static int sam_ep0enqueue(struct sam_rhport_s *rhport) * Name: sam_ep0dequeue * * Description: - * Remove the ED for EP0 from the control ED list and possibly disable control - * list processing. + * Remove the ED for EP0 from the control ED list and possibly disable + * control list processing. * * Input Parameters: - * ep0 - The control endpoint to be released. May be the control endpoint for - * an attached hub. + * ep0 - The control endpoint to be released. May be the control endpoint + * for an attached hub. * * Returned Value: * None @@ -1717,10 +1751,11 @@ static void sam_ep0dequeue(struct sam_eplist_s *ep0) * Name: sam_wdhwait * * Description: - * Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to perform the transfer). - * We do this to minimize race conditions. This logic would have to be - * expanded if we want to have more than one packet in flight at a time! + * Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to perform the + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * ****************************************************************************/ @@ -1763,10 +1798,11 @@ static int sam_wdhwait(struct sam_rhport_s *rhport, struct sam_ed_s *ed, * Name: sam_wdhasynch * * Description: - * Set the request for the Writeback Done Head callback well BEFORE enabling - * the transfer (as soon as we are absolutely committed to perform the - * transfer). We do this to minimize race conditions. This logic would have - * to be expanded if we want to have more than one packet in flight at a time! + * Set the request for the Writeback Done Head callback well BEFORE + * enabling the transfer (as soon as we are absolutely committed to + * perform the transfer). We do this to minimize race conditions. This + * logic would have to be expanded if we want to have more than one packet + * in flight at a time! * ****************************************************************************/ @@ -1820,16 +1856,18 @@ static int sam_wdhasynch(struct sam_rhport_s *rhport, struct sam_ed_s *ed, * ****************************************************************************/ -static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, - uint32_t dirpid, uint8_t *buffer, size_t buflen) +static int sam_ctrltd(struct sam_rhport_s *rhport, + struct sam_eplist_s *eplist, uint32_t dirpid, + uint8_t *buffer, size_t buflen) { struct sam_ed_s *edctrl; uint32_t toggle; uint32_t regval; int ret; + int ret2; - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ edctrl = eplist->ed; @@ -1854,11 +1892,12 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, /* Then enqueue the transfer */ edctrl->tdstatus = TD_CC_NOERROR; - ret = sam_enqueuetd(rhport, eplist, edctrl, dirpid, toggle, buffer, buflen); + ret = sam_enqueuetd(rhport, eplist, edctrl, dirpid, toggle, buffer, + buflen); if (ret == OK) { - /* Set ControlListFilled. This bit is used to indicate whether there are - * TDs on the Control list. + /* Set ControlListFilled. This bit is used to indicate whether there + * are TDs on the Control list. */ regval = sam_getreg(SAM_USBHOST_CMDST); @@ -1881,20 +1920,29 @@ static int sam_ctrltd(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, * alarm semaphore counts. */ - while (eplist->wdhwait) + while (eplist->wdhwait && ret >= 0) { - sam_takesem(&eplist->wdhsem); + ret = sam_takesem(&eplist->wdhsem); } /* Re-acquire the ECHI semaphore. The caller expects to be holding * this upon return. */ - sam_takesem(&g_ohci.exclsem); + ret2 = sam_takesem_uninterruptible(&g_ohci.exclsem); + if (ret2 < 0) + { + ret = ret2; + } + + if (ret < 0) + { + /* The thread was canceled */ + } /* Check the TD completion status bits */ - if (edctrl->tdstatus == TD_CC_NOERROR) + else if (edctrl->tdstatus == TD_CC_NOERROR) { ret = OK; } @@ -1933,7 +1981,7 @@ static void sam_rhsc_bottomhalf(void) { rhport = &g_ohci.rhport[rhpndx]; - regaddr = SAM_USBHOST_RHPORTST(rhpndx+1); + regaddr = SAM_USBHOST_RHPORTST(rhpndx + 1); rhportst = sam_getreg(regaddr); usbhost_vtrace2(OHCI_VTRACE2_RHPORTST, rhpndx + 1, (uint16_t)rhportst); @@ -1997,7 +2045,8 @@ static void sam_rhsc_bottomhalf(void) rhport->hport.hport.speed = USB_SPEED_FULL; } - usbhost_vtrace1(OHCI_VTRACE1_SPEED, rhport->hport.hport.speed); + usbhost_vtrace1(OHCI_VTRACE1_SPEED, + rhport->hport.hport.speed); } /* Check if we are now disconnected */ @@ -2099,7 +2148,8 @@ static void sam_wdh_bottomhalf(void) /* Now read the done head. */ - td = (struct sam_gtd_s *)sam_virtramaddr(g_hcca.donehead & HCCA_DONEHEAD_MASK); + td = (struct sam_gtd_s *) + sam_virtramaddr(g_hcca.donehead & HCCA_DONEHEAD_MASK); g_hcca.donehead = 0; /* Process each TD in the write done list */ @@ -2144,14 +2194,18 @@ static void sam_wdh_bottomhalf(void) * word. */ - ed->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + ed->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> + GTD_STATUS_CC_SHIFT; #ifdef HAVE_USBHOST_TRACE if (ed->tdstatus != TD_CC_NOERROR) { - /* The transfer failed for some reason... dump some diagnostic info. */ + /* The transfer failed for some reason... dump some diagnostic + * info. + */ - usbhost_trace2(OHCI_TRACE2_WHDTDSTATUS, ed->tdstatus, ed->xfrtype); + usbhost_trace2(OHCI_TRACE2_WHDTDSTATUS, ed->tdstatus, + ed->xfrtype); } #endif @@ -2214,11 +2268,11 @@ static void sam_wdh_bottomhalf(void) * Name: sam_ohci_bottomhalf * * Description: - * OHCI interrupt bottom half. This function runs on the high priority worker - * thread and was xcheduled when the last interrupt occurred. The set of - * pending interrupts is provided as the argument. OHCI interrupts were - * disabled when this function is scheduled so no further interrupts can - * occur until this work re-enables OHCI interrupts + * OHCI interrupt bottom half. This function runs on the high priority + * worker thread and was xcheduled when the last interrupt occurred. The + * set of pending interrupts is provided as the argument. OHCI interrupts + * were disabled when this function is scheduled so no further interrupts + * can occur until this work re-enables OHCI interrupts * ****************************************************************************/ @@ -2226,12 +2280,12 @@ static void sam_ohci_bottomhalf(void *arg) { uint32_t pending = (uint32_t)arg; - /* We need to have exclusive access to the OHCI data structures. Waiting here - * is not a good thing to do on the worker thread, but there is no real option - * (other than to reschedule and delay). + /* We need to have exclusive access to the OHCI data structures. Waiting + * here is not a good thing to do on the worker thread, but there is no + * real option (other than to reschedule and delay). */ - sam_takesem(&g_ohci.exclsem); + sam_takesem_uninterruptible(&g_ohci.exclsem); /* Root hub status change interrupt */ @@ -2247,9 +2301,9 @@ static void sam_ohci_bottomhalf(void *arg) if ((pending & OHCI_INT_WDH) != 0) { - /* The host controller just wrote the list of finished TDs into the HCCA - * done head. This may include multiple packets that were transferred - * in the preceding frame. + /* The host controller just wrote the list of finished TDs into the + * HCCA done head. This may include multiple packets that were + * transferred in the preceding frame. */ usbhost_vtrace1(OHCI_VTRACE1_WDHINTR, pending); @@ -2287,10 +2341,6 @@ static void sam_ohci_bottomhalf(void *arg) sam_givesem(&g_ohci.exclsem); } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ - /**************************************************************************** * Name: sam_wait * @@ -2298,17 +2348,17 @@ static void sam_ohci_bottomhalf(void *arg) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or - * disconnected. This function will not return until either (1) a device is - * connected or disconnect to/from any hub port or until (2) some failure - * occurs. On a failure, a negated errno value is returned indicating the - * nature of the failure + * disconnected. This function will not return until either (1) a device + * is connected or disconnect to/from any hub port or until (2) some + * failure occurs. On a failure, a negated errno value is returned + * indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2321,9 +2371,10 @@ static int sam_wait(struct usbhost_connection_s *conn, { irqstate_t flags; int rhpndx; + int ret; - /* Loop until a change in the connection state changes on one of the root hub - * ports or until an error occurs. + /* Loop until a change in the connection state changes on one of the root + * hub ports or until an error occurs. */ flags = enter_critical_section(); @@ -2390,15 +2441,16 @@ static int sam_wait(struct usbhost_connection_s *conn, } #endif - /* No changes on any port. Wait for a connection/disconnection event - * and check again - */ /* No changes on any port. Wait for a connection/disconnection event * and check again */ g_ohci.pscwait = true; - sam_takesem(&g_ohci.pscsem); + ret = sam_takesem(&g_ohci.pscsem); + if (ret < 0) + { + return ret; + } } } @@ -2422,8 +2474,8 @@ static int sam_wait(struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -2481,7 +2533,7 @@ static int sam_rh_enumerate(struct usbhost_connection_s *conn, * ports) */ - regaddr = SAM_USBHOST_RHPORTST(rhpndx+1); + regaddr = SAM_USBHOST_RHPORTST(rhpndx + 1); sam_putreg(OHCI_RHPORTST_PRS, regaddr); /* Wait for the port reset to complete */ @@ -2530,7 +2582,7 @@ static int sam_enumerate(struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_ep0configure * * Description: @@ -2539,31 +2591,33 @@ static int sam_enumerate(struct usbhost_connection_s *conn, * an external implementation of the enumeration logic. * * 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. A funcaddr of zero will be received if no address is yet assigned - * to the device. + * 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. A funcaddr of zero will be received if no address is + * yet assigned to the device. * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) + uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize) { struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; struct sam_eplist_s *ep0list = (struct sam_eplist_s *)ep0; struct sam_ed_s *edctrl; uint32_t hwctrl; + int ret; usbhost_vtrace2(OHCI_VTRACE2_EP0CONFIG, speed, funcaddr); DEBUGASSERT(rhport && maxpacketsize < 2048); @@ -2572,7 +2626,11 @@ static int sam_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the EP0 ED control word (preserving only speed) */ @@ -2593,35 +2651,37 @@ static int sam_ep0configure(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, (uintptr_t)edctrl + sizeof(struct ohci_ed_s)); sam_givesem(&g_ohci.exclsem); - usbhost_vtrace2(OHCI_VTRACE2_EP0CTRLED, RHPORT(rhport), (uint16_t)edctrl->hw.ctrl); + usbhost_vtrace2(OHCI_VTRACE2_EP0CTRLED, RHPORT(rhport), + (uint16_t)edctrl->hw.ctrl); UNUSED(rhport); return OK; } -/************************************************************************************ +/**************************************************************************** * Name: sam_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_epalloc(struct usbhost_driver_s *drvr, - const struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep) + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) { struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; struct sam_eplist_s *eplist; @@ -2631,8 +2691,8 @@ static int sam_epalloc(struct usbhost_driver_s *drvr, uintptr_t physaddr; int ret = -ENOMEM; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(rhport != NULL && epdesc != NULL && epdesc->hport != NULL); @@ -2660,11 +2720,15 @@ static int sam_epalloc(struct usbhost_driver_s *drvr, nxsem_setprotocol(&eplist->wdhsem, SEM_PRIO_NONE); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list, and the interrupt table. */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + goto errout_with_eplist; + } /* Allocate an ED and a tail TD for the new endpoint */ @@ -2800,30 +2864,31 @@ errout_with_ed: sam_edfree(ed); errout_with_semaphore: sam_givesem(&g_ohci.exclsem); +errout_with_eplist: kmm_free(eplist); errout: return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -2833,6 +2898,7 @@ static int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) struct sam_eplist_s *eplist = (struct sam_eplist_s *)ep; struct sam_ed_s *ed; int ret; + int ret2; DEBUGASSERT(rhport != NULL && eplist != NULL && eplist->ed != NULL && eplist->tail != NULL); @@ -2842,11 +2908,11 @@ static int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) ed = eplist->ed; DEBUGASSERT((ed->hw.headp & ED_HEADP_ADDR_MASK) == ed->hw.tailp); - /* We must have exclusive access to the ED pool, the bulk list, the periodic list - * and the interrupt table. + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list and the interrupt table. */ - sam_takesem(&g_ohci.exclsem); + ret2 = sam_takesem_uninterruptible(&g_ohci.exclsem); /* Remove the ED to the correct list depending on the transfer type */ @@ -2883,34 +2949,35 @@ static int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) nxsem_destroy(&eplist->wdhsem); kmm_free(eplist); sam_givesem(&g_ohci.exclsem); - return ret; + return ret < 0 ? ret : ret2; } /**************************************************************************** * Name: sam_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -2921,12 +2988,19 @@ static int sam_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep) static int sam_alloc(struct usbhost_driver_s *drvr, uint8_t **buffer, size_t *maxlen) { - int ret = -ENOMEM; + int ret; + DEBUGASSERT(drvr && buffer && maxlen); /* We must have exclusive access to the transfer buffer pool */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return ret; + } + + ret = -ENOMEM; *buffer = sam_tballoc(); if (*buffer) @@ -2943,19 +3017,20 @@ static int sam_alloc(struct usbhost_driver_s *drvr, * Name: sam_free * * Description: - * Some hardware supports special memory in which request and descriptor data - * can be accessed more efficiently. This method provides a mechanism to - * free that request/descriptor memory. If the underlying hardware does not - * support such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call - * to the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Never called from an interrupt handler. @@ -2964,42 +3039,46 @@ static int sam_alloc(struct usbhost_driver_s *drvr, static int sam_free(struct usbhost_driver_s *drvr, uint8_t *buffer) { + int ret; + DEBUGASSERT(drvr && buffer); /* We must have exclusive access to the transfer buffer pool */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem_uninterruptible(&g_ohci.exclsem); sam_tbfree(buffer); sam_givesem(&g_ohci.exclsem); - return OK; + return ret; } -/************************************************************************************ +/**************************************************************************** * Name: sam_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kumm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kumm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_ioalloc(struct usbhost_driver_s *drvr, uint8_t **buffer, size_t buflen) @@ -3012,28 +3091,28 @@ static int sam_ioalloc(struct usbhost_driver_s *drvr, uint8_t **buffer, return *buffer ? OK : -ENOMEM; } -/************************************************************************************ +/**************************************************************************** * Name: sam_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kumm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kumm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int sam_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) { @@ -3049,31 +3128,31 @@ static int sam_iofree(struct usbhost_driver_s *drvr, uint8_t *buffer) * Name: sam_ctrlin and sam_ctrlout * * Description: - * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3095,7 +3174,8 @@ static int sam_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, #ifdef CONFIG_USBHOST_TRACE usbhost_vtrace2(OHCI_VTRACE2_CTRLIN, RHPORT(rhport), req->req); #else - uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n", + uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x " + "len: %02x%02x\n", RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], req->len[1], req->len[0]); @@ -3103,7 +3183,11 @@ static int sam_ctrlin(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return ret; + } len = sam_getle16(req->len); ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_SETUP, (uint8_t *)req, @@ -3144,7 +3228,8 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, #ifdef CONFIG_USBHOST_TRACE usbhost_vtrace2(OHCI_VTRACE2_CTRLOUT, RHPORT(rhport), req->req); #else - uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x len: %02x%02x\n", + uinfo("RHPort%d type: %02x req: %02x value: %02x%02x index: %02x%02x " + "len: %02x%02x\n", RHPORT(rhport), req->type, req->req, req->value[1], req->value[0], req->index[1], req->index[0], req->len[1], req->len[0]); @@ -3152,7 +3237,11 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to EP0 and the control list */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return ret; + } len = sam_getle16(req->len); ret = sam_ctrltd(rhport, eplist, GTD_STATUS_DP_SETUP, (uint8_t *)req, @@ -3186,14 +3275,14 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * rhport - Internal driver root hub port state structure. * eplist - The internal representation of the device endpoint on which * to perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. - * + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3259,30 +3348,32 @@ static int sam_transfer_common(struct sam_rhport_s *rhport, return ret; } + /**************************************************************************** * Name: sam_transfer * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -3305,6 +3396,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, ssize_t nbytes; bool in; int ret; + int ret2; DEBUGASSERT(rhport && eplist && eplist->ed && eplist->tail && buffer && buflen > 0); @@ -3312,14 +3404,19 @@ static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, ed = eplist->ed; in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN; - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } - /* Set the request for the Writeback Done Head event well BEFORE enabling the - * transfer. + /* Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer. */ ret = sam_wdhwait(rhport, ed, buffer, buflen); @@ -3347,6 +3444,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, * or we will deadlock while waiting (because the working thread that * wakes this thread up needs the exclsem). */ + #warning REVISIT sam_givesem(&g_ohci.exclsem); @@ -3354,16 +3452,25 @@ static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, * alarm semaphore counts. */ - while (eplist->wdhwait) + while (eplist->wdhwait && ret >= 0) { - sam_takesem(&eplist->wdhsem); + ret = sam_takesem(&eplist->wdhsem); } /* Re-acquire the OCHI semaphore. The caller expects to be holding * this upon return. */ - sam_takesem(&g_ohci.exclsem); + ret2 = sam_takesem(&g_ohci.exclsem); + if (ret2 < 0) + { + ret = ret2; + } + + if (ret < 0) + { + return ret; + } /* Invalidate the D cache to force the ED to be reloaded from RAM */ @@ -3410,6 +3517,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, } errout: + /* Make sure that there is no outstanding request on this endpoint */ eplist->wdhwait = false; @@ -3528,20 +3636,21 @@ static void sam_asynch_completion(struct sam_eplist_s *eplist) * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -3563,14 +3672,19 @@ static int sam_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, buffer && buflen > 0 && buflen <= UINT16_MAX); ed = eplist->ed; - /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer - * pool, the bulk and interrupt lists, and the HCCA interrupt table. + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. */ - sam_takesem(&g_ohci.exclsem); + ret = sam_takesem(&g_ohci.exclsem); + if (ret < 0) + { + return ret; + } /* Set the request for the Writeback Done Head callback well BEFORE - * enabling thetransfer. + * enabling the transfer. */ ret = sam_wdhasynch(rhport, ed, callback, arg, buffer, buflen); @@ -3597,6 +3711,7 @@ static int sam_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, return OK; errout: + /* Make sure that there is no outstanding request on this endpoint */ eplist->callback = NULL; @@ -3606,7 +3721,7 @@ errout: } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: sam_cancel * * Description: @@ -3614,16 +3729,16 @@ errout: * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ static int sam_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -3694,8 +3809,8 @@ static int sam_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep) (uintptr_t)ed + sizeof(struct ohci_ed_s)); } - /* Free all transfer descriptors that were connected to the ED. In some - * race conditions with the hardware, this might be none. + /* Free all transfer descriptors that were connected to the ED. In + * some race conditions with the hardware, this might be none. */ while (td != (struct sam_gtd_s *)eplist->tail) @@ -3749,7 +3864,7 @@ static int sam_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: sam_connect * * Description: @@ -3758,17 +3873,17 @@ static int sam_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection - * related event + * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int sam_connect(struct usbhost_driver_s *drvr, @@ -3780,7 +3895,8 @@ static int sam_connect(struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -3803,17 +3919,18 @@ static int sam_connect(struct usbhost_driver_s *drvr, * Name: sam_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4135,7 +4252,7 @@ struct usbhost_connection_s *sam_ohci_initialize(int controller) g_ohci.rhport[i].connected = ((regval & OHCI_RHPORTST_CCS) != 0); usbhost_vtrace2(OHCI_VTRACE2_INITCONNECTED, - i+1, g_ohci.rhport[i].connected); + i + 1, g_ohci.rhport[i].connected); } /* Enable interrupts at the interrupt controller. If ECHI is enabled, @@ -4159,9 +4276,9 @@ struct usbhost_connection_s *sam_ohci_initialize(int controller) * Name: sam_ohci_tophalf * * Description: - * OHCI "Top Half" interrupt handler. If both EHCI and OHCI are enabled, then - * EHCI will manage the common UHPHS interrupt and will forward the interrupt - * event to this function. + * OHCI "Top Half" interrupt handler. If both EHCI and OHCI are enabled, + * then EHCI will manage the common UHPHS interrupt and will forward the + * interrupt event to this function. * ****************************************************************************/ @@ -4178,16 +4295,17 @@ int sam_ohci_tophalf(int irq, void *context, FAR void *arg) usbhost_vtrace1(OHCI_VTRACE1_INTRPENDING, intst & inten); #ifdef CONFIG_SAMA5_EHCI - /* Check the Master Interrupt Enable bit (MIE). It this function is called - * from the common UHPHS interrupt handler, there might be pending interrupts - * but with the overall interstate disabled. This could never happen if only - * OHCI were enabled because we would never get here. + /* Check the Master Interrupt Enable bit (MIE). It this function is + * called from the common UHPHS interrupt handler, there might be pending + * interrupts but with the overall interstate disabled. This could never + * happen if only OHCI were enabled because we would never get here. */ if ((inten & OHCI_INT_MIE) != 0) #endif { /* Mask out the interrupts that are not enabled */ + pending = intst & inten; if (pending != 0) { diff --git a/arch/arm/src/sama5/sam_twi.c b/arch/arm/src/sama5/sam_twi.c index 94f2bd92fa..0e16e3915d 100644 --- a/arch/arm/src/sama5/sam_twi.c +++ b/arch/arm/src/sama5/sam_twi.c @@ -182,7 +182,6 @@ struct twi_dev_s /* Low-level helper functions */ static int twi_takesem(sem_t *sem); -static int twi_takesem_uninterruptible(sem_t *sem); #define twi_givesem(sem) (nxsem_post(sem)) #ifdef CONFIG_SAMA5_TWI_REGDEBUG @@ -317,26 +316,6 @@ static int twi_takesem(sem_t *sem) return nxsem_wait(sem); } -/**************************************************************************** - * Name: twi_takesem_uninterruptible - * - * Description: - * Take the wait semaphore (handling false alarm wake-ups due to the - * receipt of signals). - * - * Input Parameters: - * dev - Instance of the SDIO device driver state structure. - * - * Returned Value: - * None - * - ****************************************************************************/ - -static int twi_takesem_uninterruptible(sem_t *sem) -{ - return nxsem_wait_uninterruptible(sem); -} - /**************************************************************************** * Name: twi_checkreg * @@ -902,7 +881,7 @@ static int twi_reset(FAR struct i2c_master_s *dev) /* Get exclusive access to the TWI device */ - ret = twi_takesem_uninterruptible(&priv->exclsem); + ret = twi_takesem(&priv->exclsem); if (ret < 0) { return ret; diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index 400c5ea37e..b36c4ed832 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/stm32/stm32_otgfshost.c * - * Copyright (C) 2012-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -75,7 +60,7 @@ * Pre-processor Definitions ****************************************************************************/ -/* Configuration *************************************************************/ +/* Configuration ************************************************************/ /* STM32 USB OTG FS Host Driver Support * @@ -140,7 +125,7 @@ # undef CONFIG_STM32_USBHOST_PKTDUMP #endif -/* HCD Setup *******************************************************************/ +/* HCD Setup ****************************************************************/ /* Hardware capabilities */ @@ -152,10 +137,10 @@ #define STM32_MAX_PKTCOUNT 256 /* Max packet count */ #define STM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */ -/* Delays **********************************************************************/ +/* Delays *******************************************************************/ -#define STM32_READY_DELAY 200000 /* In loop counts */ -#define STM32_FLUSH_DELAY 200000 /* In loop counts */ +#define STM32_READY_DELAY 200000 /* In loop counts */ +#define STM32_FLUSH_DELAY 200000 /* In loop counts */ #define STM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define STM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -271,7 +256,7 @@ struct stm32_usbhost_s volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ - struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -288,7 +273,7 @@ struct stm32_usbhost_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_STM32_USBHOST_REGDEBUG static void stm32_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -309,21 +294,24 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, # define stm32_pktdump(m,b,n) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void stm32_takesem(sem_t *sem); +static int stm32_takesem(sem_t *sem); +static int stm32_takesem_uninterruptible(sem_t *sem); #define stm32_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t stm32_getle16(const uint8_t *val); -/* Channel management **********************************************************/ +/* Channel management *******************************************************/ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv); -static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx); +static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, + int chidx); static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv); -static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, + int chidx); static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, enum stm32_chreason_e chreason); static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, @@ -338,7 +326,8 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep); static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -347,9 +336,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); -/* Control/data transfer logic *************************************************/ +/* Control/data transfer logic **********************************************/ -static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t stm32_getframe(void); #endif @@ -373,8 +363,9 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -383,7 +374,7 @@ static int stm32_out_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ /* Lower level interrupt handlers */ @@ -420,7 +411,7 @@ static void stm32_gint_disable(void); static inline void stm32_hostinit_enable(void); static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -431,26 +422,29 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int stm32_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -465,7 +459,7 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static void stm32_portreset(FAR struct stm32_usbhost_s *priv); static void stm32_flush_txfifos(uint32_t txfnum); @@ -480,9 +474,9 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct stm32_usbhost_s g_usbhost; @@ -534,8 +528,8 @@ static void stm32_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -633,7 +627,8 @@ static void stm32_putreg(uint32_t addr, uint32_t val) * ****************************************************************************/ -static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t setbits) +static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, + uint32_t setbits) { stm32_putreg(addr, (((stm32_getreg(addr)) & ~clrbits) | setbits)); } @@ -647,9 +642,43 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t set * ****************************************************************************/ -static void stm32_takesem(sem_t *sem) +static int stm32_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: stm32_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int stm32_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -808,8 +837,9 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx) { /* Interrupts required for INTR endpoints */ - regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | OTGFS_HCINT_NAK | - OTGFS_HCINT_TXERR | OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR); + regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | + OTGFS_HCINT_NAK | OTGFS_HCINT_TXERR | + OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR); /* Additional setting for IN endpoints */ @@ -833,7 +863,7 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx) { /* Interrupts required for ISOC endpoints */ - regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_ACK | OTGFS_HCINT_FRMOR); + regval |= OTGFS_HCINT_XFRC | OTGFS_HCINT_ACK | OTGFS_HCINT_FRMOR; /* Additional setting for IN endpoints */ @@ -914,21 +944,21 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(OTGFS_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_FS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx - * before reallocating the channel for other transactions. The OTG_FS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." */ hcchar = stm32_getreg(STM32_OTGFS_HCCHAR(chidx)); @@ -940,26 +970,29 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0." */ - if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK) + if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || + eptype == OTGFS_HCCHAR_EPTYP_BULK) { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK; + avail = stm32_getreg(STM32_OTGFS_HNPTXSTS) & + OTGFS_HNPTXSTS_NPTXFSAV_MASK; } - else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */ + else { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK; + avail = stm32_getreg(STM32_OTGFS_HPTXSTS) & + OTGFS_HPTXSTS_PTXFSAVL_MASK; } /* Check if there is any space available in the Tx FIFO. */ @@ -986,13 +1019,14 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, * Name: stm32_chan_waitsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the transfer). + * We do this to minimize race conditions. This logic would have to be + * expanded if we want to have more than one packet in flight at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1006,8 +1040,9 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1026,10 +1061,11 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, * Name: stm32_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1048,8 +1084,9 @@ static int stm32_chan_asynchsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1081,17 +1118,17 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, int ret; /* Disable interrupts so that the following operations will be atomic. On - * the OTG FS global interrupt needs to be disabled. However, here we disable - * all interrupts to exploit that fact that interrupts will be re-enabled - * while we wait. + * the OTG FS global interrupt needs to be disabled. However, here we + * disable all interrupts to exploit that fact that interrupts will be re- + * enabled while we wait. */ flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1101,13 +1138,17 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, * wait here. */ - nxsem_wait_uninterruptible(&chan->waitsem); + ret = stm32_takesem(&chan->waitsem); } - while (chan->waiter); + while (chan->waiter && ret >= 0); /* The transfer is complete re-enable interrupts and return the result */ - ret = -(int)chan->result; + if (ret >= 0) + { + ret = -(int)chan->result; + } + leave_critical_section(flags); return ret; } @@ -1182,7 +1223,8 @@ static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, ****************************************************************************/ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep) { FAR struct stm32_chan_s *chan; @@ -1251,8 +1293,8 @@ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -1267,8 +1309,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1276,7 +1318,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, /* Allocate a container for the control endpoint */ - ctrlep = (FAR struct stm32_ctrlinfo_s *)kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); + ctrlep = (FAR struct stm32_ctrlinfo_s *) + kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); if (ctrlep == NULL) { uerr("ERROR: Failed to allocate control endpoint container\n"); @@ -1300,7 +1343,7 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_xfrep_alloc * * Description: @@ -1313,24 +1356,24 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, - FAR const struct usbhost_epdesc_s *epdesc, - FAR usbhost_ep_t *ep) + FAR const struct usbhost_epdesc_s *epdesc, + FAR usbhost_ep_t *ep) { struct usbhost_hubport_s *hport; FAR struct stm32_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1345,10 +1388,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint + * point type is encoded in the same way in the endpoint descriptor as it + * is in the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1577,7 +1620,8 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) #if 0 /* Not used */ static inline uint16_t stm32_getframe(void) { - return (uint16_t)(stm32_getreg(STM32_OTGFS_HFNUM) & OTGFS_HFNUM_FRNUM_MASK); + return (uint16_t) + (stm32_getreg(STM32_OTGFS_HFNUM) & OTGFS_HFNUM_FRNUM_MASK); } #endif @@ -1714,8 +1758,8 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, * Name: stm32_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1933,27 +1977,30 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* For Isochronous endpoints, bInterval must be 1. Bulk - * endpoints do not have a polling interval. Rather, - * the should wait until data is received. + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. * - * REVISIT: For bulk endpoints this 1 msec delay is only - * intended to give the CPU a break from the bulk EP tight - * polling loop. But are there performance issues? + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? */ delay = 1000; } /* Wait for the next polling interval. For interrupt and - * isochronous endpoints, this is necessaryto assure the + * isochronous endpoints, this is necessary to assure the * polling interval. It is used in other cases only to - * prevent the polling from consuming too much CPU bandwidth. + * prevent the polling from consuming too much CPU + * bandwidth. * - * Small delays could require more resolution than is provided - * by the system timer. For example, if the system timer - * resolution is 10MS, then nxsig_usleep(1000) will actually request - * a delay 20MS (due to both quantization and rounding). + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). * * REVISIT: So which is better? To ignore tiny delays and * hog the system bandwidth? Or to wait for an excessive @@ -2178,8 +2225,9 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * ****************************************************************************/ -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_chan_s *chan; clock_t start; @@ -2256,14 +2304,14 @@ static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ stm32_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2440,8 +2488,8 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2487,7 +2535,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Clear the NAK and STALL Conditions. */ - stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_STALL)); + stm32_putreg(STM32_OTGFS_HCINT(chidx), + OTGFS_HCINT_NAK | OTGFS_HCINT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2514,7 +2563,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the NAK and data toggle error conditions */ - stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR)); + stm32_putreg(STM32_OTGFS_HCINT(chidx), + OTGFS_HCINT_NAK | OTGFS_HCINT_DTERR); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ @@ -2540,7 +2590,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Then handle the transfer completion event based on the endpoint type */ - if (chan->eptype == OTGFS_EPTYPE_CTRL || chan->eptype == OTGFS_EPTYPE_BULK) + if (chan->eptype == OTGFS_EPTYPE_CTRL || + chan->eptype == OTGFS_EPTYPE_BULK) { /* Halt the channel -- the CHH interrupt is expected next */ @@ -2653,11 +2704,12 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, } /* Re-activate CTRL and BULK channels. - * REVISIT: This can cause a lot of interrupts! + * + * REVISIT: This can cause a lot of interrupts! + * REVISIT: BULK endpoints are not re-activated. */ - else if (chan->eptype == OTGFS_EPTYPE_CTRL /* || - chan->eptype == OTGFS_EPTYPE_BULK */) + else if (chan->eptype == OTGFS_EPTYPE_CTRL) { /* Re-activate the channel by clearing CHDIS and assuring that * CHENA is set @@ -2693,8 +2745,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2838,7 +2890,8 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - stm32_putreg(STM32_OTGFS_HCINT(chidx), (OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK)); + stm32_putreg(STM32_OTGFS_HCINT(chidx), + OTGFS_HCINT_DTERR | OTGFS_HCINT_NAK); } /* Check for a pending CHannel Halted (CHH) interrupt */ @@ -2867,7 +2920,8 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, * transferred? */ - if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_BULK && + if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == + OTGFS_HCCHAR_EPTYP_BULK && (chan->npackets & 1) != 0) { /* Yes to both... toggle the data out PID */ @@ -3061,7 +3115,8 @@ static inline void stm32_gint_rxflvlisr(FAR struct stm32_usbhost_s *priv) { /* Read the data into the host buffer. */ - bcnt = (grxsts & OTGFS_GRXSTSH_BCNT_MASK) >> OTGFS_GRXSTSH_BCNT_SHIFT; + bcnt = (grxsts & OTGFS_GRXSTSH_BCNT_MASK) >> + OTGFS_GRXSTSH_BCNT_SHIFT; if (bcnt > 0 && priv->chan[chidx].buffer != NULL) { /* Transfer the packet from the Rx FIFO into the user buffer */ @@ -3137,8 +3192,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3197,8 +3252,9 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3226,8 +3282,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3360,15 +3416,15 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) hprt = stm32_getreg(STM32_OTGFS_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ newhprt = hprt & ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET | OTGFS_HPRT_PENCHNG | OTGFS_HPRT_POCCHNG); - /* Check for Port Overcurrent CHaNGe (POCCHNG) */ + /* Check for Port Over-urrent CHaNGe (POCCHNG) */ if ((hprt & OTGFS_HPRT_POCCHNG) != 0) { @@ -3428,7 +3484,8 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) /* Are we switching from FS to LS? */ - if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_LS6MHz) + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_LS6MHz) { usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSLSSW, 0); @@ -3450,7 +3507,8 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) /* Are we switching from LS to FS? */ - if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_FS48MHz) + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_FS48MHz) { usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSFSSW, 0); @@ -3530,7 +3588,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; @@ -3541,8 +3600,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3809,10 +3868,10 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or @@ -3833,6 +3892,7 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct stm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3857,7 +3917,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3874,7 +3935,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3882,7 +3944,11 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - stm32_takesem(&priv->pscsem); + ret = stm32_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3906,8 +3972,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3961,7 +4027,8 @@ static int stm32_rh_enumerate(FAR struct stm32_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -4017,7 +4084,7 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ep0configure * * Description: @@ -4026,38 +4093,43 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, * external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize) +static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; FAR struct stm32_ctrlinfo_s *ep0info = (FAR struct stm32_ctrlinfo_s *)ep0; FAR struct stm32_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4081,27 +4153,27 @@ static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4110,15 +4182,19 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require @@ -4139,35 +4215,36 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; + int ret; DEBUGASSERT(priv); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem_uninterruptible(&priv->exclsem); /* A single channel is represent by an index in the range of 0 to * STM32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated @@ -4184,7 +4261,9 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct stm32_ctrlinfo_s *ctrlep = (FAR struct stm32_ctrlinfo_s *)ep; + FAR struct stm32_ctrlinfo_s *ctrlep = + (FAR struct stm32_ctrlinfo_s *)ep; + stm32_chan_free(priv, ctrlep->inndx); stm32_chan_free(priv, ctrlep->outndx); @@ -4194,34 +4273,35 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } stm32_givesem(&priv->exclsem); - return OK; + return ret; } /**************************************************************************** * Name: stm32_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4255,19 +4335,20 @@ static int stm32_alloc(FAR struct usbhost_driver_s *drvr, * Name: stm32_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4283,32 +4364,34 @@ static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4331,30 +4414,31 @@ static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4368,29 +4452,31 @@ static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. * req - Describes the request to be sent. This request must lie in memory * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4422,7 +4508,11 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4505,7 +4595,11 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4574,26 +4668,27 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4607,12 +4702,14 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; ssize_t nbytes; + int ret; uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4620,7 +4717,11 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4651,20 +4752,21 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4687,7 +4789,11 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4705,7 +4811,7 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: stm32_cancel * * Description: @@ -4713,16 +4819,16 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4736,8 +4842,8 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < STM32_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being cancelled. */ flags = enter_critical_section(); @@ -4792,7 +4898,7 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_connect * * Description: @@ -4801,17 +4907,17 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int stm32_connect(FAR struct usbhost_driver_s *drvr, @@ -4826,7 +4932,8 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4847,17 +4954,18 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, * Name: stm32_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not call the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4875,20 +4983,17 @@ static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: stm32_portreset * * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in - * OTG_FS_GOTGINT), which indicates that the bus is stable again after the - * electrical debounce caused by the attachment of a pull-up resistor on DP - * (FS) or DM (LS). + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * OTG_FS_GOTGINT), which indicates that the bus is stable again after + * the electrical debounce caused by the attachment of a pull-up resistor + * on DP (FS) or DM (LS). * * Input Parameters: * priv -- USB host driver private data structure. @@ -5046,9 +5151,9 @@ static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from stm32_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from stm32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5095,14 +5200,16 @@ static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv) /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ regval = (offset | - (CONFIG_STM32_OTGFS_NPTXFIFO_SIZE << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); + (CONFIG_STM32_OTGFS_NPTXFIFO_SIZE << + OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); stm32_putreg(STM32_OTGFS_HNPTXFSIZ, regval); offset += CONFIG_STM32_OTGFS_NPTXFIFO_SIZE; /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ regval = (offset | - (CONFIG_STM32_OTGFS_PTXFIFO_SIZE << OTGFS_HPTXFSIZ_PTXFD_SHIFT)); + (CONFIG_STM32_OTGFS_PTXFIFO_SIZE << + OTGFS_HPTXFSIZ_PTXFD_SHIFT)); stm32_putreg(STM32_OTGFS_HPTXFSIZ, regval); /* If OTG were supported, we should need to clear HNP enable bit in the @@ -5286,7 +5393,8 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv) /* Deactivate the power down */ - regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | OTGFS_GCCFG_VBUSBSEN); + regval = OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | + OTGFS_GCCFG_VBUSBSEN; #if !defined(CONFIG_USBDEV_VBUSSENSING) && !defined(CONFIG_STM32_OTGFS_VBUS_CONTROL) regval |= OTGFS_GCCFG_NOVBUSSENS; #endif @@ -5348,7 +5456,8 @@ FAR struct usbhost_connection_s *stm32_otgfshost_initialize(int controller) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c index 43f267867c..3e3f924749 100644 --- a/arch/arm/src/stm32/stm32_otghshost.c +++ b/arch/arm/src/stm32/stm32_otghshost.c @@ -1,35 +1,20 @@ /**************************************************************************** * arch/arm/src/stm32/stm32_otghshost.c * - * Copyright (C) 2012-2017 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. * ****************************************************************************/ @@ -140,7 +125,7 @@ # undef CONFIG_STM32_USBHOST_PKTDUMP #endif -/* HCD Setup *******************************************************************/ +/* HCD Setup ****************************************************************/ /* Hardware capabilities */ @@ -157,10 +142,10 @@ #define STM32_MAX_PKTCOUNT 256 /* Max packet count */ #define STM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */ -/* Delays **********************************************************************/ +/* Delays *******************************************************************/ -#define STM32_READY_DELAY 200000 /* In loop counts */ -#define STM32_FLUSH_DELAY 200000 /* In loop counts */ +#define STM32_READY_DELAY 200000 /* In loop counts */ +#define STM32_FLUSH_DELAY 200000 /* In loop counts */ #define STM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define STM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -276,7 +261,7 @@ struct stm32_usbhost_s volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ - struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -293,7 +278,7 @@ struct stm32_usbhost_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_STM32_USBHOST_REGDEBUG static void stm32_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -314,21 +299,24 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, # define stm32_pktdump(m,b,n) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void stm32_takesem(sem_t *sem); +static int stm32_takesem(sem_t *sem); +static int stm32_takesem_uninterruptible(sem_t *sem); #define stm32_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t stm32_getle16(const uint8_t *val); -/* Channel management **********************************************************/ +/* Channel management *******************************************************/ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv); -static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx); +static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, + int chidx); static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv); -static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, + int chidx); static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, enum stm32_chreason_e chreason); static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, @@ -343,7 +331,8 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep); static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -352,9 +341,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); -/* Control/data transfer logic *************************************************/ +/* Control/data transfer logic **********************************************/ -static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t stm32_getframe(void); #endif @@ -378,8 +368,9 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -388,7 +379,7 @@ static int stm32_out_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ /* Lower level interrupt handlers */ @@ -425,7 +416,7 @@ static void stm32_gint_disable(void); static inline void stm32_hostinit_enable(void); static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -436,26 +427,29 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int stm32_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -470,7 +464,7 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static void stm32_portreset(FAR struct stm32_usbhost_s *priv); static void stm32_flush_txfifos(uint32_t txfnum); @@ -485,9 +479,9 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct stm32_usbhost_s g_usbhost; @@ -539,8 +533,8 @@ static void stm32_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -638,7 +632,8 @@ static void stm32_putreg(uint32_t addr, uint32_t val) * ****************************************************************************/ -static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t setbits) +static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, + uint32_t setbits) { stm32_putreg(addr, (((stm32_getreg(addr)) & ~clrbits) | setbits)); } @@ -652,9 +647,43 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, uint32_t set * ****************************************************************************/ -static void stm32_takesem(sem_t *sem) +static int stm32_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: stm32_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int stm32_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -813,8 +842,9 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx) { /* Interrupts required for INTR endpoints */ - regval |= (OTGHS_HCINT_XFRC | OTGHS_HCINT_STALL | OTGHS_HCINT_NAK | - OTGHS_HCINT_TXERR | OTGHS_HCINT_FRMOR | OTGHS_HCINT_DTERR); + regval |= (OTGHS_HCINT_XFRC | OTGHS_HCINT_STALL | + OTGHS_HCINT_NAK | OTGHS_HCINT_TXERR | + OTGHS_HCINT_FRMOR | OTGHS_HCINT_DTERR); /* Additional setting for IN endpoints */ @@ -838,7 +868,7 @@ static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx) { /* Interrupts required for ISOC endpoints */ - regval |= (OTGHS_HCINT_XFRC | OTGHS_HCINT_ACK | OTGHS_HCINT_FRMOR); + regval |= OTGHS_HCINT_XFRC | OTGHS_HCINT_ACK | OTGHS_HCINT_FRMOR; /* Additional setting for IN endpoints */ @@ -919,21 +949,21 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(OTGHS_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_HS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_HS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_HS_HCINTx - * before reallocating the channel for other transactions. The OTG_HS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_HS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_HS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_HS_HCINTx before reallocating the channel for + * other transactions. The OTG_HS host does not interrupt the + * transaction that has already been started on the USB." */ hcchar = stm32_getreg(STM32_OTGHS_HCCHAR(chidx)); @@ -945,26 +975,29 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_HS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_HS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0." */ - if (eptype == OTGHS_HCCHAR_EPTYP_CTRL || eptype == OTGHS_HCCHAR_EPTYP_BULK) + if (eptype == OTGHS_HCCHAR_EPTYP_CTRL || + eptype == OTGHS_HCCHAR_EPTYP_BULK) { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32_getreg(STM32_OTGHS_HNPTXSTS) & OTGHS_HNPTXSTS_NPTXFSAV_MASK; + avail = stm32_getreg(STM32_OTGHS_HNPTXSTS) & + OTGHS_HNPTXSTS_NPTXFSAV_MASK; } - else /* if (eptype == OTGHS_HCCHAR_EPTYP_ISOC || eptype == OTGHS_HCCHAR_EPTYP_INTR) */ + else { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32_getreg(STM32_OTGHS_HPTXSTS) & OTGHS_HPTXSTS_PTXFSAVL_MASK; + avail = stm32_getreg(STM32_OTGHS_HPTXSTS) & + OTGHS_HPTXSTS_PTXFSAVL_MASK; } /* Check if there is any space available in the Tx FIFO. */ @@ -991,13 +1024,14 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, * Name: stm32_chan_waitsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the transfer). + * We do this to minimize race conditions. This logic would have to be + * expanded if we want to have more than one packet in flight at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1011,8 +1045,9 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1031,10 +1066,11 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, * Name: stm32_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1053,8 +1089,9 @@ static int stm32_chan_asynchsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1086,17 +1123,17 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, int ret; /* Disable interrupts so that the following operations will be atomic. On - * the OTG HS global interrupt needs to be disabled. However, here we disable - * all interrupts to exploit that fact that interrupts will be re-enabled - * while we wait. + * the OTG HS global interrupt needs to be disabled. However, here we + * disable all interrupts to exploit that fact that interrupts will be re- + * enabled while we wait. */ flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1187,7 +1224,8 @@ static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, ****************************************************************************/ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep) { FAR struct stm32_chan_s *chan; @@ -1256,8 +1294,8 @@ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -1272,8 +1310,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1281,7 +1319,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, /* Allocate a container for the control endpoint */ - ctrlep = (FAR struct stm32_ctrlinfo_s *)kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); + ctrlep = (FAR struct stm32_ctrlinfo_s *) + kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); if (ctrlep == NULL) { uerr("ERROR: Failed to allocate control endpoint container\n"); @@ -1305,7 +1344,7 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_xfrep_alloc * * Description: @@ -1318,13 +1357,13 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -1334,8 +1373,8 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1350,10 +1389,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint + * point type is encoded in the same way in the endpoint descriptor as it + * is in the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1582,7 +1621,8 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) #if 0 /* Not used */ static inline uint16_t stm32_getframe(void) { - return (uint16_t)(stm32_getreg(STM32_OTGHS_HFNUM) & OTGHS_HFNUM_FRNUM_MASK); + return (uint16_t) + (stm32_getreg(STM32_OTGHS_HFNUM) & OTGHS_HFNUM_FRNUM_MASK); } #endif @@ -1719,8 +1759,8 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, * Name: stm32_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1938,27 +1978,30 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* For Isochronous endpoints, bInterval must be 1. Bulk - * endpoints do not have a polling interval. Rather, - * the should wait until data is received. + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. * - * REVISIT: For bulk endpoints this 1 msec delay is only - * intended to give the CPU a break from the bulk EP tight - * polling loop. But are there performance issues? + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? */ delay = 1000; } /* Wait for the next polling interval. For interrupt and - * isochronous endpoints, this is necessaryto assure the + * isochronous endpoints, this is necessary to assure the * polling interval. It is used in other cases only to - * prevent the polling from consuming too much CPU bandwidth. + * prevent the polling from consuming too much CPU + * bandwidth. * - * Small delays could require more resolution than is provided - * by the system timer. For example, if the system timer - * resolution is 10MS, then nxsig_usleep(1000) will actually request - * a delay 20MS (due to both quantization and rounding). + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). * * REVISIT: So which is better? To ignore tiny delays and * hog the system bandwidth? Or to wait for an excessive @@ -2183,8 +2226,9 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * ****************************************************************************/ -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_chan_s *chan; clock_t start; @@ -2261,14 +2305,14 @@ static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ stm32_flush_txfifos(OTGHS_GRSTCTL_TXFNUM_HALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2445,8 +2489,8 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG HS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2492,7 +2536,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Clear the NAK and STALL Conditions. */ - stm32_putreg(STM32_OTGHS_HCINT(chidx), (OTGHS_HCINT_NAK | OTGHS_HCINT_STALL)); + stm32_putreg(STM32_OTGHS_HCINT(chidx), + OTGHS_HCINT_NAK | OTGHS_HCINT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2519,7 +2564,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the NAK and data toggle error conditions */ - stm32_putreg(STM32_OTGHS_HCINT(chidx), (OTGHS_HCINT_NAK | OTGHS_HCINT_DTERR)); + stm32_putreg(STM32_OTGHS_HCINT(chidx), + OTGHS_HCINT_NAK | OTGHS_HCINT_DTERR); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ @@ -2545,7 +2591,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Then handle the transfer completion event based on the endpoint type */ - if (chan->eptype == OTGHS_EPTYPE_CTRL || chan->eptype == OTGHS_EPTYPE_BULK) + if (chan->eptype == OTGHS_EPTYPE_CTRL || + chan->eptype == OTGHS_EPTYPE_BULK) { /* Halt the channel -- the CHH interrupt is expected next */ @@ -2658,11 +2705,12 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, } /* Re-activate CTRL and BULK channels. - * REVISIT: This can cause a lot of interrupts! + * + * REVISIT: This can cdause a lot of intedrrupts! + * REVISIT: BULK endpoints are not re-activated. */ - else if (chan->eptype == OTGHS_EPTYPE_CTRL /* || - chan->eptype == OTGHS_EPTYPE_BULK */) + else if (chan->eptype == OTGHS_EPTYPE_CTRL) { /* Re-activate the channel by clearing CHDIS and assuring that * CHENA is set @@ -2698,8 +2746,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG HS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2843,7 +2891,8 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - stm32_putreg(STM32_OTGHS_HCINT(chidx), (OTGHS_HCINT_DTERR | OTGHS_HCINT_NAK)); + stm32_putreg(STM32_OTGHS_HCINT(chidx), + OTGHS_HCINT_DTERR | OTGHS_HCINT_NAK); } /* Check for a pending CHannel Halted (CHH) interrupt */ @@ -2872,7 +2921,8 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, * transferred? */ - if ((regval & OTGHS_HCCHAR_EPTYP_MASK) == OTGHS_HCCHAR_EPTYP_BULK && + if ((regval & OTGHS_HCCHAR_EPTYP_MASK) == + OTGHS_HCCHAR_EPTYP_BULK && (chan->npackets & 1) != 0) { /* Yes to both... toggle the data out PID */ @@ -3066,7 +3116,8 @@ static inline void stm32_gint_rxflvlisr(FAR struct stm32_usbhost_s *priv) { /* Read the data into the host buffer. */ - bcnt = (grxsts & OTGHS_GRXSTSH_BCNT_MASK) >> OTGHS_GRXSTSH_BCNT_SHIFT; + bcnt = (grxsts & OTGHS_GRXSTSH_BCNT_MASK) >> + OTGHS_GRXSTSH_BCNT_SHIFT; if (bcnt > 0 && priv->chan[chidx].buffer != NULL) { /* Transfer the packet from the Rx FIFO into the user buffer */ @@ -3142,8 +3193,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3231,8 +3282,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3365,15 +3416,15 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) hprt = stm32_getreg(STM32_OTGHS_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ newhprt = hprt & ~(OTGHS_HPRT_PENA | OTGHS_HPRT_PCDET | OTGHS_HPRT_PENCHNG | OTGHS_HPRT_POCCHNG); - /* Check for Port Overcurrent CHaNGe (POCCHNG) */ + /* Check for Port Over-urrent CHaNGe (POCCHNG) */ if ((hprt & OTGHS_HPRT_POCCHNG) != 0) { @@ -3433,7 +3484,8 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) /* Are we switching from HS to LS? */ - if ((hcfg & OTGHS_HCFG_FSLSPCS_MASK) != OTGHS_HCFG_FSLSPCS_LS6MHz) + if ((hcfg & OTGHS_HCFG_FSLSPCS_MASK) != + OTGHS_HCFG_FSLSPCS_LS6MHz) { usbhost_vtrace1(OTGHS_VTRACE1_GINT_HPRT_FSLSSW, 0); @@ -3455,7 +3507,8 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) /* Are we switching from LS to HS? */ - if ((hcfg & OTGHS_HCFG_FSLSPCS_MASK) != OTGHS_HCFG_FSLSPCS_FS48MHz) + if ((hcfg & OTGHS_HCFG_FSLSPCS_MASK) != + OTGHS_HCFG_FSLSPCS_FS48MHz) { usbhost_vtrace1(OTGHS_VTRACE1_GINT_HPRT_LSFSSW, 0); @@ -3535,7 +3588,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) /* At present, there is only support for a single OTG HS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; @@ -3546,8 +3600,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3814,10 +3868,10 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or @@ -3838,6 +3892,7 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct stm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3862,7 +3917,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3879,7 +3935,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3887,7 +3944,11 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - stm32_takesem(&priv->pscsem); + ret = stm32_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3911,8 +3972,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3966,7 +4027,8 @@ static int stm32_rh_enumerate(FAR struct stm32_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -4022,7 +4084,7 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ep0configure * * Description: @@ -4031,38 +4093,43 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, * external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize) +static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; FAR struct stm32_ctrlinfo_s *ep0info = (FAR struct stm32_ctrlinfo_s *)ep0; FAR struct stm32_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4086,27 +4153,27 @@ static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4115,15 +4182,19 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require @@ -4144,35 +4215,36 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; + int ret; DEBUGASSERT(priv); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem_uninterruptible(&priv->exclsem); /* A single channel is represent by an index in the range of 0 to * STM32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated @@ -4189,7 +4261,9 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct stm32_ctrlinfo_s *ctrlep = (FAR struct stm32_ctrlinfo_s *)ep; + FAR struct stm32_ctrlinfo_s *ctrlep = + (FAR struct stm32_ctrlinfo_s *)ep; + stm32_chan_free(priv, ctrlep->inndx); stm32_chan_free(priv, ctrlep->outndx); @@ -4199,34 +4273,35 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } stm32_givesem(&priv->exclsem); - return OK; + return ret; } /**************************************************************************** * Name: stm32_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4260,19 +4335,20 @@ static int stm32_alloc(FAR struct usbhost_driver_s *drvr, * Name: stm32_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4288,32 +4364,34 @@ static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4336,30 +4414,31 @@ static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4373,29 +4452,31 @@ static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. * req - Describes the request to be sent. This request must lie in memory * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4427,7 +4508,11 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4510,7 +4595,11 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4579,26 +4668,27 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or * ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4612,12 +4702,14 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; ssize_t nbytes; + int ret; uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4625,7 +4717,11 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4656,20 +4752,21 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4692,7 +4789,11 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4710,7 +4811,7 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: stm32_cancel * * Description: @@ -4718,16 +4819,16 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4741,8 +4842,8 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < STM32_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being cancelled. */ flags = enter_critical_section(); @@ -4797,7 +4898,7 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_connect * * Description: @@ -4806,17 +4907,17 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int stm32_connect(FAR struct usbhost_driver_s *drvr, @@ -4831,7 +4932,8 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4852,17 +4954,18 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, * Name: stm32_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4880,17 +4983,14 @@ static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: stm32_portreset * * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in * OTG_HS_GOTGINT), which indicates that the bus is stable again after the * electrical debounce caused by the attachment of a pull-up resistor on DP * (HS) or DM (LS). @@ -5049,9 +5149,9 @@ static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from stm32_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from stm32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5100,14 +5200,16 @@ static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv) /* Setup the host non-periodic Tx FIFO size (HNPTXHSIZ) */ regval = (offset | - (CONFIG_STM32_OTGHS_NPTXFIFO_SIZE << OTGHS_HNPTXFSIZ_NPTXFD_SHIFT)); + (CONFIG_STM32_OTGHS_NPTXFIFO_SIZE << + OTGHS_HNPTXFSIZ_NPTXFD_SHIFT)); stm32_putreg(STM32_OTGHS_HNPTXFSIZ, regval); offset += CONFIG_STM32_OTGHS_NPTXFIFO_SIZE; /* Set up the host periodic Tx fifo size register (HPTXHSIZ) */ regval = (offset | - (CONFIG_STM32_OTGHS_PTXFIFO_SIZE << OTGHS_HPTXFSIZ_PTXFD_SHIFT)); + (CONFIG_STM32_OTGHS_PTXFIFO_SIZE << + OTGHS_HPTXFSIZ_PTXFD_SHIFT)); stm32_putreg(STM32_OTGHS_HPTXFSIZ, regval); /* If OTG were supported, we should need to clear HNP enable bit in the @@ -5291,7 +5393,8 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv) /* Deactivate the power down */ - regval = (OTGHS_GCCFG_PWRDWN | OTGHS_GCCFG_VBUSASEN | OTGHS_GCCFG_VBUSBSEN); + regval = OTGHS_GCCFG_PWRDWN | OTGHS_GCCFG_VBUSASEN | + OTGHS_GCCFG_VBUSBSEN; #ifndef CONFIG_USBDEV_VBUSSENSING regval |= OTGHS_GCCFG_NOVBUSSENS; #endif @@ -5353,7 +5456,8 @@ FAR struct usbhost_connection_s *stm32_otghshost_initialize(int controller) /* At present, there is only support for a single OTG HS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; diff --git a/arch/arm/src/stm32f7/stm32_otghost.c b/arch/arm/src/stm32f7/stm32_otghost.c index 0eaca21904..b47bf54d63 100644 --- a/arch/arm/src/stm32f7/stm32_otghost.c +++ b/arch/arm/src/stm32f7/stm32_otghost.c @@ -154,8 +154,8 @@ /* Delays *******************************************************************/ -#define STM32_READY_DELAY 200000 /* In loop counts */ -#define STM32_FLUSH_DELAY 200000 /* In loop counts */ +#define STM32_READY_DELAY 200000 /* In loop counts */ +#define STM32_FLUSH_DELAY 200000 /* In loop counts */ #define STM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define STM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -271,7 +271,7 @@ struct stm32_usbhost_s volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ - struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -311,7 +311,8 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, /* Semaphores ***************************************************************/ -static void stm32_takesem(sem_t *sem); +static int stm32_takesem(sem_t *sem); +static int stm32_takesem_uninterruptible(sem_t *sem); #define stm32_givesem(s) nxsem_post(s); /* Byte stream access helper functions **************************************/ @@ -321,9 +322,11 @@ static inline uint16_t stm32_getle16(const uint8_t *val); /* Channel management *******************************************************/ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv); -static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx); +static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, + int chidx); static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv); -static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, + int chidx); static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, enum stm32_chreason_e chreason); static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, @@ -338,7 +341,8 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep); static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -349,7 +353,8 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, /* Control/data transfer logic **********************************************/ -static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t stm32_getframe(void); #endif @@ -373,8 +378,9 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -431,26 +437,29 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int stm32_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -480,9 +489,9 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct stm32_usbhost_s g_usbhost; @@ -530,8 +539,8 @@ static void stm32_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -644,9 +653,43 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, * ****************************************************************************/ -static void stm32_takesem(sem_t *sem) +static int stm32_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: stm32_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int stm32_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -911,21 +954,21 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(OTG_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_FS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx - * before reallocating the channel for other transactions. The OTG_FS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." */ hcchar = stm32_getreg(STM32_OTG_HCCHAR(chidx)); @@ -937,13 +980,13 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0. */ if (eptype == OTG_HCCHAR_EPTYP_CTRL || eptype == OTG_HCCHAR_EPTYP_BULK) @@ -989,7 +1032,8 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, * expanded if we want to have more than one packet in flight at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1003,8 +1047,9 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1023,10 +1068,11 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, * Name: stm32_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1045,8 +1091,9 @@ static int stm32_chan_asynchsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1086,9 +1133,9 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1179,7 +1226,8 @@ static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, ****************************************************************************/ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep) { FAR struct stm32_chan_s *chan; @@ -1264,8 +1312,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1273,7 +1321,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, /* Allocate a container for the control endpoint */ - ctrlep = (FAR struct stm32_ctrlinfo_s *)kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); + ctrlep = (FAR struct stm32_ctrlinfo_s *) + kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); if (ctrlep == NULL) { uerr("ERROR: Failed to allocate control endpoint container\n"); @@ -1326,8 +1375,8 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1342,10 +1391,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint point + * type is encoded in the same way in the endpoint descriptor as it is in + * the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1711,8 +1760,8 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, * Name: stm32_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1930,27 +1979,30 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* For Isochronous endpoints, bInterval must be 1. Bulk - * endpoints do not have a polling interval. Rather, - * the should wait until data is received. + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. * - * REVISIT: For bulk endpoints this 1 msec delay is only - * intended to give the CPU a break from the bulk EP tight - * polling loop. But are there performance issues? + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? */ delay = 1000; } /* Wait for the next polling interval. For interrupt and - * isochronous endpoints, this is necessaryto assure the + * isochronous endpoints, this is necessary to assure the * polling interval. It is used in other cases only to - * prevent the polling from consuming too much CPU bandwidth. + * prevent the polling from consuming too much CPU + * bandwidth. * - * Small delays could require more resolution than is provided - * by the system timer. For example, if the system timer - * resolution is 10MS, then nxsig_usleep(1000) will actually request - * a delay 20MS (due to both quantization and rounding). + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). * * REVISIT: So which is better? To ignore tiny delays and * hog the system bandwidth? Or to wait for an excessive @@ -2175,8 +2227,9 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * ****************************************************************************/ -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_chan_s *chan; clock_t start; @@ -2253,14 +2306,14 @@ static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ stm32_flush_txfifos(OTG_GRSTCTL_TXFNUM_HALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2437,8 +2490,8 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2484,7 +2537,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Clear the NAK and STALL Conditions. */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_NAK | OTG_HCINT_STALL)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_NAK | OTG_HCINT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2511,7 +2564,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the NAK and data toggle error conditions */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_NAK | OTG_HCINT_DTERR)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_NAK | OTG_HCINT_DTERR); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ @@ -2650,11 +2703,12 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, } /* Re-activate CTRL and BULK channels. + * * REVISIT: This can cause a lot of interrupts! + * REVISIT: The BULK endpoint is not re-activated. */ - else if (chan->eptype == OTG_EPTYPE_CTRL /* || - chan->eptype == OTG_EPTYPE_BULK */) + else if (chan->eptype == OTG_EPTYPE_CTRL) { /* Re-activate the channel by clearing CHDIS and assuring that * CHENA is set @@ -2690,8 +2744,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2835,7 +2889,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_DTERR | OTG_HCINT_NAK)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_DTERR | OTG_HCINT_NAK); } /* Check for a pending CHannel Halted (CHH) interrupt */ @@ -3134,8 +3188,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3161,7 +3215,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Extract the number of bytes available in the non-periodic Tx FIFO. */ - avail = ((regval & OTG_HNPTXSTS_NPTXFSAV_MASK) >> OTG_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + avail = ((regval & OTG_HNPTXSTS_NPTXFSAV_MASK) >> + OTG_HNPTXSTS_NPTXFSAV_SHIFT) << 2; /* Get the size to put in the Tx FIFO now */ @@ -3193,8 +3248,9 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3222,8 +3278,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3249,7 +3305,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) /* Extract the number of bytes available in the periodic Tx FIFO. */ - avail = ((regval & OTG_HPTXSTS_PTXFSAVL_MASK) >> OTG_HPTXSTS_PTXFSAVL_SHIFT) << 2; + avail = ((regval & OTG_HPTXSTS_PTXFSAVL_MASK) >> + OTG_HPTXSTS_PTXFSAVL_SHIFT) << 2; /* Get the size to put in the Tx FIFO now */ @@ -3355,9 +3412,9 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) hprt = stm32_getreg(STM32_OTG_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ newhprt = hprt & ~(OTG_HPRT_PENA | OTG_HPRT_PCDET | @@ -3516,16 +3573,17 @@ static inline void stm32_gint_ipxfrisr(FAR struct stm32_usbhost_s *priv) * Name: stm32_gint_isr * * Description: - * USB OTG FS global interrupt handler + * USB OTG global interrupt handler * ****************************************************************************/ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) { - /* At present, there is only support for a single OTG FS host. Hence it is + /* At present, there is only support for a single OTG host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; @@ -3536,8 +3594,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3793,10 +3851,6 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) leave_critical_section(flags); } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ - /**************************************************************************** * Name: stm32_wait * @@ -3804,10 +3858,10 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or @@ -3828,6 +3882,7 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct stm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3852,7 +3907,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3869,7 +3925,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3877,7 +3934,11 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - stm32_takesem(&priv->pscsem); + ret = stm32_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3901,8 +3962,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3956,7 +4017,8 @@ static int stm32_rh_enumerate(FAR struct stm32_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -4012,7 +4074,7 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ep0configure * * Description: @@ -4021,38 +4083,43 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, * external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, - uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize) +static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; FAR struct stm32_ctrlinfo_s *ep0info = (FAR struct stm32_ctrlinfo_s *)ep0; FAR struct stm32_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4076,27 +4143,27 @@ static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4105,15 +4172,19 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require @@ -4134,35 +4205,36 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; + int ret; DEBUGASSERT(priv); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem_uninterruptible(&priv->exclsem); /* A single channel is represent by an index in the range of 0 to * STM32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated @@ -4179,7 +4251,9 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct stm32_ctrlinfo_s *ctrlep = (FAR struct stm32_ctrlinfo_s *)ep; + FAR struct stm32_ctrlinfo_s *ctrlep = + (FAR struct stm32_ctrlinfo_s *)ep; + stm32_chan_free(priv, ctrlep->inndx); stm32_chan_free(priv, ctrlep->outndx); @@ -4189,34 +4263,35 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } stm32_givesem(&priv->exclsem); - return OK; + return ret; } /**************************************************************************** * Name: stm32_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4250,19 +4325,20 @@ static int stm32_alloc(FAR struct usbhost_driver_s *drvr, * Name: stm32_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4278,32 +4354,34 @@ static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4326,30 +4404,31 @@ static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4363,29 +4442,31 @@ static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4417,7 +4498,11 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4500,7 +4585,11 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4569,26 +4658,27 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or - * ctrlout methods can be called again until this function returns. + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin + * or ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4602,8 +4692,9 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; @@ -4615,7 +4706,11 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4646,20 +4741,21 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4682,7 +4778,11 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4700,7 +4800,7 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: stm32_cancel * * Description: @@ -4708,16 +4808,16 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4731,8 +4831,8 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < STM32_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being cancelled. */ flags = enter_critical_section(); @@ -4787,7 +4887,7 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_connect * * Description: @@ -4796,17 +4896,17 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int stm32_connect(FAR struct usbhost_driver_s *drvr, @@ -4821,7 +4921,8 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4842,17 +4943,18 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, * Name: stm32_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4870,20 +4972,17 @@ static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: stm32_portreset * * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in - * OTG_FS_GOTGINT), which indicates that the bus is stable again after the - * electrical debounce caused by the attachment of a pull-up resistor on DP - * (FS) or DM (LS). + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * OTG_FS_GOTGINT), which indicates that the bus is stable again after + * the electrical debounce caused by the attachment of a pull-up resistor + * on DP (FS) or DM (LS). * * Input Parameters: * priv -- USB host driver private data structure. @@ -5039,9 +5138,9 @@ static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from stm32_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from stm32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5090,14 +5189,16 @@ static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv) /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ regval = (offset | - (CONFIG_STM32F7_OTG_NPTXFIFO_SIZE << OTG_HNPTXFSIZ_NPTXFD_SHIFT)); + (CONFIG_STM32F7_OTG_NPTXFIFO_SIZE << + OTG_HNPTXFSIZ_NPTXFD_SHIFT)); stm32_putreg(STM32_OTG_HNPTXFSIZ, regval); offset += CONFIG_STM32F7_OTG_NPTXFIFO_SIZE; /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ regval = (offset | - (CONFIG_STM32F7_OTG_PTXFIFO_SIZE << OTG_HPTXFSIZ_PTXFD_SHIFT)); + (CONFIG_STM32F7_OTG_PTXFIFO_SIZE << + OTG_HPTXFSIZ_PTXFD_SHIFT)); stm32_putreg(STM32_OTG_HPTXFSIZ, regval); /* If OTG were supported, we would need to clear HNP enable bit in the @@ -5343,7 +5444,8 @@ FAR struct usbhost_connection_s *stm32_otgfshost_initialize(int controller) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; diff --git a/arch/arm/src/stm32h7/stm32_otghost.c b/arch/arm/src/stm32h7/stm32_otghost.c index dd35019488..724a3fadd0 100644 --- a/arch/arm/src/stm32h7/stm32_otghost.c +++ b/arch/arm/src/stm32h7/stm32_otghost.c @@ -159,8 +159,8 @@ /* Delays *******************************************************************/ -#define STM32_READY_DELAY 200000 /* In loop counts */ -#define STM32_FLUSH_DELAY 200000 /* In loop counts */ +#define STM32_READY_DELAY 200000 /* In loop counts */ +#define STM32_FLUSH_DELAY 200000 /* In loop counts */ #define STM32_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define STM32_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -276,7 +276,7 @@ struct stm32_usbhost_s volatile bool pscwait; /* True: Thread is waiting for a port event */ sem_t exclsem; /* Support mutually exclusive access */ sem_t pscsem; /* Semaphore to wait for a port event */ - struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ + struct stm32_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -316,7 +316,8 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, /* Semaphores ***************************************************************/ -static void stm32_takesem(sem_t *sem); +static int stm32_takesem(sem_t *sem); +static int stm32_takesem_uninterruptible(sem_t *sem); #define stm32_givesem(s) nxsem_post(s); /* Byte stream access helper functions **************************************/ @@ -326,9 +327,11 @@ static inline uint16_t stm32_getle16(const uint8_t *val); /* Channel management *******************************************************/ static int stm32_chan_alloc(FAR struct stm32_usbhost_s *priv); -static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, int chidx); +static inline void stm32_chan_free(FAR struct stm32_usbhost_s *priv, + int chidx); static inline void stm32_chan_freeall(FAR struct stm32_usbhost_s *priv); -static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_chan_configure(FAR struct stm32_usbhost_s *priv, + int chidx); static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, enum stm32_chreason_e chreason); static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, @@ -343,7 +346,8 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep); static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -354,7 +358,8 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, /* Control/data transfer logic **********************************************/ -static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx); +static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t stm32_getframe(void); #endif @@ -378,8 +383,9 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -436,26 +442,29 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); static int stm32_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -485,9 +494,9 @@ static inline int stm32_hw_initialize(FAR struct stm32_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct stm32_usbhost_s g_usbhost; @@ -535,8 +544,8 @@ static void stm32_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -649,9 +658,43 @@ static inline void stm32_modifyreg(uint32_t addr, uint32_t clrbits, * ****************************************************************************/ -static void stm32_takesem(sem_t *sem) +static int stm32_takesem(sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: stm32_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int stm32_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -916,21 +959,21 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(OTG_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_FS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx - * before reallocating the channel for other transactions. The OTG_FS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." */ hcchar = stm32_getreg(STM32_OTG_HCCHAR(chidx)); @@ -942,13 +985,13 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0. */ if (eptype == OTG_HCCHAR_EPTYP_CTRL || eptype == OTG_HCCHAR_EPTYP_BULK) @@ -994,7 +1037,8 @@ static void stm32_chan_halt(FAR struct stm32_usbhost_s *priv, int chidx, * expanded if we want to have more than one packet in flight at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1008,8 +1052,9 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1028,10 +1073,11 @@ static int stm32_chan_waitsetup(FAR struct stm32_usbhost_s *priv, * Name: stm32_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1050,8 +1096,9 @@ static int stm32_chan_asynchsetup(FAR struct stm32_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1091,9 +1138,9 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1184,7 +1231,8 @@ static void stm32_chan_wakeup(FAR struct stm32_usbhost_s *priv, ****************************************************************************/ static int stm32_ctrlchan_alloc(FAR struct stm32_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr + uint8_t speed, FAR struct stm32_ctrlinfo_s *ctrlep) { FAR struct stm32_chan_s *chan; @@ -1269,8 +1317,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1278,7 +1326,8 @@ static int stm32_ctrlep_alloc(FAR struct stm32_usbhost_s *priv, /* Allocate a container for the control endpoint */ - ctrlep = (FAR struct stm32_ctrlinfo_s *)kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); + ctrlep = (FAR struct stm32_ctrlinfo_s *) + kmm_malloc(sizeof(struct stm32_ctrlinfo_s)); if (ctrlep == NULL) { uerr("ERROR: Failed to allocate control endpoint container\n"); @@ -1331,8 +1380,8 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1347,10 +1396,10 @@ static int stm32_xfrep_alloc(FAR struct stm32_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint point + * type is encoded in the same way in the endpoint descriptor as it is in + * the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1716,8 +1765,8 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, * Name: stm32_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1935,27 +1984,30 @@ static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, } else { - /* For Isochronous endpoints, bInterval must be 1. Bulk - * endpoints do not have a polling interval. Rather, - * the should wait until data is received. + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. * - * REVISIT: For bulk endpoints this 1 msec delay is only - * intended to give the CPU a break from the bulk EP tight - * polling loop. But are there performance issues? + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? */ delay = 1000; } /* Wait for the next polling interval. For interrupt and - * isochronous endpoints, this is necessaryto assure the + * isochronous endpoints, this is necessary to assure the * polling interval. It is used in other cases only to - * prevent the polling from consuming too much CPU bandwidth. + * prevent the polling from consuming too much CPU + * bandwidth. * - * Small delays could require more resolution than is provided - * by the system timer. For example, if the system timer - * resolution is 10MS, then nxsig_usleep(1000) will actually request - * a delay 20MS (due to both quantization and rounding). + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). * * REVISIT: So which is better? To ignore tiny delays and * hog the system bandwidth? Or to wait for an excessive @@ -2180,8 +2232,9 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * ****************************************************************************/ -static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_chan_s *chan; clock_t start; @@ -2258,14 +2311,14 @@ static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ stm32_flush_txfifos(OTG_GRSTCTL_TXFNUM_HALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2442,8 +2495,8 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2489,7 +2542,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, { /* Clear the NAK and STALL Conditions. */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_NAK | OTG_HCINT_STALL)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_NAK | OTG_HCINT_STALL); /* Halt the channel when a STALL, TXERR, BBERR or DTERR interrupt is * received on the channel. @@ -2516,7 +2569,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Clear the NAK and data toggle error conditions */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_NAK | OTG_HCINT_DTERR)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_NAK | OTG_HCINT_DTERR); } /* Check for a pending FRaMe OverRun (FRMOR) interrupt */ @@ -2656,10 +2709,10 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, /* Re-activate CTRL and BULK channels. * REVISIT: This can cause a lot of interrupts! + * REVISIT: BULK channel is not re-activated. */ - else if (chan->eptype == OTG_EPTYPE_CTRL /* || - chan->eptype == OTG_EPTYPE_BULK */) + else if (chan->eptype == OTG_EPTYPE_CTRL) { /* Re-activate the channel by clearing CHDIS and assuring that * CHENA is set @@ -2695,8 +2748,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv, * Description: * USB OTG FS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2840,7 +2893,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, /* Clear the pending the Data Toggle ERRor (DTERR) and NAK interrupts */ - stm32_putreg(STM32_OTG_HCINT(chidx), (OTG_HCINT_DTERR | OTG_HCINT_NAK)); + stm32_putreg(STM32_OTG_HCINT(chidx), OTG_HCINT_DTERR | OTG_HCINT_NAK); } /* Check for a pending CHannel Halted (CHH) interrupt */ @@ -3139,8 +3192,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3166,7 +3219,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Extract the number of bytes available in the non-periodic Tx FIFO. */ - avail = ((regval & OTG_HNPTXSTS_NPTXFSAV_MASK) >> OTG_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + avail = ((regval & OTG_HNPTXSTS_NPTXFSAV_MASK) >> + OTG_HNPTXSTS_NPTXFSAV_SHIFT) << 2; /* Get the size to put in the Tx FIFO now */ @@ -3198,8 +3252,9 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3227,8 +3282,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3254,7 +3309,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) /* Extract the number of bytes available in the periodic Tx FIFO. */ - avail = ((regval & OTG_HPTXSTS_PTXFSAVL_MASK) >> OTG_HPTXSTS_PTXFSAVL_SHIFT) << 2; + avail = ((regval & OTG_HPTXSTS_PTXFSAVL_MASK) >> + OTG_HPTXSTS_PTXFSAVL_SHIFT) << 2; /* Get the size to put in the Tx FIFO now */ @@ -3360,9 +3416,9 @@ static inline void stm32_gint_hprtisr(FAR struct stm32_usbhost_s *priv) hprt = stm32_getreg(STM32_OTG_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ newhprt = hprt & ~(OTG_HPRT_PENA | OTG_HPRT_PCDET | @@ -3521,16 +3577,17 @@ static inline void stm32_gint_ipxfrisr(FAR struct stm32_usbhost_s *priv) * Name: stm32_gint_isr * * Description: - * USB OTG FS global interrupt handler + * USB OTG global interrupt handler * ****************************************************************************/ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) { - /* At present, there is only support for a single OTG FS host. Hence it is + /* At present, there is only support for a single OTG host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; @@ -3541,8 +3598,8 @@ static int stm32_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3798,10 +3855,6 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) leave_critical_section(flags); } -/**************************************************************************** - * USB Host Controller Operations - ****************************************************************************/ - /**************************************************************************** * Name: stm32_wait * @@ -3809,10 +3862,10 @@ static void stm32_txfe_enable(FAR struct stm32_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. - * hport - The location to return the hub port descriptor that detected the - * connection related event. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. * * Returned Value: * Zero (OK) is returned on success when a device is connected or @@ -3833,6 +3886,7 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, FAR struct stm32_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3857,7 +3911,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3874,7 +3929,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uinfo("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3882,7 +3938,11 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - stm32_takesem(&priv->pscsem); + ret = stm32_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3906,8 +3966,8 @@ static int stm32_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3961,7 +4021,8 @@ static int stm32_rh_enumerate(FAR struct stm32_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = stm32_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -4017,7 +4078,7 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ep0configure * * Description: @@ -4026,38 +4087,44 @@ static int stm32_enumerate(FAR struct usbhost_connection_s *conn, * external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, +static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; FAR struct stm32_ctrlinfo_s *ep0info = (FAR struct stm32_ctrlinfo_s *)ep0; FAR struct stm32_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4081,27 +4148,27 @@ static int stm32_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4110,19 +4177,25 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); - /* We must have exclusive access to the USB host hardware and state structures */ + /* We must have exclusive access to the USB host hardware and state + * structures. + */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require - * only a single channel. Control endpoints, however, are bi-diretional + * only a single channel. Control endpoints, however, are bi-directional * and require two channels, one for the IN and one for the OUT direction. */ @@ -4139,25 +4212,25 @@ static int stm32_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4167,7 +4240,7 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem_uninterruptible(&priv->exclsem); /* A single channel is represent by an index in the range of 0 to * STM32_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated @@ -4184,7 +4257,9 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct stm32_ctrlinfo_s *ctrlep = (FAR struct stm32_ctrlinfo_s *)ep; + FAR struct stm32_ctrlinfo_s *ctrlep = + (FAR struct stm32_ctrlinfo_s *)ep; + stm32_chan_free(priv, ctrlep->inndx); stm32_chan_free(priv, ctrlep->outndx); @@ -4194,34 +4269,35 @@ static int stm32_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } stm32_givesem(&priv->exclsem); - return OK; + return ret; } /**************************************************************************** * Name: stm32_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but + * an output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4255,19 +4331,20 @@ static int stm32_alloc(FAR struct usbhost_driver_s *drvr, * Name: stm32_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Never called from an interrupt handler. @@ -4283,32 +4360,34 @@ static int stm32_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen) @@ -4331,30 +4410,31 @@ static int stm32_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4368,29 +4448,31 @@ static int stm32_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. - * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4422,7 +4504,11 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4505,7 +4591,11 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4574,26 +4664,27 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or - * ctrlout methods can be called again until this function returns. + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin + * or ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4607,12 +4698,14 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; ssize_t nbytes; + int ret; uinfo("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4620,7 +4713,11 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4651,20 +4748,21 @@ static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4687,7 +4785,11 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - stm32_takesem(&priv->exclsem); + ret = stm32_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4705,7 +4807,7 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: stm32_cancel * * Description: @@ -4713,16 +4815,16 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4736,8 +4838,8 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < STM32_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being canceled. */ flags = enter_critical_section(); @@ -4792,7 +4894,7 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32_connect * * Description: @@ -4801,17 +4903,17 @@ static int stm32_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int stm32_connect(FAR struct usbhost_driver_s *drvr, @@ -4826,7 +4928,8 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4847,17 +4950,18 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, * Name: stm32_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4875,20 +4979,17 @@ static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, hport->devclass = NULL; } -/**************************************************************************** - * Initialization - ****************************************************************************/ /**************************************************************************** * Name: stm32_portreset * * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in - * OTG_FS_GOTGINT), which indicates that the bus is stable again after the - * electrical debounce caused by the attachment of a pull-up resistor on DP - * (FS) or DM (LS). + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * OTG_FS_GOTGINT), which indicates that the bus is stable again after + * the electrical debounce caused by the attachment of a pull-up resistor + * on DP (FS) or DM (LS). * * Input Parameters: * priv -- USB host driver private data structure. @@ -5044,9 +5145,9 @@ static void stm32_vbusdrive(FAR struct stm32_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from stm32_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from stm32_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5095,14 +5196,16 @@ static void stm32_host_initialize(FAR struct stm32_usbhost_s *priv) /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ regval = (offset | - (CONFIG_STM32H7_OTG_NPTXFIFO_SIZE << OTG_HNPTXFSIZ_NPTXFD_SHIFT)); + (CONFIG_STM32H7_OTG_NPTXFIFO_SIZE << + OTG_HNPTXFSIZ_NPTXFD_SHIFT)); stm32_putreg(STM32_OTG_HNPTXFSIZ, regval); offset += CONFIG_STM32H7_OTG_NPTXFIFO_SIZE; /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ regval = (offset | - (CONFIG_STM32H7_OTG_PTXFIFO_SIZE << OTG_HPTXFSIZ_PTXFD_SHIFT)); + (CONFIG_STM32H7_OTG_PTXFIFO_SIZE << + OTG_HPTXFSIZ_PTXFD_SHIFT)); stm32_putreg(STM32_OTG_HPTXFSIZ, regval); /* If OTG were supported, we should need to clear HNP enable bit in the @@ -5342,7 +5445,8 @@ FAR struct usbhost_connection_s *stm32_otgfshost_initialize(int controller) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32_usbhost_s *priv = &g_usbhost; diff --git a/arch/arm/src/stm32l4/stm32l4_otgfshost.c b/arch/arm/src/stm32l4/stm32l4_otgfshost.c index dcfce65ed0..7dbec37011 100644 --- a/arch/arm/src/stm32l4/stm32l4_otgfshost.c +++ b/arch/arm/src/stm32l4/stm32l4_otgfshost.c @@ -91,9 +91,10 @@ * Default 128 (512 bytes) * CONFIG_STM32L4_OTGFS_NPTXFIFO_SIZE - Size of the non-periodic Tx FIFO * in 32-bit words. Default 96 (384 bytes) - * CONFIG_STM32L4_OTGFS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in 32-bit - * words. Default 96 (384 bytes) - * CONFIG_STM32L4_OTGFS_DESCSIZE - Maximum size of a descriptor. Default: 128 + * CONFIG_STM32L4_OTGFS_PTXFIFO_SIZE - Size of the periodic Tx FIFO in + * 32-bit words. Default 96 (384 bytes) + * CONFIG_STM32L4_OTGFS_DESCSIZE - Maximum size of a descriptor. Default: + * 128 * CONFIG_STM32L4_OTGFS_SOFINTR - Enable SOF interrupts. Why would you ever * want to do that? * CONFIG_STM32L4_USBHOST_REGDEBUG - Enable very low-level register access @@ -139,7 +140,7 @@ # undef CONFIG_STM32L4_USBHOST_PKTDUMP #endif -/* HCD Setup *******************************************************************/ +/* HCD Setup ****************************************************************/ /* Hardware capabilities */ @@ -151,10 +152,10 @@ #define STM32L4_MAX_PKTCOUNT 256 /* Max packet count */ #define STM32L4_RETRY_COUNT 3 /* Number of ctrl transfer retries */ -/* Delays **********************************************************************/ +/* Delays *******************************************************************/ -#define STM32L4_READY_DELAY 200000 /* In loop counts */ -#define STM32L4_FLUSH_DELAY 200000 /* In loop counts */ +#define STM32L4_READY_DELAY 200000 /* In loop counts */ +#define STM32L4_FLUSH_DELAY 200000 /* In loop counts */ #define STM32L4_SETUP_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ #define STM32L4_DATANAK_DELAY SEC2TICK(5) /* 5 seconds in system ticks */ @@ -263,14 +264,14 @@ struct stm32l4_usbhost_s /* Overall driver status */ - volatile uint8_t smstate; /* The state of the USB host state machine */ - uint8_t chidx; /* ID of channel waiting for space in Tx FIFO */ - volatile bool connected; /* Connected to device */ - volatile bool change; /* Connection change */ - volatile bool pscwait; /* True: Thread is waiting for a port event */ - sem_t exclsem; /* Support mutually exclusive access */ - sem_t pscsem; /* Semaphore to wait for a port event */ - struct stm32l4_ctrlinfo_s ep0; /* Root hub port EP0 description */ + volatile uint8_t smstate; /* The state of the USB host state machine */ + uint8_t chidx; /* ID of channel waiting for space in Tx FIFO */ + volatile bool connected; /* Connected to device */ + volatile bool change; /* Connection change */ + volatile bool pscwait; /* True: Thread is waiting for a port event */ + sem_t exclsem; /* Support mutually exclusive access */ + sem_t pscsem; /* Semaphore to wait for a port event */ + struct stm32l4_ctrlinfo_s ep0; /* Root hub port EP0 description */ #ifdef CONFIG_USBHOST_HUB /* Used to pass external hub port events */ @@ -287,7 +288,7 @@ struct stm32l4_usbhost_s * Private Function Prototypes ****************************************************************************/ -/* Register operations ********************************************************/ +/* Register operations ******************************************************/ #ifdef CONFIG_STM32L4_USBHOST_REGDEBUG static void stm32l4_printreg(uint32_t addr, uint32_t val, bool iswrite); @@ -308,36 +309,41 @@ static inline void stm32l4_modifyreg(uint32_t addr, uint32_t clrbits, # define stm32l4_pktdump(m,b,n) #endif -/* Semaphores ******************************************************************/ +/* Semaphores ***************************************************************/ -static void stm32l4_takesem(FAR sem_t *sem); +static int stm32l4_takesem(FAR sem_t *sem); +static int stm32l4_takesem_uninterruptible(FAR sem_t *sem); #define stm32l4_givesem(s) nxsem_post(s); -/* Byte stream access helper functions *****************************************/ +/* Byte stream access helper functions **************************************/ static inline uint16_t stm32l4_getle16(FAR const uint8_t *val); -/* Channel management **********************************************************/ +/* Channel management *******************************************************/ static int stm32l4_chan_alloc(FAR struct stm32l4_usbhost_s *priv); -static inline void stm32l4_chan_free(FAR struct stm32l4_usbhost_s *priv, int chidx); +static inline void stm32l4_chan_free(FAR struct stm32l4_usbhost_s *priv, + int chidx); static inline void stm32l4_chan_freeall(FAR struct stm32l4_usbhost_s *priv); -static void stm32l4_chan_configure(FAR struct stm32l4_usbhost_s *priv, int chidx); -static void stm32l4_chan_halt(FAR struct stm32l4_usbhost_s *priv, int chidx, - enum stm32l4_chreason_e chreason); +static void stm32l4_chan_configure(FAR struct stm32l4_usbhost_s *priv, + int chidx); +static void stm32l4_chan_halt(FAR struct stm32l4_usbhost_s *priv, + int chidx, enum stm32l4_chreason_e chreason); static int stm32l4_chan_waitsetup(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan); #ifdef CONFIG_USBHOST_ASYNCH static int stm32l4_chan_asynchsetup(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan, - usbhost_asynch_t callback, FAR void *arg); + usbhost_asynch_t callback, + FAR void *arg); #endif static int stm32l4_chan_wait(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan); static void stm32l4_chan_wakeup(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan); static int stm32l4_ctrlchan_alloc(FAR struct stm32l4_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32l4_ctrlinfo_s *ctrlep); static int stm32l4_ctrlep_alloc(FAR struct stm32l4_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -346,9 +352,10 @@ static int stm32l4_xfrep_alloc(FAR struct stm32l4_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); -/* Control/data transfer logic *************************************************/ +/* Control/data transfer logic **********************************************/ -static void stm32l4_transfer_start(FAR struct stm32l4_usbhost_s *priv, int chidx); +static void stm32l4_transfer_start(FAR struct stm32l4_usbhost_s *priv, + int chidx); #if 0 /* Not used */ static inline uint16_t stm32l4_getframe(void); #endif @@ -362,8 +369,9 @@ static int stm32l4_ctrl_recvdata(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_ctrlinfo_s *ep0, FAR uint8_t *buffer, unsigned int buflen); static int stm32l4_in_setup(FAR struct stm32l4_usbhost_s *priv, int chidx); -static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32l4_in_next(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan); @@ -372,8 +380,9 @@ static int stm32l4_in_asynch(FAR struct stm32l4_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32l4_out_setup(FAR struct stm32l4_usbhost_s *priv, int chidx); -static ssize_t stm32l4_out_transfer(FAR struct stm32l4_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32l4_out_transfer(FAR struct stm32l4_usbhost_s *priv, + int chidx, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32l4_out_next(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan); @@ -382,12 +391,13 @@ static int stm32l4_out_asynch(FAR struct stm32l4_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif -/* Interrupt handling **********************************************************/ +/* Interrupt handling *******************************************************/ /* Lower level interrupt handlers */ static void stm32l4_gint_wrpacket(FAR struct stm32l4_usbhost_s *priv, - FAR uint8_t *buffer, int chidx, int buflen); + FAR uint8_t *buffer, int chidx, + int buflen); static inline void stm32l4_gint_hcinisr(FAR struct stm32l4_usbhost_s *priv, int chidx); static inline void stm32l4_gint_hcoutisr(FAR struct stm32l4_usbhost_s *priv, @@ -400,8 +410,10 @@ static void stm32l4_gint_disconnected(FAR struct stm32l4_usbhost_s *priv); #ifdef CONFIG_STM32L4_OTGFS_SOFINTR static inline void stm32l4_gint_sofisr(FAR struct stm32l4_usbhost_s *priv); #endif -static inline void stm32l4_gint_rxflvlisr(FAR struct stm32l4_usbhost_s *priv); -static inline void stm32l4_gint_nptxfeisr(FAR struct stm32l4_usbhost_s *priv); +static inline void + stm32l4_gint_rxflvlisr(FAR struct stm32l4_usbhost_s *priv); +static inline void + stm32l4_gint_nptxfeisr(FAR struct stm32l4_usbhost_s *priv); static inline void stm32l4_gint_ptxfeisr(FAR struct stm32l4_usbhost_s *priv); static inline void stm32l4_gint_hcisr(FAR struct stm32l4_usbhost_s *priv); static inline void stm32l4_gint_hprtisr(FAR struct stm32l4_usbhost_s *priv); @@ -417,9 +429,10 @@ static int stm32l4_gint_isr(int irq, FAR void *context, FAR void *arg); static void stm32l4_gint_enable(void); static void stm32l4_gint_disable(void); static inline void stm32l4_hostinit_enable(void); -static void stm32l4_txfe_enable(FAR struct stm32l4_usbhost_s *priv, int chidx); +static void stm32l4_txfe_enable(FAR struct stm32l4_usbhost_s *priv, + int chidx); -/* USB host controller operations **********************************************/ +/* USB host controller operations *******************************************/ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s **hport); @@ -430,32 +443,39 @@ static int stm32l4_enumerate(FAR struct usbhost_connection_s *conn, FAR struct usbhost_hubport_s *hport); static int stm32l4_ep0configure(FAR struct usbhost_driver_s *drvr, - usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, - uint16_t maxpacketsize); + usbhost_ep_t ep0, uint8_t funcaddr, + uint8_t speed, uint16_t maxpacketsize); static int stm32l4_epalloc(FAR struct usbhost_driver_s *drvr, FAR const FAR struct usbhost_epdesc_s *epdesc, FAR usbhost_ep_t *ep); -static int stm32l4_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); +static int stm32l4_epfree(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep); static int stm32l4_alloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, FAR size_t *maxlen); -static int stm32l4_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); +static int stm32l4_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); static int stm32l4_ioalloc(FAR struct usbhost_driver_s *drvr, FAR uint8_t **buffer, size_t buflen); -static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer); -static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, +static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer); +static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); -static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, +static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32l4_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, usbhost_asynch_t callback, FAR void *arg); #endif -static int stm32l4_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep); +static int stm32l4_cancel(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep); #ifdef CONFIG_USBHOST_HUB static int stm32l4_connect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport, @@ -464,12 +484,13 @@ static int stm32l4_connect(FAR struct usbhost_driver_s *drvr, static void stm32l4_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport); -/* Initialization **************************************************************/ +/* Initialization ***********************************************************/ static void stm32l4_portreset(FAR struct stm32l4_usbhost_s *priv); static void stm32l4_flush_txfifos(uint32_t txfnum); static void stm32l4_flush_rxfifo(void); -static void stm32l4_vbusdrive(FAR struct stm32l4_usbhost_s *priv, bool state); +static void stm32l4_vbusdrive(FAR struct stm32l4_usbhost_s *priv, + bool state); static void stm32l4_host_initialize(FAR struct stm32l4_usbhost_s *priv); static inline void stm32l4_sw_initialize(FAR struct stm32l4_usbhost_s *priv); @@ -479,9 +500,9 @@ static inline int stm32l4_hw_initialize(FAR struct stm32l4_usbhost_s *priv); * Private Data ****************************************************************************/ -/* In this driver implementation, support is provided for only a single a single - * USB device. All status information can be simply retained in a single global - * instance. +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single global instance. */ static struct stm32l4_usbhost_s g_usbhost; @@ -494,10 +515,6 @@ static struct usbhost_connection_s g_usbconn = .enumerate = stm32l4_enumerate, }; -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ @@ -533,8 +550,8 @@ static void stm32l4_checkreg(uint32_t addr, uint32_t val, bool iswrite) static uint32_t count = 0; static bool prevwrite = false; - /* Is this the same value that we read from/wrote to the same register last time? - * Are we polling the register? If so, suppress the output. + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. */ if (addr == prevaddr && val == preval && prevwrite == iswrite) @@ -647,9 +664,43 @@ static inline void stm32l4_modifyreg(uint32_t addr, uint32_t clrbits, * ****************************************************************************/ -static void stm32l4_takesem(FAR sem_t *sem) +static int stm32l4_takesem(FAR sem_t *sem) { - nxsem_wait_uninterruptible(sem); + return nxsem_wait_uninterruptible(sem); +} + +/**************************************************************************** + * Name: stm32l4_takesem_uninterruptible + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. This version also + * ignores attempts to cancel the thread. + * + ****************************************************************************/ + +static int stm32l4_takesem_uninterruptible(sem_t *sem) +{ + int result; + int ret = OK; + + do + { + result = nxsem_wait_uninterruptible(sem); + + /* The only expected error is ECANCELED which would occur if the + * calling thread were canceled. + */ + + DEBUGASSERT(result == OK || result == -ECANCELED); + if (ret == OK && result < 0) + { + ret = result; + } + } + while (result < 0); + + return ret; } /**************************************************************************** @@ -748,7 +799,8 @@ static inline void stm32l4_chan_freeall(FAR struct stm32l4_usbhost_s *priv) * ****************************************************************************/ -static void stm32l4_chan_configure(FAR struct stm32l4_usbhost_s *priv, int chidx) +static void stm32l4_chan_configure(FAR struct stm32l4_usbhost_s *priv, + int chidx) { FAR struct stm32l4_chan_s *chan = &priv->chan[chidx]; uint32_t regval; @@ -808,8 +860,9 @@ static void stm32l4_chan_configure(FAR struct stm32l4_usbhost_s *priv, int chidx { /* Interrupts required for INTR endpoints */ - regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | OTGFS_HCINT_NAK | - OTGFS_HCINT_TXERR | OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR); + regval |= (OTGFS_HCINT_XFRC | OTGFS_HCINT_STALL | + OTGFS_HCINT_NAK | OTGFS_HCINT_TXERR | + OTGFS_HCINT_FRMOR | OTGFS_HCINT_DTERR); /* Additional setting for IN endpoints */ @@ -914,21 +967,21 @@ static void stm32l4_chan_halt(FAR struct stm32l4_usbhost_s *priv, int chidx, uint32_t eptype; unsigned int avail; - /* Save the reason for the halt. We need this in the channel halt interrupt - * handling logic to know what to do next. + /* Save the reason for the halt. We need this in the channel halt + * interrupt handling logic to know what to do next. */ usbhost_vtrace2(OTGFS_VTRACE2_CHANHALT, chidx, chreason); priv->chan[chidx].chreason = (uint8_t)chreason; - /* "The application can disable any channel by programming the OTG_FS_HCCHARx - * register with the CHDIS and CHENA bits set to 1. This enables the OTG_FS - * host to flush the posted requests (if any) and generates a channel halted - * interrupt. The application must wait for the CHH interrupt in OTG_FS_HCINTx - * before reallocating the channel for other transactions. The OTG_FS host - * does not interrupt the transaction that has already been started on the - * USB." + /* "The application can disable any channel by programming the + * OTG_FS_HCCHARx register with the CHDIS and CHENA bits set to 1. This + * enables the OTG_FS host to flush the posted requests (if any) and + * generates a channel halted interrupt. The application must wait for + * the CHH interrupt in OTG_FS_HCINTx before reallocating the channel for + * other transactions. The OTG_FS host does not interrupt the + * transaction that has already been started on the USB." */ hcchar = stm32l4_getreg(STM32L4_OTGFS_HCCHAR(chidx)); @@ -940,26 +993,28 @@ static void stm32l4_chan_halt(FAR struct stm32l4_usbhost_s *priv, int chidx, /* Check for space in the Tx FIFO to issue the halt. * - * "Before disabling a channel, the application must ensure that there is at - * least one free space available in the non-periodic request queue (when - * disabling a non-periodic channel) or the periodic request queue (when - * disabling a periodic channel). The application can simply flush the - * posted requests when the Request queue is full (before disabling the - * channel), by programming the OTG_FS_HCCHARx register with the CHDIS bit - * set to 1, and the CHENA bit cleared to 0. + * "Before disabling a channel, the application must ensure that there is + * at least one free space available in the non-periodic request queue + * (when disabling a non-periodic channel) or the periodic request queue + * (when disabling a periodic channel). The application can simply flush + * the posted requests when the Request queue is full (before disabling + * the channel), by programming the OTG_FS_HCCHARx register with the + * CHDIS bit set to 1, and the CHENA bit cleared to 0. */ if (eptype == OTGFS_HCCHAR_EPTYP_CTRL || eptype == OTGFS_HCCHAR_EPTYP_BULK) { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32l4_getreg(STM32L4_OTGFS_HNPTXSTS) & OTGFS_HNPTXSTS_NPTXFSAV_MASK; + avail = stm32l4_getreg(STM32L4_OTGFS_HNPTXSTS) & + OTGFS_HNPTXSTS_NPTXFSAV_MASK; } - else /* if (eptype == OTGFS_HCCHAR_EPTYP_ISOC || eptype == OTGFS_HCCHAR_EPTYP_INTR) */ + else { /* Get the number of words available in the non-periodic Tx FIFO. */ - avail = stm32l4_getreg(STM32L4_OTGFS_HPTXSTS) & OTGFS_HPTXSTS_PTXFSAVL_MASK; + avail = stm32l4_getreg(STM32L4_OTGFS_HPTXSTS) & + OTGFS_HPTXSTS_PTXFSAVL_MASK; } /* Check if there is any space available in the Tx FIFO. */ @@ -986,13 +1041,15 @@ static void stm32l4_chan_halt(FAR struct stm32l4_usbhost_s *priv, int chidx, * Name: stm32l4_chan_waitsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: - * Called from a normal thread context BEFORE the transfer has been started. + * Called from a normal thread context BEFORE the transfer has been + * started. * ****************************************************************************/ @@ -1006,8 +1063,9 @@ static int stm32l4_chan_waitsetup(FAR struct stm32l4_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = true; @@ -1026,10 +1084,11 @@ static int stm32l4_chan_waitsetup(FAR struct stm32l4_usbhost_s *priv, * Name: stm32l4_chan_asynchsetup * * Description: - * Set the request for the transfer complete event well BEFORE enabling the - * transfer (as soon as we are absolutely committed to the to avoid transfer). - * We do this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! + * Set the request for the transfer complete event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! * * Assumptions: * Might be called from the level of an interrupt handler @@ -1048,8 +1107,9 @@ static int stm32l4_chan_asynchsetup(FAR struct stm32l4_usbhost_s *priv, if (priv->connected) { - /* Yes.. then set waiter to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer completed. + /* Yes.. then set waiter to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. */ chan->waiter = false; @@ -1080,18 +1140,18 @@ static int stm32l4_chan_wait(FAR struct stm32l4_usbhost_s *priv, irqstate_t flags; int ret; - /* Disable interrupts so that the following operations will be atomic. On - * the OTG FS global interrupt needs to be disabled. However, here we disable - * all interrupts to exploit that fact that interrupts will be re-enabled - * while we wait. + /* Disable interrupts so that the following operations will be atomic. + * On the OTG FS global interrupt needs to be disabled. However, here we + * disable all interrupts to exploit that fact that interrupts will be + * re-enabled while we wait. */ flags = enter_critical_section(); /* Loop, testing for an end of transfer condition. The channel 'result' - * was set to EBUSY and 'waiter' was set to true before the transfer; 'waiter' - * will be set to false and 'result' will be set appropriately when the - * transfer is completed. + * was set to EBUSY and 'waiter' was set to true before the transfer; + * 'waiter' will be set to false and 'result' will be set appropriately + * when the transfer is completed. */ do @@ -1182,7 +1242,8 @@ static void stm32l4_chan_wakeup(FAR struct stm32l4_usbhost_s *priv, ****************************************************************************/ static int stm32l4_ctrlchan_alloc(FAR struct stm32l4_usbhost_s *priv, - uint8_t epno, uint8_t funcaddr, uint8_t speed, + uint8_t epno, uint8_t funcaddr, + uint8_t speed, FAR struct stm32l4_ctrlinfo_s *ctrlep) { FAR struct stm32l4_chan_s *chan; @@ -1251,8 +1312,8 @@ static int stm32l4_ctrlchan_alloc(FAR struct stm32l4_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -1267,8 +1328,8 @@ static int stm32l4_ctrlep_alloc(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_ctrlinfo_s *ctrlep; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1301,7 +1362,7 @@ static int stm32l4_ctrlep_alloc(FAR struct stm32l4_usbhost_s *priv, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_xfrep_alloc * * Description: @@ -1314,13 +1375,13 @@ static int stm32l4_ctrlep_alloc(FAR struct stm32l4_usbhost_s *priv, * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32l4_xfrep_alloc(FAR struct stm32l4_usbhost_s *priv, FAR const struct usbhost_epdesc_s *epdesc, @@ -1330,8 +1391,8 @@ static int stm32l4_xfrep_alloc(FAR struct stm32l4_usbhost_s *priv, FAR struct stm32l4_chan_s *chan; int chidx; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(epdesc->hport != NULL); @@ -1346,10 +1407,10 @@ static int stm32l4_xfrep_alloc(FAR struct stm32l4_usbhost_s *priv, return -ENOMEM; } - /* Decode the endpoint descriptor to initialize the channel data structures. - * Note: Here we depend on the fact that the endpoint point type is - * encoded in the same way in the endpoint descriptor as it is in the OTG - * HS hardware. + /* Decode the endpoint descriptor to initialize the channel data + * structures. Note: Here we depend on the fact that the endpoint point + * type is encoded in the same way in the endpoint descriptor as it is in + * the OTG HS hardware. */ chan = &priv->chan[chidx]; @@ -1579,7 +1640,8 @@ static void stm32l4_transfer_start(FAR struct stm32l4_usbhost_s *priv, #if 0 /* Not used */ static inline uint16_t stm32l4_getframe(void) { - return (uint16_t)(stm32l4_getreg(STM32L4_OTGFS_HFNUM) & OTGFS_HFNUM_FRNUM_MASK); + return (uint16_t) + (stm32l4_getreg(STM32L4_OTGFS_HFNUM) & OTGFS_HFNUM_FRNUM_MASK); } #endif @@ -1716,8 +1778,8 @@ static int stm32l4_ctrl_senddata(FAR struct stm32l4_usbhost_s *priv, * Name: stm32l4_ctrl_recvdata * * Description: - * Receive data in the data phase of an IN control transfer. Or receive status - * in the status phase of an OUT control transfer + * Receive data in the data phase of an IN control transfer. Or receive + * status in the status phase of an OUT control transfer * ****************************************************************************/ @@ -1936,13 +1998,14 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, } else { - /* For Isochronous endpoints, bInterval must be 1. Bulk - * endpoints do not have a polling interval. Rather, - * the should wait until data is received. + /* For Isochronous endpoints, bInterval must be 1. + * Bulk endpoints do not have a polling interval. + * Rather, the should wait until data is received. * - * REVISIT: For bulk endpoints this 1 msec delay is only - * intended to give the CPU a break from the bulk EP tight - * polling loop. But are there performance issues? + * REVISIT: For bulk endpoints this 1 msec delay is + * only intended to give the CPU a break from the bulk + * EP tight polling loop. But are there performance + * issues? */ delay = 1000; @@ -1951,12 +2014,14 @@ static ssize_t stm32l4_in_transfer(FAR struct stm32l4_usbhost_s *priv, /* Wait for the next polling interval. For interrupt and * isochronous endpoints, this is necessaryto assure the * polling interval. It is used in other cases only to - * prevent the polling from consuming too much CPU bandwidth. + * prevent the polling from consuming too much CPU + * bandwidth. * - * Small delays could require more resolution than is provided - * by the system timer. For example, if the system timer - * resolution is 10MS, then nxsig_usleep(1000) will actually request - * a delay 20MS (due to both quantization and rounding). + * Small delays could require more resolution than is + * provided by the system timer. For example, if the + * system timer resolution is 10MS, then + * nxsig_usleep(1000) will actually request a delay 20MS + * (due to both quantization and rounding). * * REVISIT: So which is better? To ignore tiny delays and * hog the system bandwidth? Or to wait for an excessive @@ -2250,9 +2315,10 @@ static ssize_t stm32l4_out_transfer(FAR struct stm32l4_usbhost_s *priv, */ elapsed = clock_systimer() - start; - if (ret != -EAGAIN || /* Not a NAK condition OR */ + if (ret != -EAGAIN || /* Not a NAK condition OR */ elapsed >= STM32L4_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->xfrd > 0) /* Data has been partially transferred */ + chan->xfrd > 0) /* Data has been partially + * transferred */ { /* Break out and return the error */ @@ -2260,14 +2326,14 @@ static ssize_t stm32l4_out_transfer(FAR struct stm32l4_usbhost_s *priv, return (ssize_t)ret; } - /* Is this flush really necessary? What does the hardware do with the - * data in the FIFO when the NAK occurs? Does it discard it? + /* Is this flush really necessary? What does the hardware do with + * the data in the FIFO when the NAK occurs? Does it discard it? */ stm32l4_flush_txfifos(OTGFS_GRSTCTL_TXFNUM_HALL); - /* Get the device a little time to catch up. Then retry the transfer - * using the same buffer pointer and length. + /* Get the device a little time to catch up. Then retry the + * transfer using the same buffer pointer and length. */ nxsig_usleep(20 * 1000); @@ -2444,8 +2510,8 @@ static void stm32l4_gint_wrpacket(FAR struct stm32l4_usbhost_s *priv, * Description: * USB OTG FS host IN channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2546,7 +2612,8 @@ static inline void stm32l4_gint_hcinisr(FAR struct stm32l4_usbhost_s *priv, /* Then handle the transfer completion event based on the endpoint type */ - if (chan->eptype == OTGFS_EPTYPE_CTRL || chan->eptype == OTGFS_EPTYPE_BULK) + if (chan->eptype == OTGFS_EPTYPE_CTRL || + chan->eptype == OTGFS_EPTYPE_BULK) { /* Halt the channel -- the CHH interrupt is expected next */ @@ -2659,11 +2726,12 @@ static inline void stm32l4_gint_hcinisr(FAR struct stm32l4_usbhost_s *priv, } /* Re-activate CTRL and BULK channels. + * * REVISIT: This can cause a lot of interrupts! + * REVISIT: Bulk endpoints not re-actived. */ - else if (chan->eptype == OTGFS_EPTYPE_CTRL /* || - chan->eptype == OTGFS_EPTYPE_BULK */) + else if (chan->eptype == OTGFS_EPTYPE_CTRL) { /* Re-activate the channel by clearing CHDIS and assuring that * CHENA is set @@ -2699,8 +2767,8 @@ static inline void stm32l4_gint_hcinisr(FAR struct stm32l4_usbhost_s *priv, * Description: * USB OTG FS host OUT channels interrupt handler * - * One the completion of the transfer, the channel result byte may be set as - * follows: + * One the completion of the transfer, the channel result byte may be set + * as follows: * * OK - Transfer completed successfully * EAGAIN - If devices NAKs the transfer or NYET occurs @@ -2874,7 +2942,8 @@ static inline void stm32l4_gint_hcoutisr(FAR struct stm32l4_usbhost_s *priv, * transferred? */ - if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_BULK && + if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == + OTGFS_HCCHAR_EPTYP_BULK && (chan->npackets & 1) != 0) { /* Yes to both... toggle the data out PID */ @@ -3068,7 +3137,8 @@ static inline void stm32l4_gint_rxflvlisr(FAR struct stm32l4_usbhost_s *priv) { /* Read the data into the host buffer. */ - bcnt = (grxsts & OTGFS_GRXSTSH_BCNT_MASK) >> OTGFS_GRXSTSH_BCNT_SHIFT; + bcnt = (grxsts & OTGFS_GRXSTSH_BCNT_MASK) >> + OTGFS_GRXSTSH_BCNT_SHIFT; if (bcnt > 0 && priv->chan[chidx].buffer != NULL) { /* Transfer the packet from the Rx FIFO into the user buffer */ @@ -3144,8 +3214,8 @@ static inline void stm32l4_gint_nptxfeisr(FAR struct stm32l4_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3204,8 +3274,9 @@ static inline void stm32l4_gint_nptxfeisr(FAR struct stm32l4_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); + uinfo("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d " + "wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32l4_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3233,8 +3304,8 @@ static inline void stm32l4_gint_ptxfeisr(FAR struct stm32l4_usbhost_s *priv) chidx = priv->chidx; chan = &priv->chan[chidx]; - /* Reduce the buffer size by the number of bytes that were previously placed - * in the Tx FIFO. + /* Reduce the buffer size by the number of bytes that were previously + * placed in the Tx FIFO. */ chan->buffer += chan->inflight; @@ -3367,9 +3438,9 @@ static inline void stm32l4_gint_hprtisr(FAR struct stm32l4_usbhost_s *priv) hprt = stm32l4_getreg(STM32L4_OTGFS_HPRT); - /* Setup to clear the interrupt bits in GINTSTS by setting the corresponding - * bits in the HPRT. The HCINT interrupt bit is cleared when the appropriate - * status bits in the HPRT register are cleared. + /* Setup to clear the interrupt bits in GINTSTS by setting the + * corresponding bits in the HPRT. The HCINT interrupt bit is cleared + * when the appropriate status bits in the HPRT register are cleared. */ newhprt = hprt & ~(OTGFS_HPRT_PENA | OTGFS_HPRT_PCDET | @@ -3435,7 +3506,8 @@ static inline void stm32l4_gint_hprtisr(FAR struct stm32l4_usbhost_s *priv) /* Are we switching from FS to LS? */ - if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_LS6MHz) + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_LS6MHz) { usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_FSLSSW, 0); @@ -3457,7 +3529,8 @@ static inline void stm32l4_gint_hprtisr(FAR struct stm32l4_usbhost_s *priv) /* Are we switching from LS to FS? */ - if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != OTGFS_HCFG_FSLSPCS_FS48MHz) + if ((hcfg & OTGFS_HCFG_FSLSPCS_MASK) != + OTGFS_HCFG_FSLSPCS_FS48MHz) { usbhost_vtrace1(OTGFS_VTRACE1_GINT_HPRT_LSFSSW, 0); @@ -3537,7 +3610,8 @@ static int stm32l4_gint_isr(int irq, FAR void *context, FAR void *arg) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32l4_usbhost_s *priv = &g_usbhost; @@ -3548,8 +3622,8 @@ static int stm32l4_gint_isr(int irq, FAR void *context, FAR void *arg) * host mode */ - /* Loop while there are pending interrupts to process. This loop may save a - * little interrupt handling overhead. + /* Loop while there are pending interrupts to process. This loop may save + * a little interrupt handling overhead. */ for (; ; ) @@ -3770,7 +3844,8 @@ static inline void stm32l4_hostinit_enable(void) * ****************************************************************************/ -static void stm32l4_txfe_enable(FAR struct stm32l4_usbhost_s *priv, int chidx) +static void stm32l4_txfe_enable(FAR struct stm32l4_usbhost_s *priv, + int chidx) { FAR struct stm32l4_chan_s *chan = &priv->chan[chidx]; irqstate_t flags; @@ -3816,8 +3891,8 @@ static void stm32l4_txfe_enable(FAR struct stm32l4_usbhost_s *priv, int chidx) * Wait for a device to be connected or disconnected to/from a hub port. * * Input Parameters: - * conn - The USB host connection instance obtained as a parameter from the call to - * the USB driver initialization logic. + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. * hport - The location to return the hub port descriptor that detected the * connection related event. * @@ -3840,6 +3915,7 @@ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, FAR struct stm32l4_usbhost_s *priv = &g_usbhost; struct usbhost_hubport_s *connport; irqstate_t flags; + int ret; /* Loop until a change in connection state is detected */ @@ -3864,7 +3940,8 @@ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uvdbg("RHport Connected: %s\n", connport->connected ? "YES" : "NO"); + uvdbg("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } @@ -3881,7 +3958,8 @@ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, *hport = connport; leave_critical_section(flags); - uvdbg("Hub port Connected: %s\n", connport->connected ? "YES" : "NO"); + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); return OK; } #endif @@ -3889,7 +3967,11 @@ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, /* Wait for the next connection event */ priv->pscwait = true; - stm32l4_takesem(&priv->pscsem); + ret = stm32l4_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } } } @@ -3913,8 +3995,8 @@ static int stm32l4_wait(FAR struct usbhost_connection_s *conn, * device. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. @@ -3968,7 +4050,8 @@ static int stm32l4_rh_enumerate(FAR struct stm32l4_usbhost_s *priv, /* Allocate and initialize the root hub port EP0 channels */ - ret = stm32l4_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, &priv->ep0); + ret = stm32l4_ctrlchan_alloc(priv, 0, 0, priv->rhport.hport.speed, + &priv->ep0); if (ret < 0) { uerr("ERROR: Failed to allocate a control endpoint: %d\n", ret); @@ -4024,7 +4107,7 @@ static int stm32l4_enumerate(FAR struct usbhost_connection_s *conn, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_ep0configure * * Description: @@ -4033,38 +4116,44 @@ static int stm32l4_enumerate(FAR struct usbhost_connection_s *conn, * external implementation of the enumeration logic. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The (opaque) EP0 endpoint instance - * funcaddr - The USB address of the function containing the endpoint that EP0 - * controls + * funcaddr - The USB address of the function containing the endpoint that + * EP0 controls * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH * maxpacketsize - The maximum number of bytes that can be sent to or * received from the endpoint in a single data packet * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32l4_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, uint16_t maxpacketsize) { FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; - FAR struct stm32l4_ctrlinfo_s *ep0info = (FAR struct stm32l4_ctrlinfo_s *)ep0; + FAR struct stm32l4_ctrlinfo_s *ep0info = + (FAR struct stm32l4_ctrlinfo_s *)ep0; FAR struct stm32l4_chan_s *chan; + int ret; DEBUGASSERT(drvr != NULL && ep0info != NULL && funcaddr < 128 && maxpacketsize <= 64); /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Configure the EP0 OUT channel */ @@ -4088,27 +4177,27 @@ static int stm32l4_ep0configure(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_epalloc * * Description: * Allocate and configure one endpoint. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * epdesc - Describes the endpoint to be allocated. * ep - A memory location provided by the caller in which to receive the * allocated endpoint descriptor. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32l4_epalloc(FAR struct usbhost_driver_s *drvr, FAR const struct usbhost_epdesc_s *epdesc, @@ -4117,15 +4206,19 @@ static int stm32l4_epalloc(FAR struct usbhost_driver_s *drvr, FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; int ret; - /* Sanity check. NOTE that this method should only be called if a device is - * connected (because we need a valid low speed indication). + /* Sanity check. NOTE that this method should only be called if a device + * is connected (because we need a valid low speed indication). */ DEBUGASSERT(drvr != 0 && epdesc != NULL && ep != NULL); /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handler control pipes differently from other endpoint types. This is * because the normal, "transfer" endpoints are unidirectional an require @@ -4146,39 +4239,40 @@ static int stm32l4_epalloc(FAR struct usbhost_driver_s *drvr, return ret; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_epfree * * Description: * Free and endpoint previously allocated by DRVR_EPALLOC. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep - The endpoint to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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 int stm32l4_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; + int ret; DEBUGASSERT(priv); /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem_uninterruptible(&priv->exclsem); /* A single channel is represent by an index in the range of 0 to - * STM32L4_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an allocated - * control endpoint structure. + * STM32L4_MAX_TX_FIFOS. Otherwise, the ep must be a pointer to an + * allocated control endpoint structure. */ if ((uintptr_t)ep < STM32L4_MAX_TX_FIFOS) @@ -4191,7 +4285,9 @@ static int stm32l4_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Halt both control channel and mark the channels available */ - FAR struct stm32l4_ctrlinfo_s *ctrlep = (FAR struct stm32l4_ctrlinfo_s *)ep; + FAR struct stm32l4_ctrlinfo_s *ctrlep = + (FAR struct stm32l4_ctrlinfo_s *)ep; + stm32l4_chan_free(priv, ctrlep->inndx); stm32l4_chan_free(priv, ctrlep->outndx); @@ -4201,34 +4297,35 @@ static int stm32l4_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) } stm32l4_givesem(&priv->exclsem); - return OK; + return ret; } /**************************************************************************** * Name: stm32l4_alloc * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to allocate the request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_malloc. * - * This interface was optimized under a particular assumption. It was assumed - * that the driver maintains a pool of small, pre-allocated buffers for descriptor - * traffic. NOTE that size is not an input, but an output: The size of the - * pre-allocated buffer is returned. + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated + * buffers for descriptor traffic. NOTE that size is not an input, but an + * output: The size of the pre-allocated buffer is returned. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. - * maxlen - The address of a memory location provided by the caller in which to - * return the maximum size of the allocated buffer memory. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4263,19 +4360,20 @@ static int stm32l4_alloc(FAR struct usbhost_driver_s *drvr, * Name: stm32l4_free * * Description: - * Some hardware supports special memory in which request and descriptor data can - * be accessed more efficiently. This method provides a mechanism to free that - * request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_free(). + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Never called from an interrupt handler. @@ -4283,7 +4381,8 @@ static int stm32l4_alloc(FAR struct usbhost_driver_s *drvr, ****************************************************************************/ #warning this function name is too generic -static int stm32l4_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32l4_free(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4292,32 +4391,34 @@ static int stm32l4_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_ioalloc * * Description: * Some hardware supports special memory in which larger IO buffers can - * be accessed more efficiently. This method provides a mechanism to allocate - * the request/descriptor memory. If the underlying hardware does not support - * such "special" memory, this functions may simply map to kmm_malloc. + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. * - * This interface differs from DRVR_ALLOC in that the buffers are variable-sized. + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * buffer - The address of a memory location provided by the caller in which to - * return the allocated buffer memory address. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. * buflen - The size of the buffer required. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. * - ************************************************************************************/ + ****************************************************************************/ #warning this function name is too generic static int stm32l4_ioalloc(FAR struct usbhost_driver_s *drvr, @@ -4341,31 +4442,31 @@ static int stm32l4_ioalloc(FAR struct usbhost_driver_s *drvr, return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_iofree * * Description: - * Some hardware supports special memory in which IO data can be accessed more - * efficiently. This method provides a mechanism to free that IO buffer - * memory. If the underlying hardware does not support such "special" memory, - * this functions may simply map to kmm_free(). + * Some hardware supports special memory in which IO data can be accessed + * more efficiently. This method provides a mechanism to free that IO + * buffer memory. If the underlying hardware does not support such + * "special" memory, this functions may simply map to kmm_free(). * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * buffer - The address of the allocated buffer memory to be freed. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * 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. * - ************************************************************************************/ + ****************************************************************************/ -#warning this function name is too generic -static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) +static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, + FAR uint8_t *buffer) { /* There is no special memory requirement */ @@ -4379,29 +4480,31 @@ static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer * * Description: * Process a IN or OUT request on the control endpoint. These methods - * will enqueue the request and wait for it to complete. Only one transfer may be - * queued; Neither these methods nor the transfer() method can be called again - * until the control transfer functions returns. + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() + * method can be called again until the control transfer functions + * returns. * * These are blocking methods; these functions will not return until the * control transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * ep0 - The control endpoint to send/receive the control request. * req - Describes the request to be sent. This request must lie in memory - * created by DRVR_ALLOC. + * created by DRVR_ALLOC. * buffer - A buffer used for sending the request and for returning any * responses. This buffer must be large enough to hold the length value - * in the request description. buffer must have been allocated using DRVR_ALLOC. + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. * - * NOTE: On an IN transaction, req and buffer may refer to the same allocated - * memory. + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4409,12 +4512,14 @@ static int stm32l4_iofree(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer * ****************************************************************************/ -static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, +static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer) { FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; - FAR struct stm32l4_ctrlinfo_s *ep0info = (FAR struct stm32l4_ctrlinfo_s *)ep0; + FAR struct stm32l4_ctrlinfo_s *ep0info = + (FAR struct stm32l4_ctrlinfo_s *)ep0; uint16_t buflen; clock_t start; clock_t elapsed; @@ -4433,7 +4538,11 @@ static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4492,12 +4601,14 @@ static int stm32l4_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, return -ETIMEDOUT; } -static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, +static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer) { FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; - FAR struct stm32l4_ctrlinfo_s *ep0info = (FAR struct stm32l4_ctrlinfo_s *)ep0; + FAR struct stm32l4_ctrlinfo_s *ep0info = + (FAR struct stm32l4_ctrlinfo_s *)ep0; uint16_t buflen; clock_t start; clock_t elapsed; @@ -4516,7 +4627,11 @@ static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Loop, retrying until the retry time expires */ @@ -4584,26 +4699,27 @@ static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * * Description: * Process a request to handle a transfer descriptor. This method will - * enqueue the transfer request, blocking until the transfer completes. Only - * one transfer may be queued; Neither this method nor the ctrlin or - * ctrlout methods can be called again until this function returns. + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin + * or ctrlout methods can be called again until this function returns. * * This is a blocking method; this functions will not return until the * transfer has completed. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * * Returned Value: * On success, a non-negative value is returned that indicates the number - * of bytes successfully transferred. On a failure, a negated errno value is - * returned that indicates the nature of the failure: + * of bytes successfully transferred. On a failure, a negated errno value + * is returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4617,12 +4733,14 @@ static int stm32l4_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * ****************************************************************************/ -static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, + size_t buflen) { FAR struct stm32l4_usbhost_s *priv = (FAR struct stm32l4_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; ssize_t nbytes; + int ret; uvdbg("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4630,7 +4748,11 @@ static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return (ssize_t)ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4661,20 +4783,21 @@ static ssize_t stm32l4_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t * ctrlout methods can be called again until the transfer completes. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which to - * perform the transfer. - * buffer - A buffer containing the data to be sent (OUT endpoint) or received - * (IN endpoint). buffer must have been allocated using DRVR_ALLOC + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC * buflen - The length of the data to be sent or received. * callback - This function will be called when the transfer completes. - * arg - The arbitrary parameter that will be passed to the callback function - * when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -4697,7 +4820,11 @@ static int stm32l4_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* We must have exclusive access to the USB host hardware and state structures */ - stm32l4_takesem(&priv->exclsem); + ret = stm32l4_takesem(&priv->exclsem); + if (ret < 0) + { + return ret; + } /* Handle IN and OUT transfer slightly differently */ @@ -4715,7 +4842,7 @@ static int stm32l4_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, } #endif /* CONFIG_USBHOST_ASYNCH */ -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_cancel * * Description: @@ -4723,16 +4850,16 @@ static int stm32l4_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on which an - * asynchronous transfer should be transferred. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * an asynchronous transfer should be transferred. * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ static int stm32l4_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { @@ -4746,8 +4873,8 @@ static int stm32l4_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) DEBUGASSERT(priv && chidx < STM32L4_MAX_TX_FIFOS); chan = &priv->chan[chidx]; - /* We need to disable interrupts to avoid race conditions with the asynchronous - * completion of the transfer being cancelled. + /* We need to disable interrupts to avoid race conditions with the + * asynchronous completion of the transfer being cancelled. */ flags = enter_critical_section(); @@ -4802,26 +4929,26 @@ static int stm32l4_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) return OK; } -/************************************************************************************ +/**************************************************************************** * Name: stm32l4_connect * * Description: - * New connections may be detected by an attached hub. This method is the - * mechanism that is used by the hub class to introduce a new connection - * and port description to the system. + * New connections may be detected by an attached hub. This method is + * the mechanism that is used by the hub class to introduce a new + * connection and port description to the system. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. * hport - The descriptor of the hub port that detected the connection * related event * connected - True: device connected; false: device disconnected * * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure. + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_USBHOST_HUB static int stm32l4_connect(FAR struct usbhost_driver_s *drvr, @@ -4836,7 +4963,8 @@ static int stm32l4_connect(FAR struct usbhost_driver_s *drvr, /* Set the connected/disconnected flag */ hport->connected = connected; - uinfo("Hub port %d connected: %s\n", hport->port, connected ? "YES" : "NO"); + uinfo("Hub port %d connected: %s\n", + hport->port, connected ? "YES" : "NO"); /* Report the connection event */ @@ -4857,17 +4985,18 @@ static int stm32l4_connect(FAR struct usbhost_driver_s *drvr, * Name: stm32l4_disconnect * * Description: - * Called by the class when an error occurs and driver has been disconnected. - * The USB host driver should discard the handle to the class instance (it is - * stale) and not attempt any further interaction with the class driver instance - * (until a new instance is received from the create() method). The driver - * should not called the class' disconnected() method. + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received from + * the create() method). The driver should not called the class' + * disconnected() method. * * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the call to - * the class create() method. - * hport - The port from which the device is being disconnected. Might be a port - * on a hub. + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. Might be + * a port on a hub. * * Returned Value: * None @@ -4895,11 +5024,11 @@ static void stm32l4_disconnect(FAR struct usbhost_driver_s *drvr, * Description: * Reset the USB host port. * - * NOTE: "Before starting to drive a USB reset, the application waits for the - * OTG interrupt triggered by the debounce done bit (DBCDNE bit in - * OTG_FS_GOTGINT), which indicates that the bus is stable again after the - * electrical debounce caused by the attachment of a pull-up resistor on DP - * (FS) or DM (LS). + * NOTE: "Before starting to drive a USB reset, the application waits for + * the OTG interrupt triggered by the debounce done bit (DBCDNE bit in + * OTG_FS_GOTGINT), which indicates that the bus is stable again after + * the electrical debounce caused by the attachment of a pull-up resistor + * on DP (FS) or DM (LS). * * Input Parameters: * priv -- USB host driver private data structure. @@ -5055,9 +5184,9 @@ static void stm32l4_vbusdrive(FAR struct stm32l4_usbhost_s *priv, bool state) * * Description: * Initialize/re-initialize hardware for host mode operation. At present, - * this function is called only from stm32l4_hw_initialize(). But if OTG mode - * were supported, this function would also be called to switch between - * host and device modes on a connector ID change interrupt. + * this function is called only from stm32l4_hw_initialize(). But if OTG + * mode were supported, this function would also be called to switch + * between host and device modes on a connector ID change interrupt. * * Input Parameters: * priv -- USB host driver private data structure. @@ -5106,14 +5235,16 @@ static void stm32l4_host_initialize(FAR struct stm32l4_usbhost_s *priv) /* Setup the host non-periodic Tx FIFO size (HNPTXFSIZ) */ regval = (offset | - (CONFIG_STM32L4_OTGFS_NPTXFIFO_SIZE << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); + (CONFIG_STM32L4_OTGFS_NPTXFIFO_SIZE << + OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)); stm32l4_putreg(STM32L4_OTGFS_HNPTXFSIZ, regval); offset += CONFIG_STM32L4_OTGFS_NPTXFIFO_SIZE; /* Set up the host periodic Tx fifo size register (HPTXFSIZ) */ regval = (offset | - (CONFIG_STM32L4_OTGFS_PTXFIFO_SIZE << OTGFS_HPTXFSIZ_PTXFD_SHIFT)); + (CONFIG_STM32L4_OTGFS_PTXFIFO_SIZE << + OTGFS_HPTXFSIZ_PTXFD_SHIFT)); stm32l4_putreg(STM32L4_OTGFS_HPTXFSIZ, regval); /* If OTG were supported, we should need to clear HNP enable bit in the @@ -5219,7 +5350,8 @@ static inline void stm32l4_sw_initialize(FAR struct stm32l4_usbhost_s *priv) /* Put all of the channels back in their initial, allocated state */ - memset(priv->chan, 0, STM32L4_MAX_TX_FIFOS * sizeof(struct stm32l4_chan_s)); + memset(priv->chan, 0, + STM32L4_MAX_TX_FIFOS * sizeof(struct stm32l4_chan_s)); /* Initialize each channel */ @@ -5297,7 +5429,8 @@ static inline int stm32l4_hw_initialize(FAR struct stm32l4_usbhost_s *priv) /* Deactivate the power down */ - regval = (OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | OTGFS_GCCFG_VBUSBSEN); + regval = OTGFS_GCCFG_PWRDWN | OTGFS_GCCFG_VBUSASEN | + OTGFS_GCCFG_VBUSBSEN; #ifndef CONFIG_USBDEV_VBUSSENSING regval |= OTGFS_GCCFG_NOVBUSSENS; #endif @@ -5359,7 +5492,8 @@ FAR struct usbhost_connection_s *stm32l4_otgfshost_initialize(int controller) /* At present, there is only support for a single OTG FS host. Hence it is * pre-allocated as g_usbhost. However, in most code, the private data * structure will be referenced using the 'priv' pointer (rather than the - * global data) in order to simplify any future support for multiple devices. + * global data) in order to simplify any future support for multiple + * devices. */ FAR struct stm32l4_usbhost_s *priv = &g_usbhost;