blob: 43bbf3017c593935aa147dbcb13497b7a5f92fd5 [file] [log] [blame]
/****************************************************************************
* arch/renesas/src/rx65n/rx65n_usbdev.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/types.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <stdint.h>
#include <stdio.h>
#include <nuttx/arch.h>
#include <nuttx/kmalloc.h>
#include <nuttx/usb/usb.h>
#include <nuttx/usb/usbdev.h>
#include <nuttx/usb/usbdev_trace.h>
#include <nuttx/usb/cdc.h>
#include <nuttx/serial/serial.h>
#include <nuttx/irq.h>
#include <arch/board/board.h>
#include <arch/chip/types.h>
#include "chip.h"
#include "renesas_internal.h"
#include "rx65n_usbdev.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
#if defined(CONFIG_USBHOST) && defined(CONFIG_USBDEV)
# error "Both USB Host & Device cannot be configured"
#endif
#ifndef CONFIG_USBDEV_MAXPOWER
# define CONFIG_USBDEV_MAXPOWER 100 /* mA */
#endif
#define RX65N_NENDPOINTS (8)
#define EP0 (0)
#define EP1 (1)
#define EP2 (2)
#define EP3 (3)
#define EP4 (4)
#define EP5 (5)
#define EP6 (6)
#define EP7 (7)
#define RX65N_ENDP_BIT(ep) (1 << (ep))
#define RX65N_ENDP_ALLSET 0xff
#define RX65N_MAXPACKET_SHIFT (6)
#define RX65N_MAXPACKET_SIZE (1 << (RX65N_MAXPACKET_SHIFT))
#define RX65N_MAXPACKET_MASK (RX65N_MAXPACKET_SIZE-1)
#define RX65N_EP0MAXPACKET RX65N_MAXPACKET_SIZE
#define REQRECIPIENT_MASK (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)
/* Debug ********************************************************************/
/* Trace error codes */
#define RX65N_TRACEERR_ALLOCFAIL 0x0001
#define RX65N_TRACEERR_ATTACHIRQ 0x0002
#define RX65N_TRACEERR_BINDFAILED 0x0003
#define RX65N_TRACEERR_DRIVER 0x0004
#define RX65N_TRACEERR_DRIVERREGISTERED 0x0005
#define RX65N_TRACEERR_EPREAD 0x0006
#define RX65N_TRACEERR_EWRITE 0x0007
#define RX65N_TRACEERR_INVALIDPARMS 0x0008
#define RX65N_TRACEERR_NOEP 0x0009
#define RX65N_TRACEERR_NOTCONFIGURED 0x000a
#define RX65N_TRACEERR_NULLPACKET 0x000b
#define RX65N_TRACEERR_NULLREQUEST 0x000c
#define RX65N_TRACEERR_REQABORTED 0x000d
#define RX65N_TRACEERR_STALLEDCLRFEATURE 0x000e
#define RX65N_TRACEERR_STALLEDISPATCH 0x000f
#define RX65N_TRACEERR_STALLEDGETST 0x0010
#define RX65N_TRACEERR_STALLEDGETSTEP 0x0011
#define RX65N_TRACEERR_STALLEDGETSTRECIP 0x0012
#define RX65N_TRACEERR_STALLEDREQUEST 0x0013
#define RX65N_TRACEERR_STALLEDSETFEATURE 0x0014
#define RX65N_TRACEERR_BADGETCONFIG 0x0015
#define RX65N_TRACEERR_IRQREGISTRATION 0x001a
#define RX65N_TRACEERR_DISPATCHSTALL 0x001b
#define RX65N_TRACEERR_INVALIDCTRLREQ 0x001c
#define RX65N_TRACEERR_BADEPTYPE 0x001d
#define RX65N_TRACEERR_BADEPNO 0x001e
#define RX65N_TRACEERR_EPRESERVE 0x001f
#define RX65N_TRACEERR_BADSETCONFIG 0x0020
/* Trace interrupt codes */
#define RX65N_TRACEINTID_CLEARFEATURE 0x0001
#define RX65N_TRACEINTID_CONTROL 0x0002
#define RX65N_TRACEINTID_DISPATCH 0x0003
#define RX65N_TRACEINTID_GETENDPOINT 0x0004
#define RX65N_TRACEINTID_GETIFDEV 0x0005
#define RX65N_TRACEINTID_GETSETDESC 0x0006
#define RX65N_TRACEINTID_GETSETIFCONFIG 0x0007
#define RX65N_TRACEINTID_GETSTATUS 0x0008
#define RX65N_TRACEINTID_RESUME 0x0009
#define RX65N_TRACEINTID_SETADDRESS 0x000a
#define RX65N_TRACEINTID_SETFEATURE 0x000b
#define RX65N_TRACEINTID_SUSPEND 0x000c
#define RX65N_TRACEINTID_SYNCHFRAME 0x000d
#define RX65N_TRACEINTID_TESTMODE 0x000e
#define RX65N_TRACEINTID_TXFIFOSTALL 0x000f
#define RX65N_TRACEINTID_GETCONFIG 0x0010
#define RX65N_TRACEINTID_EPINQEMPTY 0x0011
#define RX65N_TRACEINTID_EPOUTQEMPTY 0x0012
#define RX65N_TRACEINTID_NOSTDREQ 0x0013
#define RX65N_TRACEINTID_SETCONFIG 0x0014
#define RX65N_TRACEINTID_GETSETIF 0x0015
/* Hardware interface *******************************************************/
/* This driver supports the one interrupt IN, one bulk IN
* and one bulk OUT endpoint.
*/
/* Hardware dependent sizes and numbers */
#define RX65N_BULKMAXPACKET 64 /* Bulk endpoint max packet */
#define RX65N_INTRMAXPACKET 64 /* Interrupt endpoint max packet */
/* Endpoint numbers */
#define RX65N_EP0 0 /* Control endpoint */
#define RX65N_EPBULKIN 1 /* Bulk EP for send to host */
#define RX65N_EPBULKOUT 2 /* Bulk EP for recv to host */
#define RX65N_EPINTRIN 3 /* Intr EP for host poll */
/* Request queue operations *************************************************/
#define rx65n_rqempty(ep) ((ep)->head == NULL)
#define rx65n_rqpeek(ep) ((ep)->head)
# define LSB 0
# define MSB 1
/****************************************************************************
* Private Types
****************************************************************************/
/* A container for a request so that the request make be retained in a list */
struct rx65n_req_s
{
struct usbdev_req_s req; /* Standard USB request */
struct rx65n_req_s *flink; /* Supports a singly linked list */
};
/* This is the internal representation of an endpoint */
struct rx65n_ep_s
{
/* Common endpoint fields. This must be the first thing defined in the
* structure so that it is possible to simply cast from struct usbdev_ep_s
* to struct rx65n_ep_s.
*/
struct usbdev_ep_s ep; /* Standard endpoint structure */
/* RX65N-specific fields */
struct rx65n_usbdev_s *dev; /* Reference to private driver data */
struct rx65n_req_s *head; /* Request list for this endpoint */
struct rx65n_req_s *tail;
uint8_t epphy; /* Physical EP address/index */
uint8_t stalled:1; /* Endpoint is halted */
uint8_t in:1; /* Endpoint is IN only */
uint8_t txbusy:1; /* 1: TX endpoint FIFO full */
uint8_t halted:1; /* Endpoint feature halted */
uint8_t txnullpkt:1; /* Null packet needed at end of transfer */
};
/* This structure encapsulates the overall driver state */
struct rx65n_usbdev_s
{
/* Common device fields. This must be the first thing defined in the
* structure so that it is possible to simply cast from struct usbdev_s
* to struct rx65n_usbdev_s.
*/
struct usbdev_s usbdev;
/* The bound device class driver */
struct usbdevclass_driver_s *driver;
/* RX65N-specific fields */
uint8_t stalled:1; /* 1: Protocol stalled */
#ifdef CONFIG_USBDEV_SELFPOWERED
uint8_t selfpowered:1; /* 1: Device is self powered */
#endif
uint8_t epavail; /* Bitset of available endpoints */
uint8_t paddrset:1; /* 1: Peripheral addr has been set */
uint8_t attached:1; /* 1: Host attached */
uint8_t rxpending:1; /* 1: RX pending */
uint8_t paddr; /* Peripheral address */
uint8_t ep0state;
struct work_s rx65n_interrupt_bhalf;
struct usb_ctrlreq_s ctrl;
/* The endpoint list */
struct rx65n_ep_s eplist[RX65N_NENDPOINTS];
};
/* For maintaining tables of endpoint info */
struct rx65n_epinfo_s
{
uint8_t addr; /* Logical endpoint address */
uint8_t attr; /* Endpoint attributes */
uint8_t fifo; /* FIFO mx pkt size + dual buffer bits */
#ifdef CONFIG_USBDEV_HIGHSPEED
uint16_t maxpacket; /* Max packet size */
#else
uint8_t maxpacket; /* Max packet size */
#endif
};
union wb_u
{
uint16_t w;
uint8_t b[2];
};
uint16_t g_usb_pstd_req_type; /* Type */
uint16_t g_usb_pstd_req_value; /* Value */
uint16_t g_usb_pstd_req_index; /* Index */
uint16_t g_usb_pstd_req_length; /* Length */
uint32_t g_usb_pstd_data_cnt[USB_MAXPIPE_NUM + 1u];
uint8_t *gp_usb_pstd_data[USB_MAXPIPE_NUM + 1u];
uint16_t g_usb_pstd_remote_wakeup = USB_FALSE;
uint16_t g_usb_pstd_test_mode_flag = USB_FALSE; /* Test mode flag */
uint16_t g_usb_pstd_test_mode_select;
int bytesread = 0;
struct usb_utr
{
uint16_t keyword; /* Root port / Device address / Pipe number */
uint8_t *p_tranadr; /* Transfer data Start address */
uint32_t tranlen; /* Transfer data length */
};
struct usb_utr *g_p_usb_pstd_pipe[USB_MAXPIPE_NUM + 1u];
struct usb_utr g_usb_pdata[USB_MAXPIPE_NUM + 1];
uint16_t g_usb_pstd_stall_pipe[USB_MAX_PIPE_NO + 1u];
uint8_t g_buffer[64] ;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* Register operations */
# define rx65n_getreg8(addr) getreg8(addr)
# define rx65n_getreg16(addr) getreg16(addr)
# define rx65n_getreg32(addr) getreg32(addr)
# define rx65n_putreg8(val,addr) putreg8(val,addr)
# define rx65n_putreg16(val,addr) putreg16(val,addr)
# define rx65n_putreg32(val,addr) putreg32(val,addr)
/* Request queue operations *************************************************/
struct rx65n_req_s *rx65n_rqdequeue(struct rx65n_ep_s *privep);
static void rx65n_rqenqueue(struct rx65n_ep_s *privep, struct
rx65n_req_s *req);
/* Low level data transfers and request operations */
static void rx65n_epwrite(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep, uint8_t *buf,
uint32_t nbytes);
static int rx65n_epread(uint8_t epno, struct rx65n_usbdev_s *priv,
uint8_t *buf, uint16_t nbytes);
static inline void rx65n_abortrequest(struct rx65n_ep_s *privep,
struct rx65n_req_s *privreq,
int16_t result);
static void rx65n_reqcomplete(struct rx65n_ep_s *privep, int16_t result);
static int rx65n_wrrequest(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep);
static int rx65n_rdrequest(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep);
/* Interrupt handling */
static void rx65n_dispatchrequest(struct rx65n_usbdev_s *priv);
void rx65n_ep0setup(struct rx65n_usbdev_s *priv);
static int rx65n_usbinterrupt(int irq, void *context, void *arg);
/* Endpoint methods */
static int rx65n_epconfigure(struct usbdev_ep_s *ep,
const struct usb_epdesc_s *desc, bool last);
static int rx65n_epdisable(struct usbdev_ep_s *ep);
static struct usbdev_req_s *rx65n_epallocreq(struct usbdev_ep_s *ep);
static void rx65n_epfreereq(struct usbdev_ep_s *ep,
struct usbdev_req_s *req);
static int rx65n_epsubmit(struct usbdev_ep_s *ep,
struct usbdev_req_s *privreq);
static int rx65n_epcancel(struct usbdev_ep_s *ep,
struct usbdev_req_s *privreq);
static void rx65n_cancelrequests(struct rx65n_ep_s *privep);
/* USB device controller methods */
static struct usbdev_ep_s *rx65n_allocep(struct usbdev_s *dev,
uint8_t epno, bool in,
uint8_t eptype);
static void rx65n_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep);
static int rx65n_getframe(struct usbdev_s *dev);
static int rx65n_wakeup(struct usbdev_s *dev);
static int rx65n_selfpowered(struct usbdev_s *dev, bool selfpowered);
int rx65n_pullup(struct usbdev_s *dev, bool enable);
/* Interrupt Handler */
static int rx65n_usbinterrupt(int irq, void *context, void *arg);
/* USB Helper Functions */
void usb_pstd_attach_process(void);
uint16_t usb_pstd_chk_vbsts(void);
void hw_usb_pclear_dprpu(void);
static void hw_usb_clear_aclrm(uint16_t pipeno);
static void hw_usb_set_aclrm(uint16_t pipeno);
static void usb_cstd_do_aclrm(uint16_t pipe);
static void hw_usb_set_curpipe(uint16_t pipemode, uint16_t pipeno);
static void hw_usb_rmw_fifosel(uint16_t pipemode,
uint16_t data, uint16_t bitptn);
static void usb_cstd_chg_curpipe(uint16_t pipe,
uint16_t fifosel, uint16_t isel);
static void *hw_usb_get_fifosel_adr(uint16_t pipemode);
static uint16_t hw_usb_read_fifosel(uint16_t pipemode);
static void hw_usb_set_trclr(uint16_t pipeno);
static void hw_usb_clear_trenb(uint16_t pipeno);
static void hw_usb_clear_bempenb(uint16_t pipeno);
static void hw_usb_clear_nrdyenb(uint16_t pipeno);
static void hw_usb_clear_brdyenb(uint16_t pipeno);
static uint16_t hw_usb_read_pipectr(uint16_t pipeno);
static void hw_usb_clear_pid(uint16_t pipeno, uint16_t data);
static void usb_cstd_set_nak(uint16_t pipe);
void usb_pstd_forced_termination(uint16_t pipe, uint16_t status);
void usb_pstd_detach_process(void);
static void usb_cstd_clr_stall(uint16_t pipe);
static void hw_usb_write_pipesel(uint16_t data);
static void hw_usb_write_pipecfg(uint16_t data);
static void hw_usb_write_pipemaxp(uint16_t data);
static void hw_usb_write_pipeperi(uint16_t data);
static void hw_usb_set_sqclr(uint16_t pipeno);
static void hw_usb_clear_sts_brdy(uint16_t pipeno);
static void hw_usb_clear_status_nrdy(uint16_t pipeno);
static void hw_usb_clear_status_bemp(uint16_t pipeno);
void usb_pstd_bus_reset(void);
void usb_pstd_suspend_process(void);
uint16_t usb_cstd_port_speed(void);
static void hw_usb_write_dcpcfg(uint16_t data);
static uint16_t hw_usb_read_dvstctr(void);
static int hw_usb_read_syssts(void);
void usb_pstd_save_request(void);
static void hw_usb_set_pid(uint16_t pipeno, uint16_t data);
static void hw_usb_set_mbw(uint16_t pipemode, uint16_t data);
static uint16_t hw_usb_read_dcpmaxp(void);
static uint16_t hw_usb_read_pipemaxp(void);
static void hw_usb_write_dcpmxps(uint16_t data);
uint16_t usb_pstd_pipe2fport(uint16_t pipe);
static uint16_t usb_cstd_get_pid(uint16_t pipe);
static void usb_cstd_clr_transaction_counter(uint16_t trnreg);
static uint16_t hw_usb_read_pipecfg(void);
void usb_pstd_set_stall(uint16_t pipe);
static uint16_t hw_usb_read_frmnum(void);
/****************************************************************************
* Private Data
****************************************************************************/
/* Endpoint methods */
static const struct usbdev_epops_s g_epops =
{
.configure = rx65n_epconfigure,
.disable = rx65n_epdisable,
.allocreq = rx65n_epallocreq,
.freereq = rx65n_epfreereq,
#ifdef CONFIG_USBDEV_DMA
.allocbuffer = rx65n_epallocbuffer,
.freebuffer = rx65n_epfreebuffer,
#endif
.submit = rx65n_epsubmit,
.cancel = rx65n_epcancel,
};
/* USB controller device methods */
static const struct usbdev_ops_s g_devops =
{
.allocep = rx65n_allocep,
.freeep = rx65n_freeep,
.getframe = rx65n_getframe,
.wakeup = rx65n_wakeup,
.selfpowered = rx65n_selfpowered,
.pullup = rx65n_pullup,
};
enum rx65n_ep0state_e
{
EP0STATE_WRREQUEST = 0, /* Write request in progress */
EP0STATE_RDREQUEST, /* Read request in progress */
EP0STATE_STALLED
};
/* There is only one, single, pre-allocated instance
* of the driver structure
*/
struct rx65n_usbdev_s g_usbdev;
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: rx65n_rqdequeue
*
* Description:
* Remove a request from an endpoint request queue
*
****************************************************************************/
struct rx65n_req_s *rx65n_rqdequeue(struct rx65n_ep_s *privep)
{
struct rx65n_req_s *ret = privep->head;
if (ret)
{
privep->head = ret->flink;
if (!privep->head)
{
privep->tail = NULL;
}
ret->flink = NULL;
}
return ret;
}
/****************************************************************************
* Name: rx65n_rqenqueue
*
* Description:
* Add a request from an endpoint request queue
*
****************************************************************************/
static void rx65n_rqenqueue(struct rx65n_ep_s *privep,
struct rx65n_req_s *req)
{
req->flink = NULL;
if (!privep->head)
{
privep->head = req;
privep->tail = req;
}
else
{
privep->tail->flink = req;
privep->tail = req;
}
}
/****************************************************************************
* Name: hw_usb_get_fifoctr_adr
*
* Description:
* Get FIFOCTR Address
*
****************************************************************************/
static void *hw_usb_get_fifoctr_adr(uint16_t pipemode)
{
void *p_reg = NULL;
switch (pipemode)
{
case USB_CUSE:
p_reg = (void *)RX65N_USB_CFIFOCTR;
break;
case USB_D0USE:
p_reg = (void *)RX65N_USB_D0FIFOCTR;
break;
case USB_D1USE:
p_reg = (void *)RX65N_USB_D1FIFOCTR;
break;
default:
break;
}
return p_reg;
}
/****************************************************************************
* Name: hw_usb_set_mbw
*
* Description:
* Set MBW bit
*
****************************************************************************/
static void hw_usb_set_mbw(uint16_t pipemode, uint16_t data)
{
uint16_t *p_reg;
p_reg = hw_usb_get_fifosel_adr(pipemode);
(*p_reg) &= (~USB_MBW);
if (0 != data)
{
(*p_reg) |= data;
}
}
/****************************************************************************
* Name: hw_usb_set_bclr
*
* Description:
* Set BCLR bit
*
****************************************************************************/
static void hw_usb_set_bclr(uint16_t pipemode)
{
uint16_t *p_reg;
p_reg = (uint16_t *)hw_usb_get_fifoctr_adr(pipemode);
*p_reg = USB_BCLR;
}
/****************************************************************************
* Name: hw_usb_read_fifoctr
*
* Description:
* Read FIFOCTR Register
*
****************************************************************************/
static uint16_t hw_usb_read_fifoctr(uint16_t pipemode)
{
uint16_t *p_reg;
p_reg = (uint16_t *)hw_usb_get_fifoctr_adr(pipemode);
return *p_reg;
}
/****************************************************************************
* Name: hw_usb_read_syscfg
*
* Description:
* Set Read SYSCFG Register
*
****************************************************************************/
static uint16_t hw_usb_read_syscfg(void)
{
return rx65n_getreg16(RX65N_USB_SYSCFG);
}
/****************************************************************************
* Name: usb_cstd_is_set_frdy
*
* Description:
* Set FRDY bit
*
****************************************************************************/
static uint16_t usb_cstd_is_set_frdy(uint16_t pipe, uint16_t fifosel,
uint16_t isel)
{
uint16_t buf;
uint16_t i;
/* Changes the FIFO port by the pipe. */
usb_cstd_chg_curpipe(pipe, fifosel, isel);
/* WAIT_LOOP */
for (i = 0; i < 4; i++)
{
buf = hw_usb_read_fifoctr(fifosel);
if (USB_FRDY == (uint16_t)(buf & USB_FRDY))
{
return buf;
}
buf = hw_usb_read_syscfg();
buf = hw_usb_read_syssts();
}
return USB_ERROR;
}
/****************************************************************************
* Name: hw_usb_read_dcpmaxp
*
* Description:
* Read DCPMAXP Register
*
****************************************************************************/
static uint16_t hw_usb_read_dcpmaxp(void)
{
return rx65n_getreg16(RX65N_USB_DCPMAXP);
}
/****************************************************************************
* Name: hw_usb_read_pipemaxp
*
* Description:
* Read PIPEMAXP Register
*
****************************************************************************/
static uint16_t hw_usb_read_pipemaxp(void)
{
return rx65n_getreg16(RX65N_USB_PIPEMAXP);
}
/****************************************************************************
* Name: usb_cstd_get_buf_size
*
* Description:
* Get buf size
*
****************************************************************************/
static uint16_t usb_cstd_get_buf_size(uint16_t pipe)
{
uint16_t size;
uint16_t buf;
if (USB_PIPE0 == pipe)
{
buf = hw_usb_read_dcpmaxp();
/* Max Packet Size */
size = (uint16_t)(buf & USB_MAXP);
}
else
{
/* Pipe select */
hw_usb_write_pipesel(pipe);
buf = hw_usb_read_pipemaxp();
/* Max Packet Size */
size = (uint16_t)(buf & USB_MXPS);
}
return size;
}
/****************************************************************************
* Name: usb_cstd_get_maxpacket_size
*
* Description:
* Get maxpacket size
*
****************************************************************************/
static uint16_t usb_cstd_get_maxpacket_size(uint16_t pipe)
{
uint16_t size;
uint16_t buf;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_NULL; /* Error */
}
if (USB_PIPE0 == pipe)
{
buf = hw_usb_read_dcpmaxp();
}
else
{
/* Pipe select */
hw_usb_write_pipesel(pipe);
buf = hw_usb_read_pipemaxp();
}
/* Max Packet Size */
size = (uint16_t)(buf & USB_MXPS);
return size;
}
/****************************************************************************
* Name: hw_usb_write_fifo16
*
* Description:
* Write FIFO16
*
****************************************************************************/
static void hw_usb_write_fifo16(uint16_t pipemode, uint16_t data)
{
switch (pipemode)
{
case USB_CUSE:
USB0_CFIFO16 = data;
break;
case USB_D0USE:
USB0_D0FIFO16 = data;
break;
case USB_D1USE:
USB0_D1FIFO16 = data;
break;
default :
break;
}
}
/****************************************************************************
* Name: hw_usb_write_fifo8
*
* Description:
* Write to FIFO8
*
****************************************************************************/
static void hw_usb_write_fifo8(uint16_t pipemode, uint8_t data)
{
switch (pipemode)
{
case USB_CUSE:
USB0_CFIFO8 = data;
break;
case USB_D0USE:
USB0_D0FIFO8 = data;
break;
case USB_D1USE:
USB0_D1FIFO8 = data;
break;
default :
break;
}
}
/****************************************************************************
* Name: usb_pstd_write_fifo
*
* Description:
* Write to FIFO
*
****************************************************************************/
uint8_t *usb_pstd_write_fifo(uint16_t count, uint16_t pipemode,
uint8_t *write_p)
{
uint16_t even;
/* WAIT_LOOP */
for (even = (uint16_t)(count >> 1); (0 != even); --even)
{
/* 16bit access */
hw_usb_write_fifo16(pipemode, *((uint16_t *)write_p));
/* Renewal write pointer */
write_p += sizeof(uint16_t);
}
if ((count & (uint16_t)0x0001u) != 0u)
{
/* 8bit access */
/* count == odd */
/* Change FIFO access width */
hw_usb_set_mbw(pipemode, USB_MBW_8);
/* FIFO write */
hw_usb_write_fifo8(pipemode, *write_p);
/* Return FIFO access width */
hw_usb_set_mbw(pipemode, USB_MBW_16);
/* Renewal write pointer */
write_p++;
}
return write_p;
}
/****************************************************************************
* Name: hw_usb_set_bval
*
* Description:
* Set BVAL
*
****************************************************************************/
static void hw_usb_set_bval(uint16_t pipemode)
{
uint16_t *p_reg;
p_reg = (uint16_t *)hw_usb_get_fifoctr_adr(pipemode);
(*p_reg) |= USB_BVAL;
}
/****************************************************************************
* Name: usb_pstd_write_data
*
* Description:
* Write Data
*
****************************************************************************/
uint16_t usb_pstd_write_data(uint16_t pipe, uint16_t pipemode)
{
uint16_t size;
uint16_t count;
uint16_t buf;
uint16_t mxps;
uint16_t end_flag;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_ERROR; /* Error */
}
/* Changes FIFO port by the pipe. */
if ((USB_CUSE == pipemode) && (USB_PIPE0 == pipe))
{
buf = usb_cstd_is_set_frdy(pipe, (uint16_t)USB_CUSE,
(uint16_t)USB_ISEL);
}
else
{
buf = usb_cstd_is_set_frdy(pipe, (uint16_t)pipemode, USB_FALSE);
}
/* Check error */
if (USB_ERROR == buf)
{
/* FIFO access error */
buf = usb_cstd_is_set_frdy(pipe, (uint16_t)pipemode, USB_FALSE);
}
/* Data buffer size */
size = usb_cstd_get_buf_size(pipe);
/* Max Packet Size */
mxps = usb_cstd_get_maxpacket_size(pipe);
if (g_usb_pstd_data_cnt[pipe] <= (uint32_t)size)
{
count = (uint16_t)g_usb_pstd_data_cnt[pipe];
/* Data count check */
if (0 == count)
{
/* Null Packet is end of write */
end_flag = USB_WRITESHRT;
}
else if (0 != (count % mxps))
{
/* Short Packet is end of write */
end_flag = USB_WRITESHRT;
}
else
{
if (USB_PIPE0 == pipe)
{
/* Just Send Size */
end_flag = USB_WRITING;
}
else
{
/* Write continues */
end_flag = USB_WRITEEND;
}
}
}
else
{
/* Write continues */
end_flag = USB_WRITING;
count = size;
}
gp_usb_pstd_data[pipe] = usb_pstd_write_fifo(count, pipemode,
gp_usb_pstd_data[pipe]);
/* Check data count to remain */
if (g_usb_pstd_data_cnt[pipe] < (uint32_t)size)
{
/* Clear data count */
g_usb_pstd_data_cnt[pipe] = (uint32_t)0u;
/* Read CFIFOCTR */
buf = hw_usb_read_fifoctr(pipemode);
/* Check BVAL */
if (0u == (buf & USB_BVAL))
{
/* Short Packet */
hw_usb_set_bval(pipemode);
}
}
else
{
/* Total data count - count */
g_usb_pstd_data_cnt[pipe] -= count;
}
/* End or Err or Continue */
return end_flag;
}
/****************************************************************************
* Name: hw_usb_set_nrdyenb
*
* Description:
* Set NRDYENB
*
****************************************************************************/
static void hw_usb_set_nrdyenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_NRDYENB);
regval |= (1 << pipeno);
rx65n_putreg16(regval, RX65N_USB_NRDYENB);
}
/****************************************************************************
* Name: usb_cstd_nrdy_enable
*
* Description:
* NRDY Enable
*
****************************************************************************/
static void usb_cstd_nrdy_enable(uint16_t pipe)
{
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* Enable NRDY */
hw_usb_set_nrdyenb(pipe);
}
/****************************************************************************
* Name: usb_cstd_set_buf
*
* Description:
* Set Buf
*
****************************************************************************/
static void usb_cstd_set_buf(uint16_t pipe)
{
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* PIPE control reg set */
hw_usb_set_pid(pipe, USB_PID_BUF);
}
/****************************************************************************
* Name: hw_usb_set_bempenb
*
* Description:
* Set BEMPENB
*
****************************************************************************/
static void hw_usb_set_bempenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_BEMPENB);
regval |= (1 << pipeno);
rx65n_putreg16(regval, RX65N_USB_BEMPENB);
}
/****************************************************************************
* Name: hw_usb_set_brdyenb
*
* Description:
* Set BRDYENB
*
****************************************************************************/
static void hw_usb_set_brdyenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_BRDYENB);
regval |= (1 << pipeno);
rx65n_putreg16(regval, RX65N_USB_BRDYENB);
}
/****************************************************************************
* Name: usb_pstd_ctrl_write
*
* Description:
* CTRL Write
*
****************************************************************************/
void usb_pstd_ctrl_write(uint32_t bsize, uint8_t *table)
{
g_usb_pstd_data_cnt[USB_PIPE0] = bsize;
gp_usb_pstd_data[USB_PIPE0] = table;
usb_cstd_chg_curpipe((uint16_t) USB_PIPE0,
(uint16_t) USB_CUSE, USB_FALSE);
/* Buffer clear */
hw_usb_set_bclr(USB_CUSE);
/* Interrupt enable */
/* Enable ready interrupt */
hw_usb_set_brdyenb((uint16_t) USB_PIPE0);
/* Enable not ready interrupt */
usb_cstd_nrdy_enable((uint16_t) USB_PIPE0);
/* Set PID=BUF */
usb_cstd_set_buf((uint16_t) USB_PIPE0);
}
/****************************************************************************
* Name: usb_ctrl_read
*
* Description:
* CTRL Read
*
****************************************************************************/
uint16_t usb_ctrl_read(uint32_t bsize, uint8_t *table)
{
usb_pstd_ctrl_write(bsize, table);
return OK;
}
/****************************************************************************
* Name: usb_pstd_ctrl_read
*
* Description:
* CTRL Read invoked from class driver
*
****************************************************************************/
uint16_t usb_pstd_ctrl_read(uint32_t bsize, uint8_t *table)
{
uint16_t end_flag;
g_usb_pstd_data_cnt[USB_PIPE0] = bsize;
gp_usb_pstd_data[USB_PIPE0] = table;
usb_cstd_chg_curpipe((uint16_t) USB_PIPE0, (uint16_t) USB_CUSE,
(uint16_t) USB_ISEL);
/* Buffer clear */
hw_usb_set_bclr(USB_CUSE);
hw_usb_clear_status_bemp(USB_PIPE0);
/* Peripheral Control sequence */
end_flag = usb_pstd_write_data(USB_PIPE0, USB_CUSE);
/* Peripheral control sequence */
switch (end_flag)
{
/* End of data write */
case USB_WRITESHRT :
/* Enable not ready interrupt */
usb_cstd_nrdy_enable((uint16_t) USB_PIPE0);
/* Set PID=BUF */
usb_cstd_set_buf((uint16_t) USB_PIPE0);
break;
/* End of data write (not null) */
case USB_WRITEEND :
/* Continue */
/* Continue of data write */
case USB_WRITING :
/* Enable empty interrupt */
hw_usb_set_bempenb((uint16_t) USB_PIPE0);
/* Enable not ready interrupt */
usb_cstd_nrdy_enable((uint16_t) USB_PIPE0);
/* Set PID=BUF */
usb_cstd_set_buf((uint16_t) USB_PIPE0);
break;
/* FIFO access error */
case USB_ERROR :
break;
default :
break;
}
return end_flag; /* End or error or continue */
}
/****************************************************************************
* Name: usb_pstd_buf_to_fifo
*
* Description:
* Buf to FIFO data write
*
****************************************************************************/
void usb_pstd_buf_to_fifo(uint16_t pipe, uint16_t useport)
{
uint16_t end_flag;
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* Disable Ready Interrupt */
hw_usb_clear_brdyenb(pipe);
hw_usb_clear_bempenb(pipe);
end_flag = usb_pstd_write_data(pipe, useport);
/* Check FIFO access sequence */
switch (end_flag)
{
case USB_WRITING:
/* Continue of data write */
/* Enable Ready Interrupt */
hw_usb_set_brdyenb(pipe);
/* Enable Not Ready Interrupt */
usb_cstd_nrdy_enable(pipe);
break;
case USB_WRITEEND:
/* End of data write */
/* continue */
case USB_WRITESHRT:
/* End of data write */
/* Enable Empty Interrupt */
hw_usb_set_bempenb(pipe);
/* Enable Not Ready Interrupt */
usb_cstd_nrdy_enable(pipe);
break;
case USB_ERROR:
/* FIFO access error */
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_ERR);
break;
default:
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_ERR);
break;
}
}
/****************************************************************************
* Name: usb_pstd_data_end
*
* Description:
* Data End transfer
*
****************************************************************************/
void usb_pstd_data_end(uint16_t pipe, uint16_t status)
{
uint16_t useport;
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* PID = NAK */
/* Set NAK */
usb_cstd_set_nak(pipe);
/* Pipe number to FIFO port select */
useport = USB_CUSE;
/* Disable Interrupt */
/* Disable Ready Interrupt */
hw_usb_clear_brdyenb(pipe);
/* Disable Not Ready Interrupt */
hw_usb_clear_nrdyenb(pipe);
/* Disable Empty Interrupt */
hw_usb_clear_bempenb(pipe);
/* Disable Transaction count */
usb_cstd_clr_transaction_counter(pipe);
/* Check use FIFO */
switch (useport)
{
/* CFIFO use */
case USB_CUSE:
break;
default:
break;
}
}
/****************************************************************************
* Name: usb_pstd_send_start
*
* Description:
* Send start
*
****************************************************************************/
void usb_pstd_send_start(uint16_t pipe, uint8_t *buf, uint32_t size)
{
uint16_t useport;
/* Select NAK */
usb_cstd_set_nak(pipe);
/* Set data count */
g_usb_pstd_data_cnt[pipe] = size;
/* Set data pointer */
gp_usb_pstd_data[pipe] = buf;
/* BEMP Status Clear */
hw_usb_clear_status_bemp(pipe);
/* BRDY Status Clear */
hw_usb_clear_sts_brdy(pipe);
/* Pipe number to FIFO port select */
useport = USB_CUSE;
usb_cstd_chg_curpipe(pipe, useport, USB_FALSE);
/* Buffer to FIFO data write */
usb_pstd_buf_to_fifo(pipe, useport);
/* Set BUF */
usb_cstd_set_buf(pipe);
}
/****************************************************************************
* Name: hw_usb_read_pipecfg
*
* Description:
* Read Pipecfg
*
****************************************************************************/
static uint16_t hw_usb_read_pipecfg(void)
{
return rx65n_getreg16(RX65N_USB_PIPECFG);
}
/****************************************************************************
* Name: usb_cstd_get_pipe_dir
*
* Description:
* Get pipe direction
*
****************************************************************************/
static uint16_t usb_cstd_get_pipe_dir(uint16_t pipe)
{
uint16_t buf;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_NULL; /* Error */
}
/* Pipe select */
hw_usb_write_pipesel(pipe);
/* Read Pipe direction */
buf = hw_usb_read_pipecfg();
return (uint16_t)(buf & USB_DIRFIELD);
}
/****************************************************************************
* Name: usb_cstd_get_pipe_type
*
* Description:
* Get pipe type
*
****************************************************************************/
static uint16_t usb_cstd_get_pipe_type(uint16_t pipe)
{
uint16_t buf;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_NULL; /* Error */
}
/* Pipe select */
hw_usb_write_pipesel(pipe);
/* Read Pipe direction */
buf = hw_usb_read_pipecfg();
return (uint16_t)(buf & USB_TYPFIELD);
}
/****************************************************************************
* Name: usb_pstd_chk_configured
*
* Description:
* Check Configured
*
****************************************************************************/
uint16_t usb_pstd_chk_configured(void)
{
uint16_t buf;
buf = rx65n_getreg16(RX65N_USB_INTSTS0);
/* Device Status - Configured check */
if (USB_DS_CNFG == (buf & USB_DVSQ))
{
/* Configured */
return USB_TRUE;
}
else
{
/* not Configured */
return USB_FALSE;
}
}
/****************************************************************************
* Name: hw_usb_set_trenb
*
* Description:
* Set TRENB
*
****************************************************************************/
static void hw_usb_set_trenb(uint16_t pipeno)
{
uint16_t *p_reg;
p_reg = (uint16_t *)RX65N_USB_PIPE1TRE + ((pipeno - 1) * 2);
(*p_reg) |= USB_TRENB;
}
/****************************************************************************
* Name: hw_usb_write_pipetrn
*
* Description:
* Write to PIPETRN
*
****************************************************************************/
static void hw_usb_write_pipetrn(uint16_t pipeno, uint16_t data)
{
uint16_t *p_reg;
p_reg = (uint16_t *)RX65N_USB_PIPE1TRN + ((pipeno - 1) * 2);
*p_reg = data;
}
/****************************************************************************
* Name: usb_cstd_set_transaction_counter
*
* Description:
* Set transaction counter
*
****************************************************************************/
static void usb_cstd_set_transaction_counter(uint16_t trnreg,
uint16_t trncnt)
{
hw_usb_set_trclr(trnreg);
hw_usb_write_pipetrn(trnreg, trncnt);
hw_usb_set_trenb(trnreg);
}
/****************************************************************************
* Name: usb_pstd_receive_start
*
* Description:
* Receive start
*
****************************************************************************/
void usb_pstd_receive_start(uint16_t pipe)
{
struct usb_utr *pp;
uint32_t length;
uint16_t mxps;
uint16_t useport;
/* Evacuation pointer */
pp = g_p_usb_pstd_pipe[pipe];
length = pp->tranlen;
/* Select NAK */
usb_cstd_set_nak(pipe);
/* Set data pointer */
gp_usb_pstd_data[pipe] = (uint8_t *)pp->p_tranadr;
/* Pipe number to FIFO port select */
useport = USB_CUSE;
/* Check use FIFO access */
switch (useport)
{
/* CFIFO use */
case USB_CUSE:
/* Changes the FIFO port by the pipe. */
usb_cstd_chg_curpipe(pipe, useport, USB_FALSE);
/* Max Packet Size */
mxps = usb_cstd_get_maxpacket_size(pipe);
if ((uint32_t)0u != length)
{
/* Data length check */
if ((uint32_t)0u == (length % mxps))
{
/* Set Transaction counter */
usb_cstd_set_transaction_counter(pipe, (uint16_t)(length /
mxps));
}
else
{
/* Set Transaction counter */
usb_cstd_set_transaction_counter(pipe, (uint16_t)((length
/ mxps) + (uint32_t)1u));
}
}
/* Set BUF */
usb_cstd_set_buf(pipe);
/* Enable Ready Interrupt */
hw_usb_set_brdyenb(pipe);
/* Enable Not Ready Interrupt */
usb_cstd_nrdy_enable(pipe);
break;
default:
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_ERR);
break;
}
}
/****************************************************************************
* Name: usb_pstd_set_submitutr
*
* Description:
* Set Submit Request
*
****************************************************************************/
void usb_pstd_set_submitutr(struct usb_utr *utrmsg)
{
uint16_t pipenum;
pipenum = utrmsg->keyword;
g_p_usb_pstd_pipe[pipenum] = utrmsg;
/* Check state (Configured) */
if (USB_TRUE == usb_pstd_chk_configured())
{
if (USB_DIR_P_OUT == usb_cstd_get_pipe_dir(pipenum))
{
usb_pstd_receive_start(pipenum); /* Out transfer */
}
else
{
/* In transfer */
usb_pstd_send_start(pipenum, NULL, 0);
}
}
}
/****************************************************************************
* Name: usb_pstd_transfer_start
*
* Description:
* Transfer start
*
****************************************************************************/
uint8_t usb_pstd_transfer_start(struct usb_utr *ptr)
{
usb_pstd_set_submitutr(ptr);
return OK;
}
/****************************************************************************
* Name: usb_data_write
*
* Description:
* Data write
*
****************************************************************************/
long usb_data_write(uint8_t epno, uint8_t *buf, uint32_t size)
{
uint8_t pipe;
if (epno == BULK_IN_EPNUM)
{
pipe = BULK_IN_PIPE;
}
else if (epno == INT_IN_EPNUM)
{
pipe = INT_IN_PIPE;
}
if (USB_TRUE == usb_pstd_chk_configured())
{
if (USB_DIR_P_OUT == usb_cstd_get_pipe_dir(pipe))
{
usb_pstd_receive_start(pipe); /* Out transfer */
}
else
{
/* In transfer */
usb_pstd_send_start(pipe, buf, size);
}
}
return OK;
}
/****************************************************************************
* Name: usb_data_read
*
* Description:
* Data read
*
****************************************************************************/
void usb_data_read(uint8_t *buf, uint32_t size)
{
uint8_t pipe = BULK_OUT_PIPE;
struct usb_utr *p_tran_data;
memset((void *)&g_usb_pdata, 0, ((USB_MAXPIPE_NUM + 1) *
sizeof(struct usb_utr)));
p_tran_data = (struct usb_utr *)&g_usb_pdata[pipe];
p_tran_data->p_tranadr = buf; /* Data address */
p_tran_data->tranlen = size; /* Data Size */
p_tran_data->keyword = pipe;
usb_pstd_transfer_start(p_tran_data);
}
/****************************************************************************
* Name: rx65n_epwrite
*
* Description:
* Endpoint write (IN)
*
****************************************************************************/
static void rx65n_epwrite(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep, uint8_t *buf,
uint32_t nbytes)
{
uint8_t type;
uint8_t g_buf[RX65N_USB_MAXP];
type = MSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
if (epno == 0)
{
if ((type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
{
if (type == ACM_GET_LINE_CODING)
{
usb_pstd_ctrl_read(nbytes, buf);
usb_cstd_set_buf((uint16_t)USB_PIPE0);
usb_data_read(g_buf, RX65N_USB_MAXP);
}
else
{
usb_pstd_ctrl_read(nbytes, buf);
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
}
else
{
usb_pstd_ctrl_read(nbytes, buf);
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
}
if (epno > 0)
{
usb_data_write(epno, buf, nbytes);
}
}
/****************************************************************************
* Name: rx65n_epread
*
* Description:
* Endpoint read (OUT)
*
****************************************************************************/
static int rx65n_epread(uint8_t epno, struct rx65n_usbdev_s *priv,
uint8_t *buf, uint16_t nbytes)
{
if (epno == EP0)
{
usb_ctrl_read(CDC_CLASS_DATA_LENGTH, buf);
}
else
{
usb_data_read(buf, nbytes);
if (bytesread != 0)
{
return bytesread;
}
}
return OK;
}
/****************************************************************************
* Name: rx65n_abortrequest
*
* Description:
* Discard a request
*
****************************************************************************/
static inline void rx65n_abortrequest(struct rx65n_ep_s *privep,
struct rx65n_req_s *privreq,
int16_t result)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_REQABORTED),
(uint16_t)USB_EPNO(privep->ep.eplog));
/* Save the result in the request structure */
privreq->req.result = result;
/* Callback to the request completion handler */
privreq->req.callback(&privep->ep, &privreq->req);
}
/****************************************************************************
* Name: rx65n_reqcomplete
*
* Description:
* Handle termination of a request.
*
****************************************************************************/
static void rx65n_reqcomplete(struct rx65n_ep_s *privep, int16_t result)
{
struct rx65n_req_s *privreq;
irqstate_t flags;
/* Remove the completed request at the head of the endpoint request list */
flags = enter_critical_section();
privreq = rx65n_rqdequeue(privep);
leave_critical_section(flags);
if (privreq)
{
/* If endpoint 0, temporarily reflect the state of protocol stalled
* in the callback.
*/
bool stalled = privep->stalled;
if (USB_EPNO(privep->ep.eplog) == EP0)
{
privep->stalled = privep->dev->stalled;
}
/* Save the result in the request structure */
privreq->req.result = result;
/* Callback to the request completion handler */
privreq->flink = NULL;
privreq->req.callback(&privep->ep, &privreq->req);
/* Restore the stalled indication */
privep->stalled = stalled;
}
}
/****************************************************************************
* Name: rx65n_wrrequest
*
* Description:
* Send from the next queued write request
*
* Returned Value:
* 0:not finished; 1:completed; <0:error
*
****************************************************************************/
static int rx65n_wrrequest(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep)
{
struct rx65n_req_s *privreq;
uint8_t *buf = NULL;
int nbytes;
int bytesleft;
/* We get here when an IN endpoint interrupt occurs. So now we know that
* there is no TX transfer in progress.
*/
privep->txbusy = false;
/* Check the request from the head of the endpoint request queue */
privreq = rx65n_rqpeek(privep);
if (!privreq)
{
/* There is no TX transfer in progress and no new pending TX
* requests to send.
*/
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_EPINQEMPTY), 0);
return -ENOENT;
}
epno = USB_EPNO(privep->ep.eplog);
uinfo("epno=%d req=%p: len=%d xfrd=%d nullpkt=%d\n",
epno, privreq, privreq->req.len, privreq->req.xfrd,
privep->txnullpkt);
/* Get the number of bytes left to be sent in the packet */
for (; ; )
{
bytesleft = privreq->req.len - privreq->req.xfrd;
nbytes = bytesleft;
/* Either (1) we are committed to sending the null packet
* (because txnullpkt == 1 && nbytes == 0), or
* (2) we have not yet send the last packet (nbytes > 0).
* In either case, it is appropriate to clearn txnullpkt now.
*/
privep->txnullpkt = 0;
/* If we are not sending a NULL packet, then clip the size
* to maxpacket
* and check if we need to send a following NULL packet.
*/
if (nbytes > 0)
{
/* Either send the maxpacketsize or all of the
* remaining data in request
*/
if (nbytes >= privep->ep.maxpacket)
{
nbytes = privep->ep.maxpacket;
/* Handle the case where this packet is exactly the
* maxpacketsize. Do we need to send a zero-length packet
* in this case?
*/
if (bytesleft == privep->ep.maxpacket &&
(privreq->req.flags & USBDEV_REQFLAGS_NULLPKT) != 0)
{
privep->txnullpkt = 1;
}
}
}
/* Send the packet (might be a null packet nbytes == 0) */
buf = privreq->req.buf + privreq->req.xfrd;
rx65n_epwrite(epno, priv, privep, buf, nbytes);
/* Update for the next data IN interrupt */
privreq->req.xfrd += nbytes;
bytesleft = privreq->req.len - privreq->req.xfrd;
/* If all of the bytes were sent (including any final null packet)
* then we are finished with the request buffer).
*/
if (bytesleft == 0)
{
/* Return the write request to the class driver */
usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)),
privreq->req.xfrd);
privep->txnullpkt = 0;
rx65n_reqcomplete(privep, OK);
return OK;
}
}
return OK;
}
/****************************************************************************
* Name: rx65n_rdrequest
*
* Description:
* Receive to the next queued read request
*
****************************************************************************/
static int rx65n_rdrequest(uint8_t epno, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep)
{
struct rx65n_req_s *privreq;
uint8_t *buf;
int nbytesread;
/* Check the request from the head of the endpoint request queue */
privreq = rx65n_rqpeek(privep);
if (!privreq)
{
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_EPOUTQEMPTY), 0);
return OK;
}
uinfo("len=%d xfrd=%d nullpkt=%d\n",
privreq->req.len, privreq->req.xfrd, privep->txnullpkt);
usbtrace(TRACE_READ(privep->epphy), privreq->req.xfrd);
/* Receive the next packet */
buf = privreq->req.buf + privreq->req.xfrd;
nbytesread = rx65n_epread(epno, priv, buf, privep->ep.maxpacket);
if (nbytesread < 0)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_EPREAD), nbytesread);
return ERROR;
}
/* If the receive buffer is full or if the last packet was not full
* then we are finished with the transfer.
*/
privreq->req.xfrd += nbytesread;
if (privreq->req.xfrd >= privreq->req.len ||
nbytesread < privep->ep.maxpacket)
{
usbtrace(TRACE_COMPLETE(privep->epphy), privreq->req.xfrd);
rx65n_reqcomplete(privep, OK);
}
return OK;
}
/****************************************************************************
* Name: rx65n_dispatchrequest
*
* Description:
* Provide unhandled setup actions to the class driver
*
****************************************************************************/
static void rx65n_dispatchrequest(struct rx65n_usbdev_s *priv)
{
int ret;
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_DISPATCH), 0);
if (priv && priv->driver)
{
/* Forward to the control request to the class driver implementation */
ret = CLASS_SETUP(priv->driver, &priv->usbdev, &priv->ctrl,
NULL, 0);
if (ret < 0)
{
/* Stall on failure */
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_DISPATCHSTALL), 0);
priv->stalled = 1;
}
}
}
/****************************************************************************
* Name: usb_pstd_get_current_power
*
* Description:
* Get the power type
*
****************************************************************************/
uint8_t usb_pstd_get_current_power(void)
{
uint8_t currentpower;
#ifdef CONFIG_USBDEV_SELFPOWERED
currentpower = USB_GS_SELFPOWERD;
#else
currentpower = USB_GS_BUSPOWERD;
#endif
return currentpower;
}
/****************************************************************************
* Name: usb_pstd_epadr2pipe
*
* Description:
* Get the endpoint addr to pipe number
*
****************************************************************************/
uint16_t usb_pstd_epadr2pipe(uint16_t dir_ep)
{
uint16_t i;
uint16_t direp;
uint16_t tmp;
/* Peripheral */
/* Get PIPE Number from Endpoint address */
direp = (uint16_t)(((dir_ep & 0x80) >> 3) | (dir_ep & 0x0f));
/* EP table loop */
/* WAIT_LOOP */
for (i = USB_MIN_PIPE_NO; i < (USB_MAXPIPE_NUM + 1); i++)
{
/* PIPECFG register will be set if PIPESEL register is set first */
/* Check if PIPESEL register is set before reading PIPECFG */
tmp = (rx65n_getreg16(RX65N_USB_PIPECFG)) &
(USB_DIRFIELD | USB_EPNUMFIELD);
/* EP table endpoint dir check */
if (direp == tmp)
{
return i;
}
}
return USB_ERROR;
}
/****************************************************************************
* Name: hw_usb_read_dcpctr
*
* Description:
* Read DCPCTR register
*
****************************************************************************/
uint16_t hw_usb_read_dcpctr(void)
{
return rx65n_getreg16(RX65N_USB_DCPCTR);
}
/****************************************************************************
* Name: usb_pstd_set_stall_pipe0
*
* Description:
* Set stall pipe
*
****************************************************************************/
void usb_pstd_set_stall_pipe0(void)
{
/* PIPE control reg set */
hw_usb_set_pid(USB_PIPE0, USB_PID_STALL);
}
/****************************************************************************
* Name: rx65n_ep0setup
*
* Description:
* USB Ctrl EP Setup Event
*
****************************************************************************/
void rx65n_ep0setup(struct rx65n_usbdev_s *priv)
{
struct rx65n_ep_s *ep0 = &priv->eplist[EP0];
struct rx65n_req_s *privreq = rx65n_rqpeek(ep0);
union wb_u value;
union wb_u index;
union wb_u len;
uint8_t epno;
uint8_t tbl[2];
uint16_t ep;
uint16_t buf;
uint16_t pipe;
/* Starting a control request? */
if (priv->usbdev.speed == USB_SPEED_UNKNOWN)
{
priv->usbdev.speed = USB_SPEED_FULL;
}
/* Terminate any pending requests */
while (!rx65n_rqempty(ep0))
{
int16_t result = OK;
if (privreq->req.xfrd != privreq->req.len)
{
result = -EPROTO;
}
usbtrace(TRACE_COMPLETE(ep0->epphy), privreq->req.xfrd);
rx65n_reqcomplete(ep0, result);
}
/* Assume NOT stalled */
ep0->stalled = 0;
priv->stalled = 0;
/* And extract the little-endian 16-bit values to host order */
priv->ctrl.type = LSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
priv->ctrl.req = MSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
priv->ctrl.value[0] = LSBYTE(rx65n_getreg16(RX65N_USB_USBVAL));
priv->ctrl.value[1] = MSBYTE(rx65n_getreg16(RX65N_USB_USBVAL));
priv->ctrl.index[0] = LSBYTE(rx65n_getreg16(RX65N_USB_USBINDX));
priv->ctrl.index[1] = MSBYTE(rx65n_getreg16(RX65N_USB_USBINDX));
priv->ctrl.len[0] = LSBYTE(rx65n_getreg16(RX65N_USB_USBLENG));
priv->ctrl.len[1] = MSBYTE(rx65n_getreg16(RX65N_USB_USBLENG));
uinfo("SETUP: type=%02x req=%02x value[0]=%02x value[1] =%02x \
index[0]=%02x index[1] =%02x len[0]=%02x len[1]=%02x\n",
priv->ctrl.type, priv->ctrl.req, priv->ctrl.value[0],
priv->ctrl.value[1], priv->ctrl.index[0],
priv->ctrl.index[1], priv->ctrl.len[0],
priv->ctrl.len[1]);
/* And extract the little-endian 16-bit values to host order */
value.w = GETUINT16(priv->ctrl.value);
index.w = GETUINT16(priv->ctrl.index);
len.w = GETUINT16(priv->ctrl.len);
uinfo("value=%x index=%x len=%x\n", value.w, index.w, len.w);
/* Dispatch any non-standard requests */
if ((priv->ctrl.type & USB_REQ_TYPE_MASK) != USB_REQ_TYPE_STANDARD)
{
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_NOSTDREQ), priv->ctrl.type);
/* Let the class implementation handle all non-standar requests */
priv->ctrl.req = MSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
priv->ctrl.type = LSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
if (priv->ctrl.req == ACM_SET_LINE_CODING ||
priv->ctrl.req == ACM_SET_CTRL_LINE_STATE)
{
priv->ep0state = EP0STATE_RDREQUEST;
rx65n_dispatchrequest(priv);
}
priv->ep0state = EP0STATE_WRREQUEST;
rx65n_dispatchrequest(priv);
}
/* Handle standard request. Pick off the things of interest to the
* USB device controller driver; pass what is left to the class driver
*/
switch (priv->ctrl.req)
{
case USB_REQ_GETSTATUS:
{
/* type: device-to-host; recipient = device, interface, endpoint
* value: 0
* index: zero interface endpoint
* len: 2; data = status
*/
if ((0 == value.w) && (2 == len.w))
{
tbl[0] = 0;
tbl[1] = 0;
/* Check request type */
switch (priv->ctrl.type & USB_REQ_RECIPIENT_MASK)
{
case USB_REQ_RECIPIENT_ENDPOINT:
{
/* Endpoint number */
ep = (uint16_t)(index.w & USB_EPNUMFIELD);
/* Endpoint 0 */
if (0 == ep)
{
buf = hw_usb_read_dcpctr();
if ((uint16_t)0 != (buf & USB_PID_STALL))
{
/* Halt set */
tbl[0] = USB_GS_HALT;
}
/* Control read start */
usb_pstd_ctrl_read((uint32_t)2, tbl);
}
/* EP1 to max */
else if (ep <= USB_MAX_EP_NO)
{
if (USB_TRUE == usb_pstd_chk_configured())
{
pipe =
usb_pstd_epadr2pipe(g_usb_pstd_req_index);
if (USB_ERROR == pipe)
{
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall_pipe0();
}
else
{
buf = usb_cstd_get_pid(pipe);
if ((uint16_t)0 != (buf & USB_PID_STALL))
{
/* Halt set */
tbl[0] = USB_GS_HALT;
}
/* Control read start */
usb_pstd_ctrl_read((uint32_t)2, tbl);
}
}
else
{
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall_pipe0();
}
break;
case USB_REQ_RECIPIENT_DEVICE:
{
if (0 == index.w)
{
/* Self powered / Bus powered */
tbl[0] = usb_pstd_get_current_power();
/* Support remote wakeup ? */
if (USB_TRUE == g_usb_pstd_remote_wakeup)
{
tbl[0] |= USB_GS_REMOTEWAKEUP;
}
/* Control read start */
usb_pstd_ctrl_read((uint32_t)2, tbl);
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
break;
case USB_REQ_RECIPIENT_INTERFACE:
{
if (USB_TRUE == usb_pstd_chk_configured())
{
/* 2 is number of interfaces,
* as configured by class driver
*/
if (g_usb_pstd_req_index < 2)
{
/* Control read start */
usb_pstd_ctrl_read((uint32_t)2, tbl);
}
else
{
/* Request error (not exist interface) */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
break;
default:
{
usb_pstd_set_stall_pipe0();
}
break;
}
}
}
}
break;
case USB_REQ_CLEARFEATURE:
{
/* type: host-to-device; recipient = device, interface or endpoint
* value: feature selector
* index: zero interface endpoint;
* len: zero, data = none
*/
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_CLEARFEATURE),
priv->ctrl.type);
if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) !=
USB_REQ_RECIPIENT_ENDPOINT)
{
/* Let the class implementation handle all recipients
* (except for the endpoint recipient)
*/
rx65n_dispatchrequest(priv);
}
else
{
/* Endpoint recipient */
epno = USB_EPNO(index.b[LSB]);
if (USB_ENDPOINT_HALT == value.w)
{
/* EP0 */
if (0 == epno)
{
/* Stall clear */
usb_cstd_clr_stall((uint16_t)USB_PIPE0);
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
/* EP1 to max */
else if (epno <= USB_MAX_EP_NO)
{
pipe = usb_pstd_epadr2pipe(index.w);
if (USB_ERROR == pipe)
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
else
{
if (USB_PID_BUF == usb_cstd_get_pid(pipe))
{
usb_cstd_set_nak(pipe);
/* SQCLR=1 */
hw_usb_set_sqclr(pipe);
/* Set pipe PID_BUF */
usb_cstd_set_buf(pipe);
}
else
{
usb_cstd_clr_stall(pipe);
/* SQCLR=1 */
hw_usb_set_sqclr(pipe);
}
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
}
}
break;
case USB_REQ_SETFEATURE:
{
/* type: host-to-device; recipient = device, interface, endpoint
* value: feature selector
* index: zero interface endpoint;
* len: 0; data = none
*/
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_SETFEATURE),
priv->ctrl.type);
if (((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_DEVICE) && value.w == USB_FEATURE_TESTMODE)
{
/* Special case recipient=device test mode */
uinfo ("test mode: %d\n", index.w);
}
else if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) !=
USB_REQ_RECIPIENT_ENDPOINT)
{
/* The class driver handles all recipients
* except recipient=endpoint
*/
rx65n_dispatchrequest(priv);
}
else
{
/* Handler recipient=endpoint */
epno = USB_EPNO(index.b[LSB]);
if (USB_ENDPOINT_HALT == value.w)
{
/* EP0 */
if (0 == epno)
{
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
/* EP1 to max */
else if (epno <= USB_MAX_EP_NO)
{
pipe = usb_pstd_epadr2pipe(index.w);
if (USB_ERROR == pipe)
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
else
{
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall(pipe);
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
}
break;
case USB_REQ_SETADDRESS:
{
/* type: host-to-device; recipient = device
* value: device address
* index: 0
* len: 0; data = none
*/
if ((0 == index.w) && (0 == len.w))
{
if (value.w <= 127)
{
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
break;
case USB_REQ_GETDESCRIPTOR:
case USB_REQ_SETDESCRIPTOR:
/* type: host-to-device; recipient = device
* value: descriptor type and index
* index: 0 or language ID;
* len: descriptor len; data = descriptor
*/
{
uinfo("Get Descriptor Request Got from Host");
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_GETCONFIG),
priv->ctrl.type);
/* The request seems valid... let the class
* implementation handle it
*/
rx65n_dispatchrequest(priv);
}
break;
case USB_REQ_GETCONFIGURATION:
/* type: device-to-host; recipient = device
* value: 0;
* index: 0;
* len: 1; data = configuration value
*/
case USB_REQ_SETCONFIGURATION:
/* type: host-to-device; recipient = device
* value: configuration value
* index: 0;
* len: 0; data = none
*/
{
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_SETCONFIG), 0);
if ((priv->ctrl.type & USB_REQ_RECIPIENT_MASK) ==
USB_REQ_RECIPIENT_DEVICE)
{
rx65n_dispatchrequest(priv);
}
else
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_BADSETCONFIG), 0);
priv->stalled = 1;
}
}
break;
case USB_REQ_GETINTERFACE:
/* type: device-to-host; recipient = interface
* value: 0
* index: interface;
* len: 1; data = alt interface
*/
case USB_REQ_SETINTERFACE:
/* type: host-to-device; recipient = interface
* value: alternate setting
* index: interface;
* len: 0; data = none
*/
{
/* Let the class implementation handle the request */
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_GETSETIF),
priv->ctrl.type);
rx65n_dispatchrequest(priv);
}
break;
case USB_REQ_SYNCHFRAME:
/* type: device-to-host; recipient = endpoint
* value: 0
* index: endpoint;
* len: 2; data = frame number
*/
{
usbtrace(TRACE_INTDECODE(RX65N_TRACEINTID_SYNCHFRAME), 0);
}
break;
default:
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDCTRLREQ),
priv->ctrl.req);
priv->ep0state = EP0STATE_STALLED;
}
break;
}
}
/****************************************************************************
* Name: usb_pstd_pipe2fport
*
* Description:
* Get Pipe Number to FIFO port address
*
****************************************************************************/
uint16_t usb_pstd_pipe2fport(uint16_t pipe)
{
uint16_t fifo_mode = USB_CUSE;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_NULL; /* Error */
}
return fifo_mode;
}
/****************************************************************************
* Name: hw_usb_write_pipeperi
*
* Description:
* Write to PIPE PERI register
*
****************************************************************************/
static void hw_usb_write_pipeperi(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_PIPEPERI);
}
/****************************************************************************
* Name: usb_cstd_pipe_init
*
* Description:
* Pipe initialization
*
****************************************************************************/
static void usb_cstd_pipe_init(uint16_t pipe, uint16_t pipe_cfg,
uint16_t maxpacket)
{
uint16_t pipe_peri = 0;
/* Interrupt Disable */
/* Ready Int Disable */
hw_usb_clear_brdyenb(pipe);
/* NotReady Int Disable */
hw_usb_clear_nrdyenb(pipe);
/* Empty/SizeErr Int Disable */
hw_usb_clear_bempenb(pipe);
/* PID=NAK & clear STALL */
usb_cstd_clr_stall(pipe);
/* PIPE Configuration */
hw_usb_write_pipesel(pipe);
hw_usb_write_pipecfg(pipe_cfg);
hw_usb_write_pipemaxp(maxpacket);
hw_usb_write_pipeperi(pipe_peri);
/* FIFO buffer DATA-PID initialized */
hw_usb_write_pipesel(USB_PIPE0);
/* SQCLR */
hw_usb_set_sqclr(pipe);
/* ACLRM */
usb_cstd_do_aclrm(pipe);
/* Interrupt status clear */
/* Ready Int Clear */
hw_usb_clear_sts_brdy(pipe);
/* NotReady Int Clear */
hw_usb_clear_status_nrdy(pipe);
/* Empty/SizeErr Int Clear */
hw_usb_clear_status_bemp(pipe);
}
/****************************************************************************
* Name: usb_pstd_set_pipe_reg
*
* Description:
* Set Pipe Register
*
****************************************************************************/
void usb_pstd_set_pipe_reg(uint16_t pipe_no, uint16_t pipe_cfgint,
uint16_t pipe_cfgbulkin,
uint16_t pipe_cfgbulkout, uint16_t maxpacket)
{
/* Search use pipe block */
/* WAIT_LOOP */
/* Initialization of registers associated with specified pipe. */
if (pipe_no == BULK_IN_PIPE)
{
usb_cstd_pipe_init(pipe_no, pipe_cfgbulkin, maxpacket);
}
else if (pipe_no == INT_IN_PIPE)
{
usb_cstd_pipe_init(pipe_no, pipe_cfgint, maxpacket);
}
else sif (pipe_no == BULK_OUT_PIPE)
{
usb_cstd_pipe_init(pipe_no, pipe_cfgbulkout, maxpacket);
}
}
/****************************************************************************
* Endpoint Methods
****************************************************************************/
/****************************************************************************
* Name: rx65n_epconfigure
*
* 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 is the last endpoint to be configured. Some
* hardware needs to take special action when all of the endpoints
* have been configured.
*
****************************************************************************/
static int rx65n_epconfigure(struct usbdev_ep_s *ep,
const struct usb_epdesc_s *desc, bool last)
{
uint16_t maxpacket;
uint8_t epno;
uint16_t pipe_no = 0;
uint16_t pipe_cfg_int = 0;
uint16_t pipe_cfg_bulkin = 0;
uint16_t pipe_cfg_bulkout = 0;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep || !desc)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
printf("ERROR: ep=%p desc=%p\n", ep, desc);
return -EINVAL;
}
#endif
/* Get the unadorned endpoint address */
epno = USB_EPNO(desc->addr);
usbtrace(TRACE_EPCONFIGURE, (uint16_t)epno);
DEBUGASSERT(epno == USB_EPNO(ep->eplog));
/* Set the requested type */
switch (desc->attr & USB_EP_ATTR_XFERTYPE_MASK)
{
case USB_EP_ATTR_XFER_INT: /* Interrupt endpoint */
if (USB_ISEPIN(desc->addr) && epno == INT_IN_EPNUM)
{
/* The full, logical EP number includes direction */
ep->eplog = USB_EPIN(epno);
pipe_no = INT_IN_PIPE;
pipe_cfg_int = (uint16_t)(USB_TYPFIELD_INT | USB_DIR_P_IN |
epno);
}
if (USB_ISEPOUT(desc->addr))
{
/* The full, logical EP number includes direction */
ep->eplog = USB_EPOUT(epno);
pipe_no = INT_OUT_PIPE;
pipe_cfg_int = (uint16_t)(USB_TYPFIELD_INT | USB_DIR_P_OUT |
epno);
}
break;
case USB_EP_ATTR_XFER_BULK: /* Bulk endpoint */
if (USB_ISEPIN(desc->addr) && epno == BULK_IN_EPNUM)
{
/* The full, logical EP number includes direction */
ep->eplog = USB_EPIN(epno);
pipe_no = BULK_IN_PIPE;
pipe_cfg_bulkin = (uint16_t)(USB_TYPFIELD_BULK | USB_CFG_DBLB |
USB_DIR_P_IN | epno);
}
if (USB_ISEPOUT(desc->addr))
{
/* The full, logical EP number includes direction */
ep->eplog = USB_EPOUT(epno);
pipe_no = BULK_OUT_PIPE;
pipe_cfg_bulkout = (uint16_t)(USB_TYPFIELD_BULK | USB_CFG_DBLB |
USB_SHTNAKFIELD | USB_DIR_P_OUT |
epno);
}
break;
case USB_EP_ATTR_XFER_ISOC: /* Isochronous endpoint */
/* Not Supported */
break;
case USB_EP_ATTR_XFER_CONTROL: /* Control endpoint */
hw_usb_write_dcpcfg(0);
hw_usb_write_dcpmxps(USB_DCPMAXP);
break;
default:
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_BADEPTYPE),
(uint16_t)desc->type);
return -EINVAL;
}
maxpacket = GETUINT16(desc->mxpacketsize);
hw_usb_write_pipemaxp(maxpacket);
ep->maxpacket = maxpacket;
hw_usb_write_dcpmxps(USB_DCPMAXP);
usb_pstd_set_pipe_reg(pipe_no, pipe_cfg_int, pipe_cfg_bulkin,
pipe_cfg_bulkout, maxpacket);
return OK;
}
/****************************************************************************
* Name: rx65n_epdisable
*
* Description:
* The endpoint will no longer be used
*
****************************************************************************/
static int rx65n_epdisable(struct usbdev_ep_s *ep)
{
struct rx65n_ep_s *privep = (struct rx65n_ep_s *)ep;
irqstate_t flags;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
uerr("ERROR: ep=%p\n", ep);
return -EINVAL;
}
#endif
/* Cancel any ongoing activity */
flags = enter_critical_section();
rx65n_cancelrequests(privep);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: rx65n_epallocreq
*
* Description:
* Allocate an I/O request
*
****************************************************************************/
static struct usbdev_req_s *rx65n_epallocreq(struct usbdev_ep_s *ep)
{
struct rx65n_req_s *privreq;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return NULL;
}
#endif
usbtrace(TRACE_EPALLOCREQ, USB_EPNO(ep->eplog));
privreq = kmm_malloc(sizeof(struct rx65n_req_s));
if (!privreq)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_ALLOCFAIL), 0);
return NULL;
}
memset(privreq, 0, sizeof(struct rx65n_req_s));
return &privreq->req;
}
/****************************************************************************
* Name: rx65n_epfreereq
*
* Description:
* Free an I/O request
*
****************************************************************************/
static void rx65n_epfreereq(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
{
struct rx65n_req_s *privreq = (struct rx65n_req_s *)req;
#ifdef CONFIG_DEBUG_FEATURES
if (!ep || !req)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return;
}
#endif
usbtrace(TRACE_EPFREEREQ, USB_EPNO(ep->eplog));
kmm_free(privreq);
}
/****************************************************************************
* Name: rx65n_epsubmit
*
* Description:
* Submit an I/O request to the endpoint
*
****************************************************************************/
static int rx65n_epsubmit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
{
struct rx65n_req_s *privreq = (struct rx65n_req_s *)req;
struct rx65n_ep_s *privep = (struct rx65n_ep_s *)ep;
struct rx65n_usbdev_s *priv;
irqstate_t flags;
uint8_t epno;
int ret = OK;
#ifdef CONFIG_DEBUG_FEATURES
if (!req || !req->callback || !req->buf || !ep)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
printf("ERROR: req=%p callback=%p buf=%p ep=%p\n",
req, req->callback, req->buf, ep);
return -EINVAL;
}
#endif
usbtrace(TRACE_EPSUBMIT, USB_EPNO(ep->eplog));
priv = privep->dev;
#ifdef CONFIG_DEBUG_FEATURES
if (!priv->driver)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_NOTCONFIGURED),
priv->usbdev.speed);
printf("ERROR: driver=%p\n", priv->driver);
return -ESHUTDOWN;
}
#endif
/* Handle the request from the class driver */
epno = USB_EPNO(ep->eplog);
req->result = -EINPROGRESS;
req->xfrd = 0;
flags = enter_critical_section();
/* If we are stalled, then drop all requests on the floor */
if (privep->stalled)
{
rx65n_abortrequest(privep, privreq, -EBUSY);
printf("ERROR: stalled\n");
ret = -EBUSY;
}
/* Handle IN (device-to-host) requests. NOTE: If the class device is
* using the bi-directional EP0, then we assume that they intend the EP0
* IN functionality.
*/
else if (epno == EP0)
{
/* Add the new request to the request queue for the IN endpoint */
usbtrace(TRACE_INREQQUEUED(epno), req->len);
rx65n_rqenqueue(privep, privreq);
if (priv->ep0state == EP0STATE_RDREQUEST)
{
privreq->req.len = CDC_CLASS_DATA_LENGTH;
rx65n_rdrequest(epno, priv, privep);
leave_critical_section(flags);
return OK;
}
/* If the IN endpoint FIFO is available, then transfer the data now */
if (!privep->txbusy)
{
ret = rx65n_wrrequest(epno, priv, privep);
leave_critical_section(flags);
return OK;
}
}
else if (USB_ISEPIN(ep->eplog) || epno == EP0)
{
/* Add the new request to the request queue for the IN endpoint */
usbtrace(TRACE_INREQQUEUED(epno), req->len);
rx65n_rqenqueue(privep, privreq);
if (priv->ep0state == EP0STATE_RDREQUEST)
{
rx65n_rdrequest(epno, priv, privep);
leave_critical_section(flags);
return OK;
}
/* If the IN endpoint FIFO is available, then transfer the data now */
if (!privep->txbusy)
{
ret = rx65n_wrrequest(epno, priv, privep);
}
}
/* Handle OUT (host-to-device) requests */
else
{
/* Add the new request to the request queue for the OUT endpoint */
privep->txnullpkt = 0;
rx65n_rqenqueue(privep, privreq);
usbtrace(TRACE_OUTREQQUEUED(epno), req->len);
/* This there a incoming data pending the availability of a request? */
/* This there a incoming data pending the availability of a request? */
if (priv->rxpending > 0)
{
ret = rx65n_rdrequest(epno, priv, privep);
priv->rxpending--;
}
}
leave_critical_section(flags);
return ret;
}
/****************************************************************************
* Name: rx65n_cancelrequests
****************************************************************************/
static void rx65n_cancelrequests(struct rx65n_ep_s *privep)
{
while (!rx65n_rqempty(privep))
{
usbtrace(TRACE_COMPLETE(USB_EPNO(privep->ep.eplog)),
(rx65n_rqpeek(privep))->req.xfrd);
rx65n_reqcomplete(privep, -ESHUTDOWN);
}
}
/****************************************************************************
* Name: rx65n_epcancel
*
* Description:
* Cancel an I/O request previously sent to an endpoint
*
****************************************************************************/
static int rx65n_epcancel(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
{
struct rx65n_ep_s *privep = (struct rx65n_ep_s *)ep;
irqstate_t flags;
#ifdef CONFIG_DEBUG_USB
if (!ep || !req)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
usbtrace(TRACE_EPCANCEL, USB_EPNO(ep->eplog));
flags = enter_critical_section();
rx65n_cancelrequests(privep);
leave_critical_section(flags);
return OK;
}
/****************************************************************************
* Name: rx65n_epreserve
****************************************************************************/
static inline struct rx65n_ep_s *rx65n_epreserve(struct rx65n_usbdev_s *priv,
uint8_t epset)
{
struct rx65n_ep_s *privep = NULL;
irqstate_t flags;
int epndx = 0;
flags = enter_critical_section();
epset &= priv->epavail;
if (epset)
{
/* Select the lowest bit in the set of matching, available endpoints
* (skipping EP0)
*/
for (epndx = 1; epndx < RX65N_NENDPOINTS; epndx++)
{
uint8_t bit = RX65N_ENDP_BIT(epndx);
if ((epset & bit) != 0)
{
/* Mark the endpoint no longer available */
priv->epavail &= ~bit;
/* And return the pointer to the standard endpoint structure */
privep = &priv->eplist[epndx];
break;
}
}
}
leave_critical_section(flags);
return privep;
}
/****************************************************************************
* Device Methods
****************************************************************************/
/****************************************************************************
* Name: rx65n_allocep
*
* 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 *rx65n_allocep(struct usbdev_s *dev, uint8_t epno,
bool in, uint8_t eptype)
{
struct rx65n_usbdev_s *priv = (struct rx65n_usbdev_s *)dev;
struct rx65n_ep_s *privep = NULL;
uint8_t epset = RX65N_ENDP_ALLSET;
usbtrace(TRACE_DEVALLOCEP, (uint16_t)epno);
#ifdef CONFIG_DEBUG_USB
if (!dev)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return NULL;
}
#endif
/* Ignore any direction bits in the logical address */
epno = USB_EPNO(epno);
/* A logical address of 0 means that any endpoint will do */
if (epno > 0)
{
/* Otherwise, we will return the endpoint structure only
* for the 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 (epno >= RX65N_NENDPOINTS)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_BADEPNO), (uint16_t)epno);
return NULL;
}
/* Convert the logical address to a physical OUT endpoint address and
* remove all of the candidate endpoints from the bitset except for the
* the IN/OUT pair for this logical address.
*/
epset = RX65N_ENDP_BIT(epno);
}
/* Check if the selected endpoint number is available */
privep = rx65n_epreserve(priv, epset);
if (!privep)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_EPRESERVE), (uint16_t)epset);
goto errout;
}
return &privep->ep;
errout:
return NULL;
}
/****************************************************************************
* Name: rx65n_epunreserve
****************************************************************************/
static inline void
rx65n_epunreserve(struct rx65n_usbdev_s *priv, struct rx65n_ep_s *privep)
{
irqstate_t flags = enter_critical_section();
priv->epavail |= RX65N_ENDP_BIT(USB_EPNO(privep->ep.eplog));
leave_critical_section(flags);
}
/****************************************************************************
* Name: rx65n_freeep
*
* Description:
* Free the previously allocated endpoint
*
****************************************************************************/
static void rx65n_freeep(struct usbdev_s *dev, struct
usbdev_ep_s *ep)
{
struct rx65n_usbdev_s *priv;
struct rx65n_ep_s *privep;
#ifdef CONFIG_DEBUG_USB
if (!dev || !ep)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return;
}
#endif
priv = (struct rx65n_usbdev_s *)dev;
privep = (struct rx65n_ep_s *)ep;
usbtrace(TRACE_DEVFREEEP, (uint16_t)USB_EPNO(ep->eplog));
if (priv && privep)
{
/* Mark the endpoint as available */
rx65n_epunreserve(priv, privep);
}
}
/****************************************************************************
* Name: rx65n_getframe
*
* Description:
* Returns the current frame number
*
****************************************************************************/
static int rx65n_getframe(struct usbdev_s *dev)
{
int regval;
regval = (rx65n_getreg16(RX65N_USB_FRMNUM) & RX65N_USB_FRMNUM_VAL);
return regval;
}
/****************************************************************************
* Name: rx65n_wakeup
*
* Description:
* Tries to wake up the host connected to this device
*
****************************************************************************/
static int rx65n_wakeup(struct usbdev_s *dev)
{
uint16_t regval;
regval = rx65n_getreg16 (RX65N_USB_INTENB0);
regval |= RX65N_USB_INTENB0_RSME;
rx65n_putreg16(regval, RX65N_USB_INTENB0);
return OK;
}
/****************************************************************************
* Name: rx65n_selfpowered
*
* Description:
* Sets/clears the device selfpowered feature
*
****************************************************************************/
static int rx65n_selfpowered(struct usbdev_s *dev, bool selfpowered)
{
#ifdef CONFIG_USBDEV_SELFPOWERED
struct rx65n_usbdev_s *priv = (struct rx65n_usbdev_s *)dev;
usbtrace(TRACE_DEVSELFPOWERED, (uint16_t)selfpowered);
#ifdef CONFIG_DEBUG_USB
if (!dev)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return -ENODEV;
}
#endif
priv->selfpowered = selfpowered;
return OK;
#else
/* Do Nothing for bus powered configuration */
return OK;
#endif
}
/****************************************************************************
* Name: rx65n_pullup
*
* Description:
* Software-controlled connect to/disconnect from USB host
*
****************************************************************************/
int rx65n_pullup(struct usbdev_s *dev, bool enable)
{
uint16_t regval;
/* Disable DRPD bit in SYSCFG register */
regval = rx65n_getreg16(RX65N_USB_SYSCFG);
regval &= ~(RX65N_USB_SYSCFG_DRPD);
rx65n_putreg16(regval, RX65N_USB_SYSCFG);
return OK;
}
/****************************************************************************
* Name: usb_pstd_attach_process
*
* Description:
* Set the DPRPU bit
*
****************************************************************************/
void usb_pstd_attach_process(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_SYSCFG);
regval |= (RX65N_USB_SYSCFG_DPRPU);
rx65n_putreg16(regval, RX65N_USB_SYSCFG);
}
/****************************************************************************
* Name: hw_usb_pclear_dprpu
*
* Description:
* Clear the DPRPU bit
*
****************************************************************************/
void hw_usb_pclear_dprpu(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_SYSCFG);
regval &= ~(RX65N_USB_SYSCFG_DPRPU);
rx65n_putreg16(regval, RX65N_USB_SYSCFG);
}
/****************************************************************************
* Name: hw_usb_clear_aclrm
*
* Description:
* Clear ACLRM bit
*
****************************************************************************/
static void hw_usb_clear_aclrm(uint16_t pipeno)
{
uint16_t *p_reg;
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + (pipeno - 1);
(*p_reg) &= (~USB_ACLRM);
}
/****************************************************************************
* Name: hw_usb_set_aclrm
*
* Description:
* Set ACLRM bit
*
****************************************************************************/
static void hw_usb_set_aclrm(uint16_t pipeno)
{
uint16_t *p_reg;
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + (pipeno - 1);
(*p_reg) |= USB_ACLRM;
}
/****************************************************************************
* Name: usb_cstd_do_aclrm
*
* Description:
* Control ACLRM bit
*
****************************************************************************/
static void usb_cstd_do_aclrm(uint16_t pipe)
{
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* Control ACLRM */
hw_usb_set_aclrm(pipe);
hw_usb_clear_aclrm(pipe);
}
/****************************************************************************
* Name: hw_usb_set_curpipe
*
* Description:
* Set Current Pipe
*
****************************************************************************/
static void hw_usb_set_curpipe(uint16_t pipemode, uint16_t pipeno)
{
uint16_t *p_reg;
uint16_t reg;
p_reg = hw_usb_get_fifosel_adr(pipemode);
reg = *p_reg;
if ((USB_D0USE == pipemode) || (USB_D1USE == pipemode))
{
reg &= (~USB_DREQE);
}
reg &= (~USB_CURPIPE);
*p_reg = reg;
/* WAIT_LOOP */
while (0 != ((*p_reg) & USB_CURPIPE))
{
/* Wait Clear CURPIPE */
}
reg |= pipeno;
*p_reg = reg;
}
/****************************************************************************
* Name: hw_usb_rmw_fifosel
*
* Description:
* Clear FIFOSEL bit
*
****************************************************************************/
static void hw_usb_rmw_fifosel(uint16_t pipemode, uint16_t data,
uint16_t bitptn)
{
uint16_t buf;
uint16_t *p_reg;
p_reg = (uint16_t *)hw_usb_get_fifosel_adr(pipemode);
buf = *p_reg;
buf &= (~bitptn);
buf |= (data & bitptn);
*p_reg = buf;
}
/****************************************************************************
* Name: usb_cstd_chg_curpipe
*
* Description:
* Current Pipe Check
*
****************************************************************************/
static void usb_cstd_chg_curpipe(uint16_t pipe, uint16_t fifosel,
uint16_t isel)
{
uint16_t buf;
/* Select FIFO */
switch (fifosel)
{
/* CFIFO use */
case USB_CUSE:
/* ISEL=1, CURPIPE=0 */
hw_usb_rmw_fifosel(USB_CUSE, ((USB_RCNT | isel) | pipe),
((USB_RCNT | USB_ISEL) | USB_CURPIPE));
break;
/* D0FIFO use */
case USB_D0USE:
/* D1FIFO use */
case USB_D1USE:
/* DxFIFO pipe select */
hw_usb_set_curpipe(fifosel, pipe);
/* WAIT_LOOP */
do
{
buf = hw_usb_read_fifosel(fifosel);
}
while ((uint16_t)(buf & USB_CURPIPE) != pipe);
break;
default:
break;
}
}
/****************************************************************************
* Name: hw_usb_get_fifosel_adr
*
* Description:
* Get FIFOSEL register address
*
****************************************************************************/
static void *hw_usb_get_fifosel_adr(uint16_t pipemode)
{
void *p_reg = NULL;
switch (pipemode)
{
case USB_CUSE:
p_reg = (void *)RX65N_USB_CFIFOSEL;
break;
case USB_D0USE:
p_reg = (void *)RX65N_USB_D0FIFOSEL;
break;
case USB_D1USE:
p_reg = (void *)RX65N_USB_D1FIFOSEL;
break;
default:
break;
}
return p_reg;
}
/****************************************************************************
* Name: hw_usb_read_fifosel
*
* Description:
* Read FIFOSEL Register
*
****************************************************************************/
static uint16_t hw_usb_read_fifosel(uint16_t pipemode)
{
uint16_t *p_reg;
p_reg = (uint16_t *)hw_usb_get_fifosel_adr(pipemode);
return *p_reg;
}
/****************************************************************************
* Name: hw_usb_set_trclr
*
* Description:
* Set Transaction Clear bit
*
****************************************************************************/
static void hw_usb_set_trclr(uint16_t pipeno)
{
uint16_t *p_reg;
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + ((pipeno - 1) * 2);
(*p_reg) |= USB_TRCLR;
}
/****************************************************************************
* Name: hw_usb_clear_trenb
*
* Description:
* Clear Transaction Enable
*
****************************************************************************/
static void hw_usb_clear_trenb(uint16_t pipeno)
{
uint16_t *p_reg;
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + ((pipeno - 1) * 2);
(*p_reg) &= (~USB_TRENB);
}
/****************************************************************************
* Name: usb_cstd_clr_transaction_counter
*
* Description:
* Clear Transaction Counter
*
****************************************************************************/
static void usb_cstd_clr_transaction_counter(uint16_t trnreg)
{
hw_usb_clear_trenb(trnreg);
hw_usb_set_trclr(trnreg);
}
/****************************************************************************
* Name: hw_usb_clear_bempenb
*
* Description:
* Clear BEMPENB
*
****************************************************************************/
static void hw_usb_clear_bempenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_BEMPENB);
regval &= (~(1 << pipeno));
rx65n_putreg16(regval, RX65N_USB_BEMPENB);
}
/****************************************************************************
* Name: hw_usb_clear_nrdyenb
*
* Description:
* Clear NRDYENB
*
****************************************************************************/
static void hw_usb_clear_nrdyenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_NRDYENB);
regval &= (~(1 << pipeno));
rx65n_putreg16(regval, RX65N_USB_NRDYENB);
}
/****************************************************************************
* Name: hw_usb_clear_brdyenb
*
* Description:
* Clear BRDYENB
*
****************************************************************************/
static void hw_usb_clear_brdyenb(uint16_t pipeno)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_BRDYENB);
regval &= (~(1 << pipeno));
rx65n_putreg16(regval, RX65N_USB_BRDYENB);
}
/****************************************************************************
* Name: hw_usb_read_pipectr
*
* Description:
* Read PIPECTR
*
****************************************************************************/
static uint16_t hw_usb_read_pipectr(uint16_t pipeno)
{
uint16_t *p_reg;
if (USB_PIPE0 == pipeno)
{
p_reg = (uint16_t *)RX65N_USB_DCPCTR;
}
else
{
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + (pipeno - 1);
}
return *p_reg;
}
/****************************************************************************
* Name: hw_usb_clear_pid
*
* Description:
* Clear pid
*
****************************************************************************/
static void hw_usb_clear_pid(uint16_t pipeno, uint16_t data)
{
uint16_t *p_reg;
if (USB_PIPE0 == pipeno)
{
p_reg = (uint16_t *)RX65N_USB_DCPCTR;
}
else
{
p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR) + (pipeno - 1);
}
(*p_reg) &= (~data);
}
/****************************************************************************
* Name: usb_cstd_set_nak
*
* Description:
* Set NAK
*
****************************************************************************/
static void usb_cstd_set_nak(uint16_t pipe)
{
uint16_t buf;
uint16_t n;
/* Set NAK */
hw_usb_clear_pid(pipe, (uint16_t)USB_PID_BUF);
/* The state of PBUSY continues while transmitting
* the packet when it is a detach.
*/
/* 1ms comes off when leaving because the packet
* duration might not exceed 1ms.
*/
/* Whether it is PBUSY release or
* 1ms passage can be judged.
*/
/* WAIT_LOOP */
for (n = 0; n < 0xffff; ++n)
{
/* PIPE control reg read */
buf = hw_usb_read_pipectr(pipe);
if (0 == (uint16_t)(buf & USB_PBUSY))
{
n = 0xfffe;
}
}
}
/****************************************************************************
* Name: usb_pstd_forced_termination
*
* Description:
* Clear the buffer data
*
****************************************************************************/
void usb_pstd_forced_termination(uint16_t pipe, uint16_t status)
{
uint16_t buf;
/* PID = NAK */
/* Set NAK */
usb_cstd_set_nak(pipe);
/* Disable Interrupt */
/* Disable Ready Interrupt */
hw_usb_clear_brdyenb(pipe);
/* Disable Not Ready Interrupt */
hw_usb_clear_nrdyenb(pipe);
/* Disable Empty Interrupt */
hw_usb_clear_bempenb(pipe);
usb_cstd_clr_transaction_counter(pipe);
/* Clear CFIFO-port */
buf = hw_usb_read_fifosel(USB_CUSE);
if ((buf & USB_CURPIPE) == pipe)
{
/* Changes the FIFO port by the pipe. */
usb_cstd_chg_curpipe((uint16_t)USB_PIPE0, (uint16_t)USB_CUSE,
USB_FALSE);
}
/* Do Aclr */
usb_cstd_do_aclrm(pipe);
}
/****************************************************************************
* Name: usb_cstd_clr_stall
*
* Description:
* Clear Stall
*
****************************************************************************/
static void usb_cstd_clr_stall(uint16_t pipe)
{
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
/* Set NAK */
usb_cstd_set_nak(pipe);
/* Clear STALL */
hw_usb_clear_pid(pipe, USB_PID_STALL);
}
/****************************************************************************
* Name: hw_usb_write_pipesel
*
* Description:
* Write to PIPESEL register
*
****************************************************************************/
static void hw_usb_write_pipesel(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_PIPESEL);
}
/****************************************************************************
* Name: hw_usb_write_pipecfg
*
* Description:
* Write to PIPECFG register
*
****************************************************************************/
static void hw_usb_write_pipecfg(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_PIPECFG);
}
/****************************************************************************
* Name: hw_usb_write_pipemaxp
*
* Description:
* Write to PIPEMAXP register
*
****************************************************************************/
static void hw_usb_write_pipemaxp(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_PIPEMAXP);
}
/****************************************************************************
* Name: hw_usb_write_pipeperi
*
* Description:
* Write to PIPEPERI register
*
****************************************************************************/
/****************************************************************************
* Name: hw_usb_set_sqclr
*
* Description:
* Write to SQCLR register
*
****************************************************************************/
static void hw_usb_set_sqclr(uint16_t pipeno)
{
uint16_t *p_reg;
uint16_t regval;
if (USB_PIPE0 == pipeno)
{
regval = rx65n_getreg16(RX65N_USB_DCPCTR);
regval |= USB_SQCLR;
rx65n_putreg16(regval, RX65N_USB_DCPCTR);
}
else
{
p_reg = ((uint16_t *)RX65N_USB_PIPE1CTR + (pipeno - 1));
(*p_reg) |= USB_SQCLR;
}
}
/****************************************************************************
* Name: hw_usb_clear_sts_brdy
*
* Description:
* Clear BRDY status
*
****************************************************************************/
static void hw_usb_clear_sts_brdy(uint16_t pipeno)
{
rx65n_putreg16((~(1 << pipeno)) & RX65N_USB_PIPE_ALL,
RX65N_USB_BRDYSTS);
}
/****************************************************************************
* Name: hw_usb_clear_status_nrdy
*
* Description:
* Clear NRDY status
*
****************************************************************************/
static void hw_usb_clear_status_nrdy(uint16_t pipeno)
{
rx65n_putreg16((~(1 << pipeno)) & RX65N_USB_PIPE_ALL,
RX65N_USB_NRDYSTS);
}
/****************************************************************************
* Name: usb_cstd_clr_pipe_cnfg
*
* Description:
* Clear pipe configuration
*
****************************************************************************/
static void usb_cstd_clr_pipe_cnfg(uint16_t pipe_no)
{
/* PID=NAK & clear STALL */
usb_cstd_clr_stall(pipe_no);
/* Interrupt disable */
/* Ready Int Disable */
hw_usb_clear_brdyenb(pipe_no);
/* NotReady Int Disable */
hw_usb_clear_nrdyenb(pipe_no);
/* Empty/SizeErr Int Disable */
hw_usb_clear_bempenb(pipe_no);
/* PIPE Configuration */
usb_cstd_chg_curpipe((uint16_t)USB_PIPE0, (uint16_t)USB_CUSE, USB_FALSE);
hw_usb_write_pipesel(pipe_no);
hw_usb_write_pipecfg(0);
hw_usb_write_pipemaxp(0);
hw_usb_write_pipeperi(0);
hw_usb_write_pipesel(0);
/* FIFO buffer DATA-PID initialized */
/* SQCLR */
hw_usb_set_sqclr(pipe_no);
/* ACLRM */
usb_cstd_do_aclrm(pipe_no);
usb_cstd_clr_transaction_counter(pipe_no);
/* Interrupt status clear */
/* Ready Int Clear */
hw_usb_clear_sts_brdy(pipe_no);
/* NotReady Int Clear */
hw_usb_clear_status_nrdy(pipe_no);
/* Empty/SizeErr Int Clear */
hw_usb_clear_status_bemp(pipe_no);
}
/****************************************************************************
* Name: hw_usb_clear_status_bemp
*
* Description:
* Clear BEMP status
*
****************************************************************************/
static void hw_usb_clear_status_bemp(uint16_t pipeno)
{
rx65n_putreg16((~(1 << pipeno)) & RX65N_USB_PIPE_ALL,
RX65N_USB_BEMPSTS);
}
/****************************************************************************
* Name: usb_pstd_detach_process
*
* Description:
* Set the DPRPU bit
*
****************************************************************************/
void usb_pstd_detach_process(void)
{
int i;
/* Pull-up disable */
hw_usb_pclear_dprpu();
for (i = USB_MIN_PIPE_NO; i < (USB_MAXPIPE_NUM +1); i++)
{
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_STOP);
usb_cstd_clr_pipe_cnfg(i);
}
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_STOP);
usb_cstd_clr_pipe_cnfg(i);
}
/****************************************************************************
* Name: usb_pstd_chk_vbsts
*
* Description:
* USB VBUS Status check
*
****************************************************************************/
uint16_t usb_pstd_chk_vbsts(void)
{
uint16_t buf1;
uint16_t buf2;
uint16_t buf3;
uint16_t connect_info;
/* VBUS chattering cut */
/* WAIT_LOOP */
do
{
buf1 = rx65n_getreg16(RX65N_USB_INTSTS0);
up_udelay(10);
buf2 = rx65n_getreg16(RX65N_USB_INTSTS0);
up_udelay(10);
buf3 = rx65n_getreg16(RX65N_USB_INTSTS0);
}
while (((buf1 & RX65N_USB_INTSTS0_VBSTS) !=
(buf2 & RX65N_USB_INTSTS0_VBSTS)) ||
((buf2 & RX65N_USB_INTSTS0_VBSTS) !=
(buf3 & RX65N_USB_INTSTS0_VBSTS)));
if ((uint16_t)0 != (buf1 & RX65N_USB_INTSTS0_VBSTS))
{
/* Attach */
connect_info = USB_ATTACH;
}
else
{
/* Detach */
connect_info = USB_DETACH;
}
return connect_info;
}
/****************************************************************************
* Name: hw_usb_read_dvstctr
*
* Description:
* Read DVSTCTR register
*
****************************************************************************/
static uint16_t hw_usb_read_dvstctr(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_DVSTCTR0);
return regval;
}
/****************************************************************************
* Name: usb_cstd_port_speed
*
* Description:
* Set Port Speed for USB device
*
****************************************************************************/
uint16_t usb_cstd_port_speed(void)
{
uint16_t buf;
uint16_t conn_inf;
buf = hw_usb_read_dvstctr();
/* Reset handshake status get */
buf = (uint16_t)(buf & USB_RHST);
switch (buf)
{
/* Get port speed */
case USB_HSMODE:
conn_inf = USB_HSCONNECT;
break;
case USB_FSMODE:
conn_inf = USB_FSCONNECT;
break;
case USB_LSMODE:
conn_inf = USB_LSCONNECT;
break;
case USB_HSPROC:
conn_inf = USB_NOCONNECT;
break;
default:
conn_inf = USB_NOCONNECT;
break;
}
return conn_inf;
}
/****************************************************************************
* Name: hw_usb_write_dcpcfg
*
* Description:
* Write to DCPCFG register
*
****************************************************************************/
static void hw_usb_write_dcpcfg(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_DCPCFG);
}
/****************************************************************************
* Name: hw_usb_write_dcpmxps
*
* Description:
* Write to DCPMAXP register
*
****************************************************************************/
static void hw_usb_write_dcpmxps(uint16_t data)
{
rx65n_putreg16(data, RX65N_USB_DCPMAXP);
}
/****************************************************************************
* Name: usb_pstd_bus_reset
*
* Description:
* Bus Reset
*
****************************************************************************/
void usb_pstd_bus_reset(void)
{
struct rx65n_usbdev_s *priv = &g_usbdev;
priv->usbdev.speed = USB_SPEED_FULL;
/* DCP configuration register (0x5C) */
hw_usb_write_dcpcfg(0);
hw_usb_write_dcpmxps(USB_DCPMAXP);
}
/****************************************************************************
* Name: hw_usb_pset_enb_rsme
*
* Description:
* Enable Resume Interrupt
*
****************************************************************************/
void hw_usb_pset_enb_rsme(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_INTENB0);
regval |= USB_RSME;
rx65n_putreg16(regval, RX65N_USB_INTENB0);
}
/****************************************************************************
* Name: hw_usb_read_syssts
*
* Description:
* Read System Status Register
*
****************************************************************************/
static int hw_usb_read_syssts(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_SYSSTS0);
return regval;
}
/****************************************************************************
* Name: hw_usb_pclear_enb_rsme
*
* Description:
* Disable Resume Interrupt
*
****************************************************************************/
void hw_usb_pclear_enb_rsme(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_INTENB0);
regval &= (~USB_RSME);
rx65n_putreg16(regval, RX65N_USB_INTENB0);
}
/****************************************************************************
* Name: hw_usb_pclear_sts_resm
*
* Description:
* Clear Resume state
*
****************************************************************************/
void hw_usb_pclear_sts_resm(void)
{
uint16_t regval;
regval = (uint16_t)(~USB_RESM);
rx65n_putreg16(regval, RX65N_USB_INTSTS0);
}
/****************************************************************************
* Name: usb_pstd_suspend_process
*
* Description:
* Handle Suspend State of USB
*
****************************************************************************/
void usb_pstd_suspend_process(void)
{
/* Resume interrupt enable */
hw_usb_pset_enb_rsme();
hw_usb_pclear_sts_resm();
/* RESM interrupt disable */
hw_usb_pclear_enb_rsme();
}
/****************************************************************************
* Name: hw_usb_pclear_sts_valid
*
* Description:
* Clear Valid Ststus bit
*
****************************************************************************/
void hw_usb_pclear_sts_valid(void)
{
uint16_t regval;
regval = (uint16_t)~USB_VALID;
rx65n_putreg16(regval, RX65N_USB_INTSTS0);
}
/****************************************************************************
* Name: hw_usb_read_usbreq
*
* Description:
* Read USBREQ
*
****************************************************************************/
uint16_t hw_usb_read_usbreq(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_USBREQ);
return regval;
}
/****************************************************************************
* Name: hw_usb_read_usbval
*
* Description:
* Read USBVAL
*
****************************************************************************/
uint16_t hw_usb_read_usbval(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_USBVAL);
return regval;
}
/****************************************************************************
* Name: hw_usb_read_usbindx
*
* Description:
* Read USBINDX
*
****************************************************************************/
uint16_t hw_usb_read_usbindx(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_USBINDX);
return regval;
}
/****************************************************************************
* Name: hw_usb_read_usbleng
*
* Description:
* Read USBLENG
*
****************************************************************************/
uint16_t hw_usb_read_usbleng(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_USBLENG);
return regval;
}
/****************************************************************************
* Name: usb_pstd_save_request
*
* Description:
* Save the request
*
****************************************************************************/
void usb_pstd_save_request(void)
{
/* Valid clear */
hw_usb_pclear_sts_valid();
g_usb_pstd_req_type = hw_usb_read_usbreq();
g_usb_pstd_req_value = hw_usb_read_usbval();
g_usb_pstd_req_index = hw_usb_read_usbindx();
g_usb_pstd_req_length = hw_usb_read_usbleng();
}
/****************************************************************************
* Name: usb_pstd_set_stall
*
* Description:
* Set Stall status
*
****************************************************************************/
void usb_pstd_set_stall(uint16_t pipe)
{
/* PIPE control reg set */
hw_usb_set_pid(pipe, USB_PID_STALL);
}
/****************************************************************************
* Name: hw_usb_set_pid
*
* Description:
* Set PID
*
****************************************************************************/
static void hw_usb_set_pid(uint16_t pipeno, uint16_t data)
{
uint16_t *p_reg;
if (USB_PIPE0 == pipeno)
{
p_reg = ((uint16_t *)(RX65N_USB_DCPCTR));
}
else
{
p_reg = ((uint16_t *)(RX65N_USB_PIPE1CTR)) + ((pipeno - 1));
}
(*p_reg) &= (~USB_PID);
(*p_reg) |= data;
}
/****************************************************************************
* Name: hw_usb_pset_ccpl
*
* Description:
* Set CCPL
*
****************************************************************************/
void hw_usb_pset_ccpl(void)
{
uint16_t regval;
regval = rx65n_getreg16(RX65N_USB_DCPCTR);
regval |= USB_CCPL;
rx65n_putreg16(regval, RX65N_USB_DCPCTR);
}
/****************************************************************************
* Name: usb_pstd_ctrl_end
*
* Description:
* CTRL End
*
****************************************************************************/
void usb_pstd_ctrl_end(uint16_t status)
{
/* Interrupt disable */
/* BEMP0 disable */
hw_usb_clear_bempenb((uint16_t)USB_PIPE0);
/* BRDY0 disable */
hw_usb_clear_brdyenb((uint16_t)USB_PIPE0);
/* NRDY0 disable */
hw_usb_clear_nrdyenb((uint16_t)USB_PIPE0);
hw_usb_set_mbw(USB_CUSE, USB0_CFIFO_MBW);
if ((USB_DATA_ERR == status) || (USB_DATA_OVR == status))
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
else if (USB_DATA_STOP == status)
{
/* Pipe stop */
usb_cstd_set_nak((uint16_t)USB_PIPE0);
}
else
{
/* Set CCPL bit */
hw_usb_pset_ccpl();
}
}
/****************************************************************************
* Name: usb_pstd_set_feature3
*
* Description:
* Handles the set feature request
*
****************************************************************************/
static void usb_pstd_set_feature3(void)
{
uint16_t pipe;
uint16_t ep;
if (0 == g_usb_pstd_req_length)
{
/* check request type */
switch ((g_usb_pstd_req_type & USB_BMREQUESTTYPERECIP))
{
case USB_DEVICE:
switch (g_usb_pstd_req_value)
{
case USB_DEV_REMOTE_WAKEUP:
if (0 == g_usb_pstd_req_index)
{
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
break;
case USB_TEST_MODE:
if (USB_HSCONNECT == usb_cstd_port_speed())
{
if ((g_usb_pstd_req_index < USB_TEST_RESERVED) ||
(USB_TEST_VSTMODES <= g_usb_pstd_req_index))
{
g_usb_pstd_test_mode_flag = USB_TRUE;
g_usb_pstd_test_mode_select = g_usb_pstd_req_index;
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
break;
default:
usb_pstd_set_stall_pipe0();
break;
}
break;
case USB_INTERFACE:
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall_pipe0();
break;
case USB_ENDPOINT:
/* Endpoint number */
ep = (uint16_t)(g_usb_pstd_req_index & USB_EPNUMFIELD);
if (USB_ENDPOINT_HALT == g_usb_pstd_req_value)
{
/* EP0 */
if (0 == ep)
{
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
/* EP1 to max */
else if (ep <= USB_MAX_EP_NO)
{
pipe = usb_pstd_epadr2pipe(g_usb_pstd_req_index);
if (USB_ERROR == pipe)
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
else
{
/* Set pipe USB_PID_STALL */
usb_pstd_set_stall(pipe);
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
break;
default:
/* Request error */
usb_pstd_set_stall_pipe0();
break;
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
/****************************************************************************
* Name: usb_pstd_clr_feature3
*
* Description:
* Handles the clear feature request
*
****************************************************************************/
static void usb_pstd_clr_feature3(void)
{
uint16_t pipe;
uint16_t ep;
if (0 == g_usb_pstd_req_length)
{
/* check request type */
switch ((g_usb_pstd_req_type & USB_BMREQUESTTYPERECIP))
{
case USB_DEVICE:
if ((USB_DEV_REMOTE_WAKEUP == g_usb_pstd_req_value)
&& (0 == g_usb_pstd_req_index))
{
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
break;
case USB_INTERFACE:
/* Request error */
usb_pstd_set_stall_pipe0();
break;
case USB_ENDPOINT:
/* Endpoint number */
ep = (uint16_t)(g_usb_pstd_req_index & USB_EPNUMFIELD);
if (USB_ENDPOINT_HALT == g_usb_pstd_req_value)
{
/* EP0 */
if (0 == ep)
{
/* Stall clear */
usb_cstd_clr_stall((uint16_t)USB_PIPE0);
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
/* EP1 to max */
else if (ep <= USB_MAX_EP_NO)
{
pipe = usb_pstd_epadr2pipe(g_usb_pstd_req_index);
if (USB_ERROR == pipe)
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
else
{
if (USB_PID_BUF == usb_cstd_get_pid(pipe))
{
usb_cstd_set_nak(pipe);
/* SQCLR=1 */
hw_usb_set_sqclr(pipe);
/* Set pipe PID_BUF */
usb_cstd_set_buf(pipe);
}
else
{
usb_cstd_clr_stall(pipe);
/* SQCLR=1 */
hw_usb_set_sqclr(pipe);
}
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
if (USB_TRUE == g_usb_pstd_stall_pipe[pipe])
{
g_usb_pstd_stall_pipe[pipe] = USB_FALSE;
}
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
break;
default:
usb_pstd_set_stall_pipe0();
break;
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
/****************************************************************************
* Name: usb_pstd_set_address3
*
* Description:
* Handles the Set Address request
*
****************************************************************************/
static void usb_pstd_set_address3(void)
{
if (USB_DEVICE == (g_usb_pstd_req_type & USB_BMREQUESTTYPERECIP))
{
if ((0 == g_usb_pstd_req_index) && (0 == g_usb_pstd_req_length))
{
if (g_usb_pstd_req_value <= 127)
{
/* Set pipe PID_BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Not specification */
usb_pstd_set_stall_pipe0();
}
}
else
{
/* Request error */
usb_pstd_set_stall_pipe0();
}
}
/****************************************************************************
* Name: usb_pstd_stand_req3
*
* Description:
* Handle standard request
*
****************************************************************************/
void usb_pstd_stand_req3(void)
{
uint16_t regval;
struct rx65n_usbdev_s *priv = &g_usbdev;
regval = MSBYTE(g_usb_pstd_req_type);
switch (regval)
{
case USB_REQ_CLEARFEATURE:
usb_pstd_clr_feature3();
break;
case USB_REQ_SETFEATURE:
usb_pstd_set_feature3();
break;
case USB_REQ_SETADDRESS:
usb_pstd_set_address3();
break;
case USB_REQ_SETCONFIGURATION:
usb_cstd_set_buf((uint16_t)USB_PIPE0); /* SetConfiguration3 */
break;
case USB_REQ_SETINTERFACE:
/* Let the class implementation handle
* as it requires access and updation of
* Configuration descriptor
*/
rx65n_dispatchrequest(priv);
break;
default:
break;
}
usb_pstd_ctrl_end((uint16_t)USB_CTRL_END); /* Control transfer stop(end) */
}
/****************************************************************************
* Name: usb_pstd_stand_req4
*
* Description:
* Handle standard request
*
****************************************************************************/
void usb_pstd_stand_req4(void)
{
uint16_t regval;
regval = MSBYTE(g_usb_pstd_req_type);
switch (regval)
{
case USB_REQ_GETSTATUS:
usb_cstd_set_buf((uint16_t) USB_PIPE0); /* GetStatus4 */
break;
case USB_REQ_GETDESCRIPTOR:
usb_cstd_set_buf((uint16_t) USB_PIPE0); /* GetDescriptor4 */
break;
case USB_REQ_GETCONFIGURATION:
usb_cstd_set_buf((uint16_t) USB_PIPE0); /* GetConfiguration4 */
break;
case USB_REQ_GETINTERFACE:
usb_cstd_set_buf((uint16_t) USB_PIPE0); /* GetInterface4 */
break;
case USB_REQ_SYNCHFRAME:
usb_cstd_set_buf((uint16_t) USB_PIPE0); /* SynchFrame4 */
break;
default:
break;
}
usb_pstd_ctrl_end((uint16_t)USB_CTRL_END);
}
/****************************************************************************
* Name: usb_peri_class_request
*
* Description:
* Handle Class Request
*
****************************************************************************/
void usb_peri_class_request(uint8_t type, uint16_t ctsq)
{
if ((USB_CLASS == (type & USB_BMREQUESTTYPETYPE)) ||
(USB_VENDOR == (type & USB_BMREQUESTTYPETYPE)))
{
switch (ctsq)
{
case USB_CS_IDST:
case USB_CS_RDDS:
case USB_CS_WRDS:
/* Do Nothing */
break;
case USB_CS_WRND:
usb_pstd_ctrl_end((uint16_t)USB_CTRL_END); /* class request (control write nodata status stage) */
break;
case USB_CS_RDSS:
usb_cstd_set_buf((uint16_t)USB_PIPE0);
usb_pstd_ctrl_end((uint16_t)USB_CTRL_END); /* class request (control read status stage) */
break;
case USB_CS_WRSS:
usb_cstd_set_buf((uint16_t)USB_PIPE0);
usb_pstd_ctrl_end((uint16_t)USB_CTRL_END); /* class request (control write status stage) */
break;
case USB_CS_SQER:
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR); /* End control transfer. */
break;
default:
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR); /* End control transfer. */
break;
}
}
}
/****************************************************************************
* Name: hw_usb_read_fifo16
*
* Description:
* Read FIFO16
*
****************************************************************************/
static uint16_t hw_usb_read_fifo16(uint16_t pipemode)
{
uint16_t data = 0;
switch (pipemode)
{
case USB_CUSE:
data = USB0.CFIFO.WORD;
break;
default:
break;
}
return data;
}
/****************************************************************************
* Name: usb_pstd_read_fifo
*
* Description:
* Read FIFO
*
****************************************************************************/
uint8_t *usb_pstd_read_fifo(uint16_t count, uint16_t pipemode,
uint8_t *read_p)
{
uint16_t even;
uint32_t odd_byte_data_temp;
/* WAIT_LOOP */
for (even = (uint16_t)(count >> 1); (0 != even); --even)
{
/* 16bit FIFO access */
*(uint16_t *)read_p = hw_usb_read_fifo16(pipemode);
/* Renewal read pointer */
read_p += sizeof(uint16_t);
}
if ((count & (uint16_t)0x0001) != 0)
{
/* 16bit FIFO access */
odd_byte_data_temp = hw_usb_read_fifo16(pipemode);
*read_p = LSBYTE(odd_byte_data_temp);
/* Renewal read pointer */
read_p += sizeof(uint8_t);
}
return read_p;
}
/****************************************************************************
* Name: usb_pstd_read_data
*
* Description:
* Read data
*
****************************************************************************/
uint16_t usb_pstd_read_data(uint16_t pipe, uint16_t pipemode)
{
uint16_t count;
uint16_t buf;
uint16_t mxps;
uint16_t dtln;
uint16_t end_flag;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_ERROR; /* Error */
}
/* Changes FIFO port by the pipe. */
buf = usb_cstd_is_set_frdy(pipe, (uint16_t)pipemode, USB_FALSE);
if (USB_ERROR == buf)
{
/* FIFO access error */
return USB_ERROR;
}
dtln = (uint16_t)(buf & USB_DTLN);
/* Max Packet Size */
mxps = usb_cstd_get_maxpacket_size(pipe);
g_usb_pstd_data_cnt[pipe] = RX65N_MAXPACKET_SIZE;
if (g_usb_pstd_data_cnt[pipe] < dtln)
{
/* Buffer Over ? */
end_flag = USB_READOVER;
/* Set NAK */
usb_cstd_set_nak(pipe);
count = (uint16_t)g_usb_pstd_data_cnt[pipe];
g_usb_pstd_data_cnt[pipe] = dtln;
}
else if (g_usb_pstd_data_cnt[pipe] == dtln)
{
/* Just Receive Size */
count = dtln;
if ((USB_PIPE0 == pipe) && (0 == (dtln % mxps)))
{
/* Just Receive Size */
/* Peripheral Function */
end_flag = USB_READING;
}
else
{
end_flag = USB_READEND;
/* Set NAK */
usb_cstd_set_nak(pipe);
}
}
else
{
/* Continuous Receive data */
count = dtln;
end_flag = USB_READING;
if (0 == count)
{
/* Null Packet receive */
end_flag = USB_READSHRT;
/* Select NAK */
usb_cstd_set_nak(pipe);
}
if (0 != (count % mxps))
{
/* Null Packet receive */
end_flag = USB_READSHRT;
/* Select NAK */
usb_cstd_set_nak(pipe);
}
}
if (0 == dtln)
{
/* 0 length packet */
/* Clear BVAL */
hw_usb_set_bclr(pipemode);
}
else
{
gp_usb_pstd_data[2] = g_buffer;
gp_usb_pstd_data[pipe] = usb_pstd_read_fifo(count, pipemode,
gp_usb_pstd_data[pipe]);
}
g_usb_pstd_data_cnt[pipe] -= count;
/* End or Err or Continue */
return end_flag;
}
/****************************************************************************
* Name: usb_pstd_fifo_to_buf
*
* Description:
* FIFO to BUF
*
****************************************************************************/
void usb_pstd_fifo_to_buf(uint16_t pipe, uint16_t useport)
{
uint16_t end_flag;
end_flag = USB_ERROR;
if (USB_MAXPIPE_NUM < pipe)
{
return; /* Error */
}
end_flag = usb_pstd_read_data(pipe, useport);
/* Check FIFO access sequence */
switch (end_flag)
{
case USB_READING:
/* Continue of data read */
break;
case USB_READEND:
/* End of data read */
usb_pstd_data_end(pipe, (uint16_t)USB_DATA_OK);
break;
case USB_READSHRT:
/* End of data read */
usb_pstd_data_end(pipe, (uint16_t)USB_DATA_SHT);
break;
case USB_READOVER:
/* Buffer over */
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_OVR);
break;
case USB_ERROR:
/* FIFO access error */
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_ERR);
break;
default:
usb_pstd_forced_termination(pipe, (uint16_t)USB_DATA_ERR);
break;
}
}
/****************************************************************************
* Name: usb_pstd_brdy_pipe_process
*
* Description:
* Handle BRDY Pipe for Data
*
****************************************************************************/
void usb_pstd_brdy_pipe_process(uint16_t bitsts)
{
uint16_t useport;
uint16_t i;
/* WAIT_LOOP */
for (i = USB_MIN_PIPE_NO; i <= USB_MAXPIPE_NUM; i++)
{
if (0u != (bitsts & USB_BITSET(i)))
{
/* Interrupt check */
hw_usb_clear_sts_brdy(i);
hw_usb_clear_status_bemp(i);
if (USB_NULL != g_p_usb_pstd_pipe[i])
{
/* Pipe number to FIFO port select */
useport = usb_pstd_pipe2fport(i);
if (USB_CUSE == useport)
{
if (USB_BUF2FIFO == usb_cstd_get_pipe_dir(i))
{
/* Buffer to FIFO data write */
usb_pstd_buf_to_fifo(i, useport);
}
else
{
/* FIFO to Buffer data read */
usb_pstd_fifo_to_buf(i, useport);
}
}
}
}
}
}
/****************************************************************************
* Name: usb_pstd_brdy_pipe
*
* Description:
* Handle BRDY Interrupt
*
****************************************************************************/
void usb_pstd_brdy_pipe(uint16_t bitsts, struct rx65n_usbdev_s *priv,
struct rx65n_ep_s *privep, uint16_t epno)
{
uint32_t nbytes;
if (USB_BRDY0 == (rx65n_getreg16(RX65N_USB_BRDYSTS) & USB_BRDY0))
{
hw_usb_clear_sts_brdy(USB_PIPE0);
g_usb_pstd_data_cnt[0] = CDC_CLASS_DATA_LENGTH;
switch (usb_pstd_read_data(USB_PIPE0, USB_CUSE))
{
/* End of data read */
case USB_READEND:
/* Continue */
/* End of data read */
case USB_READSHRT:
hw_usb_clear_brdyenb((uint16_t)USB_PIPE0);
break;
/* Continue of data read */
case USB_READING:
/* PID = BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
break;
/* FIFO access error */
case USB_READOVER:
/* Clear BVAL */
hw_usb_set_bclr(USB_CUSE);
/* Control transfer stop(end) */
usb_pstd_ctrl_end((uint16_t)USB_DATA_OVR);
break;
/* FIFO access error */
case USB_ERROR:
/* Control transfer stop(end) */
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR);
break;
default:
break;
}
}
else
{
/* not PIPE0 */
usb_pstd_brdy_pipe_process(bitsts);
epno = BULK_IN_EPNUM;
nbytes = RX65N_USB_MAXP - g_usb_pstd_data_cnt[BULK_OUT_PIPE];
usb_data_write(epno, g_buffer, nbytes);
rx65n_putreg16(0, RX65N_USB_BRDYSTS);
privep->head->req.buf = g_buffer;
/* EP3 is passed, because for read(),
* the endpoint list should
* always point to bulk out endpoint
*/
privep = &priv->eplist[EP3];
usb_data_read(g_buffer, RX65N_MAXPACKET_SIZE);
bytesread = nbytes;
/* The rx65n_rdrequest() function is invoked here
* to handle application specific read()
* and invoke the reqcomplete() function
* which further, unblocks the semaphore waiting
* on read()
* Failing to invoke this function will result,
* in failiure of application specific read
*
*/
rx65n_rdrequest(epno, priv, privep);
bytesread = 0;
}
}
/****************************************************************************
* Name: usb_cstd_get_pid
*
* Description:
* Get PID
*
****************************************************************************/
static uint16_t usb_cstd_get_pid(uint16_t pipe)
{
uint16_t buf;
if (USB_MAXPIPE_NUM < pipe)
{
return USB_NULL; /* Error */
}
/* PIPE control reg read */
buf = hw_usb_read_pipectr(pipe);
return (uint16_t)(buf & USB_PID);
}
/****************************************************************************
* Name: usb_pstd_bemp_pipe_process
*
* Description:
* BEMP Interrupt Handling for Pipe
*
****************************************************************************/
void usb_pstd_bemp_pipe_process(uint16_t bitsts)
{
uint16_t buf;
uint16_t i;
/* WAIT_LOOP */
for (i = USB_MIN_PIPE_NO; i <= USB_PIPE5; i++)
{
if (0 != (bitsts & USB_BITSET(i)))
{
hw_usb_clear_status_bemp(i);
/* Interrupt check */
if ((USB_NULL != g_p_usb_pstd_pipe[i]))
{
buf = usb_cstd_get_pid(i);
/* MAX packet size error ? */
if (USB_PID_STALL == (buf & USB_PID_STALL))
{
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_STALL);
}
else
{
if (USB_INBUFM != (hw_usb_read_pipectr(i) & USB_INBUFM))
{
usb_pstd_data_end(i, (uint16_t)USB_DATA_NONE);
}
else
{
/* set BEMP enable */
hw_usb_set_bempenb(i);
}
}
}
}
}
/* WAIT_LOOP */
for (i = USB_PIPE6; i <= USB_MAXPIPE_NUM; i++)
{
/* Interrupt check */
if (0 != (bitsts & USB_BITSET(i)))
{
if (USB_NULL != g_p_usb_pstd_pipe[i])
{
buf = usb_cstd_get_pid(i);
/* MAX packet size error ? */
if (USB_PID_STALL == (buf & USB_PID_STALL))
{
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_STALL);
}
else
{
/* End of data transfer */
usb_pstd_data_end(i, (uint16_t)USB_DATA_NONE);
}
}
}
}
}
/****************************************************************************
* Name: usb_pstd_bemp_pipe
*
* Description:
* BEMP Interrupt Handling
*
****************************************************************************/
void usb_pstd_bemp_pipe(uint16_t bitsts)
{
if (USB_BEMP0 == (bitsts & USB_BEMP0))
{
switch (usb_pstd_write_data(USB_PIPE0, USB_CUSE))
{
/* End of data write (not null) */
case USB_WRITEEND:
/* Continue */
/* End of data write */
case USB_WRITESHRT:
/* Enable empty interrupt */
hw_usb_clear_bempenb((uint16_t)USB_PIPE0);
break;
/* Continue of data write */
case USB_WRITING:
/* PID = BUF */
usb_cstd_set_buf((uint16_t)USB_PIPE0);
break;
/* FIFO access error */
case USB_ERROR:
/* Control transfer stop(end) */
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR);
break;
default:
break;
}
}
else
{
/* BEMP interrupt */
usb_pstd_bemp_pipe_process(bitsts);
}
}
/****************************************************************************
* Name: hw_usb_read_frmnum
*
* Description:
* Read Framenum
*
****************************************************************************/
static uint16_t hw_usb_read_frmnum(void)
{
return rx65n_getreg16(RX65N_USB_FRMNUM);
}
/****************************************************************************
* Name: usb_pstd_nrdy_pipe_process
*
* Description:
* NRDY Pipe Prrocess
*
****************************************************************************/
void usb_pstd_nrdy_pipe_process(uint16_t bitsts)
{
uint16_t buf;
uint16_t i;
/* WAIT_LOOP */
for (i = USB_MIN_PIPE_NO; i <= USB_MAXPIPE_NUM; i++)
{
if (0 != (bitsts & USB_BITSET(i)))
{
/* Interrupt check */
if (USB_NULL != g_p_usb_pstd_pipe[i])
{
if (USB_TYPFIELD_ISO == usb_cstd_get_pipe_type(i))
{
/* Wait for About 60ns */
buf = hw_usb_read_frmnum();
if (USB_OVRN == (buf & USB_OVRN))
{
/* @1 */
/* End of data transfer */
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_OVR);
}
else
{
/* @2 */
/* End of data transfer */
usb_pstd_forced_termination(i, (uint16_t)USB_DATA_ERR);
}
}
else
{
/* Non processing. */
}
}
}
}
}
/****************************************************************************
* Name: rx65n_usbdev_bottomhalf
*
* Description:
* BRDY handler in bottom half
*
****************************************************************************/
static void rx65n_usbdev_bottomhalf(void *arg)
{
struct rx65n_usbdev_s *priv = &g_usbdev;
uint32_t bottom_half_processing = (uint32_t)arg;
struct rx65n_ep_s *privep;
if (bottom_half_processing == USB_INT_BRDY)
{
uint16_t regval;
uint8_t epno;
uint16_t brdysts;
brdysts = USB0.BRDYSTS.WORD;
regval = rx65n_getreg16(RX65N_USB_PIPECFG);
regval &= USB_EPNUMFIELD;
epno = regval;
privep = &priv->eplist[epno];
usb_pstd_brdy_pipe(brdysts, priv, privep, epno);
}
}
/****************************************************************************
* Name: usb_pstd_nrdy_pipe
*
* Description:
* NRDY Interrupt handler
*
****************************************************************************/
void usb_pstd_nrdy_pipe(uint16_t bitsts)
{
/* Nrdy Pipe interrupt */
usb_pstd_nrdy_pipe_process(bitsts);
}
/****************************************************************************
* Name: rx65n_usbinterrupt
*
* Description:
* USB interrupt handler
*
****************************************************************************/
static int rx65n_usbinterrupt(int irq, void *context, void *arg)
{
struct rx65n_usbdev_s *priv = &g_usbdev;
uint8_t type;
uint16_t ists0;
uint16_t intenb0;
uint16_t intsts0;
uint16_t stginfo;
uint16_t bempsts;
uint16_t nrdysts;
static uint32_t connected_times = 0;
intenb0 = rx65n_getreg16(RX65N_USB_INTENB0);
/* Read Interrupt Status and mask out interrupts that are not enabled. */
intsts0 = rx65n_getreg16(RX65N_USB_INTSTS0) & intenb0;
nrdysts = rx65n_getreg16(RX65N_USB_NRDYSTS);
bempsts = rx65n_getreg16(RX65N_USB_BEMPSTS);
/* Check VBUS */
if ((intsts0 & RX65N_USB_INTSTS0_VBINT) == RX65N_USB_INTSTS0_VBINT)
{
rx65n_putreg16(
((~RX65N_USB_INTSTS0_VBINT) & INTSTS0_BIT_VALUES_TO_DETECT),
RX65N_USB_INTSTS0);
if (USB_ATTACH == usb_pstd_chk_vbsts())
{
priv->attached = 1;
connected_times++;
syslog(LOG_INFO, "NuttX: USB Device Connected. %d\n",
connected_times);
uinfo("Device attached\n");
usb_pstd_attach_process(); /* USB attach */
}
else
{
priv->attached = 0;
syslog(LOG_INFO, "NuttX: USB Device Disconnected. %d\n",
connected_times);
usb_pstd_detach_process(); /* USB detach */
if (priv->driver)
{
CLASS_DISCONNECT(priv->driver, &priv->usbdev);
}
}
}
intsts0 = rx65n_getreg16(RX65N_USB_INTSTS0);
if ((intsts0 & RX65N_USB_INTSTS0_DVST) == RX65N_USB_INTSTS0_DVST)
{
rx65n_putreg16(
((~RX65N_USB_INTSTS0_DVST) & INTSTS0_BIT_VALUES_TO_DETECT),
RX65N_USB_INTSTS0);
switch ((uint16_t)(intsts0 & USB_DVSQ))
{
/* Power state */
case USB_DS_POWR:
break;
/* Default state */
case USB_DS_DFLT:
uinfo("USB-reset int peri\n");
usb_pstd_bus_reset();
break;
/* Address state */
case USB_DS_ADDS:
break;
/* Configured state */
case USB_DS_CNFG:
uinfo("Device configuration int peri\n");
break;
/* Power suspend state */
case USB_DS_SPD_POWR:
/* Continue */
/* Default suspend state */
case USB_DS_SPD_DFLT:
/* Continue */
/* Address suspend state */
case USB_DS_SPD_ADDR:
/* Continue */
/* Configured Suspend state */
case USB_DS_SPD_CNFG:
uinfo("SUSPEND int peri\n");
usb_pstd_suspend_process();
break;
/* Error */
default:
break;
}
}
intsts0 = rx65n_getreg16(RX65N_USB_INTSTS0);
if ((intsts0 & RX65N_USB_INTSTS0_CTRT) == RX65N_USB_INTSTS0_CTRT)
{
rx65n_putreg16
(((~RX65N_USB_INTSTS0_CTRT) & INTSTS0_BIT_VALUES_TO_DETECT),
RX65N_USB_INTSTS0);
stginfo = (uint16_t)(rx65n_getreg16(RX65N_USB_INTSTS0) & USB_CTSQ);
if (((USB_CS_RDDS == stginfo) || (USB_CS_WRDS == stginfo))
|| (USB_CS_WRND == stginfo))
{
/* Save request register */
usb_pstd_save_request();
}
if (USB_REQ_TYPE_STANDARD ==
(g_usb_pstd_req_type & USB_BMREQUESTTYPETYPE))
{
/* Switch on the control transfer stage (CTSQ). */
switch (stginfo)
{
/* Idle or setup stage */
uinfo("stginfo =%d\n", stginfo);
case USB_CS_IDST:
case USB_CS_RDDS:
case USB_CS_WRDS:
case USB_CS_WRSS:
rx65n_ep0setup(priv);
break;
case USB_CS_RDSS:
usb_pstd_stand_req4();
break;
case USB_CS_WRND:
usb_pstd_stand_req3();
break;
/* Control sequence error */
case USB_CS_SQER:
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR);
break;
/* Illegal */
default:
usb_pstd_ctrl_end((uint16_t)USB_DATA_ERR);
break;
}
}
else
{
/* Vender Specific */
type = LSBYTE(rx65n_getreg16(RX65N_USB_USBREQ));
rx65n_ep0setup(priv);
usb_peri_class_request(type, stginfo);
}
}
ists0 = (uint16_t)(intsts0 & intenb0);
/* BRDY Interrupt Check */
if (USB_BRDY == (ists0 & USB_BRDY))
{
DEBUGVERIFY(work_queue(HPWORK, &g_usbdev.rx65n_interrupt_bhalf,
rx65n_usbdev_bottomhalf,
(void *)USB_INT_BRDY, 0));
}
/* BEMP Interrupt Check */
if ((USB_BEMP == (ists0 & USB_BEMP)))
{
usb_pstd_bemp_pipe_process(bempsts);
}
/* NRDY Interrupt Check */
if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_NRDY)) ==
RX65N_USB_INTSTS0_NRDY)
{
usb_pstd_nrdy_pipe(nrdysts);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: renesas_usbinitialize
*
* Description:
* Initialize USB hardware
*
****************************************************************************/
void renesas_usbinitialize(void)
{
/* For now there is only one USB controller, but we will always refer to
* it using a pointer
*/
struct rx65n_usbdev_s *priv = &g_usbdev;
uint32_t reg32;
uint16_t regval;
int epno;
usbtrace(TRACE_DEVINIT, 0);
/* Enable write to System registers */
regval = rx65n_getreg16(RX65N_PRCR_ADDR);
rx65n_putreg16(RX65N_PRCR_VALUE, RX65N_PRCR_ADDR);
regval = rx65n_getreg16(RX65N_PRCR_ADDR);
/* Clear bit 19 - so that USB module is released from stop state */
reg32 = getreg32(RX65N_MSTPCRB_ADDR);
reg32 &= (~RX65N_MSTPCRB_START_STOP_USB);
putreg32(reg32, RX65N_MSTPCRB_ADDR);
memset(priv, 0, sizeof(struct rx65n_usbdev_s));
priv->usbdev.ops = &g_devops;
priv->usbdev.ep0 = &priv->eplist[EP0].ep;
priv->epavail = RX65N_ENDP_ALLSET & ~RX65N_ENDP_BIT(EP0);
/* Initialize the endpoint list */
for (epno = 0; epno < RX65N_NENDPOINTS; epno++)
{
/* Set endpoint operations, reference to driver structure (not
* really necessary because there is only one controller), and
* the (physical) endpoint number which is just the index to the
* endpoint.
*/
priv->eplist[epno].ep.ops = &g_epops;
priv->eplist[epno].dev = priv;
priv->eplist[epno].ep.eplog = epno;
/* We will use a fixed maxpacket size for all endpoints (perhaps
* ISOC endpoints could have larger maxpacket???). A smaller
* packet size can be selected when the endpoint is configured.
*/
priv->eplist[epno].ep.maxpacket = RX65N_MAXPACKET_SIZE;
}
/* Select a smaller endpoint size for EP0 */
#if RX65N_EP0MAXPACKET < RX65N_MAXPACKET_SIZE
priv->eplist[EP0].ep.maxpacket = RX65N_EP0MAXPACKET;
#endif
/* Set SCKE bit in SYSCFG Register */
regval = rx65n_getreg16(RX65N_USB_SYSCFG);
regval |= (RX65N_USB_SYSCFG_SCKE);
rx65n_putreg16(regval, RX65N_USB_SYSCFG);
regval = rx65n_getreg16(RX65N_USB_PHYSLEW);
regval |= (RX65N_PHYSLEW_VALUE);
rx65n_putreg16(regval, RX65N_USB_PHYSLEW);
/* Set USBE bit in SYSCFG register */
regval = rx65n_getreg16(RX65N_USB_SYSCFG);
regval |= (RX65N_USB_SYSCFG_USBE);
rx65n_putreg16(regval, RX65N_USB_SYSCFG);
/* Set MBW bit in CFIFOSEL register */
regval = rx65n_getreg16(RX65N_USB_CFIFOSEL);
regval |= (RX65N_USB_CFIFOSEL_MBW_16);
rx65n_putreg16(regval, RX65N_USB_CFIFOSEL);
/* Set MBW bit in D0FIFOSEL register */
regval = rx65n_getreg16(RX65N_USB_D0FIFOSEL);
regval |= (RX65N_USB_D0FIFOSEL_MBW_16);
rx65n_putreg16(regval, RX65N_USB_D0FIFOSEL);
/* Set MBW bit in D1FIFOSEL register */
regval = rx65n_getreg16(RX65N_USB_D1FIFOSEL);
regval |= (RX65N_USB_D1FIFOSEL_MBW_16);
rx65n_putreg16(regval, RX65N_USB_D1FIFOSEL);
/* Set the Interrupt enable bits in INTENB0 register */
regval = rx65n_getreg16(RX65N_USB_INTENB0);
regval |= (RX65N_USB_INTENB0_BEMPE | RX65N_USB_INTENB0_BRDYE |
RX65N_USB_INTENB0_VBSE | RX65N_USB_INTENB0_DVSE |
RX65N_USB_INTENB0_CTRE);
rx65n_putreg16(regval, RX65N_USB_INTENB0);
ICU.SLIBR185.BYTE = RX65N_USBI0_SOURCE;
IPR(PERIB, INTB185) = RX65N_USBI0_PRIORITY;
if (irq_attach(RX65N_INTB185_IRQ, rx65n_usbinterrupt, NULL) != 0)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_IRQREGISTRATION),
(uint16_t)RX65N_INTB185_IRQ);
}
priv->usbdev.speed = USB_SPEED_FULL;
syslog(LOG_INFO, "Debug:USB Device Initialized, Device connected:%s\n",
priv->attached ? "YES" : "NO");
}
/****************************************************************************
* Name: renesas_usbuninitialize
* Description:
* Initialize the USB driver
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void renesas_usbuninitialize(void)
{
struct rx65n_usbdev_s *priv = &g_usbdev;
usbtrace(TRACE_DEVUNINIT, 0);
if (priv->driver)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_DRIVERREGISTERED), 0);
usbdev_unregister(priv->driver);
}
priv->usbdev.speed = USB_SPEED_UNKNOWN;
/* Disable and detach IRQs */
IEN(PERIB, INTB185) = 0U;
irq_detach(RX65N_INTB185_IRQ);
}
/****************************************************************************
* Name: usbdevclass_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)
{
int ret;
usbtrace(TRACE_DEVREGISTER, 0);
#ifdef CONFIG_DEBUG_USB
if (!driver || !driver->ops->bind || !driver->ops->unbind ||
!driver->ops->disconnect || !driver->ops->setup)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
if (g_usbdev.driver)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_DRIVER), 0);
return -EBUSY;
}
#endif
/* First hook up the driver */
g_usbdev.driver = driver;
/* Then bind the class driver */
ret = CLASS_BIND(driver, &g_usbdev.usbdev);
if (ret)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_BINDFAILED), (uint16_t)-ret);
g_usbdev.driver = NULL;
}
else
{
/* Enable USB controller interrupts */
IEN(PERIB, INTB185) = 1U;
}
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)
{
usbtrace(TRACE_DEVUNREGISTER, 0);
#ifdef CONFIG_DEBUG_FEATURES
if (driver != g_usbdev.driver)
{
usbtrace(TRACE_DEVERROR(RX65N_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
/* Unbind the class driver */
CLASS_UNBIND(driver, &g_usbdev.usbdev);
/* Disable IRQs */
IEN(PERIB, INTB185) = 0U;
/* Unhook the driver */
g_usbdev.driver = NULL;
return OK;
}