* arch/arm/src/nrf53/nrf53_usbd.c
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/param.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/spinlock.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/usbdev_trace.h>
#include "arm_internal.h"
#include "nrf53_usbd.h"
#include "hardware/nrf53_usbd.h"
#include "hardware/nrf53_usbreg.h"
#include "hardware/nrf53_utils.h"
* Pre-processor Definitions
****************************************************************************/
#define NRF53_TRACEERR_ALLOCFAIL 0x01
#define NRF53_TRACEERR_BADEPNO 0x02
#define NRF53_TRACEERR_BINDFAILED 0x03
#define NRF53_TRACEERR_DRIVER 0x04
#define NRF53_TRACEERR_DRIVERREGISTERED 0x05
#define NRF53_TRACEERR_INVALIDPARMS 0x06
#define NRF53_TRACEERR_NOEP 0x07
#define NRF53_TRACEERR_NOTCONFIGURED 0x08
#define NRF53_TRACEERR_EPOUTQEMPTY 0x09
#define NRF53_TRACEERR_EPOUTNULLPACKET 0x0b
#define NRF53_TRACEERR_EP0NOSETUP 0x0c
#define NRF53_TRACEERR_EP0SETUPSTALLED 0x0d
#define NRF53_TRACEERR_DISPATCHSTALL 0x0e
#define NRF53_TRACEERR_BADEPGETSTATUS 0x0f
#define NRF53_TRACEERR_BADDEVGETSTATUS 0x10
#define NRF53_TRACEERR_BADCLEARFEATURE 0x11
#define NRF53_TRACEERR_BADSETFEATURE 0x12
#define NRF53_TRACEERR_INVALIDCTRLREQ 0x17
#define NRF53_TRACEERR_BADGETSTATUS 0x18
#define NRF53_TRACEERR_EPINREQEMPTY 0x19
#define NRF53_TRACEERR_DMABUSY 0x20
#define NRF53_TRACEINTID_USB 1
#define NRF53_TRACEINTID_INTPENDING 2
#define NRF53_TRACEINTID_DEVRESET (10 + 0)
#define NRF53_TRACEINTID_STARTED (10 + 1)
#define NRF53_TRACEINTID_ENDEPIN (10 + 2)
#define NRF53_TRACEINTID_ENDISOIN (10 + 4)
#define NRF53_TRACEINTID_ENDEPOUT (10 + 5)
#define NRF53_TRACEINTID_ENDISOOUT (10 + 6)
#define NRF53_TRACEINTID_SOF (10 + 7)
#define NRF53_TRACEINTID_USBEVENT (10 + 8)
#define NRF53_TRACEINTID_EP0SETUP (10 + 9)
#define NRF53_TRACEINTID_EP0DATADONE (10 + 10)
#define NRF53_TRACEINTID_EPDATA (10 + 11)
#define NRF53_TRACEINTID_ISOOUTCRC (30 + 0)
#define NRF53_TRACEINTID_SUSPEND (30 + 1)
#define NRF53_TRACEINTID_RESUME (30 + 2)
#define NRF53_TRACEINTID_USBWUALLOWED (30 + 3)
#define NRF53_TRACEINTID_READY (30 + 4)
#define NRF53_TRACEINTID_DISPATCH (50 + 0)
#define NRF53_TRACEINTID_GETSTATUS (50 + 1)
#define NRF53_TRACEINTID_DEVGETSTATUS (50 + 2)
#define NRF53_TRACEINTID_IFGETSTATUS (50 + 3)
#define NRF53_TRACEINTID_CLEARFEATURE (50 + 4)
#define NRF53_TRACEINTID_SETFEATURE (50 + 5)
#define NRF53_TRACEINTID_SETADDRESS (50 + 6)
#define NRF53_TRACEINTID_GETSETDESC (50 + 7)
#define NRF53_TRACEINTID_GETSETIFCONFIG (50 + 8)
#define NRF53_TRACEINTID_SYNCHFRAME (50 + 9)
#define NRF53_TRACEINTID_EPGETSTATUS (50 + 10)
#define NRF53_TRACEINTID_TESTMODE (50 + 11)
#define NRF53_TRACEINTID_DMATASK (70 + 0)
#define NRF53_TRACEINTID_DMAACK (70 + 1)
#define NRF53_TRACEINTID_EPINSTART (70 + 2)
#define NRF53_TRACEINTID_EPINSTOP (70 + 3)
#define NRF53_TRACEINTID_EPOUTSTART (70 + 4)
#define NRF53_TRACEINTID_EPOUTSTOP (70 + 5)
#define NRF53_TRACEINTID_EP0RCVOUT (70 + 6)
#define NRF53_TRACEINTID_EP0STATUS (70 + 7)
#define USBDEV_EP0_MAXSIZE (64)
#define USBDEV_SETUP_MAXDATASIZE (USBDEV_EP0_MAXSIZE * 4)
#ifdef CONFIG_USBDEV_ISOCHRONOUS
# error not supported yet
#endif
#ifdef CONFIG_USBDEV_LOWPOWER
# error not supported yet
#endif
#define NRF53_EPPHYIN2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_IN)
#define NRF53_EPPHYOUT2LOG(epphy) ((uint8_t)(epphy)|USB_DIR_OUT)
#define EP0 (0)
#define NRF53_EP_AVAILABLE (0x0fe)
#define NRF53_MAXPACKET_SIZE (64)
#define nrf53_rqempty(ep) ((ep)->head == NULL)
#define nrf53_rqpeek(ep) ((ep)->head)
#ifdef CONFIG_USBDEV_SOFINTERRUPT
# error TODO
#else
#define NRF53_INT_DEFAULT (USBD_INT_USBRESET | \
USBD_INT_EP0DATADONE | \
USBD_INT_USBEVENT | \
USBD_INT_EP0SETUP | \
USBD_INT_EPDATA)
#endif
* ENDEPIN0-7, ENDEPOUT0-7, ENDISOIN, ENDISOOUT
*/
#define NRF53_USBD_DMAIRQ (USBD_INT_ENDEPIN(0) | USBD_INT_ENDEPIN(1) | \
USBD_INT_ENDEPIN(2) | USBD_INT_ENDEPIN(3) | \
USBD_INT_ENDEPIN(4) | USBD_INT_ENDEPIN(5) | \
USBD_INT_ENDEPIN(6) | USBD_INT_ENDEPIN(7) | \
USBD_INT_ENDEPOUT(0) | USBD_INT_ENDEPOUT(1) | \
USBD_INT_ENDEPOUT(2) | USBD_INT_ENDEPOUT(3) | \
USBD_INT_ENDEPOUT(4) | USBD_INT_ENDEPOUT(5) | \
USBD_INT_ENDEPOUT(6) | USBD_INT_ENDEPOUT(7) | \
USBD_INT_ENDISOIN | USBD_INT_ENDISOOUT)
* Private Type Definitions
****************************************************************************/
struct nrf53_ctrlreq_s
{
uint8_t type;
uint8_t req;
uint16_t value;
uint16_t index;
uint16_t len;
};
struct nrf53_req_s
{
struct usbdev_req_s req;
struct nrf53_req_s *flink;
};
struct nrf53_ep_s
{
* structure so that it is possible to simply cast from struct usbdev_ep_s
* to struct nrf53_ep_s.
*/
struct usbdev_ep_s ep;
struct nrf53_usbdev_s *dev;
struct nrf53_req_s *head;
struct nrf53_req_s *tail;
uint8_t *rxbuff;
uint8_t epphy;
uint8_t eptype:2;
uint8_t stalled:1;
uint8_t isin:1;
};
struct nrf53_usbdev_s
{
* structure so that it is possible to simply cast from struct usbdev_s
* to structnrf53_usbdev_s.
*/
struct usbdev_s usbdev;
struct usbdevclass_driver_s *driver;
uint8_t stalled:1;
uint8_t selfpowered:1;
uint8_t addressed:1;
uint8_t wakeup:1;
uint8_t ep0indone;
uint8_t ep0outdone;
uint8_t epavail[2];
bool dmanow;
uint16_t dmaepinwait;
uint16_t dmaepoutwait;
*
* ctrl
* The 8-byte SETUP request is received on the EP0 OUT endpoint and is
* saved.
*
* ep0data
* For OUT SETUP requests, the SETUP data phase must also complete
* before the SETUP command can be processed.
*
* ep0datlen
* Length of OUT DATA received in ep0data[]
*/
struct usb_ctrlreq_s ctrlreq;
uint8_t ep0data[USBDEV_SETUP_MAXDATASIZE];
uint16_t ep0datlen;
uint16_t ep0reqlen;
struct nrf53_ep_s epin[NRF53_NENDPOINTS];
struct nrf53_ep_s epout[NRF53_NENDPOINTS];
};
* Private Function Prototypes
****************************************************************************/
#define nrf53_getreg(addr) getreg32(addr)
#define nrf53_putreg(val,addr) putreg32(val,addr)
static void nrf53_startdma_task(struct nrf53_usbdev_s *priv, uint32_t addr);
static void nrf53_startdma_ack(struct nrf53_usbdev_s *priv);
static void nrf53_epout_start(struct nrf53_usbdev_s *priv, int epno);
static void nrf53_epout_stop(struct nrf53_usbdev_s *priv, int epno);
static void nrf53_epin_start(struct nrf53_usbdev_s *priv, int epno);
static void nrf53_epin_stop(struct nrf53_usbdev_s *priv, int epno);
static void nrf53_ep0rcvout_start(struct nrf53_usbdev_s *priv);
static void nrf53_ep0status_start(struct nrf53_usbdev_s *priv);
static struct nrf53_req_s *nrf53_req_remfirst(struct nrf53_ep_s *privep);
static bool nrf53_req_addlast(struct nrf53_ep_s *privep,
struct nrf53_req_s *req);
static void nrf53_ep0out_stdrequest(struct nrf53_usbdev_s *priv,
struct nrf53_ctrlreq_s *ctrlreq);
static void nrf53_ep0setup(struct nrf53_usbdev_s *priv);
static void nrf53_epin_transfer(struct nrf53_ep_s *privep, uint8_t *buf,
int nbytes);
static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
struct nrf53_ep_s *privep);
static void nrf53_epout_allow(struct nrf53_ep_s *privep);
static void nrf53_epout_transfer(struct nrf53_ep_s *privep);
static void nrf53_epout_complete(struct nrf53_ep_s *privep);
static void nrf53_ep0out_receive(struct nrf53_usbdev_s *priv);
static void nrf53_epout_receive(struct nrf53_ep_s *privep);
static void nrf53_epout_handle(struct nrf53_usbdev_s *priv,
struct nrf53_ep_s *privep);
static void nrf53_req_complete(struct nrf53_ep_s *privep, int16_t result);
static void nrf53_req_cancel(struct nrf53_ep_s *privep, int16_t status);
static int nrf53_req_dispatch(struct nrf53_usbdev_s *priv,
const struct usb_ctrlreq_s *ctrl);
static struct nrf53_ep_s *
nrf53_ep_findbyaddr(struct nrf53_usbdev_s *priv, uint16_t eplog);
static void nrf53_usbreset(struct nrf53_usbdev_s *priv);
static void nrf53_resumeinterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_suspendinterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_eventinterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_ep0setupinterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv);
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv,
uint32_t irqnow);
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv,
uint32_t irqnow);
static int nrf53_usbinterrupt(int irq, void *context, void *arg);
static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
uint16_t maxpacket);
static int nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
uint16_t maxpacket);
static int nrf53_ep_configure(struct usbdev_ep_s *ep,
const struct usb_epdesc_s *desc, bool last);
static void nrf53_ep0_configure(struct nrf53_usbdev_s *priv);
static void nrf53_epout_disable(struct nrf53_ep_s *privep);
static void nrf53_epin_disable(struct nrf53_ep_s *privep);
static int nrf53_ep_disable(struct usbdev_ep_s *ep);
static struct usbdev_req_s *nrf53_ep_allocreq(struct usbdev_ep_s *ep);
static void nrf53_ep_freereq(struct usbdev_ep_s *ep, struct usbdev_req_s *);
#ifdef CONFIG_USBDEV_DMA
static void *nrf53_ep_allocbuffer(struct usbdev_ep_s *ep, unsigned bytes);
static void nrf53_ep_freebuffer(struct usbdev_ep_s *ep, void *buf);
#endif
static int nrf53_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req);
static int nrf53_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req);
static int nrf53_ep_setstall(struct nrf53_ep_s *privep);
static int nrf53_ep_clrstall(struct nrf53_ep_s *privep);
static int nrf53_ep_stall(struct usbdev_ep_s *ep, bool resume);
static void nrf53_ep0_stall(struct nrf53_usbdev_s *priv);
static struct usbdev_ep_s *
nrf53_ep_alloc(struct usbdev_s *dev, uint8_t epno, bool in, uint8_t eptype);
static void nrf53_ep_free(struct usbdev_s *dev, struct usbdev_ep_s *ep);
static int nrf53_getframe(struct usbdev_s *dev);
static int nrf53_wakeup(struct usbdev_s *dev);
static int nrf53_selfpowered(struct usbdev_s *dev, bool selfpowered);
static int nrf53_pullup(struct usbdev_s *dev, bool enable);
static void nrf53_setaddress(struct nrf53_usbdev_s *priv, uint16_t address);
static void nrf53_swinitialize(struct nrf53_usbdev_s *priv);
static void nrf53_hwinitialize(struct nrf53_usbdev_s *priv);
* Private Data
****************************************************************************/
static struct nrf53_usbdev_s g_usbdev;
static const struct usbdev_epops_s g_epops =
{
.configure = nrf53_ep_configure,
.disable = nrf53_ep_disable,
.allocreq = nrf53_ep_allocreq,
.freereq = nrf53_ep_freereq,
#ifdef CONFIG_USBDEV_DMA
.allocbuffer = nrf53_ep_allocbuffer,
.freebuffer = nrf53_ep_freebuffer,
#endif
.submit = nrf53_ep_submit,
.cancel = nrf53_ep_cancel,
.stall = nrf53_ep_stall,
};
static const struct usbdev_ops_s g_devops =
{
.allocep = nrf53_ep_alloc,
.freeep = nrf53_ep_free,
.getframe = nrf53_getframe,
.wakeup = nrf53_wakeup,
.selfpowered = nrf53_selfpowered,
.pullup = nrf53_pullup,
};
* Public Data
****************************************************************************/
#ifdef CONFIG_USBDEV_TRACE_STRINGS
const struct trace_msg_t g_usb_trace_strings_deverror[] =
{
TRACE_STR(NRF53_TRACEERR_ALLOCFAIL),
TRACE_STR(NRF53_TRACEERR_BADEPNO),
TRACE_STR(NRF53_TRACEERR_BINDFAILED),
TRACE_STR(NRF53_TRACEERR_DRIVER),
TRACE_STR(NRF53_TRACEERR_DRIVERREGISTERED),
TRACE_STR(NRF53_TRACEERR_INVALIDPARMS),
TRACE_STR(NRF53_TRACEERR_NOEP),
TRACE_STR(NRF53_TRACEERR_NOTCONFIGURED),
TRACE_STR(NRF53_TRACEERR_EPOUTQEMPTY),
TRACE_STR(NRF53_TRACEERR_EPOUTNULLPACKET),
TRACE_STR(NRF53_TRACEERR_EP0NOSETUP),
TRACE_STR(NRF53_TRACEERR_EP0SETUPSTALLED),
TRACE_STR(NRF53_TRACEERR_DISPATCHSTALL),
TRACE_STR(NRF53_TRACEERR_BADEPGETSTATUS),
TRACE_STR(NRF53_TRACEERR_BADEPGETSTATUS),
TRACE_STR(NRF53_TRACEERR_BADDEVGETSTATUS),
TRACE_STR(NRF53_TRACEERR_BADCLEARFEATURE),
TRACE_STR(NRF53_TRACEERR_BADSETFEATURE),
TRACE_STR(NRF53_TRACEERR_INVALIDCTRLREQ),
TRACE_STR(NRF53_TRACEERR_BADGETSTATUS),
TRACE_STR(NRF53_TRACEERR_EPINREQEMPTY),
TRACE_STR_END
};
#endif
#ifdef CONFIG_USBDEV_TRACE_STRINGS
const struct trace_msg_t g_usb_trace_strings_intdecode[] =
{
TRACE_STR(NRF53_TRACEINTID_USB),
TRACE_STR(NRF53_TRACEINTID_INTPENDING),
TRACE_STR(NRF53_TRACEINTID_DEVRESET),
TRACE_STR(NRF53_TRACEINTID_STARTED),
TRACE_STR(NRF53_TRACEINTID_ENDEPIN),
TRACE_STR(NRF53_TRACEINTID_ENDISOIN),
TRACE_STR(NRF53_TRACEINTID_ENDEPOUT),
TRACE_STR(NRF53_TRACEINTID_ENDISOOUT),
TRACE_STR(NRF53_TRACEINTID_SOF),
TRACE_STR(NRF53_TRACEINTID_USBEVENT),
TRACE_STR(NRF53_TRACEINTID_EP0SETUP),
TRACE_STR(NRF53_TRACEINTID_EP0DATADONE),
TRACE_STR(NRF53_TRACEINTID_EPDATA),
TRACE_STR(NRF53_TRACEINTID_ISOOUTCRC),
TRACE_STR(NRF53_TRACEINTID_SUSPEND),
TRACE_STR(NRF53_TRACEINTID_RESUME),
TRACE_STR(NRF53_TRACEINTID_USBWUALLOWED),
TRACE_STR(NRF53_TRACEINTID_READY),
TRACE_STR(NRF53_TRACEINTID_DISPATCH),
TRACE_STR(NRF53_TRACEINTID_GETSTATUS),
TRACE_STR(NRF53_TRACEINTID_DEVGETSTATUS),
TRACE_STR(NRF53_TRACEINTID_IFGETSTATUS),
TRACE_STR(NRF53_TRACEINTID_CLEARFEATURE),
TRACE_STR(NRF53_TRACEINTID_SETFEATURE),
TRACE_STR(NRF53_TRACEINTID_SETADDRESS),
TRACE_STR(NRF53_TRACEINTID_GETSETDESC),
TRACE_STR(NRF53_TRACEINTID_GETSETIFCONFIG),
TRACE_STR(NRF53_TRACEINTID_SYNCHFRAME),
TRACE_STR(NRF53_TRACEINTID_EPGETSTATUS),
TRACE_STR(NRF53_TRACEINTID_TESTMODE),
TRACE_STR(NRF53_TRACEINTID_DMATASK),
TRACE_STR(NRF53_TRACEINTID_DMAACK),
TRACE_STR(NRF53_TRACEINTID_EPINSTART),
TRACE_STR(NRF53_TRACEINTID_EPINSTOP),
TRACE_STR(NRF53_TRACEINTID_EPOUTSTART),
TRACE_STR(NRF53_TRACEINTID_EPOUTSTOP),
TRACE_STR(NRF53_TRACEINTID_EP0RCVOUT),
TRACE_STR(NRF53_TRACEINTID_EP0STATUS),
TRACE_STR_END
};
#endif
* Private Functions
****************************************************************************/
* Name: nrf53_startdma_task and nrf53_startdma_ack
*
* Description:
* Errata [199] USBD: USBD cannot receive tasks during DMA
*
****************************************************************************/
static void nrf53_startdma_task(struct nrf53_usbdev_s *priv, uint32_t addr)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMATASK), addr);
nrf53_putreg(1, addr);
priv->dmanow = true;
}
static void nrf53_startdma_ack(struct nrf53_usbdev_s *priv)
{
if (priv->dmanow == true)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DMAACK), 0);
priv->dmanow = false;
}
}
* Name: nrf53_xxx_start and nrf53_xxx_stop
*
* Description:
* Start or stop tasks
*
****************************************************************************/
static void nrf53_epout_start(struct nrf53_usbdev_s *priv, int epno)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPOUTSTART), epno);
nrf53_startdma_task(priv, NRF53_USBD_TASKS_STARTEPOUT(epno));
}
static void nrf53_epout_stop(struct nrf53_usbdev_s *priv, int epno)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPOUTSTOP), epno);
nrf53_putreg(0, NRF53_USBD_TASKS_STARTEPOUT(epno));
}
static void nrf53_epin_start(struct nrf53_usbdev_s *priv, int epno)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPINSTART), epno);
nrf53_startdma_task(priv, NRF53_USBD_TASKS_STARTEPIN(epno));
}
static void nrf53_epin_stop(struct nrf53_usbdev_s *priv, int epno)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPINSTOP), epno);
nrf53_putreg(0, NRF53_USBD_TASKS_STARTEPIN(epno));
}
static void nrf53_ep0rcvout_start(struct nrf53_usbdev_s *priv)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0RCVOUT), 0);
nrf53_putreg(1, NRF53_USBD_TASKS_EP0RCVOUT);
}
static void nrf53_ep0status_start(struct nrf53_usbdev_s *priv)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0STATUS), 0);
nrf53_putreg(1, NRF53_USBD_TASKS_EP0STATUS);
}
* Name: nrf53_req_remfirst
*
* Description:
* Remove a request from the head of an endpoint request queue
*
****************************************************************************/
static struct nrf53_req_s *nrf53_req_remfirst(struct nrf53_ep_s *privep)
{
struct nrf53_req_s *ret = privep->head;
if (ret)
{
privep->head = ret->flink;
if (!privep->head)
{
privep->tail = NULL;
}
ret->flink = NULL;
}
return ret;
}
* Name: nrf53_req_addlast
*
* Description:
* Add a request to the end of an endpoint request queue
*
****************************************************************************/
static bool nrf53_req_addlast(struct nrf53_ep_s *privep,
struct nrf53_req_s *req)
{
bool is_empty = !privep->head;
req->flink = NULL;
if (is_empty)
{
privep->head = req;
privep->tail = req;
}
else
{
privep->tail->flink = req;
privep->tail = req;
}
return is_empty;
}
* Name: nrf53_ep0out_stdrequest
*
* Description:
* Handle a stanard request on EP0. Pick off the things of interest to the
* USB device controller driver; pass what is left to the class driver.
*
****************************************************************************/
static void
nrf53_ep0out_stdrequest(struct nrf53_usbdev_s *priv,
struct nrf53_ctrlreq_s *ctrlreq)
{
struct nrf53_ep_s *privep = NULL;
uint8_t recipient = 0;
switch (ctrlreq->req)
{
case USB_REQ_GETSTATUS:
{
* value: 0
* index: zero interface endpoint
* len: 2; data = status
*/
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_GETSTATUS), 0);
if (!priv->addressed || ctrlreq->len != 2 ||
USB_REQ_ISOUT(ctrlreq->type) || ctrlreq->value != 0)
{
priv->stalled = true;
}
else
{
switch (ctrlreq->type & USB_REQ_RECIPIENT_MASK)
{
case USB_REQ_RECIPIENT_ENDPOINT:
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPGETSTATUS), 0);
privep = nrf53_ep_findbyaddr(priv, ctrlreq->index);
if (!privep)
{
usbtrace(
TRACE_DEVERROR(NRF53_TRACEERR_BADEPGETSTATUS), 0);
priv->stalled = true;
}
break;
}
case USB_REQ_RECIPIENT_DEVICE:
case USB_REQ_RECIPIENT_INTERFACE:
{
if (ctrlreq->index == 0)
{
usbtrace(TRACE_INTDECODE(
NRF53_TRACEINTID_DEVGETSTATUS), 0);
}
else
{
usbtrace(TRACE_DEVERROR(
NRF53_TRACEERR_BADDEVGETSTATUS), 0);
priv->stalled = true;
}
break;
}
default:
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADGETSTATUS), 0);
priv->stalled = true;
break;
}
}
}
break;
}
case USB_REQ_CLEARFEATURE:
{
* value: feature selector
* index: zero interface endpoint;
* len: zero, data = none
*/
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_CLEARFEATURE), 0);
if (priv->addressed != 0 && ctrlreq->len == 0)
{
recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
(privep = nrf53_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
{
nrf53_ep_clrstall(privep);
}
else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
{
priv->wakeup = false;
}
else
{
nrf53_req_dispatch(priv, &priv->ctrlreq);
}
}
else
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADCLEARFEATURE), 0);
priv->stalled = true;
}
break;
}
case USB_REQ_SETFEATURE:
{
* value: feature selector
* index: zero interface endpoint;
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SETFEATURE), 0);
if (priv->addressed != 0 && ctrlreq->len == 0)
{
recipient = ctrlreq->type & USB_REQ_RECIPIENT_MASK;
if (recipient == USB_REQ_RECIPIENT_ENDPOINT &&
ctrlreq->value == USB_FEATURE_ENDPOINTHALT &&
(privep = nrf53_ep_findbyaddr(priv, ctrlreq->index)) != NULL)
{
nrf53_ep_setstall(privep);
}
else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
ctrlreq->value == USB_FEATURE_REMOTEWAKEUP)
{
priv->wakeup = true;
}
else if (recipient == USB_REQ_RECIPIENT_DEVICE &&
ctrlreq->value == USB_FEATURE_TESTMODE &&
((ctrlreq->index & 0xff) == 0))
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_TESTMODE), 0);
}
else
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADSETFEATURE), 0);
priv->stalled = true;
}
}
else
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADSETFEATURE), 0);
priv->stalled = true;
}
break;
}
case USB_REQ_SETADDRESS:
{
* value: device address
* index: 0
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SETADDRESS),
ctrlreq->value);
nrf53_setaddress(priv, (uint16_t)priv->ctrlreq.value[0]);
* transfer by itself.
*
* REVISTI: Documentation states that we shall not handle this
* command in the software at all, but if we don't
* send EP0STATUS response then enumeration fails.
*/
break;
}
case USB_REQ_GETDESCRIPTOR:
* value: descriptor type and index
* index: 0 or language ID;
* len: descriptor len; data = descriptor
*/
case USB_REQ_SETDESCRIPTOR:
* value: descriptor type and index
* index: 0 or language ID;
* len: descriptor len; data = descriptor
*/
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_GETSETDESC),
priv->ctrlreq.req);
nrf53_req_dispatch(priv, &priv->ctrlreq);
break;
}
case USB_REQ_GETCONFIGURATION:
* value: 0;
* index: 0;
* len: 1; data = configuration value
*/
case USB_REQ_SETCONFIGURATION:
* value: configuration value
* index: 0;
* len: 0; data = none
*/
case USB_REQ_GETINTERFACE:
* value: 0
* index: interface;
* len: 1; data = alt interface
*/
case USB_REQ_SETINTERFACE:
* value: alternate setting
* index: interface;
* len: 0; data = none
*/
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_GETSETIFCONFIG),
priv->ctrlreq.req);
nrf53_req_dispatch(priv, &priv->ctrlreq);
break;
}
case USB_REQ_SYNCHFRAME:
* value: 0
* index: endpoint;
* len: 2; data = frame number
*/
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SYNCHFRAME), 0);
break;
}
default:
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDCTRLREQ), 0);
priv->stalled = true;
}
break;
}
}
* Name: nrf53_ep0setup
*
* Description:
* USB Ctrl EP Setup Event
*
****************************************************************************/
static void nrf53_ep0setup(struct nrf53_usbdev_s *priv)
{
struct nrf53_ctrlreq_s ctrlreq;
nrf53_req_cancel(&priv->epout[EP0], -EPROTO);
nrf53_req_cancel(&priv->epin[EP0], -EPROTO);
priv->epout[EP0].stalled = false;
priv->epin[EP0].stalled = false;
priv->stalled = false;
ctrlreq.type = priv->ctrlreq.type;
ctrlreq.req = priv->ctrlreq.req;
ctrlreq.value = GETUINT16(priv->ctrlreq.value);
ctrlreq.index = GETUINT16(priv->ctrlreq.index);
ctrlreq.len = GETUINT16(priv->ctrlreq.len);
uinfo("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
ctrlreq.type, ctrlreq.req, ctrlreq.value,
ctrlreq.index, ctrlreq.len);
if ((ctrlreq.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
{
nrf53_req_dispatch(priv, &priv->ctrlreq);
}
else
{
nrf53_ep0out_stdrequest(priv, &ctrlreq);
}
if (priv->stalled)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EP0SETUPSTALLED), 0);
nrf53_ep0_stall(priv);
}
}
* Name: nrf53_epin_transfer
*
* Description:
* Start the Tx data transfer
*
****************************************************************************/
static void nrf53_epin_transfer(struct nrf53_ep_s *privep, uint8_t *buf,
int nbytes)
{
struct nrf53_usbdev_s *priv = NULL;
DEBUGASSERT(privep && privep->dev);
priv = (struct nrf53_usbdev_s *)privep->dev;
DEBUGASSERT(privep->eptype != USB_EP_ATTR_XFER_ISOC);
DEBUGASSERT(nbytes <= 64);
if (buf)
{
DEBUGASSERT(nrf53_easydma_valid((uint32_t)buf));
}
nrf53_putreg((uint32_t)buf, NRF53_USBD_EPIN_PTR(privep->epphy));
nrf53_putreg(nbytes, NRF53_USBD_EPIN_MAXCNT(privep->epphy));
nrf53_epin_start(priv, privep->epphy);
* EasyDMA transfer. Otherwise USBD is not stable.
*/
while (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPIN(privep->epphy)) == 0 &&
nrf53_getreg(NRF53_USBD_EVENTS_USBRESET) == 0);
}
* Name: nrf53_epout_allow
*
* Description:
* Allow OUT trafic on this endpoint
*
****************************************************************************/
static void nrf53_epout_allow(struct nrf53_ep_s *privep)
{
nrf53_putreg(0, NRF53_USBD_SIZE_EPOUT(privep->epphy));
}
* Name: nrf53_epout_transfer
*
* Description:
* Start the Rx data transfer
*
****************************************************************************/
static void nrf53_epout_transfer(struct nrf53_ep_s *privep)
{
struct nrf53_usbdev_s *priv = NULL;
int nbytes = 0;
DEBUGASSERT(privep && privep->dev);
priv = (struct nrf53_usbdev_s *)privep->dev;
if (privep->epphy == 0)
{
nbytes = USBDEV_EP0_MAXSIZE;
}
else
{
* endpoint
*/
nbytes = nrf53_getreg(NRF53_USBD_SIZE_EPOUT(privep->epphy));
}
DEBUGASSERT(nrf53_easydma_valid((uint32_t)privep->rxbuff));
nrf53_putreg((uint32_t)privep->rxbuff,
NRF53_USBD_EPOUT_PTR(privep->epphy));
nrf53_putreg(nbytes, NRF53_USBD_EPOUT_MAXCNT(privep->epphy));
nrf53_epout_start(priv, privep->epphy);
* EasyDMA transfer. Otherwise USBD is not stable.
*/
while (nrf53_getreg(NRF53_USBD_EVENTS_ENDEPOUT(privep->epphy)) == 0 &&
nrf53_getreg(NRF53_USBD_EVENTS_USBRESET) == 0);
}
* Name: nrf53_epin_request
*
* Description:
* Begin or continue write request processing.
*
****************************************************************************/
static void nrf53_epin_request(struct nrf53_usbdev_s *priv,
struct nrf53_ep_s *privep)
{
struct nrf53_req_s *privreq = NULL;
uint8_t *buf = NULL;
int bytesleft = 0;
int nbytes = 0;
if (priv->dmanow == true)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DMABUSY), privep->epphy);
priv->dmaepinwait |= (1 << privep->epphy);
return;
}
privreq = nrf53_rqpeek(privep);
if (!privreq)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPINREQEMPTY), privep->epphy);
return;
}
uinfo("EP%" PRId8 " req=%p: len=%" PRId16 " xfrd=%" PRId16 "\n",
privep->epphy, privreq, privreq->req.len, privreq->req.xfrd);
* complete event before we add the next packet.
*/
if (privreq->req.xfrd < privreq->req.len)
{
bytesleft = privreq->req.len - privreq->req.xfrd;
nbytes = bytesleft;
if (nbytes > 0)
{
* the request.
*/
if (nbytes >= privep->ep.maxpacket)
{
nbytes = privep->ep.maxpacket;
}
}
buf = privreq->req.buf + privreq->req.xfrd;
nrf53_epin_transfer(privep, buf, nbytes);
privreq->req.xfrd += nbytes;
}
else if (privreq->req.len == 0)
{
nrf53_epin_transfer(privep, NULL, 0);
nrf53_startdma_ack(priv);
}
if (privreq->req.xfrd >= privreq->req.len)
{
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
* yet completed).
*/
nrf53_req_complete(privep, OK);
if (privep->epphy == EP0)
{
priv->ep0indone = true;
}
}
}
* Name: nrf53_epout_complete
*
* Description:
* This function is called when an OUT transfer complete interrupt is
* received. It completes the read request at the head of the endpoint's
* request queue.
*
****************************************************************************/
static void nrf53_epout_complete(struct nrf53_ep_s *privep)
{
struct nrf53_req_s *privreq = NULL;
DEBUGASSERT(privep);
* head of the endpoint request queue.
*/
privreq = nrf53_rqpeek(privep);
DEBUGASSERT(privreq);
if (!privreq)
{
* should not happen.
*/
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
privep->epphy);
return;
}
uinfo("EP%d: len=%zu xfrd=%zu\n", privep->epphy, privreq->req.len,
privreq->req.xfrd);
* state IDLE.
*/
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
nrf53_req_complete(privep, OK);
}
* Name: nrf53_ep0out_receive
*
* Description:
* This function will simply copy the incoming data into pending request's
* data buffer.
*
****************************************************************************/
static void nrf53_ep0out_receive(struct nrf53_usbdev_s *priv)
{
struct nrf53_ep_s *privep = &priv->epout[EP0];
uint16_t bcnt = 0;
bcnt = nrf53_getreg(NRF53_USBD_EPOUT_AMOUNT(0));
uinfo("EP0: bcnt=%d\n", bcnt);
usbtrace(TRACE_READ(EP0), bcnt);
DEBUGASSERT(priv->ep0datlen + bcnt <= USBDEV_SETUP_MAXDATASIZE);
memcpy(priv->ep0data + priv->ep0datlen, privep->rxbuff, bcnt);
priv->ep0datlen += bcnt;
if (priv->ep0datlen >= priv->ep0reqlen)
{
nrf53_ep0setup(priv);
priv->ep0datlen = 0;
priv->ep0outdone = true;
}
else
{
priv->ep0outdone = false;
}
}
* Name: nrf53_epout_receive
*
* Description:
* This function will simply copy the incoming data into pending request's
* data buffer.
*
****************************************************************************/
static void nrf53_epout_receive(struct nrf53_ep_s *privep)
{
struct nrf53_req_s *privreq = NULL;
uint8_t *dest = NULL;
int buflen = 0;
int readlen = 0;
int bcnt = 0;
bcnt = nrf53_getreg(NRF53_USBD_EPOUT_AMOUNT(privep->epphy));
* queue.
*/
privreq = nrf53_rqpeek(privep);
if (!privreq)
{
* NAKing is working as expected.
*/
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
privep->epphy);
return;
}
uinfo("EP%d: len=%zu xfrd=%zu\n", privep->epphy,
privreq->req.len, privreq->req.xfrd);
usbtrace(TRACE_READ(privep->epphy), bcnt);
buflen = privreq->req.len - privreq->req.xfrd;
DEBUGASSERT(buflen > 0 && buflen >= bcnt);
readlen = MIN(buflen, bcnt);
dest = privreq->req.buf + privreq->req.xfrd;
memcpy(dest, privep->rxbuff, readlen);
privreq->req.xfrd += readlen;
if (privreq->req.xfrd >= privreq->req.len ||
readlen < privep->ep.maxpacket)
{
nrf53_epout_complete(privep);
}
}
* Name: nrf53_epout_handle
*
* Description:
*
****************************************************************************/
static void nrf53_epout_handle(struct nrf53_usbdev_s *priv,
struct nrf53_ep_s *privep)
{
struct nrf53_req_s *privreq = NULL;
DEBUGASSERT(privep->epphy != EP0);
if (priv->dmanow == true)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DMABUSY), privep->epphy);
priv->dmaepoutwait |= (1 << privep->epphy);
return;
}
* The loop is only need to look at the request queue again is an
* invalid read request is encountered.
*/
for (; ; )
{
* request queue
*/
privreq = nrf53_rqpeek(privep);
if (!privreq)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTQEMPTY),
privep->epphy);
return;
}
uinfo("EP%d: len=%d\n", privep->epphy, privreq->req.len);
* should not happen).
*/
if (privreq->req.len <= 0)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_EPOUTNULLPACKET), 0);
nrf53_req_complete(privep, OK);
}
* break out of the loop
*/
else
{
break;
}
}
nrf53_epout_transfer(privep);
}
* Name: nrf53_req_complete
*
* Description:
* Handle termination of the request at the head of the endpoint request
* queue.
*
****************************************************************************/
static void nrf53_req_complete(struct nrf53_ep_s *privep, int16_t result)
{
struct nrf53_req_s *privreq = NULL;
bool stalled = false;
privreq = nrf53_req_remfirst(privep);
DEBUGASSERT(privreq != NULL);
* in the callback.
*/
stalled = privep->stalled;
if (privep->epphy == EP0)
{
privep->stalled = privep->dev->stalled;
}
privreq->req.result = result;
privreq->req.callback(&privep->ep, &privreq->req);
privep->stalled = stalled;
}
* Name: nrf53_req_cancel
*
* Description:
* Cancel all pending requests for an endpoint
*
****************************************************************************/
static void nrf53_req_cancel(struct nrf53_ep_s *privep, int16_t status)
{
while (!nrf53_rqempty(privep))
{
usbtrace(TRACE_COMPLETE(privep->epphy),
(nrf53_rqpeek(privep))->req.xfrd);
nrf53_req_complete(privep, status);
}
}
* Name: nrf53_req_dispatch
*
* Description:
* Provide unhandled setup actions to the class driver. This is logically
* part of the USB interrupt handler.
*
****************************************************************************/
static int nrf53_req_dispatch(struct nrf53_usbdev_s *priv,
const struct usb_ctrlreq_s *ctrl)
{
int ret = -EIO;
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DISPATCH), 0);
if (priv->driver)
{
ret = CLASS_SETUP(priv->driver, &priv->usbdev, ctrl,
priv->ep0data, priv->ep0datlen);
}
if (ret < 0)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DISPATCHSTALL), 0);
priv->stalled = true;
}
return ret;
}
* Name: nrf53_ep_findbyaddr
*
* Description:
* Find the physical endpoint structure corresponding to a logic endpoint
* address
*
****************************************************************************/
static struct nrf53_ep_s *nrf53_ep_findbyaddr(struct nrf53_usbdev_s *priv,
uint16_t eplog)
{
struct nrf53_ep_s *privep = NULL;
uint8_t epphy = USB_EPNO(eplog);
if (epphy >= NRF53_NENDPOINTS)
{
return NULL;
}
if (USB_ISEPIN(eplog))
{
privep = &priv->epin[epphy];
}
else
{
privep = &priv->epout[epphy];
}
DEBUGASSERT(privep->epphy == epphy);
return privep;
}
* Name: nrf53_usbreset
*
* Description:
* Reset Usb engine
*
****************************************************************************/
static void nrf53_usbreset(struct nrf53_usbdev_s *priv)
{
struct nrf53_ep_s *privep = NULL;
uint32_t regval = 0;
int i = 0;
uinfo("nrf53_usbreset\n");
* driver should then accept any new configurations.
*/
if (priv->driver)
{
CLASS_DISCONNECT(priv->driver, &priv->usbdev);
}
priv->epavail[0] = NRF53_EP_AVAILABLE;
priv->epavail[1] = NRF53_EP_AVAILABLE;
for (i = 0; i < NRF53_NENDPOINTS ; i++)
{
privep = &priv->epin[i];
nrf53_req_cancel(privep, -ESHUTDOWN);
privep->stalled = false;
nrf53_epin_stop(priv, i);
privep = &priv->epout[i];
nrf53_req_cancel(privep, -ESHUTDOWN);
privep->stalled = false;
nrf53_epout_stop(priv, i);
}
regval = NRF53_INT_DEFAULT;
nrf53_putreg(regval, NRF53_USBD_INTEN);
nrf53_setaddress(priv, 0);
priv->usbdev.speed = USB_SPEED_FULL;
nrf53_ep0_configure(priv);
}
* Name: nrf53_resumeinterrupt
*
* Description:
* Resume/remote wakeup detected interrupt
*
****************************************************************************/
static void nrf53_resumeinterrupt(struct nrf53_usbdev_s *priv)
{
#ifdef CONFIG_USBDEV_LOWPOWER
nrf53_putreg(0, NRF53_USBD_LOWPOWER);
#endif
nrf53_usbsuspend((struct usbdev_s *)priv, true);
if (priv->driver)
{
CLASS_RESUME(priv->driver, &priv->usbdev);
}
}
* Name: nrf53_suspendinterrupt
*
* Description:
* USB suspend interrupt
*
****************************************************************************/
static void nrf53_suspendinterrupt(struct nrf53_usbdev_s *priv)
{
if (priv->driver)
{
CLASS_SUSPEND(priv->driver, &priv->usbdev);
}
#ifdef CONFIG_USBDEV_LOWPOWER
nrf53_putreg(1, NRF53_USBD_LOWPOWER);
#endif
* state
*/
nrf53_usbsuspend((struct usbdev_s *)priv, false);
}
* Name: nrf53_eventinterrupt
*
* Description:
* Handle EVENT events
*
****************************************************************************/
static void nrf53_eventinterrupt(struct nrf53_usbdev_s *priv)
{
uint32_t regval = 0;
uint32_t clr = 0;
regval = nrf53_getreg(NRF53_USBD_EVENTCAUSE);
if (regval & USBD_EVENTCAUSE_ISOOUTCRC)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ISOOUTCRC), 0);
clr |= USBD_EVENTCAUSE_ISOOUTCRC;
}
if (regval & USBD_EVENTCAUSE_SUSPEND)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SUSPEND), 0);
nrf53_suspendinterrupt(priv);
clr |= USBD_EVENTCAUSE_SUSPEND;
}
if (regval & USBD_EVENTCAUSE_RESUME)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_RESUME), 0);
nrf53_resumeinterrupt(priv);
clr |= USBD_EVENTCAUSE_RESUME;
}
if (regval & USBD_EVENTCAUSE_USBWUALLOWED)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_USBWUALLOWED), 0);
clr |= USBD_EVENTCAUSE_USBWUALLOWED;
}
if (regval & USBD_EVENTCAUSE_READY)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_READY), 0);
clr |= USBD_EVENTCAUSE_READY;
}
nrf53_putreg(clr, NRF53_USBD_EVENTCAUSE);
}
* Name: nrf53_ep0setupinterrupt
*
* Description:
* Handle EP0SETUP event
*
****************************************************************************/
static void nrf53_ep0setupinterrupt(struct nrf53_usbdev_s *priv)
{
priv->ctrlreq.type = nrf53_getreg(NRF53_USBD_BMREQUESTTYPE);
priv->ctrlreq.req = nrf53_getreg(NRF53_USBD_BREQUEST);
priv->ctrlreq.value[0] = nrf53_getreg(NRF53_USBD_WVALUEL);
priv->ctrlreq.value[1] = nrf53_getreg(NRF53_USBD_WVALUEH);
priv->ctrlreq.index[0] = nrf53_getreg(NRF53_USBD_WINDEXL);
priv->ctrlreq.index[1] = nrf53_getreg(NRF53_USBD_WINDEXH);
priv->ctrlreq.len[0] = nrf53_getreg(NRF53_USBD_WLENGTHL);
priv->ctrlreq.len[1] = nrf53_getreg(NRF53_USBD_WLENGTHH);
priv->ep0reqlen = GETUINT16(priv->ctrlreq.len);
if (USB_REQ_ISOUT(priv->ctrlreq.type))
{
priv->ep0datlen = 0;
if (priv->ep0reqlen == 0)
{
nrf53_ep0setup(priv);
}
else
{
nrf53_ep0rcvout_start(priv);
}
}
else
{
nrf53_ep0setup(priv);
}
if (priv->ep0reqlen == 0)
{
nrf53_ep0status_start(priv);
}
}
* Name: nrf53_ep0datainterrupt
*
* Description:
* Handle EP0DATADONE event
*
****************************************************************************/
static void nrf53_ep0datainterrupt(struct nrf53_usbdev_s *priv)
{
struct nrf53_ep_s *privep = NULL;
if (USB_REQ_ISOUT(priv->ctrlreq.type))
{
privep = &priv->epout[EP0];
nrf53_epout_transfer(privep);
}
else
{
if (priv->ep0indone)
{
nrf53_ep0status_start(priv);
priv->ep0indone = false;
}
else
{
privep = &priv->epin[EP0];
nrf53_epin_request(priv, privep);
}
}
}
* Name: nrf53_epdatainterrupt
*
* Description:
* Handle EPDATA event
*
****************************************************************************/
static void nrf53_epdatainterrupt(struct nrf53_usbdev_s *priv)
{
struct nrf53_ep_s *privep = NULL;
uint32_t datastatus = 0;
int epno = 0;
datastatus = nrf53_getreg(NRF53_USBD_EPDATASTATUS);
nrf53_putreg(datastatus, NRF53_USBD_EPDATASTATUS);
for (epno = 1; epno < NRF53_NENDPOINTS; epno += 1)
{
if (datastatus & USBD_EPDATASTATUS_EPIN(epno))
{
privep = &priv->epin[epno];
nrf53_epin_request(priv, privep);
}
if (datastatus & USBD_EPDATASTATUS_EPOUT(epno))
{
privep = &priv->epout[epno];
nrf53_epout_handle(priv, privep);
}
}
}
* Name: nrf53_endepininterrupt
*
* Description:
* Handle ENDEPIN events
*
****************************************************************************/
static void nrf53_endepininterrupt(struct nrf53_usbdev_s *priv,
uint32_t irqnow)
{
int epno = 0;
for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
{
if (irqnow & USBD_INT_ENDEPIN(epno))
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPIN), epno);
}
}
}
* Name: nrf53_endepoutinterrupt
*
* Description:
* Handle ENDEPOUT events
*
****************************************************************************/
static void nrf53_endepoutinterrupt(struct nrf53_usbdev_s *priv,
uint32_t irqnow)
{
struct nrf53_ep_s *privep = NULL;
int epno = 0;
for (epno = 0; epno < NRF53_NENDPOINTS; epno += 1)
{
if (irqnow & USBD_INT_ENDEPOUT(epno))
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_ENDEPOUT), epno);
if (epno == 0)
{
nrf53_ep0out_receive(priv);
if (priv->ep0outdone)
{
nrf53_ep0status_start(priv);
priv->ep0outdone = false;
}
else
{
nrf53_ep0rcvout_start(priv);
}
}
else
{
privep = &priv->epout[epno];
nrf53_epout_receive(privep);
}
}
}
}
* Name: nrf53_usbinterrupt
*
* Description:
* USB interrupt handler
*
****************************************************************************/
static int nrf53_usbinterrupt(int irq, void *context, void *arg)
{
struct nrf53_usbdev_s *priv = &g_usbdev;
struct nrf53_ep_s *privep = NULL;
uint32_t irqnow = 0;
uint32_t offset = 0;
int i = 0;
usbtrace(TRACE_INTENTRY(NRF53_TRACEINTID_USB), 0);
for (i = 0; i < USBD_INT_ALL_NUM; i++)
{
offset = NRF53_USBD_EVENTS_USBRESET + 0x04 * i;
irqnow |= nrf53_getreg(offset) << i;
nrf53_putreg(0, offset);
}
if (irqnow & USBD_INT_USBRESET)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_DEVRESET), 0);
nrf53_usbreset(priv);
goto intout;
}
#ifdef CONFIG_USBDEV_SOFINTERRUPT
if (irqnow & USBD_INT_SOF)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_SOF), 0);
}
#endif
if (irqnow & USBD_INT_USBEVENT)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_USBEVENT), 0);
nrf53_eventinterrupt(priv);
}
if (irqnow & NRF53_USBD_DMAIRQ)
{
nrf53_startdma_ack(priv);
}
if (irqnow & USBD_INT_EP0SETUP)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0SETUP), 0);
nrf53_ep0setupinterrupt(priv);
}
if (irqnow & USBD_INT_EP0DATADONE)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EP0DATADONE), 0);
nrf53_ep0datainterrupt(priv);
}
nrf53_endepoutinterrupt(priv, irqnow);
nrf53_endepininterrupt(priv, irqnow);
if (irqnow & USBD_INT_EPDATA)
{
usbtrace(TRACE_INTDECODE(NRF53_TRACEINTID_EPDATA), 0);
nrf53_epdatainterrupt(priv);
}
if (priv->dmanow == false)
{
if (priv->dmaepoutwait)
{
for (i = 0; i < NRF53_NENDPOINTS; i++)
{
if (priv->dmaepoutwait & (1 << i))
{
priv->dmaepoutwait &= ~(1 << i);
privep = &priv->epout[i];
nrf53_epout_handle(priv, privep);
break;
}
}
}
}
if (priv->dmanow == false)
{
if (priv->dmaepinwait)
{
for (i = 0; i < NRF53_NENDPOINTS; i++)
{
if (priv->dmaepinwait & (1 << i))
{
priv->dmaepinwait &= ~(1 << i);
privep = &priv->epin[i];
nrf53_epin_request(priv, privep);
break;
}
}
}
}
intout:
usbtrace(TRACE_INTEXIT(NRF53_TRACEINTID_USB), 0);
return OK;
}
* Name: nrf53_epout_configure
*
* Description:
* Configure an OUT endpoint, making it usable
*
* Input Parameters:
* privep - a pointer to an internal endpoint structure
* eptype - The type of the endpoint
* maxpacket - The max packet size of the endpoint
*
****************************************************************************/
static int nrf53_epout_configure(struct nrf53_ep_s *privep, uint8_t eptype,
uint16_t maxpacket)
{
uint32_t regval = 0;
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
if (privep->epphy == EP0)
{
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
eptype = 0;
}
regval = nrf53_getreg(NRF53_USBD_EPOUTEN);
regval |= USBD_EPOUTEN_OUT(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_EPOUTEN);
privep->ep.maxpacket = maxpacket;
privep->eptype = eptype;
privep->stalled = false;
privep->rxbuff = kmm_malloc(maxpacket);
regval = nrf53_getreg(NRF53_USBD_INTEN);
regval |= USBD_INT_ENDEPOUT(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_INTEN);
return OK;
}
* Name: nrf53_epin_configure
*
* Description:
* Configure an IN endpoint, making it usable
*
* Input Parameters:
* privep - a pointer to an internal endpoint structure
* eptype - The type of the endpoint
* maxpacket - The max packet size of the endpoint
*
****************************************************************************/
static int nrf53_epin_configure(struct nrf53_ep_s *privep, uint8_t eptype,
uint16_t maxpacket)
{
uint32_t regval = 0;
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
if (privep->epphy == EP0)
{
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_CONTROL);
}
else
{
DEBUGASSERT(eptype == USB_EP_ATTR_XFER_BULK || USB_EP_ATTR_XFER_INT);
}
regval = nrf53_getreg(NRF53_USBD_EPINEN);
regval |= USBD_EPINEN_IN(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_EPINEN);
privep->ep.maxpacket = maxpacket;
privep->eptype = eptype;
privep->stalled = false;
return OK;
}
* Name: nrf53_ep_configure
*
* Description:
* Configure endpoint, making it usable
*
* Input Parameters:
* ep - the struct usbdev_ep_s instance obtained from allocep()
* desc - A struct usb_epdesc_s instance describing the endpoint
* last - true if this last endpoint to be configured. Some hardware
* needs to take special action when all of the endpoints have been
* configured.
*
****************************************************************************/
static int nrf53_ep_configure(struct usbdev_ep_s *ep,
const struct usb_epdesc_s *desc, bool last)
{
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
uint16_t maxpacket = 0;
uint8_t eptype = 0;
int ret = 0;
usbtrace(TRACE_EPCONFIGURE, privep->epphy);
DEBUGASSERT(desc->addr == ep->eplog);
maxpacket = GETUINT16(desc->mxpacketsize);
eptype = desc->attr & USB_EP_ATTR_XFERTYPE_MASK;
if (privep->isin)
{
ret = nrf53_epin_configure(privep, eptype, maxpacket);
}
else
{
ret = nrf53_epout_configure(privep, eptype, maxpacket);
}
return ret;
}
* Name: nrf53_ep0_configure
*
* Description:
* Reset Usb engine
*
****************************************************************************/
static void nrf53_ep0_configure(struct nrf53_usbdev_s *priv)
{
nrf53_epin_configure(&priv->epin[EP0],
USB_EP_ATTR_XFER_CONTROL,
USBDEV_EP0_MAXSIZE);
nrf53_epout_configure(&priv->epout[EP0],
USB_EP_ATTR_XFER_CONTROL,
USBDEV_EP0_MAXSIZE);
}
* Name: nrf53_epout_disable
*
* Description:
* Disable an OUT endpoint will no longer be used
*
****************************************************************************/
static void nrf53_epout_disable(struct nrf53_ep_s *privep)
{
uint32_t regval = 0;
irqstate_t flags;
flags = enter_critical_section();
regval = nrf53_getreg(NRF53_USBD_EPOUTEN);
regval &= ~USBD_EPOUTEN_OUT(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_EPOUTEN);
regval = nrf53_getreg(NRF53_USBD_INTEN);
regval &= ~USBD_INT_ENDEPOUT(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_INTEN);
nrf53_req_cancel(privep, -ESHUTDOWN);
if (privep->rxbuff)
{
kmm_free(privep->rxbuff);
}
leave_critical_section(flags);
}
* Name: nrf53_epin_disable
*
* Description:
* Disable an IN endpoint when it will no longer be used
*
****************************************************************************/
static void nrf53_epin_disable(struct nrf53_ep_s *privep)
{
irqstate_t flags;
uint32_t regval = 0;
flags = enter_critical_section();
regval = nrf53_getreg(NRF53_USBD_EPINEN);
regval &= ~USBD_EPINEN_IN(privep->epphy);
nrf53_putreg(regval, NRF53_USBD_EPINEN);
nrf53_req_cancel(privep, -ESHUTDOWN);
leave_critical_section(flags);
}
* Name: nrf53_ep_disable
*
* Description:
* The endpoint will no longer be used
*
****************************************************************************/
static int nrf53_ep_disable(struct usbdev_ep_s *ep)
{
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
usbtrace(TRACE_EPDISABLE, privep->epphy);
if (privep->isin)
{
nrf53_epin_disable(privep);
}
else
{
nrf53_epout_disable(privep);
}
return OK;
}
* Name: nrf53_ep_allocreq
*
* Description:
* Allocate an I/O request
*
****************************************************************************/
static struct usbdev_req_s *nrf53_ep_allocreq(struct usbdev_ep_s *ep)
{
struct nrf53_req_s *privreq = NULL;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return NULL;
}
#endif
usbtrace(TRACE_EPALLOCREQ, ((struct nrf53_ep_s *)ep)->epphy);
privreq = kmm_malloc(sizeof(struct nrf53_req_s));
if (!privreq)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_ALLOCFAIL), 0);
return NULL;
}
memset(privreq, 0, sizeof(struct nrf53_req_s));
return &privreq->req;
}
* Name: nrf53_ep_freereq
*
* Description:
* Free an I/O request
*
****************************************************************************/
static void nrf53_ep_freereq(struct usbdev_ep_s *ep,
struct usbdev_req_s *req)
{
struct nrf53_req_s *privreq = (struct nrf53_req_s *)req;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep || !req)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return;
}
#endif
usbtrace(TRACE_EPFREEREQ, ((struct nrf53_ep_s *)ep)->epphy);
kmm_free(privreq);
}
#ifdef CONFIG_USBDEV_DMA
* Name: nrf53_ep_allocbuffer
*
* Description:
* Allocate an I/O buffer
*
****************************************************************************/
static void *nrf53_ep_allocbuffer(struct usbdev_ep_s *ep, unsigned bytes)
{
usbtrace(TRACE_EPALLOCBUFFER, ((struct nrf53_ep_s *)ep)->epphy);
return kmm_malloc(bytes);
}
* Name: nrf53_ep_freebuffer
*
* Description:
* Free an I/O buffer
*
****************************************************************************/
static void nrf53_ep_freebuffer(struct usbdev_ep_s *ep, void *buf)
{
usbtrace(TRACE_EPALLOCBUFFER, ((struct nrf53_ep_s *)ep)->epphy);
kmm_free(buf);
}
#endif
* Name: nrf53_ep_submit
*
* Description:
* Submit an I/O request to the endpoint
*
****************************************************************************/
static int nrf53_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
{
struct nrf53_req_s *privreq = (struct nrf53_req_s *)req;
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
struct nrf53_usbdev_s *priv = NULL;
irqstate_t flags;
int ret = OK;
DEBUGASSERT(privep && privep->dev);
priv = (struct nrf53_usbdev_s *)privep->dev;
#ifdef CONFIG_DEBUG_FEATURES
if (!req || !req->callback || !req->buf || !ep)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
uinfo("req=%p callback=%p buf=%p ep=%p\n",
req, req->callback, req->buf, ep);
return -EINVAL;
}
#endif
usbtrace(TRACE_EPSUBMIT, privep->epphy);
#ifdef CONFIG_DEBUG_FEATURES
if (!priv->driver)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_NOTCONFIGURED),
priv->usbdev.speed);
return -ESHUTDOWN;
}
#endif
req->result = -EINPROGRESS;
req->xfrd = 0;
flags = enter_critical_section();
if (privep->stalled)
{
ret = -EBUSY;
}
else
{
if (nrf53_req_addlast(privep, privreq))
{
* the request data buffer now.
*/
if (privep->isin)
{
usbtrace(TRACE_INREQQUEUED(privep->epphy), privreq->req.len);
nrf53_epin_request(priv, privep);
}
* setup a read into the request data buffer now (this will, of
* course, fail if there is already a read in place).
*/
else
{
usbtrace(TRACE_OUTREQQUEUED(privep->epphy), privreq->req.len);
nrf53_epout_allow(privep);
}
}
}
leave_critical_section(flags);
return ret;
}
* Name: nrf53_ep_cancel
*
* Description:
* Cancel an I/O request previously sent to an endpoint
*
****************************************************************************/
static int nrf53_ep_cancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
{
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
irqstate_t flags;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep || !req)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
usbtrace(TRACE_EPCANCEL, privep->epphy);
flags = enter_critical_section();
nrf53_req_cancel(privep, -ESHUTDOWN);
leave_critical_section(flags);
return OK;
}
* Name: nrf53_ep_setstall
*
* Description:
* Stall an endpoint
*
****************************************************************************/
static int nrf53_ep_setstall(struct nrf53_ep_s *privep)
{
uint32_t regval = 0;
if (privep->isin == 1)
{
regval |= USBD_EPSTALL_IO_IN;
}
else
{
regval |= USBD_EPSTALL_IO_OUT;
}
regval |= USBD_EPSTALL_EP(privep->epphy) | USBD_EPSTALL_IO_STALL;
nrf53_putreg(regval, NRF53_USBD_EPSTALL);
privep->stalled = true;
return OK;
}
* Name: nrf53_ep_clrstall
*
* Description:
* Resume a stalled endpoint
*
****************************************************************************/
static int nrf53_ep_clrstall(struct nrf53_ep_s *privep)
{
uint32_t regval = 0;
if (privep->isin == 1)
{
regval |= USBD_EPSTALL_IO_IN;
}
else
{
regval |= USBD_EPSTALL_IO_OUT;
}
regval |= USBD_EPSTALL_EP(privep->epphy) | USBD_EPSTALL_IO_UNSTALL;
nrf53_putreg(regval, NRF53_USBD_EPSTALL);
privep->stalled = false;
return OK;
}
* Name: nrf53_ep_stall
*
* Description:
* Stall or resume an endpoint
*
****************************************************************************/
static int nrf53_ep_stall(struct usbdev_ep_s *ep, bool resume)
{
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
irqstate_t flags;
int ret = 0;
flags = enter_critical_section();
if (resume)
{
ret = nrf53_ep_clrstall(privep);
}
else
{
ret = nrf53_ep_setstall(privep);
}
leave_critical_section(flags);
return ret;
}
* Name: nrf53_ep0_stall
*
* Description:
* Stall endpoint 0
*
****************************************************************************/
static void nrf53_ep0_stall(struct nrf53_usbdev_s *priv)
{
nrf53_putreg(1, NRF53_USBD_TASKS_EP0STALL);
priv->stalled = true;
}
* Name: nrf53_ep_alloc
*
* Description:
* Allocate an endpoint matching the parameters.
*
* Input Parameters:
* eplog - 7-bit logical endpoint number (direction bit ignored).
* Zero means that any endpoint matching the other requirements
* will suffice.
* The assigned endpoint can be found in the eplog field.
* in - true: IN (device-to-host) endpoint requested
* eptype - Endpoint type. One of {USB_EP_ATTR_XFER_ISOC,
* USB_EP_ATTR_XFER_BULK, USB_EP_ATTR_XFER_INT}
*
****************************************************************************/
static struct usbdev_ep_s *
nrf53_ep_alloc(struct usbdev_s *dev, uint8_t eplog, bool in, uint8_t eptype)
{
struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
irqstate_t flags;
uint8_t epavail = 0;
uint8_t bit = 0;
int epphy = 0;
int epno = 0;
usbtrace(TRACE_DEVALLOCEP, (uint16_t)eplog);
epphy = USB_EPNO(eplog);
flags = enter_critical_section();
epavail = priv->epavail[in];
if (epphy > 0)
{
* requested 'logical' endpoint. All of the other checks will
* still be performed.
*
* First, verify that the logical endpoint is in the range supported
* by by the hardware.
*/
if (epphy >= NRF53_NENDPOINTS)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BADEPNO), (uint16_t)epphy);
return NULL;
}
* this physical endpoint number.
*/
epavail &= (1 << epphy);
}
if (epavail)
{
* endpoints.
*/
for (epno = 1; epno < NRF53_NENDPOINTS; epno++)
{
bit = 1 << epno;
if ((epavail & bit) != 0)
{
priv->epavail[in] &= ~(1 << epno);
leave_critical_section(flags);
return in ? &priv->epin[epno].ep : &priv->epout[epno].ep;
}
}
}
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_NOEP), (uint16_t)eplog);
leave_critical_section(flags);
return NULL;
}
* Name: nrf53_ep_free
*
* Description:
* Free the previously allocated endpoint
*
****************************************************************************/
static void nrf53_ep_free(struct usbdev_s *dev, struct usbdev_ep_s *ep)
{
struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
struct nrf53_ep_s *privep = (struct nrf53_ep_s *)ep;
irqstate_t flags;
usbtrace(TRACE_DEVFREEEP, (uint16_t)privep->epphy);
if (priv && privep)
{
flags = enter_critical_section();
priv->epavail[privep->isin] |= (1 << privep->epphy);
leave_critical_section(flags);
}
}
* Name: nrf53_getframe
*
* Description:
* Returns the current frame number
*
****************************************************************************/
static int nrf53_getframe(struct usbdev_s *dev)
{
usbtrace(TRACE_DEVGETFRAME, 0);
return nrf53_getreg(NRF53_USBD_FRAMECNTR) & USBD_FRAMECNTR_MASK;
}
* Name: nrf53_wakeup
*
* Description:
* Exit suspend mode.
*
****************************************************************************/
static int nrf53_wakeup(struct usbdev_s *dev)
{
struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
irqstate_t flags;
usbtrace(TRACE_DEVWAKEUP, 0);
flags = enter_critical_section();
if (priv->wakeup)
{
#ifdef CONFIG_USBDEV_LOWPOWER
nrf53_putreg(0, NRF53_USBD_LOWPOWER);
#endif
#if 0
nrf53_putreg(USBD_DPDMVALUE_STATE_RESUME, NRF53_USBD_DPDMVALUE);
nrf53_putreg(1, NRF53_USBD_TASKS_DPDMDRIVE);
#endif
}
leave_critical_section(flags);
return OK;
}
* Name: nrf53_selfpowered
*
* Description:
* Sets/clears the device self-powered feature
*
****************************************************************************/
static int nrf53_selfpowered(struct usbdev_s *dev, bool selfpowered)
{
struct nrf53_usbdev_s *priv = (struct nrf53_usbdev_s *)dev;
usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
#ifdef CONFIG_DEBUG_FEATURES
if (!dev)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return -ENODEV;
}
#endif
priv->selfpowered = selfpowered;
return OK;
}
* Name: nrf53_pullup
*
* Description:
* Software-controlled connect to/disconnect from USB host
*
****************************************************************************/
int nrf53_pullup(struct usbdev_s *dev, bool enable)
{
if (enable)
{
nrf53_putreg(USBD_USBPULLUP_ENABLE, NRF53_USBD_USBPULLUP);
}
else
{
nrf53_putreg(USBD_USBPULLUP_DISABLE, NRF53_USBD_USBPULLUP);
}
return OK;
}
* Name: nrf53_setaddress
*
* Description:
* Set the devices USB address
*
****************************************************************************/
static void nrf53_setaddress(struct nrf53_usbdev_s *priv, uint16_t address)
{
* address?)
*/
if (address != 0)
{
priv->addressed = true;
}
else
{
priv->addressed = false;
}
}
* Name: nrf53_swinitialize
*
* Description:
* Initialize all driver data structures.
*
****************************************************************************/
static void nrf53_swinitialize(struct nrf53_usbdev_s *priv)
{
struct nrf53_ep_s *privep;
int i;
memset(priv, 0, sizeof(struct nrf53_usbdev_s));
priv->usbdev.ops = &g_devops;
priv->usbdev.ep0 = &priv->epin[EP0].ep;
priv->epavail[0] = NRF53_EP_AVAILABLE;
priv->epavail[1] = NRF53_EP_AVAILABLE;
for (i = 0; i < NRF53_NENDPOINTS; i++)
{
privep = &priv->epin[i];
privep->ep.ops = &g_epops;
privep->dev = priv;
privep->isin = 1;
* to a logical endpoint address usable by the class driver.
*/
privep->epphy = i;
privep->ep.eplog = NRF53_EPPHYIN2LOG(i);
privep->eptype = USB_EP_ATTR_XFER_CONTROL;
privep->ep.maxpacket = USBDEV_EP0_MAXSIZE;
}
for (i = 0; i < NRF53_NENDPOINTS; i++)
{
privep = &priv->epout[i];
privep->ep.ops = &g_epops;
privep->dev = priv;
* to a logical endpoint address usable by the class driver.
*/
privep->epphy = i;
privep->ep.eplog = NRF53_EPPHYOUT2LOG(i);
privep->eptype = USB_EP_ATTR_XFER_CONTROL;
privep->ep.maxpacket = USBDEV_EP0_MAXSIZE;
}
}
* Name: nrf53_hwinitialize
*
* Description:
* Configure the USB core for operation.
*
****************************************************************************/
static void nrf53_hwinitialize(struct nrf53_usbdev_s *priv)
{
while ((getreg32(NRF53_USBREG_USBREGSTATUS) &
USBREG_USBREGSTATUS_VBUSDETECT) == 0);
nrf53_putreg(USBD_ENABLE_ENABLE, NRF53_USBD_ENABLE);
while ((nrf53_getreg(NRF53_USBD_EVENTCAUSE) & USBD_EVENTCAUSE_READY) == 0);
nrf53_putreg(USBD_EVENTCAUSE_READY, NRF53_USBD_EVENTCAUSE);
nrf53_putreg(0, NRF53_USBD_EPOUTEN);
nrf53_putreg(0, NRF53_USBD_EPINEN);
}
* Public Functions
****************************************************************************/
* Name: arm_usbinitialize
*
* Description:
* Initialize the USB driver
*
****************************************************************************/
void arm_usbinitialize(void)
{
struct nrf53_usbdev_s *priv = &g_usbdev;
int ret = 0;
usbtrace(TRACE_DEVINIT, 0);
* known state.
*/
arm_usbuninitialize();
nrf53_swinitialize(priv);
ret = irq_attach(NRF53_IRQ_USBD, nrf53_usbinterrupt, NULL);
if (ret < 0)
{
uerr("ERROR: irq_attach failed: %d\n", ret);
goto errout;
}
nrf53_hwinitialize(priv);
nrf53_pullup(&priv->usbdev, false);
nrf53_usbreset(priv);
up_enable_irq(NRF53_IRQ_USBD);
return;
errout:
arm_usbuninitialize();
}
* Name: arm_usbuninitialize
*
* Description:
* Initialize the USB driver
*
****************************************************************************/
void arm_usbuninitialize(void)
{
struct nrf53_usbdev_s *priv = &g_usbdev;
irqstate_t flags;
usbtrace(TRACE_DEVUNINIT, 0);
if (priv->driver)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DRIVERREGISTERED), 0);
usbdev_unregister(priv->driver);
}
flags = enter_critical_section();
nrf53_pullup(&priv->usbdev, false);
priv->usbdev.speed = USB_SPEED_UNKNOWN;
up_disable_irq(NRF53_IRQ_USBD);
irq_detach(NRF53_IRQ_USBD);
nrf53_putreg(0, NRF53_USBD_INTEN);
nrf53_putreg(USBD_ENABLE_DISABLE, NRF53_USBD_ENABLE);
leave_critical_section(flags);
}
* Name: usbdev_register
*
* Description:
* Register a USB device class driver. The class driver's bind() method
* will be called to bind it to a USB device driver.
*
****************************************************************************/
int usbdev_register(struct usbdevclass_driver_s *driver)
{
struct nrf53_usbdev_s *priv = &g_usbdev;
int ret = 0;
usbtrace(TRACE_DEVREGISTER, 0);
#ifdef CONFIG_DEBUG_FEATURES
if (!driver || !driver->ops->bind || !driver->ops->unbind ||
!driver->ops->disconnect || !driver->ops->setup)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
if (priv->driver)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_DRIVER), 0);
return -EBUSY;
}
#endif
priv->driver = driver;
ret = CLASS_BIND(driver, &priv->usbdev);
if (ret)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_BINDFAILED), (uint16_t)-ret);
priv->driver = NULL;
}
else
{
up_enable_irq(NRF53_IRQ_USBD);
nrf53_pullup(&priv->usbdev, true);
priv->usbdev.speed = USB_SPEED_FULL;
}
return ret;
}
* Name: usbdev_unregister
*
* Description:
* Un-register usbdev class driver. If the USB device is connected to a
* USB host, it will first disconnect(). The driver is also requested to
* unbind() and clean up any device state, before this procedure finally
* returns.
*
****************************************************************************/
int usbdev_unregister(struct usbdevclass_driver_s *driver)
{
struct nrf53_usbdev_s *priv = &g_usbdev;
irqstate_t flags;
usbtrace(TRACE_DEVUNREGISTER, 0);
#ifdef CONFIG_DEBUG_FEATURES
if (driver != priv->driver)
{
usbtrace(TRACE_DEVERROR(NRF53_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
* canceled while the class driver is still bound.
*/
flags = enter_critical_section();
nrf53_usbreset(priv);
leave_critical_section(flags);
CLASS_UNBIND(driver, &priv->usbdev);
flags = enter_critical_section();
up_disable_irq(NRF53_IRQ_USBD);
nrf53_pullup(&priv->usbdev, false);
priv->driver = NULL;
leave_critical_section(flags);
return OK;
}