SAMA5 EHCI: No complete for bulk and control endpoints
This commit is contained in:
parent
577b19920e
commit
f356586fd3
@ -5424,4 +5424,7 @@
|
|||||||
* nuttx/arch/arm/src/sama5/sam_ehci.c and other files: Create a skeleton
|
* nuttx/arch/arm/src/sama5/sam_ehci.c and other files: Create a skeleton
|
||||||
environment for development of an EHCI driver. Not much in place yet
|
environment for development of an EHCI driver. Not much in place yet
|
||||||
(2013-8-20).
|
(2013-8-20).
|
||||||
|
* nuttx/arch/arm/src/sama5/sam_ehci.c: Now code complete for all
|
||||||
|
asynchronous endpoints (control and bulk); nothing yet in place
|
||||||
|
for periodic endponts (interrupt and isochronous) (2013-8-22).
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@
|
|||||||
#define CONFIG_USBHOST_INT_DISABLE 1
|
#define CONFIG_USBHOST_INT_DISABLE 1
|
||||||
|
|
||||||
#undef CONFIG_USBHOST_ISOC_DISABLE
|
#undef CONFIG_USBHOST_ISOC_DISABLE
|
||||||
#define CONFIG_USBHOST_INT_DISABLE 1
|
#define CONFIG_USBHOST_ISOC_DISABLE 1
|
||||||
|
|
||||||
/* Driver-private Definitions **************************************************/
|
/* Driver-private Definitions **************************************************/
|
||||||
|
|
||||||
@ -178,11 +178,14 @@ struct sam_epinfo_s
|
|||||||
uint8_t dirin:1; /* 1:IN endpoint 0:OUT endpoint */
|
uint8_t dirin:1; /* 1:IN endpoint 0:OUT endpoint */
|
||||||
uint8_t devaddr:7; /* Device address */
|
uint8_t devaddr:7; /* Device address */
|
||||||
uint8_t toggle:1; /* Next data toggle */
|
uint8_t toggle:1; /* Next data toggle */
|
||||||
uint8_t xfrtype:2; /* See USB_EP_ATTR_XFER_* definitions in usb.h */
|
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||||
uint8_t speed:2; /* See USB_*_SPEED definitions in ehci.h */
|
uint8_t interval; /* Polling interval */
|
||||||
|
#endif
|
||||||
uint8_t status; /* Retained token status bits (for debug purposes) */
|
uint8_t status; /* Retained token status bits (for debug purposes) */
|
||||||
volatile bool iocwait; /* TRUE: Thread is waiting for transfer completion */
|
volatile bool iocwait; /* TRUE: Thread is waiting for transfer completion */
|
||||||
uint16_t maxpacket; /* Maximum packet size */
|
uint16_t maxpacket:11; /* Maximum packet size */
|
||||||
|
uint16_t xfrtype:2; /* See USB_EP_ATTR_XFER_* definitions in usb.h */
|
||||||
|
uint16_t speed:2; /* See USB_*_SPEED definitions in ehci.h */
|
||||||
int result; /* The result of the transfer */
|
int result; /* The result of the transfer */
|
||||||
sem_t iocsem; /* Semaphore used to wait for transfer completion */
|
sem_t iocsem; /* Semaphore used to wait for transfer completion */
|
||||||
};
|
};
|
||||||
@ -236,8 +239,10 @@ struct sam_ehci_s
|
|||||||
|
|
||||||
static uint16_t sam_read16(const uint8_t *addr);
|
static uint16_t sam_read16(const uint8_t *addr);
|
||||||
static uint32_t sam_read32(const uint8_t *addr);
|
static uint32_t sam_read32(const uint8_t *addr);
|
||||||
|
#if 0 /* Not used */
|
||||||
static void sam_write16(uint16_t memval, uint8_t *addr);
|
static void sam_write16(uint16_t memval, uint8_t *addr);
|
||||||
static void sam_write32(uint32_t memval, uint8_t *addr);
|
static void sam_write32(uint32_t memval, uint8_t *addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_ENDIAN_BIG
|
#ifdef CONFIG_ENDIAN_BIG
|
||||||
static uint16_t sam_swap16(uint16_t value);
|
static uint16_t sam_swap16(uint16_t value);
|
||||||
@ -285,8 +290,10 @@ 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);
|
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_qtd_flush(struct sam_qtd_s *qtd, uint32_t **bp, void *arg);
|
||||||
static int sam_qh_flush(struct sam_qh_s *qh);
|
static int sam_qh_flush(struct sam_qh_s *qh);
|
||||||
|
|
||||||
@ -311,7 +318,6 @@ static int sam_async_transfer(struct sam_rhport_s *rhport,
|
|||||||
static int sam_qtd_ioccheck(struct sam_qtd_s *qtd, uint32_t **bp, void *arg);
|
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);
|
static int sam_qh_ioccheck(struct sam_qh_s *qh, uint32_t **bp, void *arg);
|
||||||
static inline void sam_ioc_bottomhalf(void);
|
static inline void sam_ioc_bottomhalf(void);
|
||||||
static inline void sam_err_bottomhalf(void);
|
|
||||||
static inline void sam_portsc_bottomhalf(void);
|
static inline void sam_portsc_bottomhalf(void);
|
||||||
static inline void sam_syserr_bottomhalf(void);
|
static inline void sam_syserr_bottomhalf(void);
|
||||||
static inline void sam_async_advance_bottomhalf(void);
|
static inline void sam_async_advance_bottomhalf(void);
|
||||||
@ -439,6 +445,7 @@ static inline uint32_t sam_read32(const uint8_t *addr)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#if 0 /* Not used */
|
||||||
static void sam_write16(uint16_t memval, uint8_t *addr)
|
static void sam_write16(uint16_t memval, uint8_t *addr)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ENDIAN_BIG
|
#ifdef CONFIG_ENDIAN_BIG
|
||||||
@ -449,6 +456,7 @@ static void sam_write16(uint16_t memval, uint8_t *addr)
|
|||||||
addr[1] = memval & 0xff;
|
addr[1] = memval & 0xff;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_write32
|
* Name: sam_write32
|
||||||
@ -458,6 +466,7 @@ static void sam_write16(uint16_t memval, uint8_t *addr)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#if 0 /* Not used */
|
||||||
static void sam_write32(uint32_t memval, uint8_t *addr)
|
static void sam_write32(uint32_t memval, uint8_t *addr)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_ENDIAN_BIG
|
#ifdef CONFIG_ENDIAN_BIG
|
||||||
@ -468,6 +477,7 @@ static void sam_write32(uint32_t memval, uint8_t *addr)
|
|||||||
sam_write16(memval >> 16, &addr[2]);
|
sam_write16(memval >> 16, &addr[2]);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_swap16
|
* Name: sam_swap16
|
||||||
@ -1053,6 +1063,7 @@ static int sam_qh_discard(struct sam_qh_s *qh)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#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
|
/* Invalidate the D-Cache, i.e., force reloading of the D-Cache from memory
|
||||||
@ -1063,6 +1074,7 @@ static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, void *arg)
|
|||||||
(uintptr_t)&qtd->hw + sizeof(struct ehci_qtd_s));
|
(uintptr_t)&qtd->hw + sizeof(struct ehci_qtd_s));
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_qh_invalidate
|
* Name: sam_qh_invalidate
|
||||||
@ -1072,6 +1084,7 @@ static int sam_qtd_invalidate(struct sam_qtd_s *qtd, uint32_t **bp, void *arg)
|
|||||||
*
|
*
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#if 0 /* Not used */
|
||||||
static int sam_qh_invalidate(struct sam_qh_s *qh)
|
static int sam_qh_invalidate(struct sam_qh_s *qh)
|
||||||
{
|
{
|
||||||
/* Invalidate the QH first so that we reload the qTD list head */
|
/* Invalidate the QH first so that we reload the qTD list head */
|
||||||
@ -1081,8 +1094,9 @@ static int sam_qh_invalidate(struct sam_qh_s *qh)
|
|||||||
|
|
||||||
/* Then invalidate all of the qTD entries in the queue */
|
/* Then invalidate all of the qTD entries in the queue */
|
||||||
|
|
||||||
return sam_qtd_foreach(qh, NULL, NULL);
|
return sam_qtd_foreach(qh, sam_qtd_invalidate, NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_qtd_flush
|
* Name: sam_qtd_flush
|
||||||
@ -1121,7 +1135,7 @@ static int sam_qh_flush(struct sam_qh_s *qh)
|
|||||||
|
|
||||||
/* Then flush all of the qTD entries in the queue */
|
/* Then flush all of the qTD entries in the queue */
|
||||||
|
|
||||||
return sam_qtd_foreach(qh, NULL, NULL);
|
return sam_qtd_foreach(qh, sam_qtd_flush, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -1922,8 +1936,6 @@ static inline void sam_ioc_bottomhalf(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
uvdbg("USB Interrupt (USBINT) Interrupt\n");
|
|
||||||
|
|
||||||
/* Make sure that the head of the asynchronous queue is invalidated */
|
/* Make sure that the head of the asynchronous queue is invalidated */
|
||||||
|
|
||||||
cp15_invalidate_dcache((uintptr_t)&g_asynchead.hw,
|
cp15_invalidate_dcache((uintptr_t)&g_asynchead.hw,
|
||||||
@ -1938,27 +1950,6 @@ static inline void sam_ioc_bottomhalf(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Name: sam_err_bottomhalf
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* EHCI USB Error Interrupt (USBERRINT) "Bottom Half" interrupt handler
|
|
||||||
*
|
|
||||||
* "The Host Controller sets this bit to 1 when completion of a USB transaction
|
|
||||||
* results in an error condition (e.g., error counter underflow). If the TD on
|
|
||||||
* which the error interrupt occurred also had its IOC bit set, both this bit
|
|
||||||
* and USBINT bit are set. ..."
|
|
||||||
*
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
static inline void sam_err_bottomhalf(void)
|
|
||||||
{
|
|
||||||
udbg("USB Error Interrupt (USBERRINT) Interrupt\n");
|
|
||||||
|
|
||||||
/* Remove all queued transfers */
|
|
||||||
#warning Missing logic
|
|
||||||
}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: sam_portsc_bottomhalf
|
* Name: sam_portsc_bottomhalf
|
||||||
*
|
*
|
||||||
@ -2114,8 +2105,7 @@ static inline void sam_async_advance_bottomhalf(void)
|
|||||||
{
|
{
|
||||||
udbg("Async Advance Interrupt\n");
|
udbg("Async Advance Interrupt\n");
|
||||||
|
|
||||||
/* Remove all tagged QH entries */
|
/* REVISIT: Could remove all tagged QH entries here */
|
||||||
#warning Missing logic
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -2147,24 +2137,30 @@ static void sam_ehci_bottomhalf(FAR void *arg)
|
|||||||
* "The Host Controller also sets this bit to 1 when a short packet is
|
* "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
|
* detected (actual number of bytes received was less than the expected
|
||||||
* number of bytes)."
|
* number of bytes)."
|
||||||
*/
|
*
|
||||||
|
* USB Error Interrupt (USBERRINT)
|
||||||
if ((pending & EHCI_INT_USBINT) != 0)
|
|
||||||
{
|
|
||||||
sam_ioc_bottomhalf();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* USB Error Interrupt (USBERRINT)
|
|
||||||
*
|
*
|
||||||
* "The Host Controller sets this bit to 1 when completion of a USB
|
* "The Host Controller sets this bit to 1 when completion of a USB
|
||||||
* transaction results in an error condition (e.g., error counter
|
* transaction results in an error condition (e.g., error counter
|
||||||
* underflow). If the TD on which the error interrupt occurred also
|
* underflow). If the TD on which the error interrupt occurred also
|
||||||
* had its IOC bit set, both this bit and USBINT bit are set. ..."
|
* had its IOC bit set, both this bit and USBINT bit are set. ..."
|
||||||
|
*
|
||||||
|
* We do the same thing in either case: Traverse the asynchonous queue
|
||||||
|
* and remove all of the transfers that are no longer active.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((pending & EHCI_INT_USBERRINT) != 0)
|
if ((pending & (EHCI_INT_USBINT | EHCI_INT_USBERRINT)) != 0)
|
||||||
{
|
{
|
||||||
sam_err_bottomhalf();
|
if ((pending & EHCI_INT_USBERRINT) != 0)
|
||||||
|
{
|
||||||
|
udbg("USB Error Interrupt (USBERRINT) Interrupt\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uvdbg("USB Interrupt (USBINT) Interrupt\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sam_ioc_bottomhalf();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Port Change Detect
|
/* Port Change Detect
|
||||||
@ -2403,6 +2399,8 @@ static int sam_wait(FAR struct usbhost_connection_s *conn,
|
|||||||
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
||||||
{
|
{
|
||||||
struct sam_rhport_s *rhport;
|
struct sam_rhport_s *rhport;
|
||||||
|
volatile uint32_t *regaddr;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
DEBUGASSERT(rhpndx >= 0 && rhpndx < SAM_EHCI_NRHPORT);
|
DEBUGASSERT(rhpndx >= 0 && rhpndx < SAM_EHCI_NRHPORT);
|
||||||
rhport = &g_ehci.rhport[rhpndx];
|
rhport = &g_ehci.rhport[rhpndx];
|
||||||
@ -2419,26 +2417,74 @@ static int sam_enumerate(FAR struct usbhost_connection_s *conn, int rhpndx)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add EP0 to the control list */
|
/* USB 2.0 spec says at least 50ms delay before port reset.
|
||||||
#warning Missing logic
|
* REVISIT: I think this is wrong. It needs to hold the port in
|
||||||
|
* reset for 50Msec, not wait 50Msec before resetting.
|
||||||
|
*/
|
||||||
|
|
||||||
/* USB 2.0 spec says at least 50ms delay before port reset */
|
usleep(100*1000);
|
||||||
|
|
||||||
up_mdelay(100);
|
/* Put the root hub port in reset.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* may hold Port Reset asserted to a one when the HCHalted bit is a one.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Put the root hub port in reset (the SAMA5 supports three downstream ports) */
|
DEBUGASSERT((sam_getreg(&HCOR->usbsts) & EHCI_USBSTS_HALTED) == 0);
|
||||||
#warning Missing logic
|
|
||||||
|
|
||||||
/* Wait for the port reset to complete */
|
/* paragraph 2.3.9:
|
||||||
#warning Missing logic
|
*
|
||||||
|
* "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."
|
||||||
|
*/
|
||||||
|
|
||||||
/* Release RH port 1 from reset and wait a bit */
|
regaddr = &HCOR->portsc[rhport->rhpndx];
|
||||||
#warning Missing logic
|
regval = sam_getreg(regaddr);
|
||||||
|
regval &= ~EHCI_PORTSC_PE;
|
||||||
|
regval &= EHCI_PORTSC_RESET;
|
||||||
|
sam_putreg(regval, regaddr);
|
||||||
|
|
||||||
up_mdelay(200);
|
/* USB 2.0 "Root hubs must provide an aggregate reset period of at least
|
||||||
|
* 50 ms."
|
||||||
|
*/
|
||||||
|
|
||||||
|
usleep(50*1000);
|
||||||
|
|
||||||
|
regval = sam_getreg(regaddr);
|
||||||
|
regval &= ~EHCI_PORTSC_RESET;
|
||||||
|
sam_putreg(regval, regaddr);
|
||||||
|
|
||||||
|
/* Wait for the port reset to complete
|
||||||
|
*
|
||||||
|
* Paragraph 2.3.9:
|
||||||
|
*
|
||||||
|
* "Note that when software writes a zero to this bit there may be a
|
||||||
|
* delay before the bit status changes to a zero. The bit status will
|
||||||
|
* not read as a zero until after the reset has completed. If the port
|
||||||
|
* is in high-speed mode after reset is complete, the host controller
|
||||||
|
* will automatically enable this port (e.g. set the Port Enable bit
|
||||||
|
* to a one). A host controller must terminate the reset and stabilize
|
||||||
|
* the state of the port within 2 milliseconds of software transitioning
|
||||||
|
* this bit from a one to a zero ..."
|
||||||
|
*/
|
||||||
|
|
||||||
|
while ((sam_getreg(regaddr) & EHCI_PORTSC_RESET) != 0);
|
||||||
|
usleep(200*1000);
|
||||||
|
|
||||||
/* Let the common usbhost_enumerate do all of the real work. Note that the
|
/* Let the common usbhost_enumerate do all of the real work. Note that the
|
||||||
* FunctionAddress (USB address) is set to the root hub port number for now.
|
* FunctionAddress (USB address) is set to the root hub port number + 1
|
||||||
|
* for now.
|
||||||
|
*
|
||||||
|
* REVISIT: Hub support will require better device address assignment.
|
||||||
|
* See include/nuttx/usb/usbhost_devaddr.h.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uvdbg("Enumerate the device\n");
|
uvdbg("Enumerate the device\n");
|
||||||
@ -2475,19 +2521,25 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
|
|||||||
uint16_t maxpacketsize)
|
uint16_t maxpacketsize)
|
||||||
{
|
{
|
||||||
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
||||||
|
struct sam_epinfo_s *epinfo;
|
||||||
|
|
||||||
DEBUGASSERT(rhport &&
|
DEBUGASSERT(rhport &&
|
||||||
funcaddr >= 0 && funcaddr <= SAM_EHCI_NRHPORT &&
|
funcaddr >= 0 && funcaddr <= SAM_EHCI_NRHPORT &&
|
||||||
maxpacketsize < 2048);
|
maxpacketsize < 2048);
|
||||||
|
|
||||||
|
epinfo = &rhport->ep0;
|
||||||
|
|
||||||
/* We must have exclusive access to the EHCI data structures. */
|
/* We must have exclusive access to the EHCI data structures. */
|
||||||
|
|
||||||
sam_takesem(&g_ehci.exclsem);
|
sam_takesem(&g_ehci.exclsem);
|
||||||
|
|
||||||
#warning Missing logic
|
/* Remember the new device address and max packet size */
|
||||||
|
|
||||||
|
epinfo->devaddr = funcaddr;
|
||||||
|
epinfo->maxpacket = maxpacketsize;
|
||||||
|
|
||||||
sam_givesem(&g_ehci.exclsem);
|
sam_givesem(&g_ehci.exclsem);
|
||||||
return -ENOSYS;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -2515,46 +2567,48 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
|
|||||||
static int sam_epalloc(FAR struct usbhost_driver_s *drvr,
|
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_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
|
||||||
struct sam_epinfo_s *epinfo;
|
struct sam_epinfo_s *epinfo;
|
||||||
int ret = -ENOMEM;
|
|
||||||
|
|
||||||
/* Sanity check. NOTE that this method should only be called if a device is
|
/* Sanity check. NOTE that this method should only be called if a device is
|
||||||
* connected (because we need a valid low speed indication).
|
* connected (because we need a valid low speed indication).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(rhport && epdesc && ep && rhport->connected);
|
DEBUGASSERT(drvr && epdesc && ep);
|
||||||
|
uvdbg("EP%d DIR=%s FA=%08x TYPE=%d Interval=%d Max Packet Size=%d\n",
|
||||||
|
epdesc->addr, epdesc->in ? "IN" : "OUT", epdesc->funcaddr,
|
||||||
|
epdesc->xfrtype, epdesc->interval, epdesc->mxpacketsize);
|
||||||
|
|
||||||
/* Allocate a container for the endpoint data */
|
/* Allocate a endpoint information structure */
|
||||||
|
|
||||||
epinfo = (struct sam_epinfo_s *)kzalloc(sizeof(struct sam_epinfo_s));
|
epinfo = (struct sam_epinfo_s *)kzalloc(sizeof(struct sam_epinfo_s));
|
||||||
if (!epinfo)
|
if (!epinfo)
|
||||||
{
|
{
|
||||||
udbg("ERROR: Failed to allocate EP info structure\n");
|
udbg("ERROR: Failed to allocate EP info structure\n");
|
||||||
goto errout;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the endpoint container */
|
/* Initialize the endpoint container (which is really just another form of
|
||||||
|
* 'struct usbhost_epdesc_s', packed differently and with additional
|
||||||
|
* information. A cleaner design might just embed struct usbhost_epdesc_s
|
||||||
|
* inside of struct sam_epinfo_s and just memcpy here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
epinfo->epno = epdesc->addr;
|
||||||
|
epinfo->dirin = epdesc->in;
|
||||||
|
epinfo->devaddr = epdesc->funcaddr;
|
||||||
|
epinfo->xfrtype = epdesc->xfrtype;
|
||||||
|
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||||
|
epinfo->interval = epdesc->interval;
|
||||||
|
#endif
|
||||||
|
epinfo->maxpacket = epdesc->mxpacketsize;
|
||||||
sem_init(&epinfo->iocsem, 0, 0);
|
sem_init(&epinfo->iocsem, 0, 0);
|
||||||
|
|
||||||
/* We must have exclusive access to the EHCI data structures. */
|
/* Success.. return an opaque reference to the endpoint information structure
|
||||||
|
* instance
|
||||||
sam_takesem(&g_ehci.exclsem);
|
*/
|
||||||
|
|
||||||
#warning Missing logic
|
|
||||||
|
|
||||||
/* Success.. return an opaque reference to the endpoint list container */
|
|
||||||
|
|
||||||
*ep = (usbhost_ep_t)epinfo;
|
*ep = (usbhost_ep_t)epinfo;
|
||||||
sam_givesem(&g_ehci.exclsem);
|
|
||||||
return OK;
|
return OK;
|
||||||
|
|
||||||
errout_with_semaphore:
|
|
||||||
sam_givesem(&g_ehci.exclsem);
|
|
||||||
kfree(epinfo);
|
|
||||||
errout:
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -2579,28 +2633,16 @@ errout:
|
|||||||
|
|
||||||
static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
static int sam_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
||||||
{
|
{
|
||||||
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
|
||||||
struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep;
|
struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep;
|
||||||
int ret;
|
|
||||||
|
|
||||||
DEBUGASSERT(rhport && epinfo);
|
|
||||||
|
|
||||||
/* There should not be any pending, transfers */
|
/* There should not be any pending, transfers */
|
||||||
#warning Missing logic
|
|
||||||
|
|
||||||
/* We must have exclusive access to the EHCI data structures. */
|
DEBUGASSERT(drvr && epinfo && epinfo->iocwait == 0);
|
||||||
|
|
||||||
sam_takesem(&g_ehci.exclsem);
|
/* Free the container */
|
||||||
|
|
||||||
#warning Missing logic
|
|
||||||
ret = -ENOSYS;
|
|
||||||
|
|
||||||
/* And free the container */
|
|
||||||
|
|
||||||
sem_destroy(&epinfo->iocsem);
|
|
||||||
kfree(epinfo);
|
kfree(epinfo);
|
||||||
sam_givesem(&g_ehci.exclsem);
|
return OK;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -2877,7 +2919,6 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DEBUGASSERT(rhport && epinfo && buffer && buflen > 0);
|
DEBUGASSERT(rhport && epinfo && buffer && buflen > 0);
|
||||||
#warning Missing logic
|
|
||||||
|
|
||||||
/* We must have exclusive access to the EHCI hardware and data structures. */
|
/* We must have exclusive access to the EHCI hardware and data structures. */
|
||||||
|
|
||||||
@ -2891,10 +2932,16 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
|
|||||||
ret = sam_async_transfer(rhport, epinfo, NULL, buffer, buflen);
|
ret = sam_async_transfer(rhport, epinfo, NULL, buffer, buflen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
#ifndef CONFIG_USBHOST_INT_DISABLE
|
||||||
case USB_EP_ATTR_XFER_CONTROL:
|
|
||||||
case USB_EP_ATTR_XFER_ISOC:
|
|
||||||
case USB_EP_ATTR_XFER_INT:
|
case USB_EP_ATTR_XFER_INT:
|
||||||
|
# warning "Interrupt endpoint support not emplemented"
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_USBHOST_ISOC_DISABLE
|
||||||
|
case USB_EP_ATTR_XFER_ISOC:
|
||||||
|
# warning "Isochronous endpoint support not emplemented"
|
||||||
|
#endif
|
||||||
|
case USB_EP_ATTR_XFER_CONTROL:
|
||||||
|
default:
|
||||||
udbg("ERROR: Support for transfer type %d not implemented\n");
|
udbg("ERROR: Support for transfer type %d not implemented\n");
|
||||||
ret = -ENOSYS;
|
ret = -ENOSYS;
|
||||||
break;
|
break;
|
||||||
@ -2932,10 +2979,8 @@ static void sam_disconnect(FAR struct usbhost_driver_s *drvr)
|
|||||||
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr;
|
||||||
DEBUGASSERT(rhport);
|
DEBUGASSERT(rhport);
|
||||||
|
|
||||||
/* Remove the disconnected port */
|
|
||||||
#warning Missing logic
|
|
||||||
|
|
||||||
/* Unbind the class */
|
/* Unbind the class */
|
||||||
|
/* REVISIT: Is there more that needs to be done? */
|
||||||
|
|
||||||
rhport->class = NULL;
|
rhport->class = NULL;
|
||||||
}
|
}
|
||||||
@ -3397,7 +3442,8 @@ FAR struct usbhost_connection_s *sam_ehci_initialize(int controller)
|
|||||||
|
|
||||||
for (i = 0; i < SAM_EHCI_NRHPORT; i++)
|
for (i = 0; i < SAM_EHCI_NRHPORT; i++)
|
||||||
{
|
{
|
||||||
#warning Missing logic
|
g_ehci.rhport[i].connected =
|
||||||
|
((sam_getreg(&HCOR->portsc[i]) & EHCI_PORTSC_CCS) != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable interrupts at the interrupt controller */
|
/* Enable interrupts at the interrupt controller */
|
||||||
|
Loading…
Reference in New Issue
Block a user