From 120a3604c92dabadaa425bbb9551d3965f416882 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 12 Aug 2013 16:29:33 -0600 Subject: [PATCH] More changes to USB host interface to support multiple downstream ports --- ChangeLog | 5 +++ arch/arm/src/lpc17xx/lpc17_usbhost.c | 7 +++- arch/arm/src/sama5/sam_ohci.c | 59 ++++++++++++++++------------ arch/arm/src/stm32/stm32_otgfshost.c | 7 +++- drivers/usbhost/usbhost_hidkbd.c | 12 +++++- drivers/usbhost/usbhost_skeleton.c | 14 ++++++- drivers/usbhost/usbhost_storage.c | 12 +++++- include/nuttx/usb/usbhost.h | 5 ++- 8 files changed, 86 insertions(+), 35 deletions(-) diff --git a/ChangeLog b/ChangeLog index a33513a2e5..71eb912a6d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5380,4 +5380,9 @@ breakage, but I expect some (2013-8-12). * configs/olimex-stm32-p107/nsh/defconfig and appconfig: Converted to use the kconfig-frontends tool. From Max Holtzberg (2013-8-12). + * includes/nuttx/usb/usbhost.h, et al: Continued changes to the USB + host interface to support multiple downstream ports. When a class + is disconnected, it needs to provide the FunctionAddress to the + USB HCD disconnect method so that the HCD will know which port + is being disconnected (2013-8-12). diff --git a/arch/arm/src/lpc17xx/lpc17_usbhost.c b/arch/arm/src/lpc17xx/lpc17_usbhost.c index 2fb5eb34c6..4983d1ec30 100644 --- a/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -315,7 +315,7 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr, FAR const uint8_t *buffer); static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); -static void lpc17_disconnect(FAR struct usbhost_driver_s *drvr); +static void lpc17_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr); /* Initialization **************************************************************/ @@ -2378,6 +2378,7 @@ errout: * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * funcaddr - Address of the function to be disconnected. * * Returned Values: * None @@ -2388,9 +2389,11 @@ errout: * *******************************************************************************/ -static void lpc17_disconnect(FAR struct usbhost_driver_s *drvr) +static void lpc17_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr) { struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; + DEBUGASSERT(priv && funcaddr == 1); + priv->class = NULL; } diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index 10c75558ac..937689f8b4 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -180,8 +180,14 @@ struct sam_rhport_s { + /* Root hub port status */ + volatile bool connected; /* Connected to device */ volatile bool lowspeed; /* Low speed device attached. */ + + /* The bound device class driver */ + + struct usbhost_class_s *class; }; /* This structure retains the state of the USB host controller */ @@ -195,10 +201,6 @@ struct sam_ohci_s struct usbhost_driver_s drvr; - /* The bound device class driver */ - - struct usbhost_class_s *class; - /* Driver status */ volatile bool rhswait; /* TRUE: Thread is waiting for Root Hub Status change */ @@ -368,7 +370,7 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, FAR const uint8_t *buffer); static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); -static void sam_disconnect(FAR struct usbhost_driver_s *drvr); +static void sam_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr); /* Initialization **************************************************************/ @@ -401,7 +403,6 @@ static struct sam_ohci_s g_usbhost = .transfer = sam_transfer, .disconnect = sam_disconnect, }, - .class = NULL, }; /* This is a free list of EDs and TD buffers */ @@ -1372,13 +1373,13 @@ static int sam_ohci_interrupt(int irq, FAR void *context) ullvdbg("Root Hub Status Change\n"); for (rhpndx = 0; rhpndx < SAM_USBHOST_NRHPORT; rhpndx++) { + struct sam_rhport_s *rhport = &priv->rhport[rhpndx]; uint32_t rhportst; regaddr = SAM_USBHOST_RHPORTST(rhpndx+1); rhportst = sam_getreg(regaddr); - ullvdbg("RHPORTST%d: %08x\n", - rhpndx + 1, rhportst); + ullvdbg("RHPORTST%d: %08x\n", rhpndx + 1, rhportst); if ((rhportst & OHCI_RHPORTST_CSC) != 0) { @@ -1404,11 +1405,11 @@ static int sam_ohci_interrupt(int irq, FAR void *context) { /* Connected ... Did we just become connected? */ - if (!priv->rhport[rhpndx].connected) + if (!rhport->connected) { /* Yes.. connected. */ - priv->rhport[rhpndx].connected = true; + rhport->connected = true; ullvdbg("RHPort%d connected, rhswait: %d\n", rhpndx + 1, priv->rhswait); @@ -1430,31 +1431,31 @@ static int sam_ohci_interrupt(int irq, FAR void *context) * when CCS == 1. */ - priv->rhport[rhpndx].lowspeed = + rhport->lowspeed = (rhportst & OHCI_RHPORTST_LSDA) != 0; ullvdbg("Speed: %s\n", - priv->rhport[rhpndx].lowspeed ? "LOW" : "FULL"); + rhport->lowspeed ? "LOW" : "FULL"); } /* Check if we are now disconnected */ - else if (priv->rhport[rhpndx].connected) + else if (rhport->connected) { /* Yes.. disconnect the device */ ullvdbg("RHport%d disconnected\n", rhpndx+1); - priv->rhport[rhpndx].connected = false; - priv->rhport[rhpndx].lowspeed = false; + rhport->connected = false; + rhport->lowspeed = false; /* Are we bound to a class instance? */ - if (priv->class) + if (rhport->class) { /* Yes.. Disconnect the class */ - CLASS_DISCONNECTED(priv->class); - priv->class = NULL; + CLASS_DISCONNECTED(rhport->class); + rhport->class = NULL; } /* Notify any waiters for the Root Hub Status change @@ -1671,13 +1672,17 @@ static int sam_wait(FAR struct usbhost_driver_s *drvr, FAR const bool *connected static int sam_enumerate(FAR struct usbhost_driver_s *drvr, int rhpndx) { struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr; + struct sam_rhport_s *rhport; uint32_t regaddr; + DEBUGASSERT(priv && rhpndx >= 0 && rhpndx < SAM_USBHOST_NRHPORT); + rhport = &priv->rhport[rhpndx]; + /* Are we connected to a device? The caller should have called the wait() * method first to be assured that a device is connected. */ - while (!priv->rhport[rhpndx].connected) + while (!rhport->connected) { /* No, return an error */ @@ -1708,7 +1713,7 @@ static int sam_enumerate(FAR struct usbhost_driver_s *drvr, int rhpndx) */ uvdbg("Enumerate the device\n"); - return usbhost_enumerate(drvr, rhpndx+1, &priv->class); + return usbhost_enumerate(drvr, rhpndx+1, &rhport->class); } /************************************************************************************ @@ -1740,10 +1745,11 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, uint16_t maxpacketsize) { struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr; - int rhpndx = (int)funcaddr - 1; + struct sam_rhport_s *rhport; - DEBUGASSERT(drvr && funcaddr > 0 && funcaddr <= SAM_USBHOST_NRHPORT && + DEBUGASSERT(priv && funcaddr > 0 && funcaddr <= SAM_USBHOST_NRHPORT && maxpacketsize < 2048); + rhport = &priv->rhport[funcaddr - 1]; /* We must have exclusive access to EP0 and the control list */ @@ -1754,7 +1760,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr, g_edctrl.hw.ctrl = (uint32_t)funcaddr << ED_CONTROL_FA_SHIFT | (uint32_t)maxpacketsize << ED_CONTROL_MPS_SHIFT; - if (priv->rhport[rhpndx].lowspeed) + if (rhport->lowspeed) { g_edctrl.hw.ctrl |= ED_CONTROL_S; } @@ -2395,6 +2401,7 @@ errout: * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * funcaddr - Address of the function to be disconnected. * * Returned Values: * None @@ -2405,10 +2412,12 @@ errout: * *******************************************************************************/ -static void sam_disconnect(FAR struct usbhost_driver_s *drvr) +static void sam_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr) { struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr; - priv->class = NULL; + DEBUGASSERT(priv && funcaddr > 0 && funcaddr <= SAM_USBHOST_NRHPORT); + + priv->rhport[funcaddr - 1].class = NULL; } /******************************************************************************* diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index d1b4f5f547..4f36831779 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -380,7 +380,7 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, FAR const uint8_t *buffer); static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); -static void stm32_disconnect(FAR struct usbhost_driver_s *drvr); +static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr); /* Initialization **************************************************************/ @@ -3795,6 +3795,7 @@ static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * funcaddr - Address of the function to be disconnected. * * Returned Values: * None @@ -3805,9 +3806,11 @@ static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * *******************************************************************************/ -static void stm32_disconnect(FAR struct usbhost_driver_s *drvr) +static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr) { struct stm32_usbhost_s *priv = (struct stm32_usbhost_s *)drvr; + DEBUGASSERT(priv && funcaddr == 1); + priv->class = NULL; } diff --git a/drivers/usbhost/usbhost_hidkbd.c b/drivers/usbhost/usbhost_hidkbd.c index 1710a2bb8a..6a83fb7592 100644 --- a/drivers/usbhost/usbhost_hidkbd.c +++ b/drivers/usbhost/usbhost_hidkbd.c @@ -208,6 +208,7 @@ struct usbhost_state_s volatile bool open; /* TRUE: The keyboard device is open */ volatile bool waiting; /* TRUE: waiting for keyboard data */ uint8_t ifno; /* Interface number */ + uint8_t funcaddr; /* USB function address */ int16_t crefs; /* Reference count on the driver instance */ sem_t exclsem; /* Used to maintain mutual exclusive access */ sem_t waitsem; /* Used to wait for keyboard data */ @@ -797,7 +798,7 @@ static void usbhost_destroy(FAR void *arg) /* Disconnect the USB host device */ - DRVR_DISCONNECT(priv->drvr); + DRVR_DISCONNECT(priv->drvr, priv->funcaddr); /* And free the class instance. Hmmm.. this may execute on the worker * thread and the work structure is part of what is getting freed. That @@ -1892,6 +1893,15 @@ static int usbhost_connect(FAR struct usbhost_class_s *class, { udbg("usbhost_devinit() failed: %d\n", ret); } + else + { + /* Save the function address (We will need it when we disconnect). + * NOTE that address is available in the endpoint structures as + * well. + */ + + priv->funcaddr = funcaddr; + } } /* ERROR handling: Do nothing. If we return and error during connection, diff --git a/drivers/usbhost/usbhost_skeleton.c b/drivers/usbhost/usbhost_skeleton.c index bc30eedd7c..a486f87682 100644 --- a/drivers/usbhost/usbhost_skeleton.c +++ b/drivers/usbhost/usbhost_skeleton.c @@ -1,7 +1,7 @@ /**************************************************************************** * drivers/usbhost/usbhost_skeleton.c * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -105,6 +105,7 @@ struct usbhost_state_s char devchar; /* Character identifying the /dev/skel[n] device */ volatile bool disconnected; /* TRUE: Device has been disconnected */ uint8_t ifno; /* Interface number */ + uint8_t funcaddr; /* USB function address */ int16_t crefs; /* Reference count on the driver instance */ sem_t exclsem; /* Used to maintain mutual exclusive access */ struct work_s work; /* For interacting with the worker thread */ @@ -368,7 +369,7 @@ static void usbhost_destroy(FAR void *arg) /* Disconnect the USB host device */ - DRVR_DISCONNECT(priv->drvr); + DRVR_DISCONNECT(priv->drvr, priv->funcaddr); /* And free the class instance. Hmmm.. this may execute on the worker * thread and the work structure is part of what is getting freed. That @@ -954,6 +955,15 @@ static int usbhost_connect(FAR struct usbhost_class_s *class, { udbg("usbhost_devinit() failed: %d\n", ret); } + else + { + /* Save the function address (We will need it when we disconnect). + * NOTE that address is available in the endpoint structures as + * well. + */ + + priv->funcaddr = funcaddr; + } } return ret; diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c index 89ec6238f9..bc0f78c75a 100644 --- a/drivers/usbhost/usbhost_storage.c +++ b/drivers/usbhost/usbhost_storage.c @@ -128,6 +128,7 @@ struct usbhost_state_s char sdchar; /* Character identifying the /dev/sd[n] device */ volatile bool disconnected; /* TRUE: Device has been disconnected */ uint8_t ifno; /* Interface number */ + uint8_t funcaddr; /* USB function address */ int16_t crefs; /* Reference count on the driver instance */ uint16_t blocksize; /* Block size of USB mass storage device */ uint32_t nblocks; /* Number of blocks on the USB mass storage device */ @@ -929,7 +930,7 @@ static void usbhost_destroy(FAR void *arg) /* Disconnect the USB host device */ - DRVR_DISCONNECT(priv->drvr); + DRVR_DISCONNECT(priv->drvr, priv->funcaddr); /* And free the class instance. Hmmm.. this may execute on the worker * thread and the work structure is part of what is getting freed. That @@ -1740,6 +1741,15 @@ static int usbhost_connect(FAR struct usbhost_class_s *class, { udbg("usbhost_initvolume() failed: %d\n", ret); } + else + { + /* Save the function address (We will need it when we disconnect). + * NOTE that address is available in the endpoint structures as + * well. + */ + + priv->funcaddr = funcaddr; + } } return ret; diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index d357e0b9bf..80b6f9cf6c 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -481,6 +481,7 @@ * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to * the class create() method. + * funcaddr - Address of the function to be disconnected. * * Returned Values: * None @@ -490,7 +491,7 @@ * ************************************************************************************/ -#define DRVR_DISCONNECT(drvr) ((drvr)->disconnect(drvr)) +#define DRVR_DISCONNECT(drvr,funcaddr) ((drvr)->disconnect(drvr,funcaddr)) /************************************************************************************ * Public Types @@ -684,7 +685,7 @@ struct usbhost_driver_s * (until a new instance is received from the create() method). */ - void (*disconnect)(FAR struct usbhost_driver_s *drvr); + void (*disconnect)(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr); }; /************************************************************************************