9
0
Fork 0

TD's no longer hard allocated

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3252 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
patacongo 2011-01-15 17:46:55 +00:00
parent 31bec0aa12
commit 6f6d9e781b
8 changed files with 374 additions and 188 deletions

View File

@ -112,10 +112,6 @@
#define LPC17_HCCA_SIZE 256
/* Fixed transfer descriptor size */
#define LPC17_TD_SIZE 16
/* 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
@ -136,7 +132,29 @@
#define LPC17_EDFREE_SIZE (CONFIG_USBHOST_NEDS * LPC17_ED_SIZE)
/* Configurable number of descriptor buffer (TDBUFFER) */
/* 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 LPC17_TD_SIZE 32
/* Configurable number of user transfer descriptors (TDs). */
#ifndef CONFIG_USBHOST_NTDS
# define CONFIG_USBHOST_NTDS 3
#endif
#if CONFIG_USBHOST_NTDS < 2
# error "Insufficent TDs"
#endif
/* Derived size of user trasnfer descriptor (TD) memory. */
#define LPC17_TDFREE_SIZE (CONFIG_USBHOST_NTDS * LPC17_TD_SIZE)
/* Configurable number of request/descriptor buffers (TDBUFFER) */
#ifndef CONFIG_USBHOST_TDBUFFERS
# define CONFIG_USBHOST_TDBUFFERS 2
@ -156,7 +174,7 @@
# error "TD buffer size must be an even number of 32-bit words"
#endif
#define LPC17_TDFREE_SIZE (CONFIG_USBHOST_TDBUFFERS * CONFIG_USBHOST_TDBUFSIZE)
#define LPC17_TBFREE_SIZE (CONFIG_USBHOST_TDBUFFERS * CONFIG_USBHOST_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.
@ -177,43 +195,45 @@
* LPC17_BANK1_SIZE 16384
*
* Configuration:
* CONFIG_USBHOST_OHCIRAM_SIZE 1280
* CONFIG_USBHOST_OHCIRAM_SIZE 1536
* CONFIG_USBHOST_NEDS 2
* CONFIG_USBHOST_TDBUFFERS 2
* CONFIG_USBHOST_NEDS 3
* CONFIG_USBHOST_TDBUFFERS 3
* CONFIG_USBHOST_TDBUFSIZE 128
* CONFIG_USBHOST_IOBUFSIZE 512
*
* Sizes of things
* LPC17_EDFREE_SIZE 96 (including EP0)
* LPC17_TDFREE_SIZE 256
* LPC17_IOFREE_SIZE 512
* LPC17_EDFREE_SIZE 64 0x00000040
* LPC17_TDFREE_SIZE 96 0x00000060
* LPC17_TBFREE_SIZE 384 0x00000100
* LPC17_IOFREE_SIZE 512 0x00000200
*
* Memory Layout
* LPC17_OHCIRAM_END (0x20008000 + 16384) = 0x2000c000
* LPC17_OHCIRAM_BASE (0x2000c000 - 1280) = 0x2000bb00
* LPC17_OHCIRAM_END (0x20008000 + 16384) = 0x20084000
* LPC17_OHCIRAM_BASE (0x2000c000 - 1536) = 0x2000ba00
* LPC17_OHCIRAM_SIZE 1280
* LPC17_BANK1_HEAPBASE 0x20008000
* LPC17_BANK1_HEAPSIZE (16384 - 1280) = 15104
*
* LPC17_HCCA_BASE 0x2000bb00
* LPC17_TDHEAD_ADDR 0x2000bc00
* LPC17_TDTAIL_ADDR 0x2000bc10
* LPC17_EDCTRL_ADDR 0x2000bc20
* LPC17_EDFREE_BASE 0x2000bc40
* LPC17_TDFREE_BASE 0x2000bc80
* LPC17_IOFREE_BASE 0x2000bd80
* LPC17_IOBUFFERS (0x2000c000 - 0x2000bd80) / 512 = 640/512 = 1
* LPC17_HCCA_BASE 0x20083a00 -- Communications area
* LPC17_TDTAIL_ADDR 0x20083b00 -- Common. pre-allocated tail TD
* LPC17_EDCTRL_ADDR 0x20083b20 -- Pre-allocated ED for EP0
* LPC17_EDFREE_BASE 0x20083b40 -- Free EDs
* LPC17_TDFREE_BASE 0x20083b80 -- Free TDs
* LPC17_TBFREE_BASE 0x20083be0 -- Free request/descriptor buffers
* LPC17_IOFREE_BASE 0x20083d60 -- Free large I/O buffers
* LPC17_IOBUFFERS (0x20084000 - 0x20083d60) / 512 = 672/512 = 1
*
* Wasted memory: 640-512 = 128 bytes
* Wasted memory: 672-512 = 160 bytes
*/
#define LPC17_HCCA_BASE (LPC17_OHCIRAM_BASE)
#define LPC17_TDHEAD_ADDR (LPC17_OHCIRAM_BASE + LPC17_HCCA_SIZE)
#define LPC17_TDTAIL_ADDR (LPC17_TDHEAD_ADDR + LPC17_TD_SIZE)
#define LPC17_TDTAIL_ADDR (LPC17_HCCA_BASE + LPC17_HCCA_SIZE)
#define LPC17_EDCTRL_ADDR (LPC17_TDTAIL_ADDR + LPC17_TD_SIZE)
#define LPC17_EDFREE_BASE (LPC17_EDCTRL_ADDR + LPC17_ED_SIZE)
#define LPC17_TDFREE_BASE (LPC17_EDFREE_BASE + LPC17_EDFREE_SIZE)
#define LPC17_IOFREE_BASE (LPC17_TDFREE_BASE + LPC17_TDFREE_SIZE)
#define LPC17_TBFREE_BASE (LPC17_TDFREE_BASE + LPC17_TDFREE_SIZE)
#define LPC17_IOFREE_BASE (LPC17_TBFREE_BASE + LPC17_TBFREE_SIZE)
#if LPC17_IOFREE_BASE > LPC17_OHCIRAM_END
# error "Insufficient OHCI RAM allocated"

View File

@ -118,13 +118,13 @@
/* Helper definitions */
#define HCCA ((volatile struct ohci_hcca_s *)LPC17_HCCA_BASE)
#define TDHEAD ((volatile struct ohci_gtd_s *)LPC17_TDHEAD_ADDR)
#define TDTAIL ((volatile struct ohci_gtd_s *)LPC17_TDTAIL_ADDR)
#define EDCTRL ((volatile struct lpc17_ed_s *)LPC17_EDCTRL_ADDR)
#define HCCA ((struct ohci_hcca_s *)LPC17_HCCA_BASE)
#define TDTAIL ((struct lpc17_gtd_s *)LPC17_TDTAIL_ADDR)
#define EDCTRL ((struct lpc17_ed_s *)LPC17_EDCTRL_ADDR)
#define EDFREE ((struct lpc17_ed_s *)LPC17_EDFREE_BASE)
#define TDFREE ((uint8_t *)LPC17_TDFREE_BASE)
#define TDFREE ((struct lpc17_gtd_s *)LPC17_TDFREE_BASE)
#define TBFREE ((uint8_t *)LPC17_TBFREE_BASE)
#define IOFREE ((uint8_t *)LPC17_IOFREE_BASE)
/* Descriptors *****************************************************************/
@ -181,18 +181,30 @@ struct lpc17_ed_s
uint8_t pad[15];
};
/* The following are used to manage lists of free EDs and TD buffers*/
/* 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_ohciram.h. This extra 16-bytes is used by the OHCI host driver in
* order to maintain additional endpoint-specific data.
*/
struct lpc17_edlist_s
struct lpc17_gtd_s
{
struct lpc17_edlist_s *flink; /* Link to next ED in the list */
uint32_t pad[7]; /* To make the same size as struct lpc17_ed_s */
/* Hardware specific fields */
struct ohci_gtd_s hw;
/* Software specific fields */
struct lpc17_ed_s *ed; /* Pointer to parent ED */
uint8_t pad[12];
};
struct lpc17_buflist_s
/* The following is used to manage lists of free EDs, TDs, and TD buffers */
struct lpc17_list_s
{
struct lpc17_buflist_s *flink; /* Link to next buffer in the list */
/* Variable length buffer data follows */
struct lpc17_list_s *flink; /* Link to next buffer in the list */
/* Variable length buffer data follows */
};
/*******************************************************************************
@ -223,15 +235,18 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val);
/* Descriptor helper functions *************************************************/
static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv);
static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer);
static struct lpc17_gtd_s *lpc17_tdalloc(struct lpc17_usbhost_s *priv);
static void lpc17_tdfree(struct lpc17_usbhost_s *priv, struct lpc17_gtd_s *buffer);
static uint8_t *lpc17_tballoc(struct lpc17_usbhost_s *priv);
static void lpc17_tbfree(struct lpc17_usbhost_s *priv, uint8_t *buffer);
#if LPC17_IOBUFFERS > 0
static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv);
static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer);
#endif
static void lpc17_enqueuetd(volatile struct ohci_ed_s *ed, uint32_t dirpid,
uint32_t toggle, volatile uint8_t *buffer,
size_t buflen);
static int lpc17_enqueuetd(struct lpc17_usbhost_s *priv,
struct lpc17_ed_s *ed, uint32_t dirpid,
uint32_t toggle, volatile uint8_t *buffer,
size_t buflen);
static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, uint32_t dirpid,
uint8_t *buffer, size_t buflen);
@ -291,10 +306,11 @@ static struct lpc17_usbhost_s g_usbhost =
/* This is a free list of EDs and TD buffers */
static struct lpc17_edlist_s *g_edfree;
static struct lpc17_buflist_s *g_tdfree;
static struct lpc17_list_s *g_edfree; /* List of unused EDs */
static struct lpc17_list_s *g_tdfree; /* List of unused TDs */
static struct lpc17_list_s *g_tbfree; /* List of unused transfer buffers */
#if LPC17_IOBUFFERS > 0
static struct lpc17_buflist_s *g_iofree;
static struct lpc17_list_s *g_iofree; /* List of unused I/O buffers */
#endif
/*******************************************************************************
@ -481,7 +497,7 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val)
* Name: lpc17_tdalloc
*
* Description:
* Allocate an TD buffer from the free list
* Allocate an transfer descriptor from the free list
*
* Assumptions:
* - Called from a single thread so no mutual exclusion is required.
@ -489,13 +505,23 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val)
*
*******************************************************************************/
static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv)
static struct lpc17_gtd_s *lpc17_tdalloc(struct lpc17_usbhost_s *priv)
{
uint8_t *ret = (uint8_t *)g_tdfree;
struct lpc17_gtd_s *ret;
irqstate_t flags;
/* Disable interrupts momentarily so that lpc17_tdfree is not called from the
* interrupt handler.
*/
flags = irqsave();
ret = (struct lpc17_gtd_s *)g_tdfree;
if (ret)
{
g_tdfree = ((struct lpc17_buflist_s*)ret)->flink;
g_tdfree = ((struct lpc17_list_s*)ret)->flink;
}
irqrestore(flags);
return ret;
}
@ -503,18 +529,67 @@ static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv)
* Name: lpc17_tdfree
*
* Description:
* Return an TD buffer to the free list
* Return an transfer descriptor to the free list
*
* Assumptions:
* - Only called from the WDH interrupt handler (and during initialization).
* - Interrupts are disabled in any case.
*
*******************************************************************************/
static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer)
static void lpc17_tdfree(struct lpc17_usbhost_s *priv, struct lpc17_gtd_s *td)
{
struct lpc17_buflist_s *tdfree = (struct lpc17_buflist_s *)buffer;
struct lpc17_list_s *tdfree = (struct lpc17_list_s *)td;
if (tdfree)
/* This should not happen but just to be safe, don't free the common, pre-
* allocated tail TD.
*/
if (tdfree != NULL && td != TDTAIL)
{
tdfree->flink = g_tdfree;
g_tdfree = tdfree;
tdfree->flink = g_tdfree;
g_tdfree = tdfree;
}
}
/*******************************************************************************
* Name: lpc17_tballoc
*
* Description:
* Allocate an request/descriptor transfer buffer from the free list
*
* Assumptions:
* - Called from a single thread so no mutual exclusion is required.
* - Never called from an interrupt handler.
*
*******************************************************************************/
static uint8_t *lpc17_tballoc(struct lpc17_usbhost_s *priv)
{
uint8_t *ret = (uint8_t *)g_tbfree;
if (ret)
{
g_tbfree = ((struct lpc17_list_s*)ret)->flink;
}
return ret;
}
/*******************************************************************************
* Name: lpc17_tbfree
*
* Description:
* Return an request/descriptor transfer buffer to the free list
*
*******************************************************************************/
static void lpc17_tbfree(struct lpc17_usbhost_s *priv, uint8_t *buffer)
{
struct lpc17_list_s *tbfree = (struct lpc17_list_s *)buffer;
if (tbfree)
{
tbfree->flink = g_tbfree;
g_tbfree = tbfree;
}
}
@ -536,7 +611,7 @@ static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv)
uint8_t *ret = (uint8_t *)g_iofree;
if (ret)
{
g_iofree = ((struct lpc17_buflist_s*)ret)->flink;
g_iofree = ((struct lpc17_list_s*)ret)->flink;
}
return ret;
}
@ -553,9 +628,9 @@ static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv)
#if LPC17_IOBUFFERS > 0
static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer)
{
struct lpc17_buflist_s *iofree = (struct lpc17_buflist_s *)buffer;
iofree->flink = g_iofree;
g_iofree = iofree;
struct lpc17_list_s *iofree = (struct lpc17_list_s *)buffer;
iofree->flink = g_iofree;
g_iofree = iofree;
}
#endif
@ -563,25 +638,48 @@ static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer)
* Name: lpc17_enqueuetd
*
* Description:
* Enqueue a transfer descriptor
* Enqueue a transfer descriptor. Notice that this function only supports
* queue on TD per ED.
*
*******************************************************************************/
static void lpc17_enqueuetd(volatile struct ohci_ed_s *ed, uint32_t dirpid,
uint32_t toggle, volatile uint8_t *buffer, size_t buflen)
static int lpc17_enqueuetd(struct lpc17_usbhost_s *priv,
struct lpc17_ed_s *ed, uint32_t dirpid,
uint32_t toggle, volatile uint8_t *buffer, size_t buflen)
{
TDHEAD->ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK);
TDTAIL->ctrl = 0;
TDHEAD->cbp = (uint32_t)buffer;
TDTAIL->cbp = 0;
TDHEAD->nexttd = (uint32_t)TDTAIL;
TDTAIL->nexttd = 0;
TDHEAD->be = (uint32_t)(buffer + (buflen - 1));
TDTAIL->be = 0;
struct lpc17_gtd_s *td;
int ret = -ENOMEM;
ed->headp = (uint32_t)TDHEAD | ((ed->headp) & ED_HEADP_C);
ed->tailp = (uint32_t)TDTAIL;
ed->nexted = 0;
/* Allocate a TD from the free list */
td = lpc17_tdalloc(priv);
if (td != NULL)
{
/* 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);
TDTAIL->hw.ctrl = 0;
td->hw.cbp = (uint32_t)buffer;
TDTAIL->hw.cbp = 0;
td->hw.nexttd = (uint32_t)TDTAIL;
TDTAIL->hw.nexttd = 0;
td->hw.be = (uint32_t)(buffer + (buflen - 1));
TDTAIL->hw.be = 0;
/* Configure driver-only fields in the extended TD structure */
td->ed = ed;
/* Link the td to the head of the ED's TD list */
ed->hw.headp = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C);
ed->hw.tailp = (uint32_t)TDTAIL;
ed->hw.nexted = 0;
ret = OK;
}
return ret;
}
/*******************************************************************************
@ -662,47 +760,54 @@ static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, uint32_t dirpid,
/* Then enqueue the transfer */
priv->tdstatus = TD_CC_NOERROR;
lpc17_enqueuetd(&EDCTRL->hw, dirpid, toggle, buffer, buflen);
/* Set the head of the control list to the EP0 EDCTRL (this would have to
* change if we want more than on control EP queued at a time).
*/
lpc17_putreg(LPC17_EDCTRL_ADDR, LPC17_USBHOST_CTRLHEADED);
/* Set ControlListFilled. This bit is used to indicate whether there are
* TDs on the Control list.
*/
regval = lpc17_getreg(LPC17_USBHOST_CMDST);
regval |= OHCI_CMDST_CLF;
lpc17_putreg(regval, LPC17_USBHOST_CMDST);
/* ControlListEnable. This bit is set to enable the processing of the
* Control list. Note: once enabled, it remains enabled and we may even
* complete list processing before we get the bit set. We really
* should never modify the control list while CLE is set.
*/
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval |= OHCI_CTRL_CLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
/* Wait for the Writeback Done Head interrupt */
lpc17_takesem(&priv->wdhsem);
/* Check the TDHEAD completion status bits */
if (priv->tdstatus == TD_CC_NOERROR)
ret = lpc17_enqueuetd(priv, EDCTRL, dirpid, toggle, buffer, buflen);
if (ret == OK)
{
return OK;
}
else
{
uvdbg("Bad TD completion status: %d\n", priv->tdstatus);
return -EIO;
/* Set the head of the control list to the EP0 EDCTRL (this would have to
* change if we want more than on control EP queued at a time).
*/
lpc17_putreg(LPC17_EDCTRL_ADDR, LPC17_USBHOST_CTRLHEADED);
/* Set ControlListFilled. This bit is used to indicate whether there are
* TDs on the Control list.
*/
regval = lpc17_getreg(LPC17_USBHOST_CMDST);
regval |= OHCI_CMDST_CLF;
lpc17_putreg(regval, LPC17_USBHOST_CMDST);
/* ControlListEnable. This bit is set to enable the processing of the
* Control list. Note: once enabled, it remains enabled and we may even
* complete list processing before we get the bit set. We really
* should never modify the control list while CLE is set.
*/
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval |= OHCI_CTRL_CLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
/* Wait for the Writeback Done Head interrupt */
lpc17_takesem(&priv->wdhsem);
/* Check the TD completion status bits */
if (priv->tdstatus == TD_CC_NOERROR)
{
ret = OK;
}
else
{
uvdbg("Bad TD completion status: %d\n", priv->tdstatus);
ret = -EIO;
}
}
/* Make sure that there is no outstanding request on this endpoint */
priv->wdhwait = false;
return ret;
}
/*******************************************************************************
@ -814,19 +919,6 @@ static int lpc17_usbinterrupt(int irq, FAR void *context)
lpc17_givesem(&priv->rhssem);
priv->rhswait = false;
}
/* Wake up the thread waiting for the WDH event. In my
* experience, the WHD event will occur later after the
* disconnection, but it is safer to make sure that
* there are no waiters.
*/
if (priv->wdhwait)
{
priv->tdstatus = TD_CC_DEVNOTRESPONDING;
lpc17_givesem(&priv->wdhsem);
priv->wdhwait = false;
}
}
else
{
@ -853,34 +945,57 @@ static int lpc17_usbinterrupt(int irq, FAR void *context)
if ((pending & OHCI_INT_WDH) != 0)
{
struct lpc17_gtd_s *td;
struct lpc17_gtd_s *next;
/* The host controller just wrote the list of finished TDs into the HCCA
* done head. Here we assume that only a single packet is "in flight"
* at any given time and we use only the TD at TDHEAD. So not much needs
* to be done here. In a more complex implementation we would need to
* recover these completed TDs in some meaningful way.
* at any given time.
*/
/* Since there is only one TD, we can disable further TD processing. */
#warning "This logic needs to be removed"
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE|OHCI_CTRL_CLE|OHCI_CTRL_BLE);
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
/* Get the condition code from the (single) TDHEAD TD status/control word */
/* 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.
*/
priv->tdstatus = (TDHEAD->ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT;
td = (struct lpc17_gtd_s *)HCCA->donehead;
HCCA->donehead = 0;
/* Process each TD in the write done list */
for (; td; td = next)
{
/* Get the condition code from the (single) TD status/control
* word. This obviously will not work if/when there are more
* one TD in the done list.
*/
priv->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT;
#ifdef CONFIG_DEBUG_USB
if (priv->tdstatus != TD_CC_NOERROR)
{
/* The transfer failed for some reason... dump some diagnostic info. */
if (priv->tdstatus != TD_CC_NOERROR)
{
/* The transfer failed for some reason... dump some diagnostic info. */
ulldbg("ERROR: TD CTRL:%08x/CC:%d RHPORTST1:%08x\n",
TDHEAD->ctrl, priv->tdstatus,
lpc17_getreg(LPC17_USBHOST_RHPORTST1));
}
ulldbg("ERROR: TD CTRL:%08x/CC:%d RHPORTST1:%08x\n",
td->hw.ctrl, priv->tdstatus,
lpc17_getreg(LPC17_USBHOST_RHPORTST1));
}
#endif
/* Return the TD to the free list */
next = (struct lpc17_gtd_s *)td->hw.nexttd;
lpc17_tdfree(priv, td);
}
/* And wake up the thread waiting for the WDH event */
if (priv->wdhwait)
@ -1115,7 +1230,7 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
{
/* Remove the ED from the freelist */
g_edfree = ((struct lpc17_edlist_s*)ed)->flink;
g_edfree = ((struct lpc17_list_s*)ed)->flink;
/* Configure the endpoint descriptor. */
@ -1141,12 +1256,24 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
{
ed->hw.ctrl |= ED_CONTROL_S;
}
uvdbg("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl);
/* Set the transfer type */
ed->xfrtype = epdesc->xfrtype;
/* Special Case isochronous transfer types */
#if 0 /* Isochronous transfers not yet supported */
if (ed->xfrtype == USB_EP_ATTR_XFER_ISOC)
{
ed->hw.ctrl |= ED_CONTROL_F;
}
#endif
uvdbg("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl);
/* Now add the endpoint descriptor to the appropriate list */
#warning "Missing logic"
/* Return an opaque reference to the ED */
*ep = (usbhost_ep_t)ed;
@ -1177,7 +1304,7 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
{
struct lpc17_edlist_s *ed = (struct lpc17_edlist_s *)ep;
struct lpc17_list_s *ed = (struct lpc17_list_s *)ep;
DEBUGASSERT(ed);
@ -1192,9 +1319,9 @@ static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
* Name: lpc17_alloc
*
* Description:
* Some hardware supports special memory in which transfer descriptors can
* Some hardware supports special memory in which request and descriptor data can
* be accessed more efficiently. This method provides a mechanism to allocate
* the transfer descriptor memory. If the underlying hardware does not support
* the request/descriptor memory. If the underlying hardware does not support
* such "special" memory, this functions may simply map to malloc.
*
* Input Parameters:
@ -1221,7 +1348,7 @@ static int lpc17_alloc(FAR struct usbhost_driver_s *drvr,
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr;
DEBUGASSERT(priv && buffer && maxlen);
*buffer = lpc17_tdalloc(priv);
*buffer = lpc17_tballoc(priv);
if (*buffer)
{
*maxlen = CONFIG_USBHOST_TDBUFSIZE;
@ -1234,9 +1361,9 @@ static int lpc17_alloc(FAR struct usbhost_driver_s *drvr,
* Name: lpc17_free
*
* Description:
* Some hardware supports special memory in which transfer descriptors can
* Some hardware supports special memory in which request and descriptor data can
* be accessed more efficiently. This method provides a mechanism to free that
* transfer descriptor memory. If the underlying hardware does not support
* request/descriptor memory. If the underlying hardware does not support
* such "special" memory, this functions may simply map to free().
*
* Input Parameters:
@ -1258,7 +1385,7 @@ static int lpc17_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer)
{
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr;
DEBUGASSERT(priv && buffer);
lpc17_tdfree(priv, buffer);
lpc17_tbfree(priv, buffer);
return OK;
}
@ -1477,49 +1604,55 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
/* Then enqueue the transfer */
priv->tdstatus = TD_CC_NOERROR;
lpc17_enqueuetd(&ed->hw, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen);
ret = lpc17_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen);
if (ret == OK)
{
/* Set the head of the bulk list to the EP descriptor (this would have to
* change if we want more than on bulk EP queued at a time).
*/
/* Set the head of the bulk list to the EP descriptor (this would have to
* change if we want more than on bulk EP queued at a time).
*/
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED);
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED);
/* BulkListFilled. This bit is used to indicate whether there are any
* TDs on the Bulk list.
*/
/* BulkListFilled. This bit is used to indicate whether there are any
* TDs on the Bulk list.
*/
regval = lpc17_getreg(LPC17_USBHOST_CMDST);
regval |= OHCI_CMDST_BLF;
lpc17_putreg(regval, LPC17_USBHOST_CMDST);
regval = lpc17_getreg(LPC17_USBHOST_CMDST);
regval |= OHCI_CMDST_BLF;
lpc17_putreg(regval, LPC17_USBHOST_CMDST);
/* BulkListEnable. This bit is set to enable the processing of the Bulk
* list. Note: once enabled, it remains enabled and we may even
* complete list processing before we get the bit set. We really
* should never modify the bulk list while BLE is set.
*/
/* BulkListEnable. This bit is set to enable the processing of the Bulk
* list. Note: once enabled, it remains enabled and we may even
* complete list processing before we get the bit set. We really
* should never modify the bulk list while BLE is set.
*/
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval |= OHCI_CTRL_BLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
regval |= OHCI_CTRL_BLE;
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
/* Wait for the Writeback Done Head interrupt */
/* Wait for the Writeback Done Head interrupt */
lpc17_takesem(&priv->wdhsem);
lpc17_takesem(&priv->wdhsem);
/* Check the TDHEAD completion status bits */
/* Check the TD completion status bits */
if (priv->tdstatus == TD_CC_NOERROR)
{
ret = OK;
}
else
{
uvdbg("Bad TD completion status: %d\n", priv->tdstatus);
ret = -EIO;
if (priv->tdstatus == TD_CC_NOERROR)
{
ret = OK;
}
else
{
uvdbg("Bad TD completion status: %d\n", priv->tdstatus);
ret = -EIO;
}
}
errout:
/* Make sure that there is no outstanding request on this endpoint */
priv->wdhwait = false;
/* Free any temporary IO buffers */
#if LPC17_IOBUFFERS > 0
@ -1676,10 +1809,22 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller)
udbg("Initializing Host Stack\n");
/* Show AHB SRAM memory map */
#if 0 /* Useful if you have doubts about the layout */
uvdbg("AHB SRAM:\n");
uvdbg(" HCCA: %08x %d\n", LPC17_HCCA_BASE, LPC17_HCCA_SIZE);
uvdbg(" TDTAIL: %08x %d\n", LPC17_TDTAIL_ADDR, LPC17_TD_SIZE);
uvdbg(" EDCTRL: %08x %d\n", LPC17_EDCTRL_ADDR, LPC17_ED_SIZE);
uvdbg(" EDFREE: %08x %d\n", LPC17_EDFREE_BASE, LPC17_ED_SIZE);
uvdbg(" TDFREE: %08x %d\n", LPC17_TDFREE_BASE, LPC17_EDFREE_SIZE);
uvdbg(" TBFREE: %08x %d\n", LPC17_TBFREE_BASE, LPC17_TBFREE_SIZE);
uvdbg(" IOFREE: %08x %d\n", LPC17_IOFREE_BASE, LPC17_IOBUFFERS * CONFIG_USBHOST_IOBUFSIZE);
#endif
/* Initialize all the TDs, EDs and HCCA to 0 */
memset((void*)HCCA, 0, sizeof(struct ohci_hcca_s));
memset((void*)TDHEAD, 0, sizeof(struct ohci_gtd_s));
memset((void*)TDTAIL, 0, sizeof(struct ohci_gtd_s));
memset((void*)EDCTRL, 0, sizeof(struct lpc17_ed_s));
@ -1692,14 +1837,23 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller)
lpc17_epfree(&priv->drvr, (usbhost_ep_t)&EDFREE[i]);
}
/* Initialize user-configurable TD buffers */
/* Initialize user-configurable TDs */
buffer = TDFREE;
for (i = 0; i < CONFIG_USBHOST_NTDS; i++)
{
/* Put the ED in a free list */
lpc17_tdfree(priv, &TDFREE[i]);
}
/* Initialize user-configurable request/descriptor transfer buffers */
buffer = TBFREE;
for (i = 0; i < CONFIG_USBHOST_NEDS; i++)
{
/* Put the TD buffer in a free list */
lpc17_tdfree(priv, buffer);
lpc17_tbfree(priv, buffer);
buffer += CONFIG_USBHOST_TDBUFSIZE;
}

View File

@ -327,6 +327,8 @@ mbed Configuration Options
Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
CONFIG_USBHOST_NTDS
Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE

View File

@ -439,6 +439,8 @@ Nucleus 2G Configuration Options
Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
CONFIG_USBHOST_NTDS
Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE

View File

@ -627,6 +627,8 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0
# Total size of OHCI RAM (in AHB SRAM Bank 1)
# CONFIG_USBHOST_NEDS
# Number of endpoint descriptors
# CONFIG_USBHOST_NTDS
# Number of transfer descriptors
# CONFIG_USBHOST_TDBUFFERS
# Number of transfer descriptor buffers
# CONFIG_USBHOST_TDBUFSIZE
@ -634,8 +636,9 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0
# CONFIG_USBHOST_IOBUFSIZE
# Size of one end-user I/O buffer
#
CONFIG_USBHOST_OHCIRAM_SIZE=1280
CONFIG_USBHOST_OHCIRAM_SIZE=1536
CONFIG_USBHOST_NEDS=2
CONFIG_USBHOST_NTDS=2
CONFIG_USBHOST_TDBUFFERS=3
CONFIG_USBHOST_TDBUFSIZE=128
CONFIG_USBHOST_IOBUFSIZE=512

View File

@ -684,6 +684,8 @@ Olimex LPC1766-STK Configuration Options
Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
CONFIG_USBHOST_NTDS
Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE

View File

@ -633,6 +633,8 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0
# Total size of OHCI RAM (in AHB SRAM Bank 1)
# CONFIG_USBHOST_NEDS
# Number of endpoint descriptors
# CONFIG_USBHOST_NTDS
# Number of transfer descriptors
# CONFIG_USBHOST_TDBUFFERS
# Number of transfer descriptor buffers
# CONFIG_USBHOST_TDBUFSIZE
@ -640,8 +642,9 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0
# CONFIG_USBHOST_IOBUFSIZE
# Size of one end-user I/O buffer
#
CONFIG_USBHOST_OHCIRAM_SIZE=1280
CONFIG_USBHOST_OHCIRAM_SIZE=1536
CONFIG_USBHOST_NEDS=2
CONFIG_USBHOST_NTDS=3
CONFIG_USBHOST_TDBUFFERS=3
CONFIG_USBHOST_TDBUFSIZE=128
CONFIG_USBHOST_IOBUFSIZE=512

View File

@ -275,9 +275,9 @@
* Name: DRVR_ALLOC
*
* Description:
* Some hardware supports special memory in which transfer descriptors can
* Some hardware supports special memory in which request and descriptor data can
* be accessed more efficiently. This method provides a mechanism to allocate
* the transfer descriptor memory. If the underlying hardware does not support
* the request/descriptor memory. If the underlying hardware does not support
* such "special" memory, this functions may simply map to malloc.
*
* Input Parameters:
@ -303,9 +303,9 @@
* Name: DRVR_FREE
*
* Description:
* Some hardware supports special memory in which transfer descriptors can
* Some hardware supports special memory in which request and descriptor data can
* be accessed more efficiently. This method provides a mechanism to free that
* transfer descriptor memory. If the underlying hardware does not support
* request/descriptor memory. If the underlying hardware does not support
* such "special" memory, this functions may simply map to free().
*
* Input Parameters: