From 4629d5a722c42e3fc535c708e801c58e23a5464c Mon Sep 17 00:00:00 2001 From: anjana Date: Thu, 3 Dec 2020 15:39:19 +0530 Subject: [PATCH] RX65N USB Host Driver --- arch/renesas/src/rx65n/Kconfig | 10 + arch/renesas/src/rx65n/Make.defs | 47 +- arch/renesas/src/rx65n/rx65n_definitions.h | 31 +- arch/renesas/src/rx65n/rx65n_hardware_setup.c | 5 + arch/renesas/src/rx65n/rx65n_usbhost.c | 8543 +++++++++++++++++ arch/renesas/src/rx65n/rx65n_usbhost.h | 248 + boards/renesas/rx65n/rx65n-grrose/README.txt | 87 +- .../rx65n/rx65n-grrose/src/rx65n_bringup.c | 169 +- .../rx65n/rx65n-grrose/src/rx65n_gpio.c | 20 + boards/renesas/rx65n/rx65n-rsk2mb/README.txt | 86 + .../rx65n/rx65n-rsk2mb/src/rx65n_bringup.c | 163 + .../rx65n/rx65n-rsk2mb/src/rx65n_gpio.c | 27 + 12 files changed, 9394 insertions(+), 42 deletions(-) create mode 100644 arch/renesas/src/rx65n/rx65n_usbhost.c create mode 100644 arch/renesas/src/rx65n/rx65n_usbhost.h diff --git a/arch/renesas/src/rx65n/Kconfig b/arch/renesas/src/rx65n/Kconfig index a8c7b66ece..269895caad 100644 --- a/arch/renesas/src/rx65n/Kconfig +++ b/arch/renesas/src/rx65n/Kconfig @@ -424,6 +424,11 @@ config RX65N_TEST_INTEP endif #RX65N_USBDEV +config RX65N_USBHOST + bool "USB host" + select USBHOST + select USBHOST_HAVE_ASYNCH + config RX65N_DTC bool "DTC" default n @@ -803,6 +808,11 @@ config RX65N_TEST_INTEP endif #RX65N_USBDEV +config RX65N_USBHOST + bool "USB host" + select USBHOST + select USBHOST_HAVE_ASYNCH + config RX65N_DTC bool "DTC" default n diff --git a/arch/renesas/src/rx65n/Make.defs b/arch/renesas/src/rx65n/Make.defs index 8f401d02ae..580631a968 100644 --- a/arch/renesas/src/rx65n/Make.defs +++ b/arch/renesas/src/rx65n/Make.defs @@ -1,37 +1,22 @@ -############################################################################## +############################################################################ # arch/renesas/src/rx65n/Make.defs # -# Copyright (C) 2008-2019 Gregory Nutt. All rights reserved. -# Author: Anjana +# 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 # -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: +# http://www.apache.org/licenses/LICENSE-2.0 # -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. -# 3. Neither the name NuttX nor the names of its contributors may be -# used to endorse or promote products derived from this software -# without specific prior written permission. +# 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. # -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -############################################################################## +############################################################################ HEAD_ASRC = rx65n_head.S @@ -67,6 +52,10 @@ ifeq ($(CONFIG_RX65N_RSPI),y) CHIP_CSRCS += rx65n_rspi.c endif +ifeq ($(CONFIG_USBHOST),y) +CHIP_CSRCS += rx65n_usbhost.c +endif + ifeq ($(CONFIG_I2C),y) CHIP_CSRCS += rx65n_riic.c endif diff --git a/arch/renesas/src/rx65n/rx65n_definitions.h b/arch/renesas/src/rx65n/rx65n_definitions.h index 910a900f09..ebddf201d1 100644 --- a/arch/renesas/src/rx65n/rx65n_definitions.h +++ b/arch/renesas/src/rx65n/rx65n_definitions.h @@ -847,17 +847,17 @@ * generic */ -#define USB_PIPE1 (1) -#define USB_PIPE2 (2) -#define USB_PIPE3 (3) -#define USB_PIPE4 (4) -#define USB_PIPE5 (5) -#define USB_PIPE6 (6) -#define USB_PIPE7 (7) -#define USB_PIPE8 (8) -#define USB_PIPE9 (9) -#define USB_MIN_PIPE_NO (1u) -#define USB_MAX_PIPE_NO (9) +#define USB_PIPE1 (1) +#define USB_PIPE2 (2) +#define USB_PIPE3 (3) +#define USB_PIPE4 (4) +#define USB_PIPE5 (5) +#define USB_PIPE6 (6) +#define USB_PIPE7 (7) +#define USB_PIPE8 (8) +#define USB_PIPE9 (9) +#define USB_MIN_PIPE_NO (1u) +#define USB_MAX_PIPE_NO (9) /* Details of pipe number for obtaining the pipe */ @@ -1171,6 +1171,7 @@ #define USB_DEVICE_A (0xa000u) /* Device address A */ #define USB_NODEVICE (0xf000u) /* No device */ #define USB_DEVADDRBIT (12u) +#define USB_DEFPACKET (0x0040) /* Device Address bit fields */ @@ -1448,6 +1449,14 @@ #define USB_INT_BRDY (0x0001u) #define USB_BMREQUESTTYPERECIP (0x001Fu) /* b4-0: Recipient */ +#define HUB_PORT1 (1) +#define HUB_PORT2 (2) +#define HUB_PORT3 (3) +#define HUB_PORT4 (4) + +/* StandBy RAM Address */ + +#define RX65N_SBRAM_BASE 0x000a4000 /* Start of RSPI interface related definitions */ diff --git a/arch/renesas/src/rx65n/rx65n_hardware_setup.c b/arch/renesas/src/rx65n/rx65n_hardware_setup.c index 64b3d9c684..274be019b7 100644 --- a/arch/renesas/src/rx65n/rx65n_hardware_setup.c +++ b/arch/renesas/src/rx65n/rx65n_hardware_setup.c @@ -42,6 +42,7 @@ void r_ether_port_configuration(void); void r_ether_pheriperal_enable(void); +void r_usb_port_enable(void); /**************************************************************************** * Name: r_system_init @@ -73,6 +74,10 @@ void r_system_init(void) r_ether_pheriperal_enable(); #endif +#if defined(CONFIG_USBHOST) + r_usb_port_enable(); +#endif + /* Disable writing to MPC pin function control registers */ MPC.PWPR.BIT.PFSWE = 0; diff --git a/arch/renesas/src/rx65n/rx65n_usbhost.c b/arch/renesas/src/rx65n/rx65n_usbhost.c new file mode 100644 index 0000000000..3c639f012d --- /dev/null +++ b/arch/renesas/src/rx65n/rx65n_usbhost.c @@ -0,0 +1,8543 @@ +/**************************************************************************** + * arch/renesas/src/rx65n/rx65n/rx65n_usbhost.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "up_arch.h" +#include "up_internal.h" + +#include "chip.h" +#include "rx65n_usbhost.h" + +#include "arch/rx65n/iodefine.h" +#include "rx65n_cmtw.h" + +#define INTSTS0_BIT_VALUES_TO_ACK (0xd870u) +#define INTSTS1_BIT_VALUES_TO_ACK (0xd870u) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* All I/O buffers must lie in AHB SRAM because of the OHCI DMA. + * It might be okay if no I/O buffers are used *IF* the application + * can guarantee that all end-user I/O buffers reside in AHB SRAM. + */ + +#if defined(CONFIG_USBHOST) && defined(CONFIG_USBDEV) +# error "Both USB Host & Device cannot be configured" +#endif + +#ifndef CONFIG_RX65N_USBHOST_NPREALLOC +# define CONFIG_RX65N_USBHOST_NPREALLOC 8 +#endif + +#ifndef CONFIG_DEBUG_USB_INFO +# undef CONFIG_RX65N_USBHOST_REGDEBUG +#endif + +/* USB Host Memory **********************************************************/ + +/* Periodic intervals 2, 4, 8, 16,and 32 supported */ + +#define MIN_PERINTERVAL 2 +#define MAX_PERINTERVAL 32 + +/* Descriptors **************************************************************/ + +/* TD delay interrupt value */ + +#define TD_DELAY(n) (uint32_t)((n) << GTD_STATUS_DI_SHIFT) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure retains the state of the USB host controller */ + +struct rx65n_usbhost_s +{ + /* Common device fields. This must be the first thing defined in the + * structure so that it is possible to simply cast from struct usbhost_s + * to struct rx65n_usbhost_s. + */ + + struct usbhost_driver_s drvr; + + /* This is the hub port description understood by class drivers */ + + struct usbhost_roothubport_s rhport; + + /* Driver status */ + + volatile bool change; /* Connection change */ + volatile bool connected; /* Connected to device */ + + /* Thread is waiting for a port status change */ + + volatile bool pscwait; /* Thread is waiting for a port status change */ + +#ifndef CONFIG_USBHOST_INT_DISABLE + + /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */ + + uint8_t ininterval; + + /* Minimum periodic IN EP polling interval: 2, 4, 6, 16, or 32 */ + + uint8_t outinterval; + +#endif + + sem_t exclsem; /* Support mutually exclusive access */ + + /* Semaphore to wait Write-back Done Head event */ + + sem_t pscsem; + struct work_s rx65n_interrupt_bhalf; /* Supports interrupt bottom half */ + +#ifdef CONFIG_USBHOST_HUB + + /* Used to pass external hub port events */ + + volatile struct usbhost_hubport_s *hport; +#endif +}; + +/* This structure describes one asynchronous transfer */ + +struct rx65n_usbhost_xfrinfo_s +{ + volatile bool wdhwait; /* Thread is waiting for WDH interrupt */ + + /* TD control status bits from last Write-back Done Head event */ + + volatile uint8_t tdstatus; + uint8_t *buffer; /* Transfer buffer start */ + uint16_t buflen; /* Buffer length */ + uint16_t xfrd; /* Number of bytes transferred */ + volatile uint8_t tdxfercond; + + /* New variable. added + * TD transfer condition : used for deciding + * what to do in the interrupt/bottom + * half context + */ + +#ifdef CONFIG_USBHOST_ASYNCH +#if RX65N_USBHOST_IOBUFFERS > 0 + + /* Remember the allocated DMA buffer address so that it can be freed when + * the transfer completes. + */ + + uint8_t *alloc; /* Allocated buffer */ +#endif + + /* Retain the callback information for the asynchronous transfer + * completion. + */ + + usbhost_asynch_t callback; /* Transfer complete callback */ + void *arg; /* Argument that accompanies the callback */ +#endif +}; + +/* The OCHI expects the size of an endpoint descriptor to be 16 bytes. + * However, the size allocated for an endpoint descriptor is 32 bytes. + * This extra 16-bytes is used by the OHCI host driver in + * order to maintain additional endpoint-specific data. + */ + +struct rx65n_usbhost_ed_s +{ + /* Hardware specific fields */ + + struct ohci_ed_s hw; /* 0-15 */ + + /* Software specific fields */ + + /* 16: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */ + + uint8_t xfrtype; + + /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */ + + uint8_t interval; + + /* 18: Semaphore used to wait for Writeback Done Head event */ + + sem_t wdhsem; + + /* Pointer to struct that manages asynchronous transfers on this pipe */ + + /* 16: pipe number associated with with this Endpoint */ + + uint8_t pipenum; + + struct rx65n_usbhost_xfrinfo_s *xfrinfo; +}; + +struct rx65n_usbhost_gtd_s +{ + /* Hardware specific fields */ + + struct ohci_gtd_s hw; + + /* Software specific fields */ + + struct rx65n_usbhost_ed_s *ed; /* Pointer to parent ED */ + uint8_t pad[12]; +}; + +/* The following is used to manage lists of free EDs, TDs, and TD buffers */ + +struct rx65n_usbhost_list_s +{ + struct rx65n_usbhost_list_s *flink; + + /* Link to next buffer in the list */ + + /* Variable length buffer data follows */ +}; + +struct rx65n_usbhost_ed_s __attribute__ ((aligned (32))); +struct rx65n_usbhost_gtd_s __attribute__ ((aligned (32))); + +/* This must be aligned to a 256-byte boundary */ + +static struct ohci_hcca_s g_hcca __attribute__ ((aligned (256))); +static struct ohci_hcca_s *HCCA; + +static struct rx65n_usbhost_gtd_s *TDTAIL; + +/* static struct rx65n_usbhost_ed_s g_rx65n_ep0ed; */ + +static struct rx65n_usbhost_ed_s *EDCTRL; + +static struct rx65n_usbhost_gtd_s + g_rx65n_tdlist[CONFIG_RX65N_USBHOST_NTDS]; +static struct rx65n_usbhost_ed_s + g_rx65n_edlist[CONFIG_RX65N_USBHOST_NEDS + 1]; +static uint8_t nrdy_retries[CONFIG_RX65N_USBHOST_NEDS + 1]; +#define RX65N_TD_BUF_SIZE (CONFIG_RX65N_USBHOST_TDBUFFERS * \ + CONFIG_RX65N_USBHOST_TDBUFSIZE) +static uint8_t g_tdbuffer [RX65N_TD_BUF_SIZE]; + +static uint8_t g_kbdport; +static uint16_t g_usbidx; +static uint8_t g_hubkbd; +static uint8_t g_kbdpipe; +static uint8_t g_attached; +static uint8_t g_detached; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Register operations ******************************************************/ + +#define rx65n_usbhost_getreg(addr) getreg16((volatile short *)addr) +#define rx65n_usbhost_putreg(val,addr) putreg16(val,(volatile short *)addr) +static void rx65n_usbhost_setbit (volatile short *regadd, +uint16_t setbitval); +static void rx65n_usbhost_clearbit (volatile short *regadd, + uint16_t clearbitval); + +/* Semaphores ***************************************************************/ + +static int rx65n_usbhost_takesem(sem_t *sem); +#define rx65n_usbhost_givesem(s) nxsem_post(s); + +/* Byte stream access helper functions **************************************/ + +static inline uint16_t rx65n_usbhost_getle16(const uint8_t *val); + +/* OHCI memory pool helper functions ****************************************/ + +static inline void rx65n_usbhost_edfree(struct rx65n_usbhost_ed_s *ed); +static struct rx65n_usbhost_gtd_s *rx65n_usbhost_tdalloc(uint8_t epnum); +static void rx65n_usbhost_tdfree(struct rx65n_usbhost_gtd_s *buffer); +static uint8_t *rx65n_usbhost_tballoc(void); +static void rx65n_usbhost_tbfree(uint8_t *buffer); +#if RX65N_USBHOST_IOBUFFERS > 0 +static uint8_t *rx65n_usbhhost_allocio(void); +static void rx65n_usbhhost_freeio(uint8_t *buffer); +#endif +static struct rx65n_usbhost_xfrinfo_s *rx65n_usbhost_alloc_xfrinfo(void); +static void rx65n_usbhost_free_xfrinfo + (struct rx65n_usbhost_xfrinfo_s *xfrinfo); + +/* ED list helper functions *************************************************/ + +static inline int rx65n_usbhost_addctrled(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); +static inline int rx65n_usbhost_remctrled(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); + +static inline int rx65n_usbhost_addbulked(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s + *epdesc, struct rx65n_usbhost_ed_s + *ed); + +static inline int rx65n_usbhost_rembulked(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); + +#if !defined(CONFIG_USBHOST_INT_DISABLE) || !defined(CONFIG_USBHOST_ISOC_DISABLE) +static unsigned int rx65n_usbhost_getinterval(uint8_t interval); +static void rx65n_usbhost_setinttab(uint32_t value, unsigned int interval, + unsigned int offset); +#endif + +static inline int rx65n_usbhost_addinted(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + struct rx65n_usbhost_ed_s *ed); +static inline int rx65n_usbhost_reminted(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); + +static inline int rx65n_usbhost_addisoced(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + struct rx65n_usbhost_ed_s *ed); +static inline int rx65n_usbhost_remisoced(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); + +/* Descriptor helper functions **********************************************/ + +static int rx65n_usbhost_enqueuetd(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen); +static int rx65n_usbhost_ctrltd(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, + uint32_t dirpid, uint8_t *buffer, size_t buflen); + +/* Interrupt handling *******************************************************/ + +static int rx65n_usbhost_usbinterrupt(int irq, void *context, FAR void *arg); + +/* USB host controller operations *******************************************/ + +static int rx65n_usbhost_wait(struct usbhost_connection_s *conn, + struct usbhost_hubport_s **hport); +static int rx65n_usbhost_rh_enumerate(struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport); +static int rx65n_usbhost_enumerate(struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport); + +static int rx65n_usbhost_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize); +static int rx65n_usbhost_epalloc(struct usbhost_driver_s *drvr, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep); +static int rx65n_usbhost_epfree(struct usbhost_driver_s *drvr, + usbhost_ep_t ep); +static int rx65n_usbhost_alloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t *maxlen); +static int rx65n_usbhost_free(struct usbhost_driver_s *drvr, + uint8_t *buffer); +static int rx65n_usbhost_ioalloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t buflen); +static int rx65n_usbhost_iofree(struct usbhost_driver_s *drvr, + uint8_t *buffer); +static int rx65n_usbhost_ctrlin(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + uint8_t *buffer); +static int rx65n_usbhost_ctrlout(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + const uint8_t *buffer); +static int rx65n_usbhost_transfer_common(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, uint8_t *buffer, + size_t buflen); +#if RX65N_USBHOST_IOBUFFERS > 0 +static int rx65n_usbhost_dma_alloc(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t **alloc); +static void rx65n_usbhost_dma_free(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, uint8_t *userbuffer, + size_t buflen, uint8_t *alloc); +#endif +static ssize_t rx65n_usbhost_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, + uint8_t *buffer, size_t buflen); +#ifdef CONFIG_USBHOST_ASYNCH +static void rx65n_usbhost_asynch_completion(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed); +static int rx65n_usbhost_asynch(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, FAR void *arg); +#endif +static int rx65n_usbhost_cancel(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep); +#ifdef CONFIG_USBHOST_HUB +static int rx65n_usbhost_connect(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_hubport_s *hport, + bool connected); +#endif +static void rx65n_usbhost_disconnect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport); + +/* Initialization ***********************************************************/ + +static inline void rx65n_usbhost_ep0init(struct rx65n_usbhost_s *priv); + +/* Prototype for USB Private Functions */ + +static void usb_cstd_set_nak (uint16_t pipe); +static void usb_cstd_clr_transaction_counter (uint16_t trnreg); +void usb_hstd_read_lnst (uint16_t *buf); +void usb_hstd_chk_sof (void); +void usb_hstd_attach (uint16_t result); +void usb_hstd_detach (void); +static void usb_cstd_chg_curpipe (uint16_t pipe, uint16_t fifosel, + uint16_t isel); +static void usb_cstd_do_aclrm (uint16_t pipe); +static void usb_cstd_set_buf (uint16_t pipe); +static void usb_cstd_clr_stall (uint16_t pipe); +static void usb_cstd_pipe_init (uint16_t pipe); +void usb_hstd_bus_reset (void); +uint16_t usb_hstd_detach_process (void); +static uint16_t usb_cstd_get_pipe_dir (uint16_t pipe); +static void usb_cstd_clr_pipe_cnfg (uint16_t pipe_no); + +static void *hw_usb_get_fifosel_adr (uint16_t pipemode); +static void *hw_usb_get_fifoctr_adr (uint16_t pipemode); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* In this driver implementation, support is provided for only a single a + * single USB device. All status information can be simply retained in a + * single globalinstance. + */ + +static struct rx65n_usbhost_s g_usbhost; + +/* This is the connection/enumeration interface */ + +static struct usbhost_connection_s g_usbconn = +{ + .wait = rx65n_usbhost_wait, + .enumerate = rx65n_usbhost_enumerate, +}; + +/* This is a free list of EDs and TD buffers */ + +static struct rx65n_usbhost_list_s *g_edfree; /* List of unused EDs */ +static struct rx65n_usbhost_list_s *g_tdfree; /* List of unused TDs */ +static struct rx65n_usbhost_list_s *g_tbfree; /* List of unused TBs */ +#if RX65N_USBHOST_IOBUFFERS > 0 +static struct rx65n_usbhost_list_s *g_iofree; /* unused IO buffers */ +#endif + +/* Pool and free-list of transfer structures */ + +static struct rx65n_usbhost_list_s *g_xfrfree; +static struct rx65n_usbhost_xfrinfo_s g_xfrbuffers + [CONFIG_RX65N_USBHOST_NPREALLOC]; + +/* Prototype for interrupt bottom half function */ + +static void rx65n_usbhost_bottomhalf (void *arg); + +typedef struct usb_pipe_table +{ + uint16_t use_flag; + uint16_t pipe_cfg; + uint16_t pipe_maxp; + uint16_t pipe_peri; +} usb_pipe_table_t; + +usb_pipe_table_t g_usb_pipe_table [USB_MAX_PIPE_NUM + 1]; + +uint8_t kbd_report_data [8]; +uint8_t kbd_interrupt_in_pipe = 0; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/* Prototypes to avoid errors */ + +static uint16_t usb_cstd_get_buf_size (uint16_t pipe); +static uint16_t usb_cstd_is_set_frdy (uint16_t pipe, uint16_t fifosel, + uint16_t isel); +static uint16_t usb_cstd_get_maxpacket_size (uint16_t pipe); +uint8_t *usb_hstd_read_fifo (uint16_t count, uint16_t pipemode, + uint8_t *read_p); +static uint16_t usb_cstd_get_pid (uint16_t pipe); +uint8_t *usb_hstd_write_fifo (uint16_t count, uint16_t pipemode, + uint8_t *write_p); +static void usb_cstd_set_transaction_counter (uint16_t trnreg, + uint16_t trncnt); +static void usb_cstd_nrdy_enable (uint16_t pipe); +void usb_hstd_buf_to_fifo (uint8_t *buffer, size_t buflen, uint16_t pipe, + uint16_t useport); +void usb_hstd_forced_termination (uint16_t pipe, uint16_t status); +void usb_hstd_nrdy_endprocess (uint16_t pipe); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void rx65n_usbhost_setbit (volatile short *regadd, + uint16_t setbit_val) +{ + volatile uint16_t value_to_set; + value_to_set = rx65n_usbhost_getreg(regadd); + value_to_set = value_to_set | setbit_val; + rx65n_usbhost_putreg (value_to_set, regadd); +} + +static void rx65n_usbhost_clearbit (volatile short *regadd, + uint16_t clearbit_val) +{ + volatile uint16_t value_to_clear; + value_to_clear = rx65n_usbhost_getreg(regadd); + value_to_clear = value_to_clear & (~clearbit_val); + rx65n_usbhost_putreg (value_to_clear, regadd); +} + +/**************************************************************************** + * Function Name : usb_chattaring + * Description : Remove chattaring processing + * Arguments : uint16_t *syssts : SYSSTS register value + * Return value : LNST bit value + ****************************************************************************/ + +uint16_t usb_chattaring (uint16_t *syssts) +{ + uint16_t lnst[4]; + + /* WAIT_LOOP */ + + while (1) + { + lnst[0] = (*syssts) & RX65N_USB_SYSSTS0_LNST; + up_mdelay(1); /* 1ms wait */ + lnst[1] = (*syssts) & RX65N_USB_SYSSTS0_LNST; + up_mdelay(1); /* 1ms wait */ + lnst[2] = (*syssts) & RX65N_USB_SYSSTS0_LNST; + if ((lnst[0] == lnst[1]) && (lnst[0] == lnst[2])) + { + break; + } + } + + return lnst[0]; +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_ovrcre + * Description : Set specified port's OVRCRE-bit (Overcurrent Input + * : Change Interrupt Status Enable) in the INTENB1 register. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_ovrcre (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_OVRCRE); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_enb_ovrcre + * Description : Clear the OVRCRE-bit of the specified port's INTENB1 + * : register, to prohibit VBUS interrupts. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_enb_ovrcre (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_OVRCRE); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_bchge + * Description : The BCHGE-bit (USB Bus Change Interrupt Enable) is set + * : in the specified port's INTENB1 register. This will + * : cause a BCHG interrupt when a change of USB bus state + * : has been detected. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_bchge (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_BCHGE); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_enb_bchge + * Description : The BCHGE-bit (USB Bus Change Interrupt Enable) is + * : cleared in the specified port's INTENB1 register. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_enb_bchge (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_BCHGE); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_dtche + * Description : Enable the specified port's DTCHE-interrupt + * : "Disconnection Detection" by setting the DTCHE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_dtche (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_DTCHE); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_enb_dtche + * Description : Disable the specified port's DTCHE-interrupt + * : "Disconnection Detection" by clearing the DTCHE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_enb_dtche (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_DTCHE); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_attche + * Description : Enable the specified port's ATTCHE-interrupt "Connection + * : Detection" by setting the ATTCHE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_attche (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_ATTCHE); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_enb_attche + * Description : Disable the specified port's ATTCHE-interrupt + * : "Disconnection Detection" by clearing the ATTCHE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_enb_attche (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_ATTCHE); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_signe + * Description : Enable the SIGNE-interrupt "Setup Transaction + * : Error" by setting the SIGNE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_signe (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_SIGNE); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_enb_sacke + * Description : Enable the SACKE-interrupt "Setup Transaction + * : Normal Response" by setting the SACKE-bit. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_enb_sacke (void) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_SACKE); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_ovrcr + * Description : Clear the specified port's OVRCR-bit; "Over current + * : Input Change Interrupt Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_ovrcr (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_OVRCRE) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_bchg + * Description : Clear the specified port's BCHG-bit; "USB Bus Change + * : Interrupt Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_bchg (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_BCHG) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_dtch + * Description : Clear the specified port's DTCH-bit; "USB Disconnection + * : Detection Interrupt Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_dtch (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_DTCH) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_attch + * Description : Clear the specified port's ATTCH-bit; "ATTCH Interrupt + * : Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_attch (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_ATTCH) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_sign + * Description : Clear the SIGN-bit; "Setup Transaction Error + * : Interrupt Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_sign (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_SIGN) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hclear_sts_sack + * Description : Clear the SACK-bit; "Setup Transaction Normal + * : Response Interrupt Status". + * : Interrupt Status". + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hclear_sts_sack (void) +{ + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_SACK) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); +} + +/**************************************************************************** + * Function Name : hw_usb_hwrite_dcpctr + * Description : Write the specified data value to the DCPCTR register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +void hw_usb_hwrite_dcpctr (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_DCPCTR); +} + +/**************************************************************************** + * Function Name : hw_usb_hset_sureq + * Description : Set te SUREQ-bit in the DCPCTR register + * : (Set SETUP packet send when HostController function + * : is selected) + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_sureq (void) +{ + rx65n_usbhost_setbit (RX65N_USB_DCPCTR, RX65N_USB_DCPCTR_SUREQ); +} + +/**************************************************************************** + * Function Name : hw_usb_hread_devadd + * Description : Return the DEVADD register value for the specified USB + * ; device address. + * Arguments : uint16_t devsel : USB device address value + * Return value : DEVADDx content + ****************************************************************************/ + +uint16_t hw_usb_hread_devadd (uint16_t devsel) +{ + volatile uint16_t *preg; + uint16_t devadr; + uint16_t return_value; + + devadr = devsel >> USB_DEVADDRBIT; + + if (devadr > USB_MAXDEVADDR) + { + uerr("ERROR: device address %d is more than max device \ + address. \n", devadd); + return -ENODEV; + } + else + { + preg = (uint16_t *) ((RX65N_USB_DEVADD0) + (devadr)); + return_value = ((*preg)); + return return_value; + } +} + +/**************************************************************************** + * Function Name : hw_usb_hset_usbspd + * Description : Set the DEVADD register's USBSPD for the specified + * : device address. + * Arguments : uint16_t devsel : USB device address value + * : uint16_t data : The value to write. + * Return value : none + ****************************************************************************/ + +void hw_usb_hset_usbspd (uint16_t devsel, uint8_t data) +{ + volatile uint16_t *preg; + uint16_t devadr; + + devadr = devsel; + + preg = (uint16_t *) (RX65N_USB_DEVADD0 + devadr); + + (*preg) &= (~RX65N_USB_DEVSPD); + + (*preg) |= data; +} + +/**************************************************************************** + * Function Name : hw_usb_hmodule_init + * Description : USB module initialization for USB Host mode + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_hmodule_init (void) +{ + uint16_t sts; + + rx65n_usbhost_setbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_SCKE); + up_mdelay(1); + + /* wait until SCKE bit is set */ + + while (1) + { + uint16_t regval; + regval = rx65n_usbhost_getreg(RX65N_USB_SYSCFG); + if (regval & RX65N_USB_SYSCFG_SCKE) + break; + } + + putreg32(0x05, RX65N_USB_PHYSLEW); + + rx65n_usbhost_setbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_DCFM); + + rx65n_usbhost_setbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_DRPD); + + sts = usb_chattaring((uint16_t *) RX65N_USB_SYSSTS0); + + rx65n_usbhost_setbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_USBE); + + rx65n_usbhost_setbit (RX65N_USB_CFIFOSEL, RX65N_USB_CFIFOSEL_MBW_16); + rx65n_usbhost_setbit (RX65N_USB_D0FIFOSEL, RX65N_USB_DFIFOSEL_MBW_16); + rx65n_usbhost_setbit (RX65N_USB_D1FIFOSEL, RX65N_USB_DFIFOSEL_MBW_16); + + switch (sts) + { + case RX65N_USB_SYSSTS0_LNST_LS_JSTS : + case RX65N_USB_SYSSTS0_LNST_FS_JSTS : /* USB device already connected */ + + syslog (LOG_INFO, "USB Device already connected\n\r"); + rx65n_usbhost_setbit (RX65N_USB_DVSTCTR0, RX65N_USB_DVSTCTR0_USBRST); + up_mdelay(20); /* Need to wait greater equal 10ms in USB spec */ + rx65n_usbhost_clearbit (RX65N_USB_DVSTCTR0, + RX65N_USB_DVSTCTR0_USBRST); + + /* WAIT_LOOP */ + + while (((rx65n_usbhost_getreg(RX65N_USB_DVSTCTR0)) & + RX65N_USB_DVSTCTR0_RHST) == 4) + { + /* Wait till the reset is completed */ + + up_mdelay(1); + } + + if (((rx65n_usbhost_getreg(RX65N_USB_DVSTCTR0)) & + RX65N_USB_DVSTCTR0_RHST) == + RX65N_USB_DVSTCTR0_SPEED_LOW) + { + rx65n_usbhost_setbit (RX65N_USB_SOFCFG, + RX65N_USB_SOFCFG_TRNENSEL); + } + + rx65n_usbhost_setbit (RX65N_USB_DVSTCTR0, + RX65N_USB_DVSTCTR0_UACT); + break; + + case RX65N_USB_SYSSTS0_LNST_SE0 : /* USB device not connected */ + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_ATTCHE); + break; + + default : + break; + } + + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_OVRCRE) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); + rx65n_usbhost_setbit (RX65N_USB_INTENB0, (RX65N_USB_INTENB0_BEMPE | + RX65N_USB_INTENB0_NRDYE | RX65N_USB_INTENB0_BRDYE)); + rx65n_usbhost_setbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_ATTCHE); +} + +/**************************************************************************** + * Function Name : hw_usb_read_syscfg + * Description : Returns the SYSCFG register value. + * Arguments : none + * Return value : SYSCFG content. + ****************************************************************************/ + +uint16_t hw_usb_read_syscfg (void) +{ + return (rx65n_usbhost_getreg(RX65N_USB_SYSCFG)); +} + +/**************************************************************************** + * Function Name : hw_usb_set_usbe + * Description : Enable USB operation. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_set_usbe (void) +{ + rx65n_usbhost_setbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_USBE); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_usbe + * Description : Enable USB operation. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_clear_usbe (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_SYSCFG, RX65N_USB_SYSCFG_USBE); +} + +/**************************************************************************** + * Function Name : hw_usb_read_syssts + * Description : Returns the value of the specified port's SYSSTS + * : register. + * Arguments : none + * Return value : SYSSTS0 content + ****************************************************************************/ + +static uint16_t hw_usb_read_syssts (void) +{ + return (rx65n_usbhost_getreg(RX65N_USB_SYSSTS0)); +} + +/**************************************************************************** + * Function Name : hw_usb_read_dvstctr + * Description : Returns the specified port's DVSTCTR register content. + * Arguments : none + * Return value : DVSTCTR0 content + ****************************************************************************/ + +static uint16_t hw_usb_read_dvstctr (void) +{ + return (rx65n_usbhost_getreg(RX65N_USB_DVSTCTR0)); +} + +/**************************************************************************** + * Function Name : hw_usb_rmw_dvstctr + * Description : Read-modify-write the specified port's DVSTCTR. + * Arguments : uint16_t data : The value to write. + * : uint16_t bitptn: Bit pattern to read-modify-write. + * Return value : none + ****************************************************************************/ + +void hw_usb_rmw_dvstctr (uint16_t data, uint16_t bitptn) +{ + uint16_t buf; + + buf = rx65n_usbhost_getreg (RX65N_USB_DVSTCTR0); + buf &= (~bitptn); + buf |= (data & bitptn); + + rx65n_usbhost_putreg(buf, RX65N_USB_DVSTCTR0); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_dvstctr + * Description : Clear the bit pattern specified in argument, of the + * : specified port's DVSTCTR register. + * Arguments : uint16_t bitptn: Bit pattern to read-modify-write. + * Return value : none + ****************************************************************************/ + +void hw_usb_clear_dvstctr (uint16_t bitptn) +{ + rx65n_usbhost_clearbit (RX65N_USB_DVSTCTR0, bitptn); +} + +/**************************************************************************** + * Function Name : hw_usb_set_vbout + * Description : Set specified port's VBOUT-bit in the DVSTCTR register. + * : (To output a "High" to pin VBOUT.) + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_set_vbout (void) +{ + rx65n_usbhost_setbit (RX65N_USB_DVSTCTR0, RX65N_USB_DVSTCTR0_VBUSEN); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_vbout + * Description : Clear specified port's VBOUT-bit in the DVSTCTR register + * : (To output a "Low" to pin VBOUT.) + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_clear_vbout (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_DVSTCTR0, RX65N_USB_DVSTCTR0_VBUSEN); +} + +/**************************************************************************** + * Function Name : hw_usb_read_fifo16 + * Description : Data is read from the specified pipemode's FIFO register + * : 16-bits wide, corresponding to the specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : CFIFO/D0FIFO/D1FIFO content (16-bit) + ****************************************************************************/ + +static uint16_t hw_usb_read_fifo16 (uint16_t pipemode) +{ + uint16_t data = 0; + + switch (pipemode) + { + case RX65N_USB_USING_CFIFO : + data = USB0.CFIFO.WORD; + break; + + case RX65N_USB_USING_D0FIFO : + data = rx65n_usbhost_getreg (RX65N_USB_D0FIFO); + break; + + case RX65N_USB_USING_D1FIFO : + data = rx65n_usbhost_getreg (RX65N_USB_D1FIFO); + break; + + default : + syslog (LOG_INFO, "Debug : %s(): Line : %d what is this \ + pipe mode?? %d\n", __func__, __LINE__, pipemode); + break; + } + + return data; +} + +/**************************************************************************** + * Function Name : hw_usb_write_fifo16 + * Description : Data is written to the specified pipemode's FIFO + * : register, 16-bits wide, corresponding to the specified + * : PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_fifo16 (uint16_t pipemode, uint16_t data) +{ + switch (pipemode) + { + case RX65N_USB_USING_CFIFO : + data = rx65n_usbhost_putreg (data, RX65N_USB_CFIFO); + break; + + case RX65N_USB_USING_D0FIFO : + data = rx65n_usbhost_putreg (data, RX65N_USB_D0FIFO); + break; + + case RX65N_USB_USING_D1FIFO : + data = rx65n_usbhost_putreg (data, RX65N_USB_D1FIFO); + break; + + default : + syslog (LOG_INFO, "Debug : %s(): Line : %d what is this \ + pipe mode?? %d\n", __func__, __LINE__, pipemode); + break; + } +} + +/**************************************************************************** + * Function Name : hw_usb_write_fifo8 + * Description : Data is written to the specified pipemode's FIFO + * : register, 8-bits wide, corresponding to the specified + * : PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * : uint8_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_fifo8 (uint16_t pipemode, uint8_t data) +{ + switch (pipemode) + { + case USB_CUSE : + + /* USB0_CFIFO8 = data; */ + + putreg8 (data, RX65N_USB_CFIFO); + break; + + case USB_D0USE : + + /* USB0_D0FIFO8 = data; */ + + putreg8 (data, RX65N_USB_D0FIFO); + break; + + case USB_D1USE : + + /* USB0_D1FIFO8 = data; */ + + putreg8 (data, RX65N_USB_D1FIFO); + break; + + default : + syslog (LOG_INFO, "Debug : %s(): Line : %d Debug hook...\n", + __func__, __LINE__); + break; + } +} + +/**************************************************************************** + * Function Name : hw_usb_get_fifosel_adr + * Description : Returns the *address* of the FIFOSEL register + * : corresponding to specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : none + ****************************************************************************/ + +static void *hw_usb_get_fifosel_adr (uint16_t pipemode) +{ + void *p_reg = NULL; + + switch (pipemode) + { + case RX65N_USB_USING_CFIFO : + p_reg = (void *)RX65N_USB_CFIFOSEL; + break; + + case RX65N_USB_USING_D0FIFO : + p_reg = (void *)RX65N_USB_D0FIFOSEL; + break; + + case RX65N_USB_USING_D1FIFO : + p_reg = (void *)RX65N_USB_D1FIFOSEL; + break; + + default : + syslog (LOG_INFO, + "Debug : %s(): Line : %d what is this pipe mode?? %d\n", + __func__, __LINE__, pipemode); + break; + } + + return p_reg; +} + +/**************************************************************************** + * Function Name : hw_usb_read_fifosel + * Description : Returns the value of the specified pipemode's FIFOSEL + * : register. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : FIFOSEL content + ****************************************************************************/ + +static uint16_t hw_usb_read_fifosel (uint16_t pipemode) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) hw_usb_get_fifosel_adr(pipemode); + + return *p_reg; +} + +/**************************************************************************** + * Function Name : hw_usb_rmw_fifosel + * Description : Data is written to the specified pipemode's FIFOSEL + * : register (the FIFOSEL corresponding to the specified + * : PIPEMODE), using read-modify-write. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * : uint16_t data : Setting value + * : uint16_t bitptn : bitptn: Bit pattern to + * : read-modify-write. + * Return value : none + ****************************************************************************/ + +static void hw_usb_rmw_fifosel (uint16_t pipemode, uint16_t data, + uint16_t bitptn) +{ + uint16_t buf; + volatile 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; +} + +/**************************************************************************** + * Function Name : hw_usb_set_mbw + * Description : Set MBW-bits (CFIFO Port Access Bit Width) of the + * : FIFOSEL corresponding to the specified PIPEMODE, to + * : select 8 or 16-bit wide FIFO port access. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * : uint16_t data : Setting value + * : (data = 0x0400), 32 bit (data = 0x0800) access mode. + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_mbw (uint16_t pipemode, uint16_t data) +{ + volatile uint16_t *p_reg; + + p_reg = hw_usb_get_fifosel_adr(pipemode); + (*p_reg) &= (~RX65N_USB_CFIFOSEL_MBW_16); + + if (0 != data) + { + (*p_reg) |= RX65N_USB_CFIFOSEL_MBW_16; + } +} + +/**************************************************************************** + * Function Name : hw_usb_set_curpipe + * Description : Set pipe to the number given; in the FIFOSEL + * : corresponding to specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_curpipe (uint16_t pipemode, uint16_t pipeno) +{ + volatile uint16_t *p_reg; + volatile uint16_t reg; + + p_reg = hw_usb_get_fifosel_adr(pipemode); + reg = *p_reg; + +#ifdef CONFIG_RX65N_USBHOST_DMA + if ((USB_D0USE == pipemode) || (USB_D1USE == pipemode)) + { + if (false == usb_check_use_usba_module(ptr)) + { + reg &= (~USB_DREQE); + } + } +#endif /* NOT_USING_D0_D1_FIFO */ + + reg &= (~RX65N_USB_CFIFOSEL_CURPIPE_MASK); + *p_reg = reg; + + reg |= pipeno; + + *p_reg = reg; +} + +/**************************************************************************** + * Function Name : hw_usb_get_fifoctr_adr + * Description : Returns the *address* of the FIFOCTR register + * : corresponding to specified PIPEMODE. + * : (FIFO Port Control Register.) + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : none + ****************************************************************************/ + +static void *hw_usb_get_fifoctr_adr (uint16_t pipemode) +{ + void *p_reg = NULL; + switch (pipemode) + { + case RX65N_USB_USING_CFIFO : + p_reg = (void *)RX65N_USB_CFIFOCTR; + break; + + case RX65N_USB_USING_D0FIFO : + p_reg = (void *)RX65N_USB_D0FIFOCTR; + break; + + case RX65N_USB_USING_D1FIFO : + p_reg = (void *)RX65N_USB_D0FIFOCTR; + break; + + default : + syslog (LOG_INFO, "Debug : %s(): Line : %d what is this \ + pipe mode?? %d\n", + __func__, __LINE__, pipemode); + break; + } + + return p_reg; +} + +/**************************************************************************** + * Function Name : hw_usb_read_fifoctr + * Description : Returns the value of the FIFOCTR register corresponding + * : to specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : FIFOCTR content + ****************************************************************************/ + +static uint16_t hw_usb_read_fifoctr (uint16_t pipemode) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) hw_usb_get_fifoctr_adr(pipemode); + + return *p_reg; +} + +/**************************************************************************** + * Function Name : hw_usb_set_bval + * Description : Set BVAL (Buffer Memory Valid Flag) to the number given; + * : in the FIFOCTR corresponding to the specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_bval (uint16_t pipemode) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) hw_usb_get_fifoctr_adr(pipemode); + + (*p_reg) |= RX65N_USB_FIFOCTR_BVAL; +} + +/**************************************************************************** + * Function Name : hw_usb_set_bclr + * Description : Set BCLR (CPU Buffer Clear) to the number given; in the + * : FIFOCTR corresponding to the specified PIPEMODE. + * Arguments : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_bclr (uint16_t pipemode) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) hw_usb_get_fifoctr_adr(pipemode); + + *p_reg = RX65N_USB_FIFOCTR_BCLR; +} + +/**************************************************************************** + * Function Name : hw_usb_set_intenb + * Description : Bit(s) to be set in INTENB register, + * : enabling the respective USB interrupt(s). + * Arguments : uint16_t data : Bit pattern: Respective interrupts + * : with '1' will be enabled. + * Return value : none + ****************************************************************************/ + +void hw_usb_set_intenb (uint16_t data) +{ + rx65n_usbhost_setbit (RX65N_USB_INTENB0, data); +} + +/**************************************************************************** + * Function Name : hw_usb_set_brdyenb + * Description : A bit is set in the specified pipe's BRDYENB, enabling + * : the respective pipe BRDY interrupt(s). + * Arguments : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_brdyenb (uint16_t pipeno) +{ + rx65n_usbhost_setbit (RX65N_USB_BRDYENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_brdyenb + * Description : Clear the PIPExBRDYE-bit of the specified pipe to + * : prohibit BRDY interrupts of that pipe. + * Arguments : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_brdyenb (uint16_t pipeno) +{ + rx65n_usbhost_clearbit (RX65N_USB_BRDYENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_set_nrdyenb + * Description : A bit is set in the specified pipe's NRDYENB, enabling + * : the respective pipe NRDY interrupt(s). + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_nrdyenb (uint16_t pipeno) +{ + rx65n_usbhost_setbit (RX65N_USB_NRDYENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_nrdyenb + * Description : Clear the PIPExNRDYE-bit of the specified pipe to + * : prohibit NRDY interrupts of that pipe. + * Arguments : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_nrdyenb (uint16_t pipeno) +{ + rx65n_usbhost_clearbit (RX65N_USB_NRDYENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_set_bempenb + * Description : A bit is set in the specified pipe's BEMPENB enabling + * : the respective pipe's BEMP interrupt(s). + * Arguments : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_bempenb (uint16_t pipeno) +{ + rx65n_usbhost_setbit (RX65N_USB_BEMPENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_bempenb + * Description : Clear the PIPExBEMPE-bit of the specified pipe to + * : prohibit BEMP interrupts of that pipe. + * Arguments : uint16_t pipeno : Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_bempenb (uint16_t pipeno) +{ + rx65n_usbhost_clearbit (RX65N_USB_BEMPENB, (1 << pipeno)); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_sts_sofr + * Description : Clear the SOFR-bit (Frame Number Refresh Interrupt + * : Status) of the clear SOF interrupt status. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void hw_usb_clear_sts_sofr (void) +{ + rx65n_usbhost_clearbit (RX65N_USB_INTSTS0, RX65N_USB_INTSTS0_SOFR); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_sts_brdy + * Description : Clear the PIPExBRDY status bit of the specified pipe to + * : clear its BRDY interrupt status. + * Arguments : uint16_t pipeno: Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_sts_brdy (uint16_t pipeno) +{ + rx65n_usbhost_putreg((~(1 << pipeno)) & RX65N_USB_PIPE_ALL, + RX65N_USB_BRDYSTS); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_status_nrdy + * Description : Clear the PIPExNRDY status bit of the specified pipe to + * : clear its NRDY interrupt status. + * Arguments : uint16_t pipeno: Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_status_nrdy (uint16_t pipeno) +{ + rx65n_usbhost_putreg((~(1 << pipeno)) & RX65N_USB_PIPE_ALL, + RX65N_USB_NRDYSTS); +} + +/**************************************************************************** + * Function Name : hw_usb_clear_status_bemp + * Description : Clear the PIPExBEMP status bit of the specified pipe to + * : its BEMP interrupt status. + * Arguments : uint16_t pipeno: Pipe number. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_status_bemp (uint16_t pipeno) +{ + rx65n_usbhost_putreg((~(1 << pipeno)) & RX65N_USB_PIPE_ALL, + RX65N_USB_BEMPSTS); +} + +/**************************************************************************** + * Function Name : hw_usb_write_dcpcfg + * Description : Specified data is written to DCPCFG register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_dcpcfg (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_DCPCFG); +} + +/**************************************************************************** + * Function Name : hw_usb_read_dcpmaxp + * Description : Returns DCPMAXP register content. + * Arguments : none + * Return value : DCPMAXP content + ****************************************************************************/ + +static uint16_t hw_usb_read_dcpmaxp (void) +{ + return rx65n_usbhost_getreg (RX65N_USB_DCPMAXP); +} + +/**************************************************************************** + * Function Name : hw_usb_write_dcpmxps + * Description : Specified data is written to DCPMAXP register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_dcpmxps (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_DCPMAXP); +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipesel + * Description : Specified data is written to PIPESEL register. + * Arguments : uint16_t data : The value to write. + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_pipesel (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_PIPESEL); +} + +/**************************************************************************** + * Function Name : hw_usb_read_pipecfg + * Description : Returns PIPECFG register content. + * Arguments : none + * Return value : PIPECFG content + ****************************************************************************/ + +static uint16_t hw_usb_read_pipecfg (void) +{ + return rx65n_usbhost_getreg (RX65N_USB_PIPECFG); +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipecfg + * Description : Specified data is written to PIPECFG register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_pipecfg (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_PIPECFG); +} + +/**************************************************************************** + * Function Name : hw_usb_read_pipemaxp + * Description : Returns PIPEMAXP register content. + * Arguments : none + * Return value : PIPEMAXP content + ****************************************************************************/ + +static uint16_t hw_usb_read_pipemaxp (void) +{ + return rx65n_usbhost_getreg (RX65N_USB_PIPEMAXP); +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipemaxp + * Description : Specified data is written to PIPEMAXP register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_pipemaxp (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_PIPEMAXP); +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipeperi + * Description : Specified data is written to PIPEPERI register. + * Arguments : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_pipeperi (uint16_t data) +{ + rx65n_usbhost_putreg (data, RX65N_USB_PIPEPERI); +} + +/**************************************************************************** + * Function Name : hw_usb_read_pipectr + * Description : Returns DCPCTR or the specified pipe's PIPECTR register + * : content. The Pipe Control Register returned is + * : determined by the specified pipe number. + * Arguments : uint16_t pipeno : Pipe number. + * Return value : PIPExCTR content + ****************************************************************************/ + +static uint16_t hw_usb_read_pipectr (uint16_t pipeno) +{ + volatile uint16_t *p_reg; + + /* Control pipe */ + + if (pipeno == 0) + { + p_reg = (uint16_t *)RX65N_USB_DCPCTR; + } + else + { + p_reg = (uint16_t *)(RX65N_USB_PIPE1CTR + (pipeno - 1)); + } + + return (rx65n_usbhost_getreg (p_reg)); +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipectr + * Description : Specified data is written to the specified pipe's + * : PIPEPERI register. + * Arguments : uint16_t pipeno : Pipe number + * : uint16_t data : Setting value + * Return value : none + ****************************************************************************/ + +void hw_usb_write_pipectr (uint16_t pipeno, uint16_t data) +{ + volatile 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; +} + +/**************************************************************************** + * Function Name : hw_usb_set_aclrm + * Description : The ACLRM-bit (Auto Buffer Clear Mode) is set in the + * : specified pipe's control register. + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_aclrm (uint16_t pipeno) +{ + volatile 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) |= RX65N_USB_PIPECTR_ACLRM; +} + +/**************************************************************************** + * Function Name : hw_usb_clear_aclrm + * Description : Clear the ACLRM bit in the specified pipe's control + * : register to disable Auto Buffer Clear Mode. + * : its BEMP interrupt status. + * Arguments : usb_utr_t *ptr : Pointer to usb_utr_t structure. + * : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_aclrm (uint16_t pipeno) +{ + volatile 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) &= (~RX65N_USB_PIPECTR_ACLRM); +} + +/**************************************************************************** + * Function Name : hw_usb_set_sqclr + * Description : The SQCLR-bit (Toggle Bit Clear) is set in the specified + * : pipe's control register. Setting SQSET to 1 makes DATA0 + * : the expected data in the pipe's next transfer. + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_sqclr (uint16_t pipeno) +{ + volatile 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) |= RX65N_USB_PIPECTR_SQCLR; +} + +/**************************************************************************** + * Function Name : hw_usb_set_sqset + * Description : The SQSET-bit (Toggle Bit Set) is set in the specified + * : pipe's control register. Setting SQSET to 1 makes DATA1 + * : the expected data in the next transfer. + * Arguments : usb_utr_t *ptr : Pointer to usb_utr_t structure. + * : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +void hw_usb_set_sqset (uint16_t pipeno) +{ + volatile 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) |= RX65N_USB_PIPECTR_SQSET; +} + +/**************************************************************************** + * Function Name : hw_usb_set_pid + * Description : Set the specified PID of the specified pipe's + * : DCPCTR/PIPECTR register. + * Arguments : uint16_t pipeno : Pipe number + * : uint16_t data : NAK/BUF/STALL. + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_pid (uint16_t pipeno, uint16_t data) +{ + volatile 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) &= (~RX65N_USB_PIPECTR_PID_MASK); + (*p_reg) |= data; +} + +/**************************************************************************** + * Function Name : hw_usb_clear_pid + * Description : Clear the specified PID-bits of the specified pipe's + * : DCPCTR/PIPECTR register. + * Arguments : uint16_t pipeno : Pipe number + * : uint16_t data : NAK/BUF/STALL - to be cleared. + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_pid (uint16_t pipeno, uint16_t data) +{ + volatile 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) &= (~RX65N_USB_PIPECTR_PID_MASK); +} + +/**************************************************************************** + * Function Name : hw_usb_set_trenb + * Description : The TRENB-bit (Transaction Counter Enable) is set in + * : the specified pipe's control register, to enable the + * : counter. + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_trenb (uint16_t pipeno) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) RX65N_USB_PIPE1TRE + ((pipeno - 1) * 2); + + (*p_reg) |= RX65N_USB_PIPETRE_TRENB; +} + +/**************************************************************************** + * Function Name : hw_usb_clear_trenb + * Description : The TRENB-bit (Transaction Counter Enable) is cleared in + * : the specified pipe's control register, to disable the + * : counter. + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_clear_trenb (uint16_t pipeno) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) RX65N_USB_PIPE1TRE + ((pipeno - 1) * 2); + + (*p_reg) &= (~RX65N_USB_PIPETRE_TRENB); +} + +/**************************************************************************** + * Function Name : hw_usb_set_trclr + * Description : The TRENB-bit (Transaction Counter Clear) is set in the + * : specified pipe's control register to clear the current + * : counter value. + * Arguments : uint16_t pipeno : Pipe number + * Return value : none + ****************************************************************************/ + +static void hw_usb_set_trclr (uint16_t pipeno) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) RX65N_USB_PIPE1TRE + ((pipeno - 1) * 2); + (*p_reg) |= RX65N_USB_PIPETRE_TRCLR; +} + +/**************************************************************************** + * Function Name : hw_usb_write_pipetrn + * Description : Specified data is written to the specified pipe's + * : PIPETRN register. + * Arguments : uint16_t pipeno : Pipe number + * : uint16_t data : The value to write. + * Return value : none + ****************************************************************************/ + +static void hw_usb_write_pipetrn (uint16_t pipeno, uint16_t data) +{ + volatile uint16_t *p_reg; + + p_reg = (uint16_t *) RX65N_USB_PIPE1TRN + ((pipeno - 1) * 2); + + *p_reg = data; +} + +/**************************************************************************** + * Function Name : usb_hstd_bchg_enable + * Description : Enable BCHG interrupt for the specified USB port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_bchg_enable (void) +{ + hw_usb_hclear_sts_bchg(); + hw_usb_hset_enb_bchge(); +} + +/**************************************************************************** + * Function Name : usb_hstd_bchg_disable + * Description : Disable BCHG interrupt for specified USB port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_bchg_disable (void) +{ + hw_usb_hclear_sts_bchg(); + hw_usb_hclear_enb_bchge(); +} + +/**************************************************************************** + * Function Name : usb_hstd_set_uact + * Description : Start sending SOF to the connected USB device. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_set_uact (void) +{ + hw_usb_rmw_dvstctr(RX65N_USB_DVSTCTR0_UACT, + ((RX65N_USB_DVSTCTR0_USBRST | + RX65N_USB_DVSTCTR0_RESUME) | + RX65N_USB_DVSTCTR0_UACT)); +} + +/**************************************************************************** + * Function Name : usb_hstd_attch_enable + * Description : Enable ATTCH (attach) interrupt of the specified USB + * : port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_attch_enable (void) +{ + /* ATTCH status Clear */ + + hw_usb_hclear_sts_attch(); + + /* Attach enable */ + + hw_usb_hset_enb_attche(); +} + +/**************************************************************************** + * Function Name : usb_hstd_attch_disable + * Description : Disable ATTCH (attach) interrupt of the specified USB + * : port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_attch_disable (void) +{ + /* ATTCH Clear */ + + hw_usb_hclear_sts_attch(); + + /* Attach disable */ + + hw_usb_hclear_enb_attche(); +} + +/**************************************************************************** + * Function Name : usb_hstd_dtch_enable + * Description : Enable DTCH (detach) interrupt of the specified USB + * : port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_dtch_enable (void) +{ + /* DTCH Clear */ + + hw_usb_hclear_sts_dtch(); + + /* Detach enable */ + + hw_usb_hset_enb_dtche(); +} + +/**************************************************************************** + * Function Name : usb_hstd_dtch_disable + * Description : Disable DTCH (detach) interrupt of the specified USB + * : port. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_dtch_disable (void) +{ + /* DTCH Clear */ + + hw_usb_hclear_sts_dtch(); + + /* Detach disable */ + + hw_usb_hclear_enb_dtche(); +} + +/**************************************************************************** + * Function Name : usb_hstd_berne_enable + * Description : Enable BRDY/NRDY/BEMP interrupt. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_berne_enable (void) +{ + /* Enable BEMP, NRDY, BRDY */ + + hw_usb_set_intenb((RX65N_USB_INTENB0_BEMPE | + RX65N_USB_INTENB0_NRDYE) | + RX65N_USB_INTENB0_BRDYE); +} + +/**************************************************************************** + * Function Name : usb_hstd_do_sqtgl + * Description : Toggle setting of the toggle-bit for the specified pipe + * : by argument. + * Arguments : uint16_t pipe : Pipe number. + * : uint16_t toggle : Current toggle status. + * Return value : none + ****************************************************************************/ + +void usb_hstd_do_sqtgl (uint16_t pipe, uint16_t toggle) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Check toggle */ + + if (RX65N_USB_DCPCTR_SQMON == (toggle & RX65N_USB_DCPCTR_SQMON)) + { + /* Do pipe SQSET */ + + hw_usb_set_sqset(pipe); + } + else + { + /* Do pipe SQCLR */ + + hw_usb_set_sqclr(pipe); + } +} + +/**************************************************************************** + * Function Name : usb_hstd_write_data_control_pipe + * Description : Request the USB FIFO to write data, and manage the size + * : of written data. + * Arguments : uint8_t buf_add : Buffer address + * : size_t buf_size : Size of the data + * Return value : uint16_t end_flag + ****************************************************************************/ + +uint16_t usb_hstd_write_data_control_pipe (uint8_t * buf_add, + size_t buf_size) +{ + uint16_t size; + uint16_t count = 0; + uint16_t buffer; + uint16_t mxps; + uint16_t end_flag; + + buffer = usb_cstd_is_set_frdy(USB_PIPE0, + (uint16_t) RX65N_USB_USING_CFIFO, + (uint16_t) RX65N_USB_CFIFOSEL_ISEL); + + /* Check error */ + + if (USB_FIFOERROR == buffer) + { + /* FIFO access error */ + + return (USB_FIFOERROR); + } + + /* Data buffer size */ + + size = buf_size; + + /* Max Packet Size */ + + mxps = usb_cstd_get_maxpacket_size(USB_PIPE0); + + /* Data size check */ + + if (buf_size <= (uint32_t) size) + { + count = buf_size; + + /* Data count check */ + + if (0 == count) + { + end_flag = USB_WRITESHRT; + } + else if (0 != (count % mxps)) + { + /* Short Packet is end of write */ + + end_flag = USB_WRITESHRT; + } + else + { + end_flag = USB_WRITING; + } + } + else + { + /* Write continues */ + + end_flag = USB_WRITING; + count = mxps; + } + + buf_add = usb_hstd_write_fifo(count, USB_CUSE, buf_add); + g_rx65n_edlist[USB_PIPE0].xfrinfo->xfrd += count; + + /* Check data count to remain */ + + /* Check if this affects any of the standard requrest commands... */ + + if (buf_size <= (uint32_t) size) + { + /* Clear data count */ + + buffer = hw_usb_read_fifoctr(USB_CUSE); /* Read CFIFOCTR */ + + /* Check BVAL */ + + if (0u == (buffer & USB_BVAL)) + { + /* Short Packet */ + + hw_usb_set_bval(USB_CUSE); + } + } + + return end_flag; +} + +/**************************************************************************** + * Function Name : usb_hstd_write_data + * Description : Switch PIPE, request the USB FIFO to write data, and + * : manage the size of written data. + * Arguments : uint16_t pipe : Pipe no. + * : uint16_t pipemode : CUSE/D0DMA/D1DMA + * Return value : uint16_t end_flag + ****************************************************************************/ + +uint16_t usb_hstd_write_data (uint8_t * buf_add, size_t buf_size, +uint16_t pipe, uint16_t pipemode) +{ + uint16_t size; + uint16_t count = 0; + uint16_t buffer; + uint16_t mxps; + uint16_t end_flag; + + if (USB_MAX_PIPE_NO < pipe) + { + return USB_WRITESHRT; /* Error */ + } + + /* Changes FIFO port by the pipe. */ + + buffer = usb_cstd_is_set_frdy(pipe, (uint16_t) pipemode, USB_FALSE); + + /* Check error */ + + if (USB_FIFOERROR == buffer) + { + /* FIFO access error */ + + return (USB_FIFOERROR); + } + + /* Data buffer size */ + + size = usb_cstd_get_buf_size(pipe); + + /* Max Packet Size */ + + mxps = usb_cstd_get_maxpacket_size(pipe); + + /* Data size check */ + + if (buf_size <= (uint32_t) size) + { + count = buf_size; + + /* Data count check */ + + if (0 == count) + { + end_flag = USB_WRITESHRT; + } + else if (0 != (count % mxps)) + { + /* Short Packet is end of write */ + + end_flag = USB_WRITESHRT; + } + else + { + { + /* Write continues */ + + end_flag = USB_WRITEEND; + } + } + } + else + { + /* Write continues */ + + end_flag = USB_WRITING; + count = mxps; + } + + buf_add = usb_hstd_write_fifo(count, pipemode, buf_add); + g_rx65n_edlist[pipe].xfrinfo->xfrd += count; + g_rx65n_edlist[pipe].xfrinfo->buffer += count; + + /* Check data count to remain */ + + if (buf_size <= (uint32_t) size) + { + /* Clear data count */ + + buffer = hw_usb_read_fifoctr(pipemode); /* Read CFIFOCTR */ + + /* Check BVAL */ + + if (0u == (buffer & USB_BVAL)) + { + /* Short Packet */ + + hw_usb_set_bval(pipemode); + } + } + + return end_flag; +} + +/**************************************************************************** + * Function Name : usb_hstd_receive_start + * Description : Start data reception using CPU/DMA transfer to USB + * : Host/USB device. + * Arguments : uint16_t pipe : Pipe no. + * Return value : none + ****************************************************************************/ + +void usb_hstd_receive_start (uint8_t *buffer, size_t buflen, uint8_t pipe) +{ + uint32_t length; + uint16_t mxps; + uint16_t useport; + + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Select NAK */ + + usb_cstd_set_nak(pipe); + + /* Ignore count clear */ + + hw_usb_clear_status_bemp((uint16_t) pipe); /* BEMP Status Clear */ + hw_usb_clear_sts_brdy(pipe); /* BRDY Status Clear */ + hw_usb_clear_status_nrdy (pipe); /* NRDY Status Clear */ + nrdy_retries[pipe] = 0; /* Initialize theh NRDY retries to 0 */ + useport = USB_CUSE; + + /* Changes the FIFO port by the pipe. */ + + usb_cstd_chg_curpipe(pipe, useport, USB_FALSE); + mxps = usb_cstd_get_maxpacket_size(pipe); /* Max Packet Size */ + + length = buflen; + + 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)); + } + } + + usb_cstd_set_buf(pipe); /* Set BUF */ + + /* Enable Ready Interrupt */ + + hw_usb_set_brdyenb(pipe); + + /* Enable Not Ready Interrupt */ + + usb_cstd_nrdy_enable(pipe); +} + +/**************************************************************************** + * Function Name : usb_hstd_send_start + * Description : Start data transmission using CPUtransfer to USB host/ + * : /device. + * Arguments : uint8_t pipe : Pipe no. + * Return value : none + ****************************************************************************/ + +void usb_hstd_send_start (uint8_t *buffer, size_t buflen, uint8_t pipe) +{ + uint16_t useport; + + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + usb_cstd_set_nak(pipe); /* Select NAK */ + hw_usb_clear_status_bemp(pipe); /* BEMP Status Clear */ + hw_usb_clear_sts_brdy(pipe); /* BRDY Status Clear */ + hw_usb_clear_status_nrdy (pipe); /* NRDY Status Clear */ + nrdy_retries[pipe] = 0; /* Initialize theh NRDY retries to 0 */ + + /* Pipe number to FIFO port select */ + + useport = USB_CUSE; + + /* Changes the FIFO port by the pipe. */ + + usb_cstd_chg_curpipe(pipe, useport, USB_FALSE); + + /* Buffer to FIFO data write */ + + usb_hstd_buf_to_fifo(buffer, buflen, pipe, useport); + usb_cstd_set_buf(pipe); /* Set BUF */ +} + +/**************************************************************************** + * Function Name : usb_hstd_get_pipe_no + * Description : Get PIPE No. + * Arguments : uint8_t type : Transfer Type.(USB_EP_BULK/USB_EP_INT) + * : uint8_t dir : (USB_PIPE_DIR_IN/USB_PIPE_DIR_OUT) + * Return value : Pipe no (USB_PIPE1->USB_PIPE9:OK, USB_NULL:Error) + ****************************************************************************/ + +uint8_t usb_hstd_get_pipe_no (uint8_t type, uint8_t dir) +{ + uint8_t pipe_no = USB_NULL; + uint16_t pipe; + + if (USB_EP_BULK == type) + { + /* BULK PIPE Loop */ + + /* WAIT_LOOP */ + + if (dir == USB_EP_IN) + { + pipe = USB_BULK_PIPE_START; + } + else + { + pipe = USB_BULK_PIPE_START + 1; + } + + for (; pipe < (USB_BULK_PIPE_END + 1); pipe = pipe + 2) + { + if (USB_FALSE == g_usb_pipe_table[pipe].use_flag) + { + /* Check Free pipe */ + + pipe_no = pipe; /* Set Free pipe */ + break; + } + } + } + + if (USB_EP_INT == type) + { + /* Interrupt PIPE Loop */ + + /* WAIT_LOOP */ + + for (pipe = USB_INT_PIPE_START; pipe < (USB_INT_PIPE_END +1); pipe++) + { + if (USB_FALSE == g_usb_pipe_table[pipe].use_flag) + { + /* Check Free pipe */ + + pipe_no = pipe; /* Set Free pipe */ + break; + } + } + } + + return pipe_no; +} + +/**************************************************************************** + * Function Name : usb_hstd_read_data_control_pipe + * Description : Request to read data from USB FIFO, and manage the size + * : of the data read. + * Arguments : None + * Return value : USB_READING / USB_READEND / USB_READSHRT / USB_READOVER + ****************************************************************************/ + +uint16_t usb_hstd_read_data_control_pipe (void) +{ + uint16_t count; + uint16_t buffer; + uint16_t mxps; + uint16_t dtln; + uint16_t end_flag; + + /* Changes FIFO port by the pipe. */ + + buffer = usb_cstd_is_set_frdy(USB_PIPE0, (uint16_t) USB_CUSE, USB_FALSE); + + if (USB_FIFOERROR == buffer) + { + /* FIFO access error */ + + return (USB_FIFOERROR); + syslog (LOG_INFO, "FIFO ERROR"); + } + + dtln = (uint16_t) (buffer & RX65N_USB_FIFOCTR_DTLN); + + /* Max Packet Size */ + + mxps = usb_cstd_get_maxpacket_size(USB_PIPE0); + + /* now calculate the count */ + + count = g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->buflen - + g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->xfrd; + + if (count < dtln) + { + /* Buffer Over ? */ + + end_flag = USB_READOVER; + usb_cstd_set_nak(USB_PIPE0); /* Set NAK */ + count = g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->xfrd; + g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->xfrd = dtln; + } + + else if (count == dtln) + { + /* Just Receive Size */ + + count = dtln; + end_flag = USB_READEND; + usb_cstd_set_nak(USB_PIPE0); /* Set NAK */ + } + else + { + /* Continus Receive data */ + + count = dtln; + + end_flag = USB_READING; + if ((0 == count) || (0 != (count % mxps))) + { + /* Null Packet receive */ + + end_flag = USB_READSHRT; + usb_cstd_set_nak(USB_PIPE0); /* Select NAK */ + } + } + + if (0 == dtln) + { + /* 0 length packet */ + + /* Clear BVAL */ + + hw_usb_set_bclr(USB_CUSE); + } + else + { + g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->buffer = usb_hstd_read_fifo( + count, USB_CUSE, g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->buffer); + } + + g_rx65n_tdlist[USB_PIPE0].ed->xfrinfo->xfrd += count; + + return (end_flag); +} + +/**************************************************************************** + * Function Name : usb_hstd_read_data + * Description : Request to read data from USB FIFO, and manage the size + * : of the data read. + * Arguments : uint16_t pipe : Pipe no. + * : uint16_t pipemode : Pipe mode (CFIFO/D0FIFO/D1FIFO) + * Return value : USB_READING / USB_READEND / USB_READSHRT / USB_READOVER + ****************************************************************************/ + +uint16_t usb_hstd_read_data (uint16_t pipe, uint16_t pipemode) +{ + uint16_t count; + uint16_t buffer; + uint16_t mxps; + uint16_t dtln; + uint16_t end_flag = 0; + + if (USB_MAX_PIPE_NO < pipe) + { + return USB_ERROR; /* Error */ + } + + if (pipe != 0) /* Data transfer for non CTRL pipe */ + { + buffer = usb_cstd_is_set_frdy(pipe, (uint16_t) pipemode, USB_FALSE); + + if (USB_FIFOERROR == buffer) + { + return (USB_FIFOERROR); + } + + dtln = (uint16_t) (buffer & RX65N_USB_FIFOCTR_DTLN); + mxps = usb_cstd_get_maxpacket_size(pipe); + + /* now calculate the count */ + + if (pipe == g_kbdpipe) + { + /* For HID KBD read the received data */ + + count = dtln; + } + else + { + count = g_rx65n_edlist[pipe].xfrinfo->buflen - + g_rx65n_edlist[pipe].xfrinfo->xfrd; + } + + if (count < dtln) + { + /* Buffer Over ? */ + + count = dtln; + end_flag = USB_READOVER; + } + + else if (count == dtln) + { + /* Just Receive Size */ + + count = dtln; + end_flag = USB_READEND; + usb_cstd_set_nak(pipe); + } + else + { + /* Continus Receive data */ + + count = dtln; + + end_flag = USB_READING; + if ((0 == count) || (0 != (count % mxps))) + { + /* Null Packet receive */ + + end_flag = USB_READSHRT; + } + } + + usb_hstd_read_fifo(count, + pipemode, g_rx65n_edlist[pipe].xfrinfo->buffer); + + g_rx65n_edlist[pipe].xfrinfo->xfrd += count; + + if (pipe == g_kbdpipe) + { + /* For HID KBD read pointer should not be incremented */ + } + else + { + g_rx65n_edlist[pipe].xfrinfo->buffer += count; + } + } + + return (end_flag); +} + +/**************************************************************************** + * Function Name : usb_hstd_data_end + * Description : Set USB registers as appropriate after data + * : transmission/reception, and call the callback function + * : as transmission/reception is complete. + * Arguments : uint16_t pipe : Pipe no. + * : uint16_t status : Transfer status type. + * Return value : none + ****************************************************************************/ + +void usb_hstd_data_end (uint16_t pipe, uint16_t status) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* 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); + + /* Disable Transaction count */ + + usb_cstd_clr_transaction_counter(pipe); +} + +/**************************************************************************** + * Function Name : usb_hstd_buf_to_fifo + * Description : Set USB registers as required to write from data buffer + * : to USBFIFO, to have USB FIFO to write data to bus. + * Arguments : uint16_t pipe : Pipe no. + * : uint16_t useport : Port no. + * Return value : none + ****************************************************************************/ + +void usb_hstd_buf_to_fifo (uint8_t *buffer, size_t buflen, uint16_t pipe, + uint16_t useport) +{ + uint16_t end_flag; + + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Disable Ready and empty Interrupt */ + + hw_usb_clear_brdyenb(pipe); + hw_usb_clear_bempenb(pipe); + + end_flag = usb_hstd_write_data(buffer, buflen, pipe, useport); + + switch (end_flag) + { + case USB_WRITING : + + /* 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_FIFOERROR : + + /* FIFO access error */ + + syslog (LOG_INFO, "### FIFO access error \n"); + usb_hstd_forced_termination(pipe, (uint16_t) USB_DATA_ERR); + break; + + default : + usb_hstd_forced_termination(pipe, (uint16_t) USB_DATA_ERR); + break; + } +} + +/**************************************************************************** + * Function Name : usb_hstd_brdy_pipe_process + * Description : Search for the PIPE No. that BRDY interrupt occurred, + * : and request data transmission/reception from the PIPE + * Arguments : uint16_t bitsts : BRDYSTS Register & BRDYENB + * : Register + * Return value : none + ****************************************************************************/ + +void usb_hstd_brdy_pipe_process (uint16_t bitsts) +{ + uint16_t i; + uint16_t end_flag; + size_t data_len; + uint8_t *data_address; + uint16_t buffer; +#ifdef CONFIG_USBHOST_ASYNCH + struct rx65n_usbhost_s *priv = &g_usbhost; +#endif + + for (i = USB_MIN_PIPE_NO; i <= USB_MAX_PIPE_NO; i++) + { + if (0 != (bitsts & USB_BITSET(i))) + { + /* Clear the Interrupt status bit - clear for both BEMP and BRDY */ + + hw_usb_clear_sts_brdy (i); + hw_usb_clear_status_bemp (i); + if (RX65N_USB_PIPECFG_DIR == usb_cstd_get_pipe_dir(i)) + { + /* Buffer to FIFO data write */ + + data_len = g_rx65n_edlist[i].xfrinfo->buflen - + g_rx65n_edlist[i].xfrinfo->xfrd; + buffer = usb_cstd_get_pid(i); + + /* MAX packet size error ? */ + + if (RX65N_USB_DCPCTR_PIDSTALL == (buffer & + RX65N_USB_DCPCTR_PIDSTALL)) + { + syslog (LOG_INFO, "### STALL Pipe %d\n", i); + usb_hstd_forced_termination(i, + (uint16_t) USB_DATA_STALL); + } + else + { + if (data_len == 0) + { + syslog (LOG_INFO, "BRDY can NOT be with 0 len\ + data for pipe\n", i); + } + + /* If still data is present - let the data + * transfer coninue + * + */ + + else + { + data_address = g_rx65n_edlist[i].xfrinfo->buffer; + usb_hstd_buf_to_fifo(data_address, data_len, i, + USB_CUSE); + usb_cstd_set_buf(i); /* Set BUF */ + } + } + } + else + { + /* FIFO to Buffer data read */ + + end_flag = usb_hstd_read_data(i, USB_CUSE); + + if (end_flag != USB_READING) + { +#ifdef CONFIG_USBHOST_ASYNCH + if ((i == g_kbdpipe) && + (NULL == g_rx65n_edlist[i].xfrinfo->callback)) +#else + if (i == g_kbdpipe) +#endif + { + usb_cstd_clr_stall(i); + } + + else + { + usb_hstd_data_end(i, (uint16_t) USB_DATA_OK); + g_rx65n_edlist[i].xfrinfo->tdstatus = + TD_CC_NOERROR; + +#ifdef CONFIG_USBHOST_ASYNCH + if ((g_rx65n_edlist[i].xfrinfo != 0) + && (g_rx65n_edlist[i].xfrinfo->callback)) + { + hw_usb_write_dcpmxps((uint16_t) (USB_DEFPACKET + + USB_DEVICE_1)); + rx65n_usbhost_asynch_completion(priv, + &g_rx65n_edlist[i]); + } + +#endif + } + + rx65n_usbhost_givesem(&g_rx65n_edlist[i].wdhsem); + } + } + } + } + + return; +} + +/**************************************************************************** + * Function Name : usb_hstd_nrdy_pipe_process + * Description : Search for PIPE No. that occurred NRDY interrupt, and + * : execute the process for PIPE when NRDY interrupt + * : occurred + * Arguments : uint16_t bitsts : NRDYSTS Register & NRDYENB Register + * Return value : none + ****************************************************************************/ + +void usb_hstd_nrdy_pipe_process (uint16_t bitsts) +{ + uint16_t i; + + /* WAIT_LOOP */ + + for (i = USB_MIN_PIPE_NO; i <= USB_MAX_PIPE_NO; i++) + { + if (0 != (bitsts & USB_BITSET(i))) + { + hw_usb_clear_status_nrdy (i); + usb_hstd_nrdy_endprocess(i); + } + } + + return; +} + +/**************************************************************************** + * Function Name : usb_hstd_bemp_pipe_process + * Description : Search for PIPE No. that BEMP interrupt occurred, and + * : complete data transmission for the PIPE + * Arguments : uint16_t bitsts : BEMPSTS Register & BEMPENB Register + * Return value : none + ****************************************************************************/ + +void usb_hstd_bemp_pipe_process (uint16_t bitsts) +{ + uint16_t buffer; + uint16_t i; + size_t data_len; + + /* WAIT_LOOP */ + + for (i = USB_MIN_PIPE_NO; i <= USB_PIPE5; i++) + { + if (0 != (bitsts & USB_BITSET(i))) + { + /* Clear the Interrupt status bit */ + + hw_usb_clear_status_bemp (i); + hw_usb_clear_sts_brdy (i); + + data_len = g_rx65n_edlist[i].xfrinfo->buflen - + g_rx65n_edlist[i].xfrinfo->xfrd; + buffer = usb_cstd_get_pid(i); + + /* MAX packet size error ? */ + + if (RX65N_USB_DCPCTR_PIDSTALL == (buffer & + RX65N_USB_DCPCTR_PIDSTALL)) + { + syslog (LOG_INFO, "### STALL Pipe %d\n", i); + usb_hstd_forced_termination(i, (uint16_t) USB_DATA_STALL); + } + else + { + if (data_len == 0) + { + usb_hstd_data_end(i, (uint16_t) USB_DATA_OK); + g_rx65n_edlist[i].xfrinfo->tdstatus = TD_CC_NOERROR; + + /* Release the semaphore for this pipe */ + + rx65n_usbhost_givesem(&g_rx65n_edlist[i].wdhsem); + } + + else + { + syslog (LOG_INFO, "BEMP can NOT be with %d len data \ + for pipe\n", data_len, i); + } + } + } + } + + return; +} + +/**************************************************************************** + * Function Name : usb_hstd_get_pipe_peri_value + * Description : Get value to be set in PIPEPERI + * Arguments : uint8_t binterval : bInterval for ENDPOINT Descriptor + * Return value : Value for set PIPEPERI + ****************************************************************************/ + +uint16_t usb_hstd_get_pipe_peri_value (uint8_t binterval) +{ + uint16_t pipe_peri = USB_NULL; + uint16_t work1; + uint16_t work2; + + /* Set interval counter */ + + if (0 != binterval) + { + /* FS/LS interrupt */ + + /* The time of the FS/LS interrupt forwarding of the interval is + * specified by the unit of ms. It is necessary to calculate to + * specify USB-IP by the n-th power of two. NAK rate of the control + * and the bulk transfer doesn't correspond. + */ + + work1 = binterval; + work2 = 0; + for (; work1 != 0; work2++ ) + { + work1 = (uint16_t)(work1 >> 1); + } + + if (0 != work2) + { + /* Interval time */ + + pipe_peri |= (uint16_t)(work2 - 1); + } + } + + return pipe_peri; +} + +/**************************************************************************** + * Function Name : usb_hstd_chk_attach + * Description : Checks whether USB Device is attached or not and return + * : USB speed of USB Device + * Arguments : none + * Return value : uint16_t : connection status + * : : (USB_ATTACHF/USB_ATTACHL/USB_DETACH/USB_OK) + * Note : Please change for your SYSTEM + ****************************************************************************/ + +uint16_t usb_hstd_chk_attach (void) +{ + uint16_t buf[3]; + usb_hstd_read_lnst(buf); + + if (0 == (uint16_t) (buf[1] & RX65N_USB_DVSTCTR0_RHST)) + { + if (RX65N_USB_SYSSTS0_LNST_FS_JSTS == (buf[0] & 3)) + { + /* High/Full speed device */ + + return USB_ATTACHF; + } + else if (RX65N_USB_SYSSTS0_LNST_LS_JSTS == (buf[0] & 3)) + { + /* Low speed device */ + + return USB_ATTACHL; + } + else if (RX65N_USB_SYSSTS0_LNST_SE0 == (buf[0] & 3)) + { + syslog (LOG_INFO, "Debug: Detach device\n\r"); + } + else + { + syslog (LOG_INFO, "Attach unknown speed device\n"); + } + } + else + { + syslog (LOG_INFO, "Already device attached\n\r"); + return 0; + } + + return USB_DETACH; +} + +/**************************************************************************** + * Function Name : usb_hstd_chk_clk + * Description : Checks SOF sending setting when USB Device is detached + * : or suspended , BCHG interrupt enable setting and + *: clock stop processing + * Arguments : uint16_t event : device state + * Return value : none + ****************************************************************************/ + +void usb_hstd_chk_clk (uint16_t event) +{ + if ((USB_DETACH == event) || (USB_SUSPEND == event)) + { + usb_hstd_chk_sof(); + + /* Enable port BCHG interrupt */ + + usb_hstd_bchg_enable(); + } +} + +/**************************************************************************** + * Function Name : usb_hstd_detach_process + * Description : Handles the require processing when USB device is + * : detached (Data transfer forcibly termination processing + *: to the connected USB Device, the clock supply stop setting and + *: the USB interrupt disable setting etc) + * Arguments : none + * Return value : Device speed + ****************************************************************************/ + +uint16_t usb_hstd_detach_process (void) +{ + uint16_t connect_inf; + uint16_t i; + + /* ATTCH interrupt disable */ + + usb_hstd_attch_disable(); + + /* DTCH interrupt disable */ + + usb_hstd_dtch_disable(); + usb_hstd_bchg_disable(); + + /* Check if control pipe in use */ + + if (RX65N_USB_PIPECTR_PIDBUF == usb_cstd_get_pid(USB_PIPE0)) + { + /* End of data transfer (IN/OUT) */ + + usb_hstd_forced_termination(USB_PIPE0, (uint16_t) USB_DATA_STOP); + } + + usb_cstd_clr_pipe_cnfg(USB_PIPE0); + + /* WAIT_LOOP */ + + for (i = USB_MIN_PIPE_NO; i <= USB_MAX_PIPE_NO; i++) + { + /* Not control transfer */ + + /* Is this pipe used */ + + if (g_usb_pipe_table[i].use_flag == USB_TRUE) + { + /* PID=BUF ? */ + + if (RX65N_USB_PIPECTR_PIDBUF == usb_cstd_get_pid(i)) + { + /* End of data transfer (IN/OUT) */ + + usb_hstd_forced_termination(i, (uint16_t) USB_DATA_STOP); + } + + usb_cstd_clr_pipe_cnfg(i); + } + } + + /* Decide USB Line state (ATTACH) */ + + connect_inf = usb_hstd_chk_attach(); + switch (connect_inf) + { + case USB_ATTACHL : + usb_hstd_attach(connect_inf); + break; + + case USB_ATTACHF : + usb_hstd_attach(connect_inf); + break; + + case USB_DETACH : + + /* USB detach */ + + usb_hstd_detach(); + + /* Check clock */ + + usb_hstd_chk_clk((uint16_t) USB_DETACH); + break; + + default : + + /* USB detach */ + + usb_hstd_detach(); + + /* Check clock */ + + usb_hstd_chk_clk((uint16_t) USB_DETACH); + break; + } + + return connect_inf; +} + +/**************************************************************************** + * Function Name : usb_hstd_read_lnst + * Description : Reads LNST register two times, checks whether these + * : values are equal and returns the value of DVSTCTR + * : register that correspond to the port specified by 2nd + * : argument. + * Arguments : uint16_t *buf : Pointer to the buffer to store DVSTCTR + * : register + * Return value : none + * Note : Please change for your SYSTEM + ****************************************************************************/ + +void usb_hstd_read_lnst (uint16_t *buf) +{ + /* WAIT_LOOP */ + + if (g_attached) + { + do + { + buf[0] = hw_usb_read_syssts(); + + /* 30ms wait */ + + up_mdelay(30); + buf[1] = hw_usb_read_syssts(); + if ((buf[0] & RX65N_USB_SYSSTS0_LNST) == + (buf[1] & RX65N_USB_SYSSTS0_LNST)) + { + /* 20ms wait */ + + up_mdelay(20); + buf[1] = hw_usb_read_syssts(); + } + } + while (((buf[0] & RX65N_USB_SYSSTS0_LNST) != + (buf[1] & RX65N_USB_SYSSTS0_LNST)) || (((buf[0] & 3) == 0))); + buf[1] = hw_usb_read_dvstctr(); + } + + if (g_detached) + { + do + { + buf[0] = hw_usb_read_syssts(); + + /* 30ms wait */ + + up_mdelay(30); + buf[1] = hw_usb_read_syssts(); + if ((buf[0] & RX65N_USB_SYSSTS0_LNST) == + (buf[1] & RX65N_USB_SYSSTS0_LNST)) + { + /* 20ms wait */ + + up_mdelay(20); + buf[1] = hw_usb_read_syssts(); + } + } + while (((buf[0] & RX65N_USB_SYSSTS0_LNST) != + (buf[1] & RX65N_USB_SYSSTS0_LNST))); + buf[1] = hw_usb_read_dvstctr(); + } +} + +/**************************************************************************** + * Function Name : usb_hstd_attach_process + * Description : Interrupt disable setting when USB Device is attached + * : handles the required interrupt disable setting etc when + * : USB device is attached. + * Arguments : none + * Return value : Speed of the device + * Note : Please change for your SYSTEM + ****************************************************************************/ + +uint16_t usb_hstd_attach_process (void) +{ + uint16_t connect_inf; + + /* ATTCH interrupt disable */ + + usb_hstd_attch_disable(); + + /* DTCH interrupt disable */ + + usb_hstd_dtch_disable(); + usb_hstd_bchg_disable(); + + /* Decide USB Line state (ATTACH) */ + + connect_inf = usb_hstd_chk_attach(); + switch (connect_inf) + { + case USB_ATTACHL : + usb_hstd_attach(connect_inf); + break; + + case USB_ATTACHF : + usb_hstd_attach(connect_inf); + break; + + case USB_DETACH : + + /* USB detach */ + + usb_hstd_detach(); + + /* Check clock */ + + usb_hstd_chk_clk((uint16_t) USB_DETACH); + break; + + default : + usb_hstd_attach((uint16_t) USB_ATTACHF); + break; + } + + return connect_inf; +} + +/**************************************************************************** + * Function Name : usb_hstd_chk_sof + * Description : Checks whether SOF is sended or not + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_chk_sof (void) +{ + up_mdelay(1); +} + +/**************************************************************************** + * Function Name : usb_hstd_bus_reset + * Description : Setting USB register when BUS Reset + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_bus_reset (void) +{ + uint16_t buf; + uint16_t i; + + /* USBRST=1, UACT=0 */ + + hw_usb_rmw_dvstctr(RX65N_USB_DVSTCTR0_USBRST, + (RX65N_USB_DVSTCTR0_USBRST | RX65N_USB_DVSTCTR0_UACT)); + + /* Wait 50ms */ + + up_mdelay(50); /* usb_cpu_delay_xms((uint16_t) 50); */ + + /* USBRST=0, RESUME=0, UACT=1 */ + + usb_hstd_set_uact(); + + /* Wait 10ms or more (USB reset recovery) */ + + up_mdelay(20); /* usb_cpu_delay_xms((uint16_t) 20); */ + + /* WAIT_LOOP */ + + /* If DVSTCTR0 last 3 bits i.e. RHST bit fields are 1xx. + * Then the USB reset is still in progress + */ + + for (i = 0, buf = 0x04; (i < 3) && (0x04 == buf); ++i) + { + /* DeviceStateControlRegister - ResetHandshakeStatusCheck */ + + buf = hw_usb_read_dvstctr(); + buf = (uint16_t) (buf & RX65N_USB_DVSTCTR0_RHST); + if (0x04 == buf) + { + /* Wait */ + + up_mdelay(10); + } + } + + /* 30ms wait */ + + up_mdelay(30); +} + +/**************************************************************************** + * Function Name : usb_hstd_write_fifo + * Description : Write specified amount of data to specified USB FIFO. + * Arguments : uint16_t count : Write size + * : uint16_t pipemode : The mode of CPU/DMA(D0)/DMA(D1). + * : uint16_t *write_p : Address of buffer of data to write + * Return value : The incremented address of last argument (write_p). + ****************************************************************************/ + +uint8_t *usb_hstd_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) + { + /* 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; +} + +/**************************************************************************** + * Function Name : usb_hstd_read_fifo + * Description : Read specified buffer size from the USB FIFO. + * Arguments : uint16_t count :Read size + * : uint16_t pipemode:The mode of CPU/DMA(D0)/DMA(D1). + * : uint16_t *read_p :Address of buffer to store the read + * : data + * Return value : Pointer to a buffer that contains the data to be read + * : next. + ****************************************************************************/ + +uint8_t *usb_hstd_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); + + /* Condition compilation by the difference of the little endian */ + + *read_p = (uint8_t) (odd_byte_data_temp & 0x00ff); + + /* Renewal read pointer */ + + read_p += sizeof(uint8_t); + } + + return read_p; +} + +/**************************************************************************** + * Function Name : usb_hstd_forced_termination + * Description : Terminate data transmission and reception. + * Arguments : uint16_t pipe : Pipe Number + * : uint16_t status : Transfer status type + * Return value : none + * Note : In the case of timeout status, it does not call + * : back. + ****************************************************************************/ + +void usb_hstd_forced_termination (uint16_t pipe, uint16_t status) +{ + uint16_t buffer; + + /* PID = NAK */ + + /* Set NAK */ + + usb_cstd_set_nak(pipe); + + /* 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 */ + + buffer = hw_usb_read_fifosel(USB_CUSE); + if ((buffer & USB_CURPIPE) == pipe) + { + /* Changes the FIFO port by the pipe. */ + + usb_cstd_chg_curpipe((uint16_t) USB_PIPE0, + (uint16_t) USB_CUSE, USB_FALSE); + } + +#ifdef DMA_DTC_NOT_ENABLED +#if ((USB_CFG_DTC == USB_CFG_ENABLE) || (USB_CFG_DMA == USB_CFG_ENABLE)) + + /* Clear D0FIFO-port */ + + buffer = hw_usb_read_fifosel(ptr, USB_D0USE); + if ((buffer & USB_CURPIPE) == pipe) + { + /* Changes the FIFO port by the pipe. */ + + usb_cstd_chg_curpipe(ptr, (uint16_t) USB_PIPE0, + (uint16_t) USB_D0USE, USB_FALSE); + } + + /* Clear D1FIFO-port */ + + buffer = hw_usb_read_fifosel(ptr, USB_D1USE); + if ((buffer & USB_CURPIPE) == pipe) + { + /* Changes the FIFO port by the pipe. */ + + usb_cstd_chg_curpipe(ptr, (uint16_t) USB_PIPE0, + (uint16_t) USB_D1USE, USB_FALSE); + } + +#endif /* ((USB_CFG_DTC==USB_CFG_ENABLE)||(USB_CFG_DMA==USB_CFG_ENABLE)) */ +#endif /* DMA_DTC_NOT_ENABLED */ + + /* Do Aclr */ + + usb_cstd_do_aclrm(pipe); +} + +/**************************************************************************** + * Function Name : usb_hstd_nrdy_endprocess + * Description : NRDY interrupt processing. (Forced termination of + * : data transmission and reception of specified pipe.) + * Arguments : uint16_t pipe : Pipe No + * Return value : none + * Note : none + ****************************************************************************/ + +void usb_hstd_nrdy_endprocess (uint16_t pipe) +{ + uint16_t buffer; + + /* Host Function */ + + hw_usb_write_pipesel(pipe); /* Select the pipe */ + buffer = usb_cstd_get_pid(pipe); /* Read the PID of selected pipe */ + usb_cstd_set_nak(pipe); /* Set PIPE to NAK. Stop sending tokens. */ + + /* STALL ? */ + + if (RX65N_USB_DCPCTR_PIDSTALL == (buffer & RX65N_USB_DCPCTR_PIDSTALL)) + { + usb_hstd_forced_termination(pipe, USB_DATA_STALL); + } + else + { + /* Wait for About 60ns */ + + buffer = hw_usb_read_syssts(); + + if (nrdy_retries[pipe] >= 1) + { + /* Data Device Ignore X 3 call back */ + + /* End of data transfer */ + + usb_hstd_forced_termination(pipe, USB_DATA_TMO); + + g_rx65n_edlist[pipe].xfrinfo->tdstatus = TD_CC_DEVNOTRESPONDING; + + /* Release the semaphore for this pipe */ + + rx65n_usbhost_givesem(&g_rx65n_edlist[pipe].wdhsem); + } + else + { + nrdy_retries[pipe]++; /* Increment and note error count */ + + /* 5ms wait */ + + up_mdelay(1); + + /* PIPEx Data Retry */ + + usb_hstd_data_end(pipe, (uint16_t) USB_DATA_TMO); + hw_usb_set_bclr(USB_CUSE); /* Clear Buffer on CPU side */ + g_rx65n_edlist[pipe].xfrinfo->tdstatus = TD_CC_DEVNOTRESPONDING; + + /* 5ms wait */ + + usb_cstd_pipe_init (pipe); + + /* Release the semaphore for this pipe */ + + rx65n_usbhost_givesem(&g_rx65n_edlist[pipe].wdhsem); + } + } +} + +/**************************************************************************** + * Function Name : usb_hstd_bus_int_disable + * Description : Disable USB Bus Interrupts OVRCR, ATTCH, DTCH, and BCHG. + * Arguments : none + * Return : none + ****************************************************************************/ + +void usb_hstd_bus_int_disable (void) +{ + /* ATTCH interrupt disable */ + + usb_hstd_attch_disable(); + + /* DTCH interrupt disable */ + + usb_hstd_dtch_disable(); + + /* BCHG interrupt disable */ + + usb_hstd_bchg_disable(); +} + +/**************************************************************************** + * Function Name : usb_hstd_attach + * Description : Set USB registers as required when USB device is + * : attached, and notify MGR (manager) task that attach + * : event occurred. + * Arguments : uint16_t result : Result. + * Return value : none + ****************************************************************************/ + +void usb_hstd_attach (uint16_t result) +{ + /* DTCH interrupt enable */ + + usb_hstd_dtch_enable(); + + /* Interrupt Enable */ + + usb_hstd_berne_enable(); + + usb_hstd_bus_reset(); +} + +/**************************************************************************** + * Function Name : usb_hstd_detach + * Description : Set USB register as required when USB device is detached + * : and notify MGR (manager) task that detach occurred. + * Arguments : none + * Return value : none + ****************************************************************************/ + +void usb_hstd_detach (void) +{ + /* DVSTCTR clear */ + + hw_usb_clear_dvstctr((uint16_t) (RX65N_USB_DVSTCTR0_RWUPE | + RX65N_USB_DVSTCTR0_USBRST | + RX65N_USB_DVSTCTR0_RESUME | + RX65N_USB_DVSTCTR0_UACT)); + + /* ATTCH interrupt enable */ + + usb_hstd_attch_enable(); +} + +/**************************************************************************** + * Function Name : usb_cstd_get_buf_size + * Description : Return buffer size, or max packet size, of specified + * : pipe. + * Arguments : uint16_t pipe : Pipe number. + * Return value : uint16_t : FIFO buffer size or max packet size. + ****************************************************************************/ + +static uint16_t usb_cstd_get_buf_size (uint16_t pipe) +{ + uint16_t size = 0; + uint16_t buffer; + + if (USB_PIPE0 == pipe) + { + /* Not continuation transmit */ + + buffer = hw_usb_read_dcpmaxp(); + + /* Max Packet Size */ + + size = (uint16_t) (buffer & RX65N_USB_DCPMAXP_MXPS_MASK); + } + else + { + /* Pipe select */ + + hw_usb_write_pipesel(pipe); + + /* Read the maximum packet size of selected pipe */ + + buffer = hw_usb_read_pipemaxp (); + + /* Max Packet Size */ + + size = (uint16_t) (buffer & RX65N_USB_PIPEMAXP_MXPSMASK); + } + + return size; +} + +/**************************************************************************** + * Function Name : usb_cstd_pipe_init + * Description : Initialization of registers associated with specified + * : pipe. + * Arguments : uint16_t pipe : Pipe Number + * Return value : none + ****************************************************************************/ + +static void usb_cstd_pipe_init (uint16_t pipe) +{ + /* 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); + + rx65n_usbhost_putreg(pipe, RX65N_USB_PIPESEL); + rx65n_usbhost_putreg(g_usb_pipe_table[pipe].pipe_cfg, + RX65N_USB_PIPECFG); + rx65n_usbhost_putreg(g_usb_pipe_table[pipe].pipe_maxp, + RX65N_USB_PIPEMAXP); + rx65n_usbhost_putreg(g_usb_pipe_table[pipe].pipe_peri, + RX65N_USB_PIPEPERI); + + /* 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); +} + +/**************************************************************************** + * Function Name : usb_cstd_clr_pipe_cnfg + * Description : Clear specified pipe configuration register. + * Arguments : uint16_t pipe_no : pipe number + * Return value : none + ****************************************************************************/ + +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); +} + +/**************************************************************************** + * Function Name : usb_cstd_set_nak + * Description : Set up to NAK the specified pipe. + * Arguments : uint16_t pipe : Pipe Number + * Return value : none + ****************************************************************************/ + +static void usb_cstd_set_nak (uint16_t pipe) +{ + uint16_t buf; + uint16_t n; + + /* Set NAK */ + + hw_usb_clear_pid(pipe, 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 < 0xffffu; ++n) + { + /* PIPE control reg read */ + + buf = hw_usb_read_pipectr(pipe); + if (0 == (uint16_t) (buf & RX65N_USB_DCPCTR_PID_MASK)) + { + n = 0xfffeu; + } + } +} + +/**************************************************************************** + * Function Name : usb_cstd_is_set_frdy + * Description : Changes the specified FIFO port by the specified pipe. + * Arguments : uint16_t pipe : Pipe Number + * : uint16_t fifosel : FIFO select + * : uint16_t isel : ISEL bit status + * Return value : FRDY status + ****************************************************************************/ + +static uint16_t usb_cstd_is_set_frdy (uint16_t pipe, uint16_t fifosel, + uint16_t isel) +{ + uint16_t buffer; + 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++) + { + buffer = hw_usb_read_fifoctr(fifosel); + + if (RX65N_USB_FIFOCTR_FRDY == (uint16_t) (buffer & + RX65N_USB_FIFOCTR_FRDY)) + { + return (buffer); + } + + buffer = hw_usb_read_syscfg(); + buffer = hw_usb_read_syssts(); + (void)nxsig_usleep(1); + } + + return (RX65N_USB_FIFO_ERROR); +} + +/**************************************************************************** + * Function Name : usb_cstd_chg_curpipe + * Description : Switch FIFO and pipe number. + * Arguments : uint16_t pipe : Pipe number. + * : uint16_t fifosel : FIFO selected (CPU, D0, D1..) + * : uint16_t isel : CFIFO Port Access Direction. + * : (Pipe1 to 9:Set to 0) + * Return value : none + ****************************************************************************/ + +void usb_cstd_chg_curpipe (uint16_t pipe, uint16_t fifosel, uint16_t isel) +{ + uint16_t buffer; + + /* Select FIFO */ + + switch (fifosel) + { + /* CFIFO use */ + + case RX65N_USB_USING_CFIFO : + + /* ISEL=1, CURPIPE=0 */ + + hw_usb_rmw_fifosel(USB_CUSE, ((USB_RCNT | isel) | pipe), + ((USB_RCNT | USB_ISEL) | USB_CURPIPE)); + + /* WAIT_LOOP */ + + do + { + buffer = hw_usb_read_fifosel(USB_CUSE); + } + + while ((buffer & (uint16_t) (USB_ISEL | USB_CURPIPE)) != + (uint16_t) (isel | pipe)); + break; + +#ifdef DTC_DMA_ENABLED +#if ((USB_CFG_DTC == USB_CFG_ENABLE) || (USB_CFG_DMA == USB_CFG_ENABLE)) + + /* D0FIFO use */ + + case USB_D0USE : + + /* D1FIFO use */ + + case USB_D1USE : + + /* DxFIFO pipe select */ + + hw_usb_set_curpipe (fifosel, pipe); + + /* WAIT_LOOP */ + + do + { + buffer = hw_usb_read_fifosel (fifosel); + } + while ((uint16_t)(buffer & USB_CURPIPE) != pipe); + break; + +#endif /* ((USB_CFG_DTC==USB_CFG_ENABLE||(USB_CFG_DMA==USB_CFG_ENABLE))*/ +#endif /* DTC_DMA_ENABLED */ + + default : + break; + } +} + +/**************************************************************************** + * Function Name : usb_cstd_set_transaction_counter + * Description : Set specified Pipe Transaction Counter Register. + * Arguments : uint16_t trnreg : Pipe number + * : uint16_t trncnt : Transaction counter + * Return value : none + ****************************************************************************/ + +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); +} + +/**************************************************************************** + * Function Name : usb_cstd_clr_transaction_counter + * Description : Clear specified Pipe Transaction Counter Register. + * Arguments : uint16_t trnreg : Pipe Number + * Return value : none + ****************************************************************************/ + +static void usb_cstd_clr_transaction_counter (uint16_t trnreg) +{ + hw_usb_clear_trenb(trnreg); + hw_usb_set_trclr(trnreg); +} + +/**************************************************************************** + * Function Name : usb_cstd_nrdy_enable + * Description : Enable NRDY interrupt of the specified pipe. + * Arguments : uint16_t pipe : Pipe number. + * Return value : none + ****************************************************************************/ + +static void usb_cstd_nrdy_enable (uint16_t pipe) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Enable NRDY */ + + hw_usb_set_nrdyenb(pipe); +} + +/**************************************************************************** + * Function Name : usb_cstd_get_pid + * Description : Fetch specified pipe's PID. + * Arguments : uint16_t pipe : Pipe number. + * Return value : uint16_t PID-bit status + ****************************************************************************/ + +static uint16_t usb_cstd_get_pid (uint16_t pipe) +{ + uint16_t buf; + + if (USB_MAX_PIPE_NO < pipe) + { + return USB_NULL; /* Error */ + } + + /* PIPE control reg read */ + + buf = hw_usb_read_pipectr(pipe); + return (uint16_t) (buf & RX65N_USB_DCPCTR_PID_MASK); +} + +/**************************************************************************** + * Function Name : usb_cstd_get_maxpacket_size + * Description : Fetch MaxPacketSize of the specified pipe. + * Arguments : uint16_t pipe : Pipe number. + * Return value : uint16_t MaxPacketSize + ****************************************************************************/ + +static uint16_t usb_cstd_get_maxpacket_size (uint16_t pipe) +{ + uint16_t size; + uint16_t buffer; + + if (USB_MAX_PIPE_NO < pipe) + { + return USB_NULL; /* Error */ + } + + if (USB_PIPE0 == pipe) + { + buffer = hw_usb_read_dcpmaxp(); + } + else + { + /* Pipe select */ + + hw_usb_write_pipesel(pipe); + buffer = hw_usb_read_pipemaxp(); + } + + /* Max Packet Size */ + + size = (uint16_t) (buffer & RX65N_USB_DCPMAXP_MXPS_MASK); + + return size; +} + +/**************************************************************************** + * Function Name : usb_cstd_get_pipe_dir + * Description : Get PIPE DIR + * Arguments : uint16_t pipe : Pipe number. + * Return value : uint16_t pipe direction. + ****************************************************************************/ + +static uint16_t usb_cstd_get_pipe_dir (uint16_t pipe) +{ + uint16_t buffer; + + if (USB_MAX_PIPE_NO < pipe) + { + return USB_NULL; /* Error */ + } + + /* Pipe select */ + + hw_usb_write_pipesel(pipe); + + /* Read Pipe direction */ + + buffer = hw_usb_read_pipecfg(); + return (uint16_t) (buffer & RX65N_USB_PIPECFG_DIR); +} + +/**************************************************************************** + * Function Name : usb_cstd_do_aclrm + * Description : Set the ACLRM-bit (Auto Buffer Clear Mode) of the + * : specified pipe. + * Arguments : uint16_t pipe : Pipe number. + * Return value : none + ****************************************************************************/ + +static void usb_cstd_do_aclrm (uint16_t pipe) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Control ACLRM */ + + hw_usb_set_aclrm(pipe); + hw_usb_clear_aclrm(pipe); +} + +/**************************************************************************** + * Function Name : usb_cstd_set_buf + * Description : Set PID (packet ID) of the specified pipe to BUF. + * Arguments : uint16_t pipe : Pipe number. + * Return value : none + ****************************************************************************/ + +static void usb_cstd_set_buf (uint16_t pipe) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* PIPE control reg set */ + + hw_usb_set_pid(pipe, RX65N_USB_DCPCTR_PIDBUF); +} + +/**************************************************************************** + * Function Name : usb_cstd_clr_stall + * Description : Set up to NAK the specified pipe, and clear the + * : STALL-bit set to the PID of the specified pipe. + * Arguments : usb_utr_t *ptr : Pointer to usb_utr_t structure. + * : uint16_t pipe : Pipe number. + * Return value : none + * Note : PID is set to NAK. + ****************************************************************************/ + +static void usb_cstd_clr_stall (uint16_t pipe) +{ + if (USB_MAX_PIPE_NO < pipe) + { + return; /* Error */ + } + + /* Set NAK */ + + usb_cstd_set_nak(pipe); + + /* Clear STALL */ + + hw_usb_clear_pid(pipe, RX65N_USB_DCPCTR_PIDSTALL); +} + +/**************************************************************************** + * Function Name : usb_hstd_ctrl_write_start + * Description : Start data stage of Control Write transfer. + * Arguments : uint32_t Bsize : Data Size + * : uint8_t *Table : Data Table Address + * Return : uint16_t : USB_WRITEEND / USB_WRITING + * : : USB_WRITESHRT / USB_FIFOERROR + ****************************************************************************/ + +uint16_t usb_hstd_ctrl_write_start (uint8_t * buf_add, size_t buf_size) +{ + uint16_t end_flag; + + /* PID=NAK & clear STALL */ + + usb_cstd_clr_stall((uint16_t) USB_PIPE0); + + /* DCP Configuration Register (0x5c) */ + + hw_usb_write_dcpcfg((USB_CNTMDFIELD | USB_DIRFIELD)); + + hw_usb_set_sqset(USB_PIPE0); /* SQSET=1, PID=NAK */ + + hw_usb_clear_status_bemp(USB_PIPE0); + + end_flag = usb_hstd_write_data_control_pipe (buf_add, buf_size); + + switch (end_flag) + { + /* End of data write */ + + case USB_WRITESHRT : + + /* Next stage is Control write status stage */ + + /* Enable Empty Interrupt */ + + hw_usb_set_bempenb((uint16_t) USB_PIPE0); + + /* Enable Not Ready Interrupt */ + + usb_cstd_nrdy_enable((uint16_t) USB_PIPE0); + + /* Set 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 BUF */ + + usb_cstd_set_buf((uint16_t) USB_PIPE0); + break; + + /* FIFO access error */ + + case USB_FIFOERROR : + break; + + default : + break; + } + + /* End or Err or Continue */ + + return (end_flag); +} + +/**************************************************************************** + * Function Name : usb_hstd_ctrl_read_start + * Description : Start data stage of Control Read transfer. + * Arguments : none + * Return : none + ****************************************************************************/ + +void usb_hstd_ctrl_read_start (void) +{ + /* PID=NAK & clear STALL */ + + usb_cstd_clr_stall((uint16_t) USB_PIPE0); + + /* DCP Configuration Register (0x5c) */ + + hw_usb_write_dcpcfg(RX65N_USB_PIPECFG_SHTNAK); + + /* SQSET=1, PID=NAK */ + + hw_usb_hwrite_dcpctr(RX65N_USB_DCPCTR_SQSET); + + /* 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); + usb_cstd_set_buf((uint16_t) USB_PIPE0); /* Set BUF */ +} + +/**************************************************************************** + * Function Name : usb_host_read_pipe_start + * Description : Start data stage of data Read transfer. + * Arguments : uint32_t Bsize : Data Size + * : uint8_t *Table : Data Table Address + * Return : none + ****************************************************************************/ + +void usb_host_read_pipe_start (uint16_t pipe) +{ + uint16_t config_reg; + uint16_t ctrl_reg; + + /* PID=NAK & clear STALL */ + + usb_cstd_clr_stall((uint16_t) pipe); + + config_reg = hw_usb_read_pipecfg(); + + /* Pipe disabled at the end of transfer i.e. it is set to NAK */ + + config_reg = config_reg | RX65N_USB_PIPECFG_SHTNAK; + + /* Set the direction as read */ + + config_reg = config_reg & ~(RX65N_USB_PIPECFG_DIR); + hw_usb_write_pipecfg (config_reg); + + ctrl_reg = hw_usb_read_pipectr (pipe); + ctrl_reg = ctrl_reg | RX65N_USB_PIPECTR_SQSET; + hw_usb_write_pipectr (pipe, ctrl_reg); + + /* usb_hstd_do_sqtgl((uint16_t) USB_PIPE0, 0); */ + + /* Interrupt enable */ + + /* Enable Ready Interrupt */ + + hw_usb_set_brdyenb((uint16_t) pipe); + + /* Enable Not Ready Interrupt */ + + usb_cstd_nrdy_enable((uint16_t) pipe); + + /* Set BUF */ + + usb_cstd_set_buf((uint16_t) pipe); +} + +/**************************************************************************** + * Function Name : usb_hstd_status_start + * Description : Start status stage of Control Command. + * Arguments : none + ****************************************************************************/ + +void usb_hstd_status_start (void) +{ + /* Interrupt Disable */ + + /* BEMP0 Disable */ + + hw_usb_clear_bempenb((uint16_t) USB_PIPE0); + + /* BRDY0 Disable */ + + hw_usb_clear_brdyenb((uint16_t) USB_PIPE0); +} + +/**************************************************************************** + * Function Name : usb_hstd_ctrl_end + * Description : Call the user registered callback function that notifies + * : completion of a control transfer. + * Arguments : uint16_t status : Transfer status + * Return : none + ****************************************************************************/ + +void usb_hstd_ctrl_end (uint16_t status) +{ + /* Interrupt Disable */ + + hw_usb_clear_bempenb((uint16_t) USB_PIPE0); /* BEMP0 Disable */ + hw_usb_clear_brdyenb((uint16_t) USB_PIPE0); /* BRDY0 Disable */ + hw_usb_clear_nrdyenb((uint16_t) USB_PIPE0); /* NRDY0 Disable */ + + usb_cstd_clr_stall((uint16_t) USB_PIPE0); /* PID=NAK & clear STALL */ + hw_usb_set_mbw(USB_CUSE, USB0_CFIFO_MBW); + + /* SUREQ=1, SQCLR=1, PID=NAK */ + + hw_usb_hwrite_dcpctr((uint16_t) (USB_SUREQCLR | USB_SQCLR)); + + /* CFIFO buffer clear */ + + usb_cstd_chg_curpipe((uint16_t) USB_PIPE0, + (uint16_t) USB_CUSE, USB_FALSE); + hw_usb_set_bclr(USB_CUSE); /* Clear BVAL */ + usb_cstd_chg_curpipe((uint16_t) USB_PIPE0, + (uint16_t) USB_CUSE, (uint16_t) USB_ISEL); + hw_usb_set_bclr(USB_CUSE); /* Clear BVAL */ +} + +/**************************************************************************** + * Function Name : usb_hstd_brdy_pipe + * Description : BRDY Interrupt + * Arguments : uint16_t bitsts : BRDYSTS Reg & BRDYENB Reg + * Return value : none + ****************************************************************************/ + +void usb_hstd_brdy_pipe (void) +{ + uint16_t bitsts; + + bitsts = rx65n_usbhost_getreg (RX65N_USB_BRDYSTS); + + /* When operating by the host function, usb_hstd_brdy_pipe() is executed + * without fail because only one BRDY message is issued even when the + * demand of PIPE0 and PIPEx has been generated at the same time. + */ + + if (USB_BRDY0 == (bitsts & USB_BRDY0)) + { + hw_usb_clear_sts_brdy (USB_PIPE0); + + /* Branch by the Control transfer stage management */ + + if (EDCTRL->xfrinfo->tdxfercond == USB_STATUSRD) + { + /* This interrupt occurred due to setup packet status stage of + * writing NULL packet. + */ + + /* Call this to end the setup packet */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_END); + + rx65n_usbhost_givesem(&EDCTRL->wdhsem); + return; /* Nothing else to do here... as of now... */ + } + + switch (EDCTRL->xfrinfo->tdxfercond) + { + /* Data stage of Control read transfer */ + + case USB_DATARD : + EDCTRL->xfrinfo->tdxfercond = usb_hstd_read_data_control_pipe (); + + switch (EDCTRL->xfrinfo->tdxfercond) + { + /* End of data read */ + + case USB_READEND : + + /* continue */ + + /* End of data read */ + + case USB_READSHRT : + + usb_hstd_status_start(); + break; + + case USB_READING : /* Continue of data read */ + + /* Still data is there - so set the condition for + * reading in next interrupt... + */ + + EDCTRL->xfrinfo->tdxfercond = USB_DATARD; + break; + + case USB_READOVER : /* FIFO access error */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_OVR); + break; + + case USB_FIFOERROR : /* FIFO access error */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_ERR); + syslog(LOG_INFO, "ERROR"); + break; + + default : + break; + } + break; + + /* Data stage of Control read transfer */ + + case USB_DATARDCNT : + + switch (usb_hstd_read_data_control_pipe ()) + { + case USB_READEND : /* End of data read */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_READING); + break; + + case USB_READSHRT : /* End of data read */ + + /* Control Read/Write Status */ + + usb_hstd_status_start(); + break; + + case USB_READING : /* Continue of data read */ + + /* Still data is there - so set the condition for + * reading in next interrupt... + */ + + EDCTRL->xfrinfo->tdxfercond = USB_DATARDCNT; + break; + + case USB_READOVER : /* FIFO access error */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_OVR); + break; + + case USB_FIFOERROR : /* FIFO access error */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_ERR); + syslog(LOG_INFO, "ERROR"); + break; + + default : + break; + } + break; + + /* Status stage Control write (NoData control) transfer */ + + case USB_STATUSWR : + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_END); + break; + + default : + break; + } + + if ((EDCTRL->xfrinfo->tdxfercond == USB_READEND) || + (EDCTRL->xfrinfo->tdxfercond == USB_READSHRT) || + (EDCTRL->xfrinfo->tdxfercond == USB_READOVER)) + { + rx65n_usbhost_givesem(&EDCTRL->wdhsem); + } + + hw_usb_clear_sts_brdy (USB_PIPE0); /* This was missing? */ + } + + /* BRDY interrupt */ + + usb_hstd_brdy_pipe_process(bitsts); +} + +/**************************************************************************** + * Function Name : usb_hstd_nrdy_pipe + * Description : NRDY Interrupt + * Arguments : usb_utr_t *ptr : Pointer to usb_utr_t structure. + * : uint16_t bitsts : NRDYSTS Reg & NRDYENB Reg + * Return value : none + ****************************************************************************/ + +void usb_hstd_nrdy_pipe (void) +{ + uint16_t buffer; + uint16_t bitsts; + + bitsts = rx65n_usbhost_getreg (RX65N_USB_NRDYSTS); /* ptr->status; */ + + /* When operating by the host function, usb_hstd_nrdy_pipe() + * is executed without fail because + * only one NRDY message is issued even when the demand of + * PIPE0 and PIPEx has been generated at the same time. + */ + + if (USB_NRDY0 == (bitsts & USB_NRDY0)) + { + hw_usb_clear_status_nrdy (USB_PIPE0); + + /* Get Pipe PID from pipe number */ + + buffer = usb_cstd_get_pid((uint16_t) USB_PIPE0); + + /* STALL ? */ + + if (RX65N_USB_DCPCTR_PIDSTALL == (buffer & + RX65N_USB_DCPCTR_PIDSTALL)) + { + /* PIPE0 STALL call back */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_STALL); + } + else + { + /* Control Data Stage Device Ignore X 3 call back */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_ERR); + } + } + + /* Nrdy Pipe interrupt */ + + usb_hstd_nrdy_pipe_process(bitsts); +} + +/**************************************************************************** + * Function Name : usb_hstd_bemp_pipe + * Description : BEMP interrupt + * Arguments : uint16_t bitsts : BEMPSTS Reg & BEMPENB Reg + * Return value : none + ****************************************************************************/ + +void usb_hstd_bemp_pipe (void) +{ + uint16_t buffer; + uint16_t bitsts; + + bitsts = rx65n_usbhost_getreg (RX65N_USB_BEMPSTS); /* ptr->status; */ + + /* When operating by the host function, usb_hstd_bemp_pipe() + * is executed without fail because + * only one BEMP message is issued even when the demand of PIPE0 + * and PIPEx has been generated at the same time. + */ + + if (USB_BEMP0 == (bitsts & USB_BEMP0)) + { + hw_usb_clear_status_bemp (USB_PIPE0); + if (EDCTRL->xfrinfo->tdxfercond == USB_STATUSWR) + { + /* This interrupt occurred due to setup packet status + * stage of writing NULL packet. + */ + + /* BEMP0 Disable */ + + hw_usb_clear_bempenb((uint16_t) USB_PIPE0); + + /* BRDY0 Disable */ + + hw_usb_clear_brdyenb((uint16_t) USB_PIPE0); + + /* Call this to end the setup packet */ + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_END); + + rx65n_usbhost_givesem(&EDCTRL->wdhsem); + return; /* As of now, Nothing else to do here... */ + } + + /* Get Pipe PID from pipe number */ + + buffer = usb_cstd_get_pid((uint16_t) USB_PIPE0); + + /* MAX packet size error ? */ + + if (RX65N_USB_DCPCTR_PIDSTALL == (buffer & RX65N_USB_DCPCTR_PIDSTALL)) + { + /* PIPE0 STALL call back */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_STALL); + } + else + { + /* Branch by the Control transfer stage management */ + + switch (bitsts) + { + /* Continuas of data stage (Control write) */ + + case USB_DATAWR : + + /* We should not get into this... */ + + /* Buffer to CFIFO data write */ + + switch (usb_hstd_write_data_control_pipe (0, 0)) + { + /* End of data write */ + + case USB_WRITESHRT : + + hw_usb_set_bempenb((uint16_t) USB_PIPE0); + + /* Enable Not Ready Interrupt */ + + usb_cstd_nrdy_enable((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); + break; + + /* FIFO access error */ + + case USB_FIFOERROR : + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_ERR); + break; + + default : + break; + } + break; + + /* Next stage to Control write data */ + + case USB_DATAWRCNT : + + /* Buffer to CFIFO data write */ + + /* We should not get here... */ + + switch (usb_hstd_write_data_control_pipe (0, 0)) + { + /* End of data write */ + + case USB_WRITESHRT : + + hw_usb_set_bempenb((uint16_t) USB_PIPE0); + + /* Enable Not Ready Interrupt */ + + usb_cstd_nrdy_enable((uint16_t) USB_PIPE0); + break; + + /* End of data write (not null) */ + + case USB_WRITEEND : + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_WRITING); + break; + + /* 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); + break; + + /* FIFO access error */ + + case USB_FIFOERROR : + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_DATA_ERR); + break; + + default : + break; + } + break; + + case USB_STATUSWR : /* End of data stage (Control write) */ + usb_hstd_status_start(); + break; + + /* Status stage of Control read transfer */ + + case USB_STATUSRD : + + /* Control Read/Write End */ + + usb_hstd_ctrl_end((uint16_t) USB_CTRL_END); + break; + + default : + break; + } + } + } + + usb_hstd_bemp_pipe_process(bitsts); /* BEMP interrupt */ +} + +/**************************************************************************** + * Name: rx65n_usbhost_printreg + * + * Description: + * Print the contents of an RX65N register operation + * + ****************************************************************************/ + +#ifdef CONFIG_RX65N_USBHOST_REGDEBUG +static void rx65n_usbhost_printreg(uint32_t addr, uint32_t val, bool iswrite) +{ + uinfo("%08x%s%08x\n", addr, iswrite ? "<-" : "->", val); +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_checkreg + * + * Description: + * Get the contents of an RX65N register + * + ****************************************************************************/ + +#ifdef CONFIG_RX65N_USBHOST_REGDEBUG +static void rx65n_usbhost_checkreg(uint32_t addr, uint32_t val, bool iswrite) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + static bool prevwrite = false; + + /* Is this the same value that we read from/wrote to the same register + * last time? Are we polling the register? If so, suppress the output. + */ + + if (addr == prevaddr && val == preval && prevwrite == iswrite) + { + /* Yes.. Just increment the count */ + + count++; + } + else + { + /* No this is a new address or value or operation. Were there any + * duplicate accesses before this one? + */ + + if (count > 0) + { + /* Yes.. Just one? */ + + if (count == 1) + { + /* Yes.. Just one */ + + rx65n_usbhost_printreg(prevaddr, preval, prevwrite); + } + else + { + /* No.. More than one. */ + + uinfo("[repeats %d more times]\n\r", count); + } + } + + /* Save the new address, value, count, and operation for next time */ + + prevaddr = addr; + preval = val; + count = 0; + prevwrite = iswrite; + + /* Show the new regisgter access */ + + rx65n_usbhost_printreg(addr, val, iswrite); + } +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_getreg + * + * Description: + * Get the contents of an RX65N register + * + ****************************************************************************/ + +#ifdef CONFIG_RX65N_USBHOST_REGDEBUG +static uint16_t rx65n_usbhost_getreg(uint32_t addr) +{ + /* Read the value from the register */ + + uint16_t val = getreg16(addr); + + /* Check if we need to print this value */ + + rx65n_usbhost_checkreg(addr, val, false); + return val; +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_putreg + * + * Description: + * Set the contents of an RX65N register to a value + * + ****************************************************************************/ + +#ifdef CONFIG_RX65N_USBHOST_REGDEBUG +static void rx65n_usbhost_putreg(uint16_t val, uint32_t addr) +{ + /* Check if we need to print this value */ + + rx65n_usbhost_checkreg(addr, val, true); + + /* Write the value */ + + putreg16(val, addr); +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_takesem + * + * Description: + * This is just a wrapper to handle the annoying behavior of semaphore + * waits that return due to the receipt of a signal. + * + ****************************************************************************/ + +static int rx65n_usbhost_takesem(sem_t *sem) +{ + int ret; + + do + { + /* Take the semaphore (perhaps waiting) */ + + ret = nxsem_wait(sem); + + /* The only case that an error should occur here is if the wait was + * awakened by a signal. + */ + + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret == -EINTR); + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_getle16 + * + * Description: + * Get a (possibly unaligned) 16-bit little endian value. + * + ****************************************************************************/ + +static inline uint16_t rx65n_usbhost_getle16(const uint8_t *val) +{ + return (uint16_t)val[1] << 8 | (uint16_t)val[0]; +} + +/**************************************************************************** + * Name: rx65n_usbhost_edfree + * + * Description: + * Return an endpoint descriptor to the free list + * + ****************************************************************************/ + +static inline void rx65n_usbhost_edfree(struct rx65n_usbhost_ed_s *ed) +{ + struct rx65n_usbhost_list_s *entry = (struct rx65n_usbhost_list_s *)ed; + + /* Put the ED back into the free list */ + + entry->flink = g_edfree; + g_edfree = entry; +} + +/**************************************************************************** + * Name: rx65n_usbhost_tdalloc + * + * Description: + * Allocate an transfer descriptor from the free list + * + * Assumptions: + * - Never called from an interrupt handler. + * - Protected from concurrent access to the TD pool by the interrupt + * handler + * - Protection from re-entrance must be assured by the caller + * + ****************************************************************************/ + +static struct rx65n_usbhost_gtd_s *rx65n_usbhost_tdalloc(uint8_t ep_num) +{ + /* Currently each TD would associate with one EP. So the ep_numb is + * passed to tdalloc fucntion and it would return the TD with this, + * there is no need to free this + */ + + memset(&(g_rx65n_tdlist[ep_num]), 0, sizeof(struct rx65n_usbhost_gtd_s)); + return &(g_rx65n_tdlist[ep_num]); +} + +/**************************************************************************** + * Name: rx65n_tdfree + * + * Description: + * Return an transfer descriptor to the free list + * + * Assumptions: + * Only called from the WDH interrupt handler (and during initialization). + * Interrupts are disabled in any case. + * + ****************************************************************************/ + +static void rx65n_usbhost_tdfree(struct rx65n_usbhost_gtd_s *td) +{ + struct rx65n_usbhost_list_s *tdfree = (struct rx65n_usbhost_list_s *)td; + + /* This should not happen but just to be safe, don't free the common, pre- + * allocated tail TD. + */ + + if (tdfree != NULL && td != TDTAIL) + { + tdfree->flink = g_tdfree; + g_tdfree = tdfree; + } +} + +/**************************************************************************** + * Name: rx65n_usbhost_tballoc + * + * Description: + * Allocate an request/descriptor transfer buffer from the free list + * + * Assumptions: + * - Never called from an interrupt handler. + * - Protection from re-entrance must be assured by the caller + * + ****************************************************************************/ + +static uint8_t *rx65n_usbhost_tballoc(void) +{ + uint8_t *ret = (uint8_t *)g_tbfree; + + if (ret) + { + g_tbfree = ((struct rx65n_usbhost_list_s *)ret)->flink; + } + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_tbfree + * + * Description: + * Return an request/descriptor transfer buffer to the free list + * + ****************************************************************************/ + +static void rx65n_usbhost_tbfree(uint8_t *buffer) +{ + struct rx65n_usbhost_list_s *tbfree = + (struct rx65n_usbhost_list_s *)buffer; + + if (tbfree) + { + tbfree->flink = g_tbfree; + g_tbfree = tbfree; + } +} + +/**************************************************************************** + * Name: rx65n_usbhhost_allocio + * + * Description: + * Allocate an IO buffer from the free list + * + * Assumptions: + * - Never called from an interrupt handler. + * - Protection from re-entrance must be assured by the caller + * + ****************************************************************************/ + +#if RX65N_USBHOST_IOBUFFERS > 0 +static uint8_t *rx65n_usbhhost_allocio(void) +{ + uint8_t *ret; + irqstate_t flags; + + flags = enter_critical_section(); + ret = (uint8_t *)g_iofree; + if (ret) + { + g_iofree = ((struct rx65n_usbhost_list_s *)ret)->flink; + } + + leave_critical_section(flags); + return ret; +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhhost_freeio + * + * Description: + * Return an TD buffer to the free list + * + ****************************************************************************/ + +#if RX65N_USBHOST_IOBUFFERS > 0 +static void rx65n_usbhhost_freeio(uint8_t *buffer) +{ + struct rx65n_usbhost_list_s *iofree; + irqstate_t flags; + + /* Could be called from the interrupt level */ + + flags = enter_critical_section(); + iofree = (struct rx65n_usbhost_list_s *)buffer; + iofree->flink = g_iofree; + g_iofree = iofree; + leave_critical_section(flags); +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_alloc_xfrinfo + * + * Description: + * Allocate an asynchronous data structure from the free list + * + * Assumptions: + * - Never called from an interrupt handler. + * - Protection from re-entrance must be assured by the caller + * + ****************************************************************************/ + +static struct rx65n_usbhost_xfrinfo_s *rx65n_usbhost_alloc_xfrinfo(void) +{ + struct rx65n_usbhost_xfrinfo_s *ret; + irqstate_t flags; + + flags = enter_critical_section(); + ret = (struct rx65n_usbhost_xfrinfo_s *)g_xfrfree; + + if (ret) + { + g_xfrfree = ((struct rx65n_usbhost_list_s *)ret)->flink; + } + + leave_critical_section(flags); + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhhost_freeio + * + * Description: + * Return an TD buffer to the free list + * + ****************************************************************************/ + +static void rx65n_usbhost_free_xfrinfo(struct + rx65n_usbhost_xfrinfo_s *xfrinfo) +{ + struct rx65n_usbhost_list_s *node; + irqstate_t flags; + + /* Could be called from the interrupt level */ + + flags = enter_critical_section(); + node = (struct rx65n_usbhost_list_s *)xfrinfo; + node->flink = g_xfrfree; + g_xfrfree = node; + leave_critical_section(flags); +} + +/**************************************************************************** + * Name: rx65n_usbhost_addctrled + * + * Description: + * Helper function to add an ED to the control list. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_addctrled(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ + /* Ctrl ED is always used and statically assigned */ + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_remctrled + * + * Description: + * Helper function remove an ED from the control list. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_remctrled(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ + /* Ctrl ED is always used and statically assigned */ + + /* The semaphore for the USB HID keyboard is released */ + + if (g_kbdport == g_usbidx) + { + rx65n_usbhost_givesem(&g_rx65n_edlist[g_kbdpipe].wdhsem); + } + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_addbulked + * + * Description: + * Helper function to add an ED to the bulk list. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_addbulked(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + struct rx65n_usbhost_ed_s *ed) +{ +#ifndef CONFIG_USBHOST_BULK_DISABLE + irqstate_t flags; + uint8_t pipe_no; + uint16_t pipe_cfg; + uint16_t pipe_maxp; + + /* Pipe Cycle Control Register is not needed for bulk pipe */ + + /* uint16_t pipe_peri; */ + + /* Disable bulk list processing while we modify the list */ + + flags = enter_critical_section(); + pipe_no = ed->pipenum; + + /* To begin with start config as Bulk pipe */ + + pipe_cfg = 0x4000; + + /* Update the direction */ + + /* Direction is in */ + + if (epdesc->in) + { + pipe_cfg = pipe_cfg & ~ (RX65N_USB_PIPECFG_DIR); + pipe_cfg = pipe_cfg | RX65N_USB_PIPECFG_SHTNAK; + } + else + { + pipe_cfg = pipe_cfg | (RX65N_USB_PIPECFG_DIR); + } + + /* Finally update the address */ + + pipe_cfg = pipe_cfg | ((epdesc->addr) & RX65N_USB_PIPECFG_EPNUM_MASK); + + /* Update pipe_maxp : Begin with initial value from device address */ + + pipe_maxp = rx65n_usbhost_getreg(RX65N_USB_DCPMAXP); + pipe_maxp &= ~(RX65N_USB_PIPEMAXP_MXPSMASK); + pipe_maxp = pipe_maxp | (epdesc->mxpacketsize); + + /* Now all the values are ready to be written */ + + g_usb_pipe_table[pipe_no].pipe_cfg = pipe_cfg; + g_usb_pipe_table[pipe_no].pipe_maxp = pipe_maxp; + g_usb_pipe_table[pipe_no].pipe_peri = 0; + + /* Now update these values in the requried pipe */ + + usb_cstd_pipe_init (pipe_no); + leave_critical_section(flags); + + return OK; + +#else + return -ENOSYS; +#endif +} + +/**************************************************************************** + * Name: rx65n_usbhost_rembulked + * + * Description: + * Helper function remove an ED from the bulk list. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_rembulked(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ +/* This function requires implementation + * for OHCI specific interrupt disabling + * As RX65N is not OHCI compliant, this function + * need not be implemented + */ + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_getinterval + * + * Description: + * Convert the endpoint polling interval into a HCCA table increment + * + ****************************************************************************/ + +#if !defined(CONFIG_USBHOST_INT_DISABLE) || \ + !defined(CONFIG_USBHOST_ISOC_DISABLE) +static unsigned int rx65n_usbhost_getinterval(uint8_t interval) +{ + /* The bInterval field of the endpoint descriptor contains the polling + * interval for interrupt and isochronous endpoints. For other types of + * endpoint, this value should be ignored. bInterval is provided in units + * of 1MS frames. + */ + + if (interval < 3) + { + return 2; + } + else if (interval < 7) + { + return 4; + } + else if (interval < 15) + { + return 8; + } + else if (interval < 31) + { + return 16; + } + else + { + return 32; + } +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_setinttab + * + * Description: + * Set the interrupt table to the selected value using the provided + * interval and offset. + * + ****************************************************************************/ + +#if !defined(CONFIG_USBHOST_INT_DISABLE) || \ +!defined(CONFIG_USBHOST_ISOC_DISABLE) +static void rx65n_usbhost_setinttab(uint32_t value, unsigned int interval, + unsigned int offset) +{ + unsigned int i; + + for (i = offset; i < HCCA_INTTBL_WSIZE; i += interval) + { + HCCA->inttbl[i] = value; + } +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_addinted + * + * Description: + * Helper function to add an ED to the HCCA interrupt table. + * + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: + * + * 1. IN EDs get the even entries, OUT EDs get the odd entries. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. + * + * This has the following consequences: + * + * 1. The minimum support polling rate is 2MS, and + * 2. Some devices may get polled at a much higher rate than they request + * + ****************************************************************************/ + +static inline int rx65n_usbhost_addinted(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + struct rx65n_usbhost_ed_s *ed) +{ +#ifndef CONFIG_USBHOST_INT_DISABLE + unsigned int interval; + unsigned int offset; + uint32_t head; + uint8_t pipe_no; + uint16_t pipe_cfg; + uint16_t pipe_maxp; + uint16_t pipe_peri; + + /* Get the quantized interval value associated with this ED and save it + * in the ED. + */ + + interval = rx65n_usbhost_getinterval(epdesc->interval); + + ed->interval = interval; + uinfo("interval: %d->%d\n\r", epdesc->interval, interval); + + /* Get the offset associated with the ED direction. IN EDs get the even + * entries, OUT EDs get the odd entries. + * + * Get the new, minimum interval. Add IN/OUT EDs are scheduled together + * at the minimum interval of all IN/OUT EDs. + */ + + if (epdesc->in) + { + offset = 0; + if (priv->ininterval > interval) + { + priv->ininterval = interval; + } + else + { + interval = priv->ininterval; + } + } + + else + { + offset = 1; + if (priv->outinterval > interval) + { + priv->outinterval = interval; + } + else + { + interval = priv->outinterval; + } + } + + uinfo("min interval: %d offset: %d\n\r", interval, offset); + + /* Get value for Interval Error Detection Interval */ + + pipe_no = ed->pipenum; + + if (epdesc->mxpacketsize != 1) + { + g_kbdpipe = pipe_no; + kbd_interrupt_in_pipe = pipe_no; + } + else + { + g_kbdpipe = 0; + } + + /* To begin with start config as INT pipe */ + + pipe_cfg = 0x8000; + + /* Update the direction */ + + /* Direction is in */ + + if (epdesc->in) + { + pipe_cfg = pipe_cfg & ~ (RX65N_USB_PIPECFG_DIR); + } + else + { + pipe_cfg = pipe_cfg | ~ (RX65N_USB_PIPECFG_DIR); + } + + /* Finally update the address */ + + pipe_cfg = pipe_cfg | ((epdesc->addr) & RX65N_USB_PIPECFG_EPNUM_MASK); + + /* Update pipe_maxp : Begin with initial value from endpoint address */ + + pipe_maxp = rx65n_usbhost_getreg(RX65N_USB_DCPMAXP); + pipe_maxp &= ~(RX65N_USB_PIPEMAXP_MXPSMASK); + pipe_maxp = pipe_maxp | (epdesc->mxpacketsize); + + /* Now get the Pipe Peri values */ + + pipe_peri = usb_hstd_get_pipe_peri_value (epdesc->interval); + + /* Now all the values are ready to be written */ + + g_usb_pipe_table[pipe_no].pipe_cfg = pipe_cfg; + g_usb_pipe_table[pipe_no].pipe_maxp = pipe_maxp; + g_usb_pipe_table[pipe_no].pipe_peri = pipe_peri; + + /* Now update these values in the requried pipe */ + + usb_cstd_pipe_init (pipe_no); + + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + DEBUGASSERT(ed->xfrinfo == NULL); + + xfrinfo = rx65n_usbhost_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + rx65n_usbhost_free_xfrinfo(xfrinfo); + uerr("ERROR: rx65n_usbhost_alloc_xfrinfo failed\n\r"); + return -ENOMEM; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct rx65n_usbhost_xfrinfo_s)); + xfrinfo->buffer = &kbd_report_data[0]; + xfrinfo->buflen = epdesc->mxpacketsize; + xfrinfo->tdxfercond = USB_DATARD; + + ed->xfrinfo = xfrinfo; + + /* Start the reading the interrupt pipe for KBD */ + + /* Now start the interrupt pipe */ + + usb_host_read_pipe_start (pipe_no); + + /* Get the head of the first of the duplicated entries. The first offset + * entry is always guaranteed to contain the common ED list head. + */ + + head = HCCA->inttbl[offset]; + + /* Clear all current entries in the interrupt table for this direction */ + + rx65n_usbhost_setinttab(0, 2, offset); + + /* Add the new ED before the old head of the periodic ED list and set the + * new ED as the head ED in all of the appropriate entries of the HCCA + * interrupt table. + */ + + ed->hw.nexted = head; + rx65n_usbhost_setinttab((uint32_t)ed, interval, offset); + uinfo("head: %08x next: %08x\n\r", ed, head); + + return OK; +#else + return -ENOSYS; +#endif +} + +/**************************************************************************** + * Name: rx65n_usbhost_reminted + * + * Description: + * Helper function to remove an ED from the HCCA interrupt table. + * + * To avoid reshuffling the table so much and to keep life simple in + * general, the following rules are applied: + * + * 1. IN EDs get the even entries, OUT EDs get the odd entries. + * 2. Add IN/OUT EDs are scheduled together at the minimum interval of + * all IN/OUT EDs. + * + * This has the following consequences: + * + * 1. The minimum support polling rate is 2MS, and + * 2. Some devices may get polled at a much higher rate than they + * request. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_reminted(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ + /* This function is to disable OHCI specific interrupts + * As, RX65N is not OHCI compliant, this function does not require + * any implementation + */ + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_addisoced + * + * Description: + * Helper functions to add an ED to the periodic table. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_addisoced(struct rx65n_usbhost_s *priv, + const struct usbhost_epdesc_s *epdesc, + struct rx65n_usbhost_ed_s *ed) +{ +#ifndef CONFIG_USBHOST_ISOC_DISABLE + printf("Isochronous endpoints not yet supported\n\r"); +#endif + return -ENOSYS; +} + +/**************************************************************************** + * Name: rx65n_usbhost_remisoced + * + * Description: + * Helper functions to remove an ED from the periodic table. + * + ****************************************************************************/ + +static inline int rx65n_usbhost_remisoced(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ +#ifndef CONFIG_USBHOST_ISOC_DISABLE + printf("Isochronous endpoints not yet supported\n\r"); +#endif + return -ENOSYS; +} + +/**************************************************************************** + * Name: rx65n_usbhost_enqueuetd + * + * Description: + * Enqueue a transfer descriptor. Notice that this function only supports + * queue on TD per ED. + * + ****************************************************************************/ + +static int rx65n_usbhost_enqueuetd(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen) +{ + struct rx65n_usbhost_gtd_s *td; + int ret = -ENOMEM; + + /* Allocate a TD from the free list */ + + /* Currently each TD would associate with one EP. So the epnumb + * is passed to tdalloc fucntion and it would return the TD with + * this, there is no need to free this - there is no need + */ + + td = rx65n_usbhost_tdalloc(ed->pipenum); + + if (td != NULL) + { + /* Initialize allocated TD and link it before the common tail TD. */ + + td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | + toggle | GTD_STATUS_CC_MASK); + TDTAIL->hw.ctrl = 0; + td->hw.cbp = (uint32_t)buffer; + TDTAIL->hw.cbp = 0; + td->hw.nexttd = (uint32_t)TDTAIL; + TDTAIL->hw.nexttd = 0; + td->hw.be = (uint32_t)(buffer + (buflen - 1)); + TDTAIL->hw.be = 0; + + /* Configure driver-only fields in the extended TD structure */ + + td->ed = ed; + + /* Link the td to the head of the ED's TD list */ + + ed->hw.headp = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C); + ed->hw.tailp = (uint32_t)TDTAIL; + ret = OK; + } + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_wdhwait + * + * Description: + * Set the request for the Writeback Done Head event well BEFORE enabling + * the transfer (as soon as we are absolutely committed to the to avoid + * transfer). We do this to minimize race conditions. This logic would + * have to be expanded if we want to have more than one packet in flight + * at a time! + * + ****************************************************************************/ + +static int rx65n_usbhost_wdhwait(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + irqstate_t flags = enter_critical_section(); + int ret = -ENODEV; + + DEBUGASSERT(ed && ed->xfrinfo); + xfrinfo = ed->xfrinfo; + + /* Is the device still connected? */ + + if (priv->connected) + { + /* Yes.. then set wdhwait to indicate that we expect to be informed + * when either (1) the device is disconnected, or (2) the transfer + * completed. + */ + + xfrinfo->wdhwait = true; + ret = OK; + } + + leave_critical_section(flags); + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_ctrltd + * + * Description: + * Process a IN or OUT request on the control endpoint. This function + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. + * + * These are blocking methods; these functions will not return until the + * control transfer has completed. + * + ****************************************************************************/ + +static int rx65n_usbhost_ctrltd(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, + uint32_t dirpid, uint8_t *buffer, size_t buflen) +{ + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + uint32_t toggle; + int ret; + uint16_t sdata; + + /* Allocate a structure to retain the information needed when the + * transfer completes. + */ + + DEBUGASSERT(ed->xfrinfo == NULL); + + xfrinfo = rx65n_usbhost_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + uerr("ERROR: rx65n_usbhost_alloc_xfrinfo failed\n\r"); + return -ENOMEM; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct rx65n_usbhost_xfrinfo_s)); + xfrinfo->buffer = buffer; + xfrinfo->buflen = buflen; + + /* copy the transfer condition - any way we are copying this + * address to ed just 2 lines after this... + */ + + xfrinfo->tdxfercond = ed->xfrinfo->tdxfercond; + + ed->xfrinfo = xfrinfo; + + /* Set the request for the Write-back Done Head event well BEFORE + * enabling the transfer. + */ + + if (priv->connected) + { + ret = rx65n_usbhost_wdhwait(priv, ed); + if (ret < 0) + { + syslog(LOG_INFO, "ERROR: Device disconnected\n\r"); + goto errout_with_xfrinfo; + } + } + + /* Configure the toggle field in the TD */ + + if (dirpid == GTD_STATUS_DP_SETUP) + { + toggle = GTD_STATUS_T_DATA0; + } + else + { + toggle = GTD_STATUS_T_DATA1; + } + + /* Then enqueue the transfer */ + + xfrinfo->tdstatus = TD_CC_NOERROR; + ret = rx65n_usbhost_enqueuetd(priv, ed, dirpid, toggle, buffer, buflen); + + if (ret == OK) + { + /* Set ControlListFilled. This bit is used to indicate whether there + * are TDs on the Control list. + */ + + if (dirpid == GTD_STATUS_DP_SETUP) + { + rx65n_usbhost_takesem(&priv->exclsem); + + /* Set DATA0 bit of DCPCTR */ + + rx65n_usbhost_setbit (RX65N_USB_DCPCTR, RX65N_USB_DCPCTR_SQCLR); + + sdata = *(ed->xfrinfo->buffer) | (*(ed->xfrinfo->buffer + 1) << 8); + + /* Request type and Request */ + + rx65n_usbhost_putreg (sdata, RX65N_USB_USBREQ); + sdata = *(ed->xfrinfo->buffer + 2) | + (*(ed->xfrinfo->buffer + 3) << 8); + rx65n_usbhost_putreg (sdata, RX65N_USB_USBVAL); /* wValue */ + sdata = *(ed->xfrinfo->buffer + 4) | + (*(ed->xfrinfo->buffer + 5) << 8); + rx65n_usbhost_putreg (sdata, RX65N_USB_USBINDX); /* wIndex */ + sdata = *(ed->xfrinfo->buffer + 6) | + (*(ed->xfrinfo->buffer + 7) << 8); + rx65n_usbhost_putreg (sdata, RX65N_USB_USBLENG); /* wLen */ + + rx65n_usbhost_setbit (RX65N_USB_DCPCTR, RX65N_USB_DCPCTR_SQSET); + + hw_usb_hclear_sts_sign(); + hw_usb_hclear_sts_sack(); + + hw_usb_hset_enb_signe(); + hw_usb_hset_enb_sacke(); + hw_usb_hset_sureq(); + + /* At this point every thing is done w.r.t hardware to send the + * setup packet... Now release the exclusive access semaphore and + * wait for wdhsem + */ + + rx65n_usbhost_givesem(&priv->exclsem); + + /* Wait for the Writeback Done Head interrupt */ + + if (priv->connected) + { + rx65n_usbhost_takesem(&ed->wdhsem); + } + + /* Disable setup packet status response */ + + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, + RX65N_USB_INTENB1_SACKE | RX65N_USB_INTENB1_SIGNE); + } + + else if (dirpid == GTD_STATUS_DP_IN) + { + rx65n_usbhost_takesem(&priv->exclsem); + + /* BEMP0 Disable */ + + hw_usb_clear_bempenb((uint16_t) USB_PIPE0); + + /* BRDY0 Disable */ + + hw_usb_clear_brdyenb((uint16_t) USB_PIPE0); + + usb_hstd_ctrl_read_start(); + + /* At this point every thing is done w.r.t hardware to setup + * to receive the setup data... Now wait for interrupt + */ + + rx65n_usbhost_givesem (&priv->exclsem); + + if (priv->connected) + { + rx65n_usbhost_takesem(&ed->wdhsem); + } + } + + else if (dirpid == GTD_STATUS_DP_OUT) + { + rx65n_usbhost_takesem(&priv->exclsem); + + /* process setup packet status phase */ + + usb_hstd_ctrl_write_start(buffer, buflen); + + rx65n_usbhost_givesem (&priv->exclsem); + + if (priv->connected) + { + rx65n_usbhost_takesem(&ed->wdhsem); + } + + /* Disable Empty Interrupt */ + + hw_usb_clear_bempenb((uint16_t) USB_PIPE0); + + /* Disable Not Ready Interrupt */ + + hw_usb_clear_nrdyenb((uint16_t) USB_PIPE0); + } + + /* Check the TD completion status bits */ + + if (xfrinfo->tdstatus == TD_CC_NOERROR) + { + ret = OK; + } + else + { + uerr("ERROR: Bad TD completion status: %d\n\r", xfrinfo->tdstatus); + ret = xfrinfo->tdstatus == TD_CC_STALL ? -EPERM : -EIO; + } + } + else + { + } + + /* Make sure that there is no outstanding request on this endpoint */ + +errout_with_xfrinfo: + rx65n_usbhost_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_usbinterrupt + * + * Description: + * USB interrupt handler + * + ****************************************************************************/ + +static int rx65n_usbhost_usbinterrupt(int irq, void *context, FAR void *arg) +{ + uint16_t intenb0; + uint16_t intenb1; + uint16_t intsts0; + uint16_t intsts1; + uint16_t ack_interrupt; + + /* Read Interrupt Status and mask out interrupts that are not enabled. */ + + intenb0 = rx65n_usbhost_getreg (RX65N_USB_INTENB0); + intenb1 = rx65n_usbhost_getreg (RX65N_USB_INTENB1); + intsts0 = rx65n_usbhost_getreg (RX65N_USB_INTSTS0); + intsts1 = rx65n_usbhost_getreg (RX65N_USB_INTSTS1); + + if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_SACK)) == + RX65N_USB_INTSTS1_SACK) + { + hw_usb_hclear_sts_sack(); + + /* Disable setup packet status response */ + + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_SACKE | + RX65N_USB_INTENB1_SIGNE); + + /* release the EP0 ep->wdhsem semaphore */ + + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_SACK_INT, 0)); + } + + /* Is it ERROR for Setup packet... */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_SIGN)) == + RX65N_USB_INTSTS1_SIGN) + { + hw_usb_hclear_sts_sign(); + + /* Disable setup packet status response */ + + rx65n_usbhost_clearbit (RX65N_USB_INTENB1, RX65N_USB_INTENB1_SACKE | + RX65N_USB_INTENB1_SIGNE); + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_SIGN_INT, 0)); + } + + /* Check for EOFERR interrupt... Not using it though */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_EOFERR)) == + RX65N_USB_INTSTS1_EOFERR) + { + rx65n_usbhost_putreg (((~RX65N_USB_INTSTS1_EOFERR) & + INTSTS1_BIT_VALUES_TO_ACK), RX65N_USB_INTSTS1); + } + + /* Check for over current condition... */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_OVRCRE)) == + RX65N_USB_INTSTS1_OVRCRE) + { + ack_interrupt = INTSTS1_BIT_VALUES_TO_ACK & + (~(RX65N_USB_INTSTS1_OVRCRE)); + + /* Acknowledge the OVRCR interrupt */ + + rx65n_usbhost_putreg (ack_interrupt, RX65N_USB_INTSTS1); + } + + /* Check for attach condition... */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_ATTCH)) == + RX65N_USB_INTSTS1_ATTCH) + { + hw_usb_hclear_sts_attch(); + + usb_hstd_bus_int_disable(); + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_ATTACHED_INT, 0)); + } + + /* Check for detach condition... */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_DTCH)) == + RX65N_USB_INTSTS1_DTCH) + { + hw_usb_hclear_sts_dtch(); + + usb_hstd_bus_int_disable(); + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_DETACHED_INT, 0)); + } + + /* Check for BCHG interrupt... Not using it though */ + + else if ((((intsts1 & intenb1) & RX65N_USB_INTSTS1_BCHG)) == + RX65N_USB_INTSTS1_BCHG) + { + hw_usb_hclear_sts_bchg(); + hw_usb_hclear_enb_bchge(); + } + + /* Check for BRDY interrupt... */ + + else if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_BRDY)) == + RX65N_USB_INTSTS0_BRDY) + { + /* Schedule the workque for processing */ + + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_BRDY_INT, 0)); + } + + /* Check for BEMP interrupt... */ + + else if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_BEMP)) == + RX65N_USB_INTSTS0_BEMP) + { + /* Schedule the workque for processing */ + + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_BEMP_INT, 0)); + } + + /* Check for NRDY interrupt... */ + + else if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_NRDY)) == + RX65N_USB_INTSTS0_NRDY) + { + /* Schedule the workque for processing */ + + DEBUGASSERT(work_available(&g_usbhost.rx65n_interrupt_bhalf)); + + DEBUGVERIFY(work_queue(HPWORK, &g_usbhost.rx65n_interrupt_bhalf, + rx65n_usbhost_bottomhalf, + (void *)USB_PROCESS_NRDY_INT, 0)); + } + + /* Check for SOF interrupt... Not using though */ + + else if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_SOFR)) == + RX65N_USB_INTSTS0_SOFR) + { + hw_usb_clear_sts_sofr(); + } + + /* Check for VBINT interrupt... Not using though */ + + else if ((((intsts0 & intenb0) & RX65N_USB_INTSTS0_VBINT)) == + RX65N_USB_INTSTS0_VBINT) + { + rx65n_usbhost_clearbit (RX65N_USB_INTSTS0, RX65N_USB_INTSTS0_VBINT); + } + + /* If none of the interrupt - what happens? */ + + else + { + syslog (LOG_INFO, "Unhandled interrupt. INTENB0 = 0x%x, \ + INTENB1 = 0x%x, INTSTS0 = 0x%x and INTSTS1 = 0x%x\n\r", + intenb0, intenb1, intsts0, intsts1); + } + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_bottomhalf + * + * Description: + * OHCI interrupt bottom half. This function runs on the high priority + * worker thread and was xcheduled when the last interrupt occurred. + * Possibly this acts as host_thread functionality which is present in + * FIT driver + ****************************************************************************/ + +static void rx65n_usbhost_bottomhalf (void *arg) +{ + struct rx65n_usbhost_s *priv = &g_usbhost; + uint32_t bottom_half_processing = (uint32_t)arg; + uint16_t device_speed; + + /* connected_times variable is used to check the number of times */ + + /* connected and disconnected */ + + static uint32_t connected_times = 0; + + /* We need to have exclusive access to the OHCI data structures. + * Waiting here is not a good thing to do on the worker thread, but there + * is no real option (other than to reschedule and delay). + */ + + rx65n_usbhost_takesem(&g_usbhost.exclsem); + + if (bottom_half_processing == USB_PROCESS_SACK_INT) + { + EDCTRL->xfrinfo->tdstatus = TD_CC_NOERROR; + hw_usb_hclear_sts_sack(); + rx65n_usbhost_givesem(&EDCTRL->wdhsem); + } + + else if (bottom_half_processing == USB_PROCESS_SIGN_INT) + { + EDCTRL->xfrinfo->tdstatus = TD_CC_PIDCHECKFAILURE; + hw_usb_hclear_sts_sign(); + rx65n_usbhost_givesem(&EDCTRL->wdhsem); + } + + else if (bottom_half_processing == USB_PROCESS_ATTACHED_INT) + { + g_attached = true; + device_speed = usb_hstd_attach_process (); + if (!priv->connected) + { + /* Yes.. connected. */ + + connected_times ++; + syslog (LOG_INFO, "NuttX: USB Device Connected. %d\n", + connected_times); + priv->connected = true; + priv->change = true; + + /* Update the speed of the connected device */ + + if (device_speed == USB_ATTACHL) + { + g_usbhost.rhport.hport.speed = USB_SPEED_LOW; + } + else + { + g_usbhost.rhport.hport.speed = USB_SPEED_FULL; + } + + /* Notify any waiters */ + + if (priv->pscwait) + { + priv->pscwait = false; + rx65n_usbhost_givesem(&priv->pscsem); + } + } + else + { + syslog (LOG_INFO, "WARNING: Spurious status change (connected)\n"); + } + + g_attached = false; + } + + else if (bottom_half_processing == USB_PROCESS_DETACHED_INT) + { + g_detached = true; + device_speed = usb_hstd_detach_process (); + + if (priv->connected) + { + /* Yes.. disconnect the device */ + + syslog (LOG_INFO, "NuttX: USB Device Disconnected. %d\n", + connected_times); + priv->connected = false; + priv->change = true; + + /* As detach calls several free functions, make sure access to */ + + /* hardware is available */ + + rx65n_usbhost_givesem(&g_usbhost.exclsem); + + /* Are we bound to a class instance? */ + + if (g_kbdpipe) + { + rx65n_usbhost_givesem(&g_rx65n_edlist[g_kbdpipe].wdhsem); + } + + g_kbdpipe = 0; + if (priv->rhport.hport.devclass) + { + /* Yes.. Disconnect the class */ + + CLASS_DISCONNECTED(priv->rhport.hport.devclass); + priv->rhport.hport.devclass = NULL; + } + + /* Notify any waiters for the Root Hub Status change event */ + + if (priv->pscwait) + { + rx65n_usbhost_givesem(&priv->pscsem); + priv->pscwait = false; + } + + return; + } + else + { + syslog (LOG_INFO, "WARNING: Spurious status change \ + (disconnected)\n"); + } + + g_detached = false; + } + + else if (bottom_half_processing == USB_PROCESS_BRDY_INT) + { + usb_hstd_brdy_pipe(); + } + + else if (bottom_half_processing == USB_PROCESS_BEMP_INT) + { + usb_hstd_bemp_pipe(); + } + + else if (bottom_half_processing == USB_PROCESS_NRDY_INT) + { + usb_hstd_nrdy_pipe(); + } + + /* If the bottom half is not any of the above then log the + * reason for bottom half being called + */ + + else + { + (void)nxsig_usleep(100); + uwarn("WARNING: un known bottomhalf. Value is %d\n", + bottom_half_processing); + syslog (LOG_INFO, "WARNING: un known bottomhalf. Value is %d\n", + bottom_half_processing); + } + + rx65n_usbhost_givesem(&g_usbhost.exclsem); +} + +/**************************************************************************** + * USB Host Controller Operations + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_usbhost_wait + * + * Description: + * Wait for a device to be connected or disconnected to/from a hub port. + * + * Input Parameters: + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The location to return the hub port descriptor that detected + * the connection related event. + * + * Returned Value: + * Zero (OK) is returned on success when a device is connected or + * disconnected. This function will not return until either (1) a device + * is connected or disconnect to/from any hub port or until (2) some + * failure occurs. On a failure, a negated errno value is returned + * indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_wait(struct usbhost_connection_s *conn, + struct usbhost_hubport_s **hport) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)&g_usbhost; + struct usbhost_hubport_s *connport; + irqstate_t flags; + int ret; + + flags = enter_critical_section(); + for (; ; ) + { + /* Is there a change in the connection state of the single root hub + * port? + */ + + if (priv->change) + { + connport = &priv->rhport.hport; + priv->change = false; + + /* Yes.. check for false alarms */ + + if (priv->connected != connport->connected) + { + /* Not a false alarm.. Remember the new state */ + + connport->connected = priv->connected; + + /* And return the root hub port */ + + *hport = connport; + leave_critical_section(flags); + + uinfo("RHport Connected: %s\n", + connport->connected ? "YES" : "NO"); + + return OK; + } + } + +#ifdef CONFIG_USBHOST_HUB + /* Is a device connected to an external hub? */ + + if (priv->hport) + { + /* Yes.. return the external hub port */ + + connport = (struct usbhost_hubport_s *)priv->hport; + priv->hport = NULL; + + *hport = connport; + leave_critical_section(flags); + + uinfo("Hub port Connected: %s\n", + connport->connected ? "YES" : "NO"); + return OK; + } + +#endif + /* Wait for the next connection event */ + + priv->pscwait = true; + ret = rx65n_usbhost_takesem(&priv->pscsem); + if (ret < 0) + { + return ret; + } + } +} + +/**************************************************************************** + * Name: rx65n_usbhost_enumerate + * + * Description: + * Enumerate the connected device. As part of this enumeration process, + * the driver will (1) get the device's configuration descriptor, (2) + * extract the class ID info from the configuration descriptor, (3) call + * usbhost_findclass() to find the class that supports this device, (4) + * call the create() method on the struct usbhost_registry_s interface + * to get a class instance, and finally (5) call the connect() method + * of the struct usbhost_class_s interface. After that, the class is in + * charge of the sequence of operations. + * + * Input Parameters: + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The descriptor of the hub port that has the newly connected + * device. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_rh_enumerate(struct usbhost_connection_s *conn, + struct usbhost_hubport_s *hport) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)&g_usbhost; + DEBUGASSERT(conn != NULL && hport != NULL && hport->port == 0); + + /* Are we connected to a device? The caller should have called the wait() + * method first to be assured that a device is connected. + */ + + while (!priv->connected) + { + /* No, return an error */ + + uwarn("WARNING: Not connected\n"); + + return -ENODEV; + } + + /* USB 2.0 spec says at least 50ms delay before port reset */ + + (void)nxsig_usleep(100 * 1000); + + /* Put RH port 1 in reset. + * Currently supporting only single downstream port) + */ + + (void)nxsig_usleep(200 * 1000); + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_enumerate + * + * Description: + * Enumerate the connected device. As part of this enumeration process, + * the driver will (1) get the device's configuration descriptor, (2) + * extract the class ID info from the configuration descriptor, (3) call + * usbhost_findclass() to find the class that supports this device, (4) + * call the create() method on the struct usbhost_registry_s interface + * to get a class instance, and finally (5) call the connect() method + * of the struct usbhost_class_s interface. After that, the class is in + * charge of the sequence of operations. + * + * Input Parameters: + * conn - The USB host connection instance obtained as a parameter from + * the call to the USB driver initialization logic. + * hport - The descriptor of the hub port that has the newly connected + * device. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_enumerate(FAR struct usbhost_connection_s *conn, + FAR struct usbhost_hubport_s *hport) +{ + int ret; + + DEBUGASSERT(hport); + + /* If this is a connection on the root hub, then we need to go to + * little more effort to get the device speed. If it is a connection + * on an external hub, then we already have that information. + */ + +#ifdef CONFIG_USBHOST_HUB + if (ROOTHUB(hport)) +#endif + { + ret = rx65n_usbhost_rh_enumerate(conn, hport); + if (ret < 0) + { + return ret; + } + } + + /* Then let the common usbhost_enumerate do the real enumeration. */ + + uinfo("Enumerate the device\n"); + + ret = usbhost_enumerate(hport, &hport->devclass); + if (ret < 0) + { + uerr("ERROR: Enumeration failed: %d\n", ret); + syslog (LOG_INFO, "ERROR: Enumeration failed: %d\n", ret); + } + + else + { + syslog (LOG_INFO, "Root Hub Port device enumerated"); + } + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_ep0configure + * + * Description: + * Configure endpoint 0. This method is normally used internally by the + * enumerate() method but is made available at the interface to support + * an external implementation of the enumeration logic. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from + * the call to the class create() method. + * ep0 - The (opaque) EP0 endpoint instance + * funcaddr - The USB address of the function containing the endpoint + * that EP0 controls + * speed - The speed of the port USB_SPEED_LOW, _FULL, or _HIGH + * mps (maxpacketsize) - The maximum number of bytes that can be sent + * to or received from the endpoint in a single data packet + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_ep0configure(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, + uint8_t funcaddr, uint8_t speed, + uint16_t maxpacketsize) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + uint16_t current_dcpmaxp; + + DEBUGASSERT(drvr != NULL && ep0 != NULL && + funcaddr < 128 && maxpacketsize < 2048); + + /* We must have exclusive access to EP0 and the control list */ + + rx65n_usbhost_takesem(&priv->exclsem); + usb_cstd_set_nak(USB_PIPE0); + + /* Make sure, all the DEVADDn registers are set to default state */ + + /* if (funcaddr == 0) */ + + hw_usb_hset_usbspd (funcaddr, (speed << 6)); + + /* else + * hw_usb_hset_usbspd (funcaddr, (1 << 6)); + * debug_ptr = RX65N_USB_DEVADD0+funcaddr; + */ + + current_dcpmaxp = hw_usb_read_dcpmaxp (); + current_dcpmaxp = current_dcpmaxp & (~RX65N_USB_DCPMAXP_MXPS_MASK); + current_dcpmaxp |= maxpacketsize; + current_dcpmaxp = current_dcpmaxp & (~RX65N_USB_DCPMAXP_DEVADDR_MASK); + current_dcpmaxp |= funcaddr << RX65N_USB_DCPMAXP_DEVADDR_SHIFT; + hw_usb_write_dcpmxps (current_dcpmaxp); + + hw_usb_set_curpipe (USB_CUSE, USB_PIPE0); + hw_usb_set_bclr (USB_CUSE); + + rx65n_usbhost_givesem(&priv->exclsem); + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_epalloc + * + * Description: + * Allocate and configure one endpoint. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * epdesc - Describes the endpoint to be allocated. + * ep - A memory location provided by the caller in which to receive the + * allocated endpoint descriptor. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_epalloc(struct usbhost_driver_s *drvr, + const struct usbhost_epdesc_s *epdesc, + usbhost_ep_t *ep) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct usbhost_hubport_s *hport; + struct rx65n_usbhost_ed_s *ed; + int ret = -ENOMEM; + uint8_t pipe_num; + uint8_t pipe_type; + uint8_t pipe_dir; + + /* Sanity check. NOTE that this method should only be called if a + * device is connected (because we need a valid low speed indication). + */ + + DEBUGASSERT(priv && epdesc && ep && priv->connected); + + /* We must have exclusive access to the ED pool, the bulk list, the + * periodic list and the interrupt table. + */ + + rx65n_usbhost_takesem(&priv->exclsem); + + /* Take the ED descriptor from the list of ED Array - based on pipe num + * Also note it down as part of ED structurie itself + * for futer use - if needed + * Take the next ED from the beginning of the free list + */ + + /* DEBUGASSERT(pipe_no == USB_NULL); */ + + if (epdesc->in) + { + pipe_dir = USB_EP_IN; + } + else + { + pipe_dir = USB_EP_OUT; + } + + if ((epdesc->xfrtype) == USB_EP_ATTR_XFER_CONTROL) + { + pipe_type = USB_EP_CTRL; + } + else if ((epdesc->xfrtype) == USB_EP_ATTR_XFER_BULK) + { + pipe_type = USB_EP_BULK; + } + else if ((epdesc->xfrtype) == USB_EP_ATTR_XFER_INT) + { + pipe_type = USB_EP_INT; + } + else + { + pipe_type = USB_EP_ISO; + } + + pipe_num = usb_hstd_get_pipe_no (pipe_type, pipe_dir); + DEBUGASSERT(pipe_no == USB_NULL); + g_usb_pipe_table[pipe_num].use_flag = USB_TRUE; + + ed = &g_rx65n_edlist[pipe_num]; + if (ed) + { + /* Remove the ED from the freelist */ + + /* Configure the endpoint descriptor. */ + + memset((void *)ed, 0, sizeof(struct rx65n_usbhost_ed_s)); + + hport = epdesc->hport; + ed->hw.ctrl = (uint32_t)(hport->funcaddr) << ED_CONTROL_FA_SHIFT | + (uint32_t)(epdesc->addr) << ED_CONTROL_EN_SHIFT | + (uint32_t)(epdesc->mxpacketsize) << ED_CONTROL_MPS_SHIFT; + + /* Note down the pipe number for reference */ + + ed ->pipenum = pipe_num; + + /* Get the direction of the endpoint. For control endpoints, the + * direction is in the TD. + */ + + if (epdesc->xfrtype == USB_EP_ATTR_XFER_CONTROL) + { + ed->hw.ctrl |= ED_CONTROL_D_TD1; + } + else if (epdesc->in) + { + ed->hw.ctrl |= ED_CONTROL_D_IN; + } + else + { + ed->hw.ctrl |= ED_CONTROL_D_OUT; + } + + /* Check for a low-speed device */ + + if (hport->speed == USB_SPEED_LOW) + { + ed->hw.ctrl |= ED_CONTROL_S; + } + + /* Set the transfer type */ + + ed->xfrtype = epdesc->xfrtype; + + /* Special Case isochronous transfer types */ + + uinfo("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl); + + /* Initialize the semaphore that is used to wait for the endpoint + * WDH event. The wdhsem semaphore is used for signaling and, hence, + * should not have priority inheritance enabled. + */ + + nxsem_init(&ed->wdhsem, 0, 0); + nxsem_set_protocol(&ed->wdhsem, SEM_PRIO_NONE); + + /* Link the common tail TD to the ED's TD list */ + + ed->hw.headp = (uint32_t)TDTAIL; + ed->hw.tailp = (uint32_t)TDTAIL; + + /* Now add the endpoint descriptor to the appropriate list */ + + switch (ed->xfrtype) + { + case USB_EP_ATTR_XFER_CONTROL: + ret = rx65n_usbhost_addctrled(priv, ed); + break; + + case USB_EP_ATTR_XFER_BULK: + ret = rx65n_usbhost_addbulked(priv, epdesc, ed); + break; + + case USB_EP_ATTR_XFER_INT: + ret = rx65n_usbhost_addinted(priv, epdesc, ed); + break; + + case USB_EP_ATTR_XFER_ISOC: + ret = rx65n_usbhost_addisoced(priv, epdesc, ed); + break; + + default: + ret = -EINVAL; + break; + } + + /* Was the ED successfully added? */ + + if (ret < 0) + { + /* No.. destroy it and report the error */ + + uerr("ERROR: Failed to queue ED for transfer type: %d\n", + ed->xfrtype); + nxsem_destroy(&ed->wdhsem); + rx65n_usbhost_edfree(ed); + } + else + { + /* Yes.. return an opaque reference to the ED */ + + *ep = (usbhost_ep_t)ed; + } + } + + rx65n_usbhost_givesem(&priv->exclsem); + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_epfree + * + * Description: + * Free and endpoint previously allocated by DRVR_EPALLOC. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The endpint to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_epfree(struct usbhost_driver_s *drvr, + usbhost_ep_t ep) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct rx65n_usbhost_ed_s *ed = (struct rx65n_usbhost_ed_s *)ep; + int ret; + + /* There should not be any pending, real TDs linked to this ED */ + + DEBUGASSERT(ed && (ed->hw.headp & ED_HEADP_ADDR_MASK) == TDTAIL_ADDR); + + /* We must have exclusive access to the ED pool, the bulk list, + * the periodic list and the interrupt table. + */ + + rx65n_usbhost_takesem(&priv->exclsem); + + /* Remove the ED to the correct list depending on the trasfer type */ + + switch (ed->xfrtype) + { + case USB_EP_ATTR_XFER_CONTROL: + ret = rx65n_usbhost_remctrled(priv, ed); + break; + + case USB_EP_ATTR_XFER_BULK: + ret = rx65n_usbhost_rembulked(priv, ed); + break; + + case USB_EP_ATTR_XFER_INT: + ret = rx65n_usbhost_reminted(priv, ed); + break; + + case USB_EP_ATTR_XFER_ISOC: + ret = rx65n_usbhost_remisoced(priv, ed); + break; + + default: + ret = -EINVAL; + break; + } + + /* Put the ED back into the free list */ + + rx65n_usbhost_edfree(ed); + rx65n_usbhost_givesem(&priv->exclsem); + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_alloc + * + * Description: + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a mechanism + * to allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may + * simply map to kmm_malloc. + * + * This interface was optimized under a particular assumption. It was + * assumed that the driver maintains a pool of small, pre-allocated buffers + * for descriptor traffic. NOTE that size is not an input, but an output: + * The size of the pre-allocated buffer is returned. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * maxlen - The address of a memory location provided by the caller in + * which to return the maximum size of the allocated buffer memory. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value i + * returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_alloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t *maxlen) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + + DEBUGASSERT(priv && buffer && maxlen); + int ret = -ENOMEM; + + /* We must have exclusive access to the transfer buffer pool */ + + rx65n_usbhost_takesem(&priv->exclsem); + + *buffer = rx65n_usbhost_tballoc(); + if (*buffer) + { + *maxlen = CONFIG_RX65N_USBHOST_TDBUFSIZE; + ret = OK; + } + + rx65n_usbhost_givesem(&priv->exclsem); + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_free + * + * Description: + * Some hardware supports special memory in which request and descriptor + * data can be accessed more efficiently. This method provides a + * mechanism to free that request/descriptor memory. If the underlying + * hardware does not support such "special" memory, this functions may + * simply map to kmm_free(). + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of the allocated buffer memory to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure + * + * Assumptions: + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_free(struct usbhost_driver_s *drvr, uint8_t *buffer) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + DEBUGASSERT(buffer); + + /* We must have exclusive access to the transfer buffer pool */ + + rx65n_usbhost_takesem(&priv->exclsem); + rx65n_usbhost_tbfree(buffer); + rx65n_usbhost_givesem(&priv->exclsem); + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_ioalloc + * + * Description: + * Some hardware supports special memory in which larger IO buffers can + * be accessed more efficiently. This method provides a mechanism to + * allocate the request/descriptor memory. If the underlying hardware + * does not support such "special" memory, this functions may simply map + * to kmm_malloc. + * + * This interface differs from DRVR_ALLOC in that the buffers are + * variable-sized. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of a memory location provided by the caller in + * which to return the allocated buffer memory address. + * buflen - The size of the buffer required. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * returned indicating the nature of the failure + * value is + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_ioalloc(struct usbhost_driver_s *drvr, + uint8_t **buffer, size_t buflen) +{ + FAR uint8_t *alloc; + + DEBUGASSERT(drvr && buffer && buflen > 0); + + /* There is no special memory requirement */ + + alloc = (FAR uint8_t *)kmm_malloc(buflen); + if (!alloc) + { + return -ENOMEM; + } + + /* Return the allocated buffer */ + + *buffer = alloc; + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_iofree + * + * Description: + * Some hardware supports special memory in which IO data can be + * accessed more efficiently. This method provides a mechanism to free + * that IO buffer memory. If the underlying hardware does not support + * such "special" memory, this functions may simply map to kmm_free(). + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * buffer - The address of the allocated buffer memory to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure + * + * Assumptions: + * This function will *not* be called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_iofree(struct usbhost_driver_s *drvr, + uint8_t *buffer) +{ + DEBUGASSERT(drvr && buffer); + +#if RX65N_USBHOST_IOBUFFERS > 0 + rx65n_usbhhost_freeio(buffer); + return OK; +#else + return -ENOSYS; +#endif +} + +/**************************************************************************** + * Name: rx65n_usbhost_ctrlin and rx65n_usbhost_ctrlout + * + * Description: + * Description: + * Process a IN or OUT request on the control endpoint. These methods + * will enqueue the request and wait for it to complete. Only one + * transfer may be queued; Neither these methods nor the transfer() method + * can be called again until the control transfer functions returns. + * + * These are blocking methods; these functions will not return until the + * control transfer has completed. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep0 - The control endpoint to send/receive the control request. + * req - Describes the request to be sent. This request must lie in + * memory created by DRVR_ALLOC. + * buffer - A buffer used for sending the request and for returning any + * responses. This buffer must be large enough to hold the length value + * in the request description. buffer must have been allocated using + * DRVR_ALLOC. + * + * NOTE: On an IN transaction, req and buffer may refer to the same + * allocated memory. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated + * errno value is returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_ctrlin(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, + const struct usb_ctrlreq_s *req, + uint8_t *buffer) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct rx65n_usbhost_ed_s *ed = (struct rx65n_usbhost_ed_s *)ep0; + uint16_t len; + int ret; + uint8_t req_type; + uint8_t req_req; + + uint8_t *local_buf; + local_buf = buffer; + + DEBUGASSERT(priv != NULL && ed != NULL && req != NULL); + + uinfo("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n", + req->type, req->req, req->value[1], req->value[0], + req->index[1], req->index[0], req->len[1], req->len[0]); + + /* We must have exclusive access to EP0 and the control list */ + + len = rx65n_usbhost_getle16(req->len); + req_type = req->type; + req_req = req->req; + + if (req_type == (USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | + USB_REQ_RECIPIENT_INTERFACE) && + (req_req == USBHID_REQUEST_GETREPORT)) + { + /* No need to check for this class request */ + } + else + { + ed->xfrinfo->tdxfercond = USB_SETUPRD; + ret = rx65n_usbhost_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, + (uint8_t *)req, USB_SIZEOF_CTRLREQ); + + if (ret == OK) + { + if (len) + { + ed->xfrinfo->tdxfercond = USB_DATARD; + ret = rx65n_usbhost_ctrltd(priv, ed, GTD_STATUS_DP_IN, + buffer, len); + g_usbidx = USB0.USBINDX; + } + + if (ret == OK) + { + ed->xfrinfo->tdxfercond = USB_STATUSWR; + ret = rx65n_usbhost_ctrltd(priv, ed, + GTD_STATUS_DP_OUT, NULL, 0); + } + } + } + + /* If this is Get Report request */ + + if (req_type == (USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS | + USB_REQ_RECIPIENT_INTERFACE) && + (req_req == USBHID_REQUEST_GETREPORT)) + { + rx65n_usbhost_takesem (&g_rx65n_edlist[kbd_interrupt_in_pipe].wdhsem); + + *(local_buf + 0) = kbd_report_data [0]; + *(local_buf + 1) = kbd_report_data [1]; + *(local_buf + 2) = kbd_report_data [2]; + *(local_buf + 3) = kbd_report_data [3]; + *(local_buf + 4) = kbd_report_data [4]; + *(local_buf + 5) = kbd_report_data [5]; + *(local_buf + 6) = kbd_report_data [6]; + *(local_buf + 7) = kbd_report_data [7]; + ret = OK; + + /* Reset the transferred count so that for the next interrupt */ + + /* for read does the calculation correctly */ + + g_rx65n_edlist[kbd_interrupt_in_pipe].xfrinfo->xfrd = 0; + usb_cstd_set_buf((uint16_t) kbd_interrupt_in_pipe); /* Set BUF */ + } + + return ret; +} + +static int rx65n_usbhost_ctrlout(struct usbhost_driver_s *drvr, + usbhost_ep_t ep0, const struct usb_ctrlreq_s *req, + const uint8_t *buffer) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct rx65n_usbhost_ed_s *ed = (struct rx65n_usbhost_ed_s *)ep0; + uint16_t len; + int ret; + static int dev_addressed_state = 0; + + /* Assumption : This control out is called first time for + * set address command. Just reseting the bus after the + * set address command + */ + + if (dev_addressed_state == 0) + { + /* Not sure, if the reset is needed or not - at least the FIT code + * does not have reset... + * so removing it... + * usb_hstd_bus_reset(); + */ + + dev_addressed_state = 0xff; + } + + DEBUGASSERT(priv != NULL && ed != NULL && req != NULL); + + uinfo("type:%02x req:%02x value:%02x%02x index:%02x%02x len:%02x%02x\n", + req->type, req->req, req->value[1], req->value[0], + req->index[1], req->index[0], req->len[1], req->len[0]); + + /* We must have exclusive access to EP0 and the control list */ + + len = rx65n_usbhost_getle16(req->len); + ed->xfrinfo->tdxfercond = USB_SETUPWR; + ret = rx65n_usbhost_ctrltd(priv, ed, GTD_STATUS_DP_SETUP, + (uint8_t *)req, USB_SIZEOF_CTRLREQ); + + if (ret == OK) + { + if (len) + { + ed->xfrinfo->tdxfercond = USB_DATAWR; + ret = rx65n_usbhost_ctrltd(priv, ed, GTD_STATUS_DP_OUT, + (uint8_t *)buffer, len); + } + + if (ret == OK) + { + ed->xfrinfo->tdxfercond = USB_STATUSRD; + ret = rx65n_usbhost_ctrltd(priv, ed, GTD_STATUS_DP_IN, NULL, 0); + } + } + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_transfer_common + * + * Description: + * Initiate a request to handle a transfer descriptor. This method will + * enqueue the transfer request and return immediately + * + * Input Parameters: + * priv - Internal driver state structure. + * ed - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure. + * + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static int rx65n_usbhost_transfer_common(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, + uint8_t *buffer, + size_t buflen) +{ + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + uint32_t dirpid; + bool in; + int ret; + + xfrinfo = ed->xfrinfo; + in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN; + + uinfo("EP%u %s toggle:%u maxpacket:%u buflen:%lu\n", + (ed->hw.ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT, + in ? "IN" : "OUT", + (ed->hw.headp & ED_HEADP_C) != 0 ? 1 : 0, + (ed->hw.ctrl & ED_CONTROL_MPS_MASK) >> ED_CONTROL_MPS_SHIFT, + (unsigned long)buflen); + + /* Get the direction of the endpoint */ + + if (in) + { + dirpid = GTD_STATUS_DP_IN; + } + else + { + dirpid = GTD_STATUS_DP_OUT; + } + + /* Then enqueue the transfer */ + + xfrinfo->tdstatus = TD_CC_NOERROR; + + ret = rx65n_usbhost_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, + buffer, buflen); + + if (ed->pipenum == USB_PIPE6 && in == 1) + { + usb_hstd_receive_start (buffer, buflen, ed->pipenum); + } + + if (ret == OK) + { + /* BulkListFilled. This bit is used to indicate whether there are any + * TDs on the Bulk list. + */ + + if (ed->xfrtype == USB_EP_ATTR_XFER_BULK) + { + if (in) + { + usb_hstd_receive_start (buffer, buflen, ed->pipenum); + } + else + { + usb_hstd_send_start (buffer, buflen, ed->pipenum); + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: rx65n_usbhost_dma_alloc + * + * Description: + * Allocate DMA memory to perform a transfer, copying user data as + * necessary + * Input Parameters: + * priv - Internal driver state structure. + * ed - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * userbuffer - The user buffer containing the data to be sent (OUT + * endpoint) or received (IN endpoint). + * buflen - The length of the data to be sent or received. + * alloc - The location to return the allocated DMA buffer. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +#if RX65N_USBHOST_IOBUFFERS > 0 +static int rx65n_usbhost_dma_alloc(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, + uint8_t *userbuffer, + size_t buflen, uint8_t **alloc) +{ + syslog (LOG_INFO, "Debug : %s(): Line : %d\n", __func__, __LINE__); + + /* This need to be impemented if DMA is used */ + + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_dma_free + * + * Description: + * Free allocated DMA memory. + * + * Input Parameters: + * priv - Internal driver state structure. + * ed - The IN or OUT endpoint descriptor for the device endpoint + * on which to perform the transfer. + * userbuffer - The user buffer containing the data to be sent + * (OUT endpoint) or received (IN endpoint). + * buflen - The length of the data to be sent or received. + * alloc - The allocated DMA buffer to be freed. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure. + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static void rx65n_usbhost_dma_free(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed, + uint8_t *userbuffer, + size_t buflen, uint8_t *newbuffer) +{ + syslog (LOG_INFO, "Debug : %s(): Line : %d\n", __func__, __LINE__); +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_transfer + * + * Description: + * Process a request to handle a transfer descriptor. This method will + * enqueue the transfer request, blocking until the transfer completes. + * Only one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until this function returns. + * + * This is a blocking method; this functions will not return until the + * transfer has completed. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * + * Returned Value: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno + * value is returned that indicates the nature of the failure: + * + * EAGAIN - If devices NAKs the transfer (or NYET or other error where + * it may be appropriate to restart the entire transaction). + * EPERM - If the endpoint stalls + * EIO - On a TX or data toggle error + * EPIPE - Overrun errors + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static ssize_t rx65n_usbhost_transfer(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, uint8_t *buffer, size_t buflen) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct rx65n_usbhost_ed_s *ed = (struct rx65n_usbhost_ed_s *)ep; + struct rx65n_usbhost_xfrinfo_s *xfrinfo; +#if RX65N_USBHOST_IOBUFFERS > 0 + uint8_t *alloc = NULL; + uint8_t *userbuffer = NULL; +#endif + ssize_t nbytes; + int ret; + uint8_t transfer_retry_count = 0; + + DEBUGASSERT(priv && ed && buffer && buflen > 0); + + if (nrdy_retries[ed->pipenum] != 0) + { + /* nRdy has occured alreday - just return with -ve value, + * so that file close is also completes with this error + * + */ + + return -EBUSY; + } + + do + { + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt + * table. + * + */ + + rx65n_usbhost_takesem(&priv->exclsem); + + /* Allocate a structure to retain the information needed when the + * transfer completes. + * + */ + + DEBUGASSERT(ed->xfrinfo == NULL); + + xfrinfo = rx65n_usbhost_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + uerr("ERROR: rx65n_usbhost_alloc_xfrinfo failed\n"); + nbytes = -ENOMEM; + rx65n_usbhost_givesem(&priv->exclsem); + goto errout_with_sem; + } + + /* Newly added condition */ + + if (xfrinfo < 0) + { + uerr("ERROR: rx65n_usbhost_alloc_xfrinfo failed\n"); + nbytes = -ENOMEM; + goto errout_with_xfrinfo; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct rx65n_usbhost_xfrinfo_s)); + xfrinfo->buffer = buffer; + xfrinfo->buflen = buflen; + + /* To begin with transferred bytes = 0 */ + + xfrinfo->xfrd = 0; + + ed->xfrinfo = xfrinfo; + +#if RX65N_USBHOST_IOBUFFERS > 0 + /* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */ + + ret = rx65n_usbhost_dma_alloc(priv, ed, buffer, buflen, &alloc); + if (ret < 0) + { + uerr("ERROR: rx65n_usbhost_dma_alloc failed: %d\n", ret); + nbytes = (ssize_t)ret; + goto errout_with_xfrinfo; + } + + /* If a buffer was allocated, then use it instead of the + * callers buffer + * + */ + + if (alloc) + { + userbuffer = buffer; + buffer = alloc; + } +#endif + + /* Set the request for the Writeback Done Head event well + * BEFORE enabling + * the transfer. + */ + + ret = rx65n_usbhost_wdhwait(priv, ed); + if (ret < 0) + { + uerr("ERROR: Device disconnected\n"); + nbytes = (ssize_t)ret; + goto errout_with_buffers; + } + + /* Set up the transfer */ + + ret = rx65n_usbhost_transfer_common(priv, ed, buffer, buflen); + rx65n_usbhost_givesem(&priv->exclsem); + if (ret < 0) + { + uerr("ERROR: rx65n_usbhost_transfer_common failed: %d\n", ret); + nbytes = (ssize_t)ret; + goto errout_with_wdhwait; + } + + /* Wait for the Write-back Done Head interrupt */ + + if (priv->connected) + { + rx65n_usbhost_takesem(&ed->wdhsem); + } + + /* Update the buffer pointer for next buffer operation */ + + /* Check the TD completion status bits */ + + if (xfrinfo->tdstatus == TD_CC_NOERROR) + { + /* Return the number of bytes successfully transferred */ + + nbytes = xfrinfo->xfrd; + DEBUGASSERT(nbytes >= 0 && nbytes <= buflen); + } + else + { + /* Map the bad completion status to something that a class driver + * might understand. + */ + + uerr("ERROR: Bad TD completion status: %d\n", xfrinfo->tdstatus); + + switch (xfrinfo->tdstatus) + { + case TD_CC_STALL: + nbytes = -EPERM; + break; + + /* This case is newly added for NRDY issue */ + + case TD_CC_DEVNOTRESPONDING: + xfrinfo->wdhwait = false; + transfer_retry_count ++; + nbytes = -EBUSY; + break; + + case TD_CC_USER: + nbytes = -ESHUTDOWN; + break; + + default: + nbytes = -EIO; + break; + } + } + +errout_with_wdhwait: + + /* Make sure that there is no outstanding request on this endpoint */ + + xfrinfo->wdhwait = false; + +errout_with_buffers: +#if RX65N_USBHOST_IOBUFFERS > 0 + + /* Free any temporary IO buffers */ + + rx65n_usbhost_dma_free(priv, ed, userbuffer, buflen, alloc); +#endif + +errout_with_xfrinfo: + + /* Make sure that there is no outstanding request on this endpoint */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; + } + while (0); +errout_with_sem: + + /* rx65n_usbhost_givesem(&priv->exclsem); */ + + return nbytes; +} + +/**************************************************************************** + * Name: rx65n_usbhost_asynch_completion + * + * Description: + * This function is called at the interrupt level when an asynchronous + * transfer completes. It performs the pending callback. + * + * Input Parameters: + * priv - Internal driver state structure. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * the transfer was performed. + * + * Returned Value: + * None + * + * Assumptions: + * - Called from the interrupt level + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static void rx65n_usbhost_asynch_completion(struct rx65n_usbhost_s *priv, + struct rx65n_usbhost_ed_s *ed) +{ + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + usbhost_asynch_t callback; + void *arg; + ssize_t nbytes; + + DEBUGASSERT(ed != NULL && ed->xfrinfo != NULL); + xfrinfo = ed->xfrinfo; + + DEBUGASSERT(xfrinfo->wdhwait == false && xfrinfo->callback != NULL && + xfrinfo->buffer != NULL && xfrinfo->buflen > 0); + + /* Check the TD completion status bits */ + + if (xfrinfo->tdstatus == TD_CC_NOERROR) + { + /* Provide the number of bytes successfully transferred */ + + nbytes = xfrinfo->xfrd; + } + else + { + /* Map the bad completion status to something that a class driver + * might understand. + */ + + uerr("ERROR: Bad TD completion status: %d\n", xfrinfo->tdstatus); + + switch (xfrinfo->tdstatus) + { + case TD_CC_STALL: + nbytes = -EPERM; + break; + + case TD_CC_USER: + nbytes = -ESHUTDOWN; + break; + + default: + nbytes = -EIO; + break; + } + } + +#if RX65N_USBHOST_IOBUFFERS > 0 + + /* Free any temporary IO buffers */ + + rx65n_usbhost_dma_free(priv, ed, xfrinfo->buffer, xfrinfo->buflen, + xfrinfo->alloc); +#endif + + /* Extract the callback information before freeing the buffer */ + + callback = xfrinfo->callback; + arg = xfrinfo->arg; + + /* Make sure that there is no outstanding request on this endpoint */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; + + /* Then perform the callback */ + + callback(arg, nbytes); +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_asynch + * + * Description: + * Process a request to handle a transfer descriptor. This method will + * enqueue the transfer request and return immediately. When the transfer + * completes, the callback will be invoked with the provided transfer. + * This method is useful for receiving interrupt transfers which may come + * infrequently. + * + * Only one transfer may be queued; Neither this method nor the ctrlin or + * ctrlout methods can be called again until the transfer completes. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on which + * to perform the transfer. + * buffer - A buffer containing the data to be sent (OUT endpoint) or + * received (IN endpoint). buffer must have been allocated using + * DRVR_ALLOC + * buflen - The length of the data to be sent or received. + * callback - This function will be called when the transfer completes. + * arg - The arbitrary parameter that will be passed to the callback + * function when the transfer completes. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * returned indicating the nature of the failure + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_ASYNCH +static int rx65n_usbhost_asynch(struct usbhost_driver_s *drvr, + usbhost_ep_t ep, + uint8_t *buffer, size_t buflen, + usbhost_asynch_t callback, void *arg) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + struct rx65n_usbhost_ed_s *ed = (struct rx65n_usbhost_ed_s *)ep; + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + int ret; + + DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && + buffer && buflen > 0 && callback); + + /* We must have exclusive access to the endpoint, the TD pool, the I/O + * buffer pool, the bulk and interrupt lists, and the HCCA interrupt table. + */ + + rx65n_usbhost_takesem(&priv->exclsem); + + /* Allocate a structure to retain the information needed when the + * asynchronous transfer completes. + */ + + DEBUGASSERT(ed->xfrinfo == NULL); + + xfrinfo = rx65n_usbhost_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + uerr("ERROR: rx65n_usbhost_alloc_xfrinfo failed\n"); + ret = -ENOMEM; + goto errout_with_sem; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct rx65n_usbhost_xfrinfo_s)); + xfrinfo->buffer = buffer; + xfrinfo->buflen = buflen; + xfrinfo->callback = callback; + xfrinfo->arg = arg; + + ed->xfrinfo = xfrinfo; + +#if RX65N_USBHOST_IOBUFFERS > 0 + /* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */ + + ret = rx65n_usbhost_dma_alloc(priv, ed, buffer, buflen, &xfrinfo->alloc); + if (ret < 0) + { + uerr("ERROR: rx65n_usbhost_dma_alloc failed: %d\n", ret); + goto errout_with_sem; + } + + /* If a buffer was allocated, then use it instead of the callers buffer */ + + if (xfrinfo->alloc) + { + buffer = xfrinfo->alloc; + } +#endif + + /* Set up the transfer */ + + ret = rx65n_usbhost_transfer_common(priv, ed, buffer, buflen); + if (ret < 0) + { + uerr("ERROR: rx65n_usbhost_transfer_common failed: %d\n", ret); + goto errout_with_asynch; + } + + /* And return now. The callback will be invoked when the transfer + * completes. + */ + + /* Enable Ready Interrupt */ + + rx65n_usbhost_givesem(&priv->exclsem); + return OK; + +errout_with_asynch: +#if RX65N_USBHOST_IOBUFFERS > 0 + + /* Free any temporary IO buffers */ + + rx65n_usbhost_dma_free(priv, ed, buffer, buflen, xfrinfo->alloc); +#endif + + /* Free the transfer structure */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; + +errout_with_sem: + rx65n_usbhost_givesem(&priv->exclsem); + return ret; +} +#endif /* CONFIG_USBHOST_ASYNCH */ + +/**************************************************************************** + * Name: rx65n_usbhost_cancel + * + * Description: + * Cancel a pending transfer on an endpoint. Cancelled synchronous or + * asynchronous transfer will complete normally with the error -ESHUTDOWN. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * ep - The IN or OUT endpoint descriptor for the device endpoint on + * which an asynchronous transfer should be transferred. + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno value + * is returned indicating the nature of the failure. + * + ****************************************************************************/ + +static int rx65n_usbhost_cancel(FAR struct usbhost_driver_s *drvr, + usbhost_ep_t ep) +{ +#ifdef CONFIG_USBHOST_ASYNCH + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; +#endif + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + irqstate_t flags; + + /* These first steps must be atomic as possible */ + + flags = enter_critical_section(); + + /* It is possible there there is no transfer to be in progress */ + + xfrinfo = g_rx65n_edlist[USB_PIPE6].xfrinfo; + if (xfrinfo) + { + /* It might be possible for no transfer to be in progress (callback == + * NULL and wdhwait == false) + */ + +#ifdef CONFIG_USBHOST_ASYNCH + if (xfrinfo->callback || xfrinfo->wdhwait) +#else + if (xfrinfo->wdhwait) +#endif + { + /* Control endpoints should not come through this path and + * isochronous endpoints are not yet implemented. So we only have + * to distinguish bulk and interrupt endpoints. + */ + + if (g_rx65n_edlist[USB_PIPE6].xfrtype == USB_EP_ATTR_XFER_BULK) + { + g_rx65n_edlist[USB_PIPE6].hw.headp = (uint32_t)TDTAIL; + g_rx65n_edlist[USB_PIPE6].xfrinfo = NULL; + } + else + { + /* Remove the TDs attached to the ED, keeping the Ed in the + * list. + */ + + g_rx65n_edlist[USB_PIPE6].hw.headp = (uint32_t)TDTAIL; + } + + xfrinfo->tdstatus = TD_CC_USER; + + /* If there is a thread waiting for the transfer to complete, then + * wake up the thread. + */ + + if (xfrinfo->wdhwait) + { +#ifdef CONFIG_USBHOST_ASYNCH + /* Yes.. there should not also be a callback scheduled */ + + DEBUGASSERT(xfrinfo->callback == NULL); +#endif + + /* Wake up the waiting thread */ + + rx65n_usbhost_givesem(&g_rx65n_edlist[USB_PIPE6].wdhsem); + + /* And free the transfer structure */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + g_rx65n_edlist[USB_PIPE6].xfrinfo = NULL; + } +#ifdef CONFIG_USBHOST_ASYNCH + else + { + /* Otherwise, perform the callback and free the transfer + * structure. + */ + + rx65n_usbhost_asynch_completion(priv, + &g_rx65n_edlist[USB_PIPE6]); + usb_cstd_clr_pipe_cnfg(USB_PIPE6); + g_usb_pipe_table[USB_PIPE6].use_flag = USB_FALSE; + } +#endif + } + else + { + /* Just free the transfer structure */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + g_rx65n_edlist[USB_PIPE6].xfrinfo = NULL; + } + } + + /* Determine the return value */ + + leave_critical_section(flags); + return OK; +} + +/**************************************************************************** + * Name: rx65n_usbhost_connect + * + * Description: + * New connections may be detected by an attached hub. This method is the + * mechanism that is used by the hub class to introduce a new connection + * and port description to the system. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The descriptor of the hub port that detected the connection + * related event + * connected - True: device connected; false: device disconnected + * + * Returned Value: + * On success, zero (OK) is returned. On a failure, a negated errno + * value is returned indicating the nature of the failure. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST_HUB +static int rx65n_usbhost_connect(FAR struct usbhost_driver_s *drvr, + FAR struct usbhost_hubport_s *hport, + bool connected) +{ + struct rx65n_usbhost_s *priv = (struct rx65n_usbhost_s *)drvr; + DEBUGASSERT(priv != NULL && hport != NULL); + + int ret; + + /* Set the connected/disconnected flag */ + + hport->connected = connected; + uinfo("Hub port %d connected: %s\n", hport->port, + connected ? "YES" : "NO"); + + /* Report the connection event */ + + priv->hport = hport; + ret = usbhost_enumerate(hport, &hport->devclass); + if (ret < 0) + { + syslog (LOG_INFO, "Enumeration failed with %d", ret); + } + + hw_usb_write_dcpmxps((uint16_t) (USB_DEFPACKET + USB_DEVICE_1)); + + if (hport->speed == USB_SPEED_LOW) + { + switch (hport->port) + { + case HUB_PORT1: + case HUB_PORT2: + case HUB_PORT3: + case HUB_PORT4: + g_kbdport = hport->port; + g_hubkbd = true; + break; + + default: + syslog (LOG_INFO, "Undefined Port"); + break; + } + } + + if (ret >= 0) + { + syslog (LOG_INFO, "Hub Port device enumerated\n\r"); + } + + return OK; +} +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_disconnect + * + * Description: + * Called by the class when an error occurs and driver has been + * disconnected. The USB host driver should discard the handle to the + * class instance (it is stale) and not attempt any further interaction + * with the class driver instance (until a new instance is received + * from the create() method). + * The driver should not called the class' disconnected() method. + * + * Input Parameters: + * drvr - The USB host driver instance obtained as a parameter from the + * call to the class create() method. + * hport - The port from which the device is being disconnected. + * Might be a port on a hub. + * + * Returned Value: + * None + * + * Assumptions: + * - Only a single class bound to a single device is supported. + * - Never called from an interrupt handler. + * + ****************************************************************************/ + +static void rx65n_usbhost_disconnect(struct usbhost_driver_s *drvr, + struct usbhost_hubport_s *hport) +{ + int i; + struct rx65n_usbhost_s *priv = &g_usbhost; + uint16_t pipe; + + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + uint8_t *buffer; + DEBUGASSERT(hport != NULL); + + if (hport->port) + { + if (hport->speed == USB_SPEED_LOW) + { + g_usb_pipe_table[kbd_interrupt_in_pipe].use_flag = USB_FALSE; + + for (i = 0, xfrinfo = g_xfrbuffers; + i < CONFIG_RX65N_USBHOST_NPREALLOC; + i++, xfrinfo++) + { + /* Put the transfer structure in a free list */ +#ifdef CONFIG_USBHOST_ASYNCH + if (!(xfrinfo->callback)) +#endif + { + rx65n_usbhost_free_xfrinfo(xfrinfo); + g_rx65n_edlist[kbd_interrupt_in_pipe].xfrinfo = NULL; + } + } + + g_kbdpipe = 0; + g_hubkbd = false; + syslog (LOG_INFO, "KBD Device Disconnected from Hub\n\r"); + } + + if (hport->speed == USB_SPEED_FULL) + { + for (pipe = USB_BULK_PIPE_START ; pipe <= USB_BULK_PIPE_END; + pipe++) + { + if (g_usb_pipe_table[pipe].use_flag == USB_TRUE) + { + g_usb_pipe_table[pipe].use_flag = USB_FALSE; + } + } + + syslog (LOG_INFO, "MSC Device Disconnected from Hub\n\r"); + } + } + + else if (!hport->port) + { + if (g_usbhost.rhport.hport.speed == USB_SPEED_LOW) + { + g_usb_pipe_table[kbd_interrupt_in_pipe].use_flag = USB_FALSE; + for (i = 0, xfrinfo = g_xfrbuffers; + i < CONFIG_RX65N_USBHOST_NPREALLOC; + i++, xfrinfo++) + { + /* Put the transfer structure in a free list */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + g_rx65n_edlist[kbd_interrupt_in_pipe].xfrinfo = NULL; + } + } + + if (g_usbhost.rhport.hport.speed == USB_SPEED_FULL) + { + if (g_hubkbd) + { + /* If Keyboard device is connected, and the USB Hub disconnect + * task is invoked, then make the Hub task sleep, + * so that in this time the keyboard task completes + * its disconnection event. + * + */ + + nxsig_usleep(100000); + } + + for (i = 0; i < CONFIG_RX65N_USBHOST_NEDS; i++) + { + /* Put the ED in a free list */ + + rx65n_usbhost_edfree(&g_rx65n_edlist[i]); + } + + /* Initialize user-configurable TDs */ + + for (i = 0; i < CONFIG_RX65N_USBHOST_NTDS; i++) + { + /* Put the TD in a free list */ + + rx65n_usbhost_tdfree(&g_rx65n_tdlist[i]); + } + + /* Initialize user-configurable request/descriptor transfer + * buffers + */ + + buffer = g_tdbuffer; + + for (i = 0; i < CONFIG_RX65N_USBHOST_TDBUFFERS; i++) + { + /* Put the TD buffer in a free list */ + + rx65n_usbhost_tbfree(buffer); + buffer += CONFIG_RX65N_USBHOST_TDBUFSIZE; + } + + /* Initialize transfer structures */ + + for (i = 0, xfrinfo = g_xfrbuffers; + i < CONFIG_RX65N_USBHOST_NPREALLOC; + i++, xfrinfo++) + { + /* Put the transfer structure in a free list */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + } + + /* Wait 50MS then perform hardware reset */ + + up_mdelay(50); + + /* Set up the root hub port EP0 */ + + rx65n_usbhost_ep0init(priv); + + /* To begin with make all pipes are available */ + + for (i = USB_MIN_PIPE_NUM; i < (USB_MAX_PIPE_NUM +1); i++) + { + g_usb_pipe_table[i].use_flag = USB_FALSE; + } + } + } + + hport->devclass = NULL; +} + +/**************************************************************************** + * Initialization + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_usbhost_ep0init + * + * Description: + * Initialize ED for EP0, add it to the control ED list, and enable + * control transfers. + * + * Input Parameters: + * priv - private driver state instance. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static inline void rx65n_usbhost_ep0init(struct rx65n_usbhost_s *priv) +{ + /* Initialize the common tail TD. */ + + memset(TDTAIL, 0, sizeof(struct rx65n_usbhost_gtd_s)); + TDTAIL->ed = EDCTRL; + + /* Link the common tail TD to the ED's TD list */ + + memset(EDCTRL, 0, sizeof(struct rx65n_usbhost_ed_s)); + EDCTRL->hw.headp = (uint32_t)TDTAIL; + EDCTRL->hw.tailp = (uint32_t)TDTAIL; + EDCTRL->xfrtype = USB_EP_ATTR_XFER_CONTROL; + + /* Set the head of the control list to the NULL (for now). */ + + /* Then add EP0 to the empty Control List */ + + rx65n_usbhost_addctrled(priv, EDCTRL); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rx65n_usbhost_initialize + * + * Description: + * Initialize USB host device controller hardware. + * + * Input Parameters: + * controller -- If the device supports more than USB host controller, then + * this identifies which controller is being initialized. Normally, this + * is just zero. + * + * Returned Value: + * And instance of the USB host interface. The controlling task should + * use this interface to (1) call the wait() method to wait for a device + * to be connected, and (2) call the enumerate() method to bind the + * device to a class driver. + * + * Assumptions: + * - This function should called in the initialization sequence in order + * to initialize the USB device functionality. + * - Class drivers should be initialized prior to calling this function. + * Otherwise, there is a race condition if the device is already . + * connected + ****************************************************************************/ + +struct usbhost_connection_s *rx65n_usbhost_initialize(int controller) +{ + struct rx65n_usbhost_s *priv = &g_usbhost; + struct usbhost_driver_s *drvr; + struct usbhost_hubport_s *hport; + struct rx65n_usbhost_xfrinfo_s *xfrinfo; + uint32_t reg32; + uint8_t *buffer; + irqstate_t flags; + int i; + + DEBUGASSERT(controller == 0); + DEBUGASSERT(sizeof(struct rx65n_ed_s) <= RX65N_ED_SIZE); + DEBUGASSERT(sizeof(struct rx65n_usbhost_gtd_s) <= RX65N_TD_SIZE); + + /* Initialize all the TDs, EDs (including EDCTRL i.e. + * Control Endpoint) and HCCA to 0 + */ + + /* Set HCCA base address */ + + HCCA = &g_hcca; + + /* Set TD TAIL address */ + + TDTAIL = &g_rx65n_tdlist[0]; + + /* Set ED Tail address as well... */ + + /* EDCTRL = &g_rx65n_ep0ed; */ + + /* Set first element as CTRL pipe - as there is always + * only one CTRL pipe + */ + + EDCTRL = &g_rx65n_edlist[0]; + + memset((void *)TDTAIL, 0, + ((sizeof(struct ohci_gtd_s)) * (CONFIG_RX65N_USBHOST_NTDS))); + memset((void *)(&g_rx65n_edlist[0]), 0, + ((sizeof(struct rx65n_usbhost_ed_s)) * + (CONFIG_RX65N_USBHOST_NEDS))); + memset((void *)EDCTRL, 0, sizeof(struct rx65n_usbhost_ed_s)); + memset((void *)HCCA, 0, sizeof(struct ohci_hcca_s)); + + /* Initialize the state data structure */ + + /* Initialize the device operations */ + + drvr = &priv->drvr; + drvr->ep0configure = rx65n_usbhost_ep0configure; + drvr->epalloc = rx65n_usbhost_epalloc; + drvr->epfree = rx65n_usbhost_epfree; + drvr->alloc = rx65n_usbhost_alloc; + drvr->free = rx65n_usbhost_free; + drvr->ioalloc = rx65n_usbhost_ioalloc; + drvr->iofree = rx65n_usbhost_iofree; + drvr->ctrlin = rx65n_usbhost_ctrlin; + drvr->ctrlout = rx65n_usbhost_ctrlout; + drvr->transfer = rx65n_usbhost_transfer; +#ifdef CONFIG_USBHOST_ASYNCH + drvr->asynch = rx65n_usbhost_asynch; +#endif + drvr->cancel = rx65n_usbhost_cancel; +#ifdef CONFIG_USBHOST_HUB + drvr->connect = rx65n_usbhost_connect; +#endif + drvr->disconnect = rx65n_usbhost_disconnect; + + /* Initialize the public port representation */ + + hport = &priv->rhport.hport; + hport->drvr = drvr; +#ifdef CONFIG_USBHOST_HUB + hport->parent = NULL; +#endif + hport->ep0 = EDCTRL; + hport->speed = USB_SPEED_FULL; + hport->funcaddr = 0; + + /* Initialize function address generation logic */ + + usbhost_devaddr_initialize(&priv->rhport); + + /* Initialize semaphores */ + + nxsem_init(&priv->pscsem, 0, 0); + nxsem_init(&priv->exclsem, 0, 1); + + /* The pscsem semaphore is used for signaling and, hence, should not have + * priority inheritance enabled. + */ + + nxsem_set_protocol(&priv->pscsem, SEM_PRIO_NONE); + +#ifndef CONFIG_USBHOST_INT_DISABLE + priv->ininterval = MAX_PERINTERVAL; + priv->outinterval = MAX_PERINTERVAL; +#endif + + /* Enable write to System registers */ + + putreg16(RX65N_PRCR_VALUE, RX65N_PRCR_ADDR); + + /* Start CMT module */ + + reg32 = getreg32(RX65N_MSTPCRB_ADDR); + + /* Clear bit 19 - so that USB module is released from stop state */ + + reg32 &= (~RX65N_MSTPCRB_START_STOP_USB); + putreg32(reg32, RX65N_MSTPCRB_ADDR); + + reg32 = getreg32(RX65N_MSTPCRB_ADDR); + + /* Enable power by setting PCUSB in the PCONP register. + * Disable interrupts because this register may be shared with other + * drivers. + */ + + flags = enter_critical_section(); + putreg32(0, RX65N_USB_DPUSR0R); /* FIT code writes 0 to this DPUSR0R */ + + hw_usb_hmodule_init(); + rx65n_usbhost_setbit (RX65N_USB_SOFCFG, RX65N_USB_SOFCFG_TRNENSEL); + + hw_usb_set_vbout (); + up_mdelay(100); + + leave_critical_section(flags); + + /* The EDCTRL wdhsem semaphore is used for signaling and, hence, should + * not have priority inheritance enabled. + */ + + nxsem_init(&EDCTRL->wdhsem, 0, 0); + nxsem_set_protocol(&EDCTRL->wdhsem, SEM_PRIO_NONE); + + /* Initialize user-configurable EDs */ + + for (i = 0; i < CONFIG_RX65N_USBHOST_NEDS; i++) + { + /* Put the ED in a free list */ + + rx65n_usbhost_edfree(&g_rx65n_edlist[i]); + } + + /* Initialize user-configurable TDs */ + + for (i = 0; i < CONFIG_RX65N_USBHOST_NTDS; i++) + { + /* Put the TD in a free list */ + + rx65n_usbhost_tdfree(&g_rx65n_tdlist[i]); + } + + /* Initialize user-configurable request/descriptor transfer + * buffers + */ + + buffer = g_tdbuffer; + + for (i = 0; i < CONFIG_RX65N_USBHOST_TDBUFFERS; i++) + { + /* Put the TD buffer in a free list */ + + rx65n_usbhost_tbfree(buffer); + buffer += CONFIG_RX65N_USBHOST_TDBUFSIZE; + } + +#if RX65N_USBHOST_IOBUFFERS > 0 + /* Initialize user-configurable IO buffers */ + + buffer = (uint8_t *)RX65N_USBHOST_IOFREE_BASE; + for (i = 0; i < RX65N_USBHOST_IOBUFFERS; i++) + { + /* Put the IO buffer in a free list */ + + rx65n_usbhhost_freeio(buffer); + buffer += CONFIG_RX65N_USBHOST_IOBUFSIZE; + } +#endif + + /* Initialize transfer structures */ + + for (i = 0, xfrinfo = g_xfrbuffers; + i < CONFIG_RX65N_USBHOST_NPREALLOC; + i++, xfrinfo++) + { + /* Put the transfer structure in a free list */ + + rx65n_usbhost_free_xfrinfo(xfrinfo); + } + + /* Wait 50MS then perform hardware reset */ + + up_mdelay(50); + + /* Set up the root hub port EP0 */ + + rx65n_usbhost_ep0init(priv); + + /* To begin with make all pipes are available */ + + for (i = USB_MIN_PIPE_NUM; i < (USB_MAX_PIPE_NUM +1); i++) + { + g_usb_pipe_table[i].use_flag = USB_FALSE; + } + + /* Attach USB host controller interrupt handler */ + + ICU.SLIBR185.BYTE = 0x3eu; + IPR(PERIB, INTB185) = _0F_CMTW_PRIORITY_LEVEL15; + + if (irq_attach(RX65N_INTB185_IRQ, rx65n_usbhost_usbinterrupt, + NULL) != 0) + { + syslog (LOG_INFO, "ERROR: Failed to attach IRQ\n"); + return NULL; + } + + IEN(PERIB, INTB185) = 1U; + + syslog (LOG_INFO, "Debug:USB host Initialized, Device connected:%s\n\r", + priv->connected ? "YES" : "NO"); + + return &g_usbconn; +} diff --git a/arch/renesas/src/rx65n/rx65n_usbhost.h b/arch/renesas/src/rx65n/rx65n_usbhost.h new file mode 100644 index 0000000000..58952692d2 --- /dev/null +++ b/arch/renesas/src/rx65n/rx65n_usbhost.h @@ -0,0 +1,248 @@ +/**************************************************************************** + * arch/renesas/src/rx65n/rx65n/rx65n_usbhost.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. + * + ****************************************************************************/ + +#ifndef __ARCH_RENESAS_SRC_RX65N_USBHOST_H +#define __ARCH_RENESAS_SRC_RX65N_USBHOST_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include "rx65n_definitions.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Default, no-OHCI Case ****************************************************/ + +#define RX65N_USBHOST_HAVE_BANK 0x20004000 +#define RX65N_USBHOST_MEMORYBASE 0x20004000 +#define RX65N_USBHOST_MEMORYSIZE 0x4000 +#undef RX65N_USBHOST_HEAPBASE +#undef RX65N_USBHOST_HEAPSIZE + +#ifdef RX65N_USBHOST_HAVE_BANK +# define RX65N_USBHOST_HEAPBASE RX65N_USBHOST_MEMORYBASE +# define RX65N_USBHOST_HEAPSIZE RX65N_USBHOST_MEMORYSIZE +#endif + +#if defined(CONFIG_USBHOST) && defined(RX65N_NUSBHOST) > 0 + +/* OHCI RAM Configuration ***************************************************/ + +#ifndef RX65N_USBHOST_HAVE_BANK +# error "Phani needs to look into this AHB SRAM Bank1 is not available for OHCI RAM" +#endif + +/* OHCI/Heap Memory Allocation **********************************************/ + +/* Configured Size of the region at the end of AHB SRAM BANK1 set set aside + * for the OHCI. This size must fit within AHB SRAM Bank 1 and also be a + * multiple of 256 bytes. + */ + +#ifndef CONFIG_RX65N_USBHOST_RAM_SIZE +# define CONFIG_RX65N_USBHOST_RAM_SIZE RX65N_USBHOST_MEMORYSIZE +#endif + +#if CONFIG_RX65N_USBHOST_RAM_SIZE > RX65N_USBHOST_HEAPBASE +# error "USB Host RAM size cannot exceed the size of AHB SRAM Bank 1" +#endif + +#if (CONFIG_RX65N_USBHOST_RAM_SIZE & 0xff) != 0 +# error "RX65N RAM size must be in multiples of 256 bytes" +#endif + +#define RX65N_USBHOST_RAM_END (RX65N_USBHOST_HAVE_BANK + RX65N_USBHOST_MEMORYBASE) + +/* Numbers and Sizes of Things **********************************************/ + +/* Fixed size of the OHCI control area */ + +#define RX65N_USBHOST_HCCA_SIZE 256 + +/* Fixed endpoint descriptor size. The actual size required by the hardware + * is only 16 bytes, however, we set aside an additional 16 bytes for for + * internal use by the OHCI host driver. 16-bytes is set aside because the + * EDs must still be aligned to 16-byte boundaries. + */ + +#define RX65N_USBHOST_ED_SIZE 32 + +/* Configurable number of user endpoint descriptors (EDs). This number + * excludes the control endpoint that is always allocated. + */ + +#ifndef CONFIG_RX65N_USBHOST_NEDS +# define CONFIG_RX65N_USBHOST_NEDS 9 + +#endif + +/* Derived size of user endpoint descriptor (ED) memory. */ + +#define RX65N_USBHOST_EDFREE_SIZE (CONFIG_RX65N_USBHOST_NEDS * RX65N_USBHOST_ED_SIZE) + +/* Fixed transfer descriptor size. The actual size required by the hardware + * is only 16 bytes, however, we set aside an additional 16 bytes for for + * internal use by the OHCI host driver. 16-bytes is set aside because the + * TDs must still be aligned to 16-byte boundaries. + */ + +#define RX65N_USBHOST_TD_SIZE 32 + +/* Configurable number of user transfer descriptors (TDs). */ + +#ifndef CONFIG_RX65N_USBHOST_NTDS +# define CONFIG_RX65N_USBHOST_NTDS 10 +#endif + +#if CONFIG_RX65N_USBHOST_NTDS < 2 +# error "Insufficent TDs" +#endif + +/* Derived size of user transfer descriptor (TD) memory. */ + +#define RX65N_USBHOST_TDFREE_SIZE (CONFIG_RX65N_USBHOST_NTDS * RX65N_USBHOST_TD_SIZE) + +/* Configurable number of request/descriptor buffers (TDBUFFER) */ + +#ifndef CONFIG_RX65N_USBHOST_TDBUFFERS + +# define CONFIG_RX65N_USBHOST_TDBUFFERS 10 + +#endif + +#if CONFIG_RX65N_USBHOST_TDBUFFERS < 2 + +# error "At least two TD buffers are required" +#endif + +/* Configurable size of a TD buffer */ + +#if CONFIG_RX65N_USBHOST_TDBUFFERS > 0 && !defined(CONFIG_RX65N_USBHOST_TDBUFSIZE) +# define CONFIG_RX65N_USBHOST_TDBUFSIZE 128 + +#endif + +#if (CONFIG_RX65N_USBHOST_TDBUFSIZE & 3) != 0 +# error "TD buffer size must be an even number of 32-bit words" +#endif + +#define RX65N_USBHOST_TBFREE_SIZE (CONFIG_RX65N_USBHOST_TDBUFFERS * CONFIG_RX65N_USBHOST_TDBUFSIZE) + +/* Configurable size of an IO buffer. The number of IO buffers will be + * determined by what is left at the end of the BANK1 memory setup aside + * of OHCI RAM. + */ + +#ifndef CONFIG_RX65N_USBHOST_IOBUFSIZE +# define CONFIG_RX65N_USBHOST_IOBUFSIZE 512 +#endif + +#if (CONFIG_RX65N_USBHOST_IOBUFSIZE & 3) != 0 +# error "IO buffer size must be an even number of 32-bit words" +#endif + +#define RX65N_USBHOST_HCCA_BASE 1 + +#define RX65N_USBHOST_TDTAIL_ADDR 2 + +#define RX65N_USBHOST_EDCTRL_ADDR 3 + +#define RX65N_USBHOST_EDFREE_BASE 4 + +#define RX65N_USBHOST_TDFREE_BASE 5 + +#define RX65N_USBHOST_TBFREE_BASE 6 + +#define RX65N_USBHOST_IOFREE_BASE 7 + +/* Finally, use the remainder of the allocated OHCI for IO buffers */ + +#if CONFIG_RX65N_USBHOST_IOBUFSIZE > 0 +# define RX65N_USBHOST_IOBUFFERS 0 +#else +# define RX65N_USBHOST_IOBUFFERS 0 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: rx65n_usbhost_initialize + * + * Description: + * Initialize USB host device controller hardware. + * + * Input Parameters: + * controller -- If the device supports more than USB host controller, then + * this identifies which controller is being initialized. Normally, this + * is just zero. + * + * Returned Value: + * And instance of the USB host interface. The controlling task should + * use this interface to (1) call the wait() method to wait for a device + * to be connected, and (2) call the enumerate() method to bind the device + * to a class driver. + * + * Assumptions: + * - This function should called in the initialization sequence in order + * to initialize the USB device functionality. + * - Class drivers should be initialized prior to calling this function. + * Otherwise, there is a race condition if the device is already connected. + * + ****************************************************************************/ + +#ifdef CONFIG_USBHOST +struct usbhost_connection_s; +FAR struct usbhost_connection_s *rx65n_usbhost_initialize(int controller); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* #if defined(CONFIG_USBHOST) && defined(RX65N_NUSBHOST) > 0 */ +#endif /* __ARCH_RENESAS_SRC_RX65N_USBHOST_H */ diff --git a/boards/renesas/rx65n/rx65n-grrose/README.txt b/boards/renesas/rx65n/rx65n-grrose/README.txt index 6ef8a25377..6d700591a8 100644 --- a/boards/renesas/rx65n/rx65n-grrose/README.txt +++ b/boards/renesas/rx65n/rx65n-grrose/README.txt @@ -17,7 +17,8 @@ Contents - RSPI - RIIC - DTC - - Debugging + - USB Host + - USB Host Hub - Debugging Board Features @@ -225,6 +226,20 @@ RSPI For GRROSE board only channel 1 can be tested since RSPI channel1 pinout is only brought out as Pin number 2 and 3 in CN4 is used for MOSIB and MISOB respectively. +USB Host +============= +For the RX65N RSK2MB board, to be used as USB Device, the following Jumper settings need to be done + +J7 Short Pin 1 & Pin 2 +J16 Short Pin 2 & Pin 3 + +USB Device +============= +For the RX65N RSK2MB board, to be used as USB Device, the following Jumper settings need to be done + +J7 Short Pin 2 & Pin 3 +J16 Short Pin 1 & Pin 2 + RTC ========== @@ -299,6 +314,76 @@ DTC Testing DTC has been tested using RSPI driver. +USB Host Configurations +-------------------------- +The following configurations need to be enabled for USB Host Mode driver to +support USB HID Keyboard class and MSC Class. + +CONFIG_USBHOST=y +CONFIG_USBHOST_HIDKBD=y +CONFIG_FS_FAT=y +CONFIG_EXAMPLES_HIDKBD=y + +USB Host Driver Testing +------------------------ +The Following Class Drivers were tested as mentioned below : + +- USB HID Keyboard Class +On the NuttX Console "hidkbd" application was executed + +nsh> hidkbd +The characters typed from the keyboard were executed correctly. + +- USB MSC Class + +The MSC device is enumerated as sda in /dev directory. + +The block device is mounted using the command as mentioned below : + +mount -t vfat /dev/sda /mnt + +The MSC device is mounted in /dev directory + +The copy command is executed to test the Read/Write functionality + +cp /mnt/ /mnt/file_copy.txt + +USB Host Hub Configurations +-------------------------- +The following configurations need to be enabled for USB Host Mode driver to +support USB HID Keyboard class and MSC Class. + +CONFIG_RX65N_USBHOST=y +CONFIG_USBHOST_HUB=y +CONFIG_USBHOST_ASYNCH=y +CONFIG_USBHOST=y +CONFIG_USBHOST_HIDKBD=y +CONFIG_FS_FAT=y +CONFIG_EXAMPLES_HIDKBD=y + +USB Host Hub Driver Testing +------------------------ +The Following Class Drivers were tested as mentioned below : + +- USB HID Keyboard Class +On the NuttX Console "hidkbd" application was executed + +nsh> hidkbd +The characters typed from the keyboard were executed correctly. + +- USB MSC Class +The MSC device is enumerated as sda in /dev directory. + +The block device is mounted using the command as mentioned below : + +mount -t vfat /dev/sda /mnt + +The MSC device is mounted in /dev directory + +The copy command is executed to test the Read/Write functionality + +cp /mnt/ /mnt/file_copy.txt + Debugging ========== diff --git a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c index ffe982c5f2..ff94fabeb6 100644 --- a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c +++ b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_bringup.c @@ -32,8 +32,12 @@ #include #include -#include +#include +#include +#include + +#include "rx65n_usbhost.h" #include "rx65n_grrose.h" #include #ifdef CONFIG_LIB_BOARDCTL @@ -60,6 +64,165 @@ # include # include "rx65n_riic.h" #endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#define NSH_HAVE_USBHOST 1 + +/* USB Host */ + +#ifndef CONFIG_USBHOST +# undef NSH_HAVE_USBHOST +#endif + +#ifdef NSH_HAVE_USBHOST +# ifndef CONFIG_USBHOST_DEFPRIO +# define CONFIG_USBHOST_DEFPRIO 100 +# endif +# ifndef CONFIG_USBHOST_STACKSIZE +# ifdef CONFIG_USBHOST_HUB +# define CONFIG_USBHOST_STACKSIZE 1536 +# else +# define CONFIG_USBHOST_STACKSIZE 1024 +# endif +# endif +#endif + +#ifdef NSH_HAVE_USBHOST +static struct usbhost_connection_s *g_usbconn; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +#ifdef NSH_HAVE_USBHOST +static int nsh_waiter(int argc, char *argv[]) +{ + struct usbhost_hubport_s *hport; + + syslog(LOG_INFO, "nsh_waiter: Running\n\r"); + for (; ; ) + { + /* Wait for the device to change state */ + + DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport)); + syslog(LOG_INFO, "nsh_waiter: %s\n\r", + hport->connected ? "Host:connected" : "Host:disconnected"); + + /* Did we just become connected? */ + + if (hport->connected && hport->port == 0) + { + /* Yes.. enumerate the newly connected device */ + + (void)CONN_ENUMERATE(g_usbconn, hport); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} +#endif + +/**************************************************************************** + * Name: nsh_usbhostinitialize + * + * Description: + * Initialize SPI-based microSD. + * + ****************************************************************************/ + +#ifdef NSH_HAVE_USBHOST +static int nsh_usbhostinitialize(void) +{ + int pid; + int ret; + + /* First, register all of the class drivers needed to support the drivers + * that we care about: + */ + + syslog(LOG_INFO, "Register class drivers\n\r"); + +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub class support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + uerr("ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_MSC + /* Register the USB host Mass Storage Class */ + + ret = usbhost_msc_initialize(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the mass storage class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_CDCACM + /* Register the CDC/ACM serial class */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the KBD class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_HIDKBD + /* Register the HID KBD class */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the CDC/ACM serial class: %d\n", ret); + } +#endif + + /* Then get an instance of the USB host interface */ + + g_usbconn = rx65n_usbhost_initialize(0); + if (g_usbconn) + { + /* Start a thread to handle device connection. */ + + syslog(LOG_INFO, "Start nsh_waiter\n\r"); + + pid = kthread_create("usbhost", CONFIG_USBHOST_DEFPRIO, + CONFIG_USBHOST_STACKSIZE, + (main_t)nsh_waiter, (FAR char * const *)NULL); + syslog(LOG_INFO, "USBHost: Created pid = %d\n\r", pid); + return pid < 0 ? -ENOEXEC : OK; + } + + return -ENODEV; +} +#else +# define nsh_usbhostinitialize() (OK) +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -230,6 +393,10 @@ int rx65n_bringup(void) (void)rx65n_dtc_initialize(); #endif +#if defined(CONFIG_USBHOST) + ret = nsh_usbhostinitialize(); +#endif + #ifdef CONFIG_RX65N_RSPI (void)rx65n_rspi_initialize(); #endif diff --git a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c index 6588df83dd..60a373075f 100644 --- a/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c +++ b/boards/renesas/rx65n/rx65n-grrose/src/rx65n_gpio.c @@ -178,6 +178,26 @@ void r_usbdev_port_enable(void) } #endif +/**************************************************************************** + * Name: r_usb_port_enable + * + * Description: + * USB Enabling for RX65N RSK2MB + ****************************************************************************/ + +#if defined(CONFIG_USBHOST) +void r_usb_port_enable(void) +{ + /* Set VBUS pin for USB */ + + MPC.P16PFS.BYTE = 0x11u; + + /* PORT1.PMR.BYTE |= 0x40; */ + + PORT1.PMR.BIT.B6 = 1u; +} +#endif + /**************************************************************************** * Name: sci0_init_port * diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/README.txt b/boards/renesas/rx65n/rx65n-rsk2mb/README.txt index b6af98c474..74ff236e55 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/README.txt +++ b/boards/renesas/rx65n/rx65n-rsk2mb/README.txt @@ -16,6 +16,8 @@ Contents - RSPI - RIIC - DTC + - USB Host + - USB Host Hub - Debugging Board Features @@ -193,6 +195,20 @@ Channel1: Pin number 35 and 36 in JA3 is used for MOSIB and MISOB respectively Channel2: Pin number 18 and 19 in JA3 is used for MOSIC and MISOC respectively and for enabling these pin need to select DSW-SEL0 by making off SW4-4 +USB Host +============= +For the RX65N RSK2MB board, to be used as USB Device, the following Jumper settings need to be done + +J7 Short Pin 1 & Pin 2 +J16 Short Pin 2 & Pin 3 + +USB Device +============= +For the RX65N RSK2MB board, to be used as USB Device, the following Jumper settings need to be done + +J7 Short Pin 2 & Pin 3 +J16 Short Pin 1 & Pin 2 + RTC ========== @@ -272,6 +288,76 @@ DTC Testing DTC has been tested using RSPI driver. +USB Host Configurations +-------------------------- +The following configurations need to be enabled for USB Host Mode driver to +support USB HID Keyboard class and MSC Class. + +CONFIG_USBHOST=y +CONFIG_USBHOST_HIDKBD=y +CONFIG_FS_FAT=y +CONFIG_EXAMPLES_HIDKBD=y + +USB Host Driver Testing +------------------------ +The Following Class Drivers were tested as mentioned below : + +- USB HID Keyboard Class +On the NuttX Console "hidkbd" application was executed + +nsh> hidkbd +The characters typed from the keyboard were executed correctly. + +- USB MSC Class + +The MSC device is enumerated as sda in /dev directory. + +The block device is mounted using the command as mentioned below : + +mount -t vfat /dev/sda /mnt + +The MSC device is mounted in /dev directory + +The copy command is executed to test the Read/Write functionality + +cp /mnt/ /mnt/file_copy.txt + +USB Host Hub Configurations +-------------------------- +The following configurations need to be enabled for USB Host Mode driver to +support USB HID Keyboard class and MSC Class. + +CONFIG_RX65N_USBHOST=y +CONFIG_USBHOST_HUB=y +CONFIG_USBHOST_ASYNCH=y +CONFIG_USBHOST=y +CONFIG_USBHOST_HIDKBD=y +CONFIG_FS_FAT=y +CONFIG_EXAMPLES_HIDKBD=y + +USB Host Hub Driver Testing +------------------------ +The Following Class Drivers were tested as mentioned below : + +- USB HID Keyboard Class +On the NuttX Console "hidkbd" application was executed + +nsh> hidkbd +The characters typed from the keyboard were executed correctly. + +- USB MSC Class +The MSC device is enumerated as sda in /dev directory. + +The block device is mounted using the command as mentioned below : + +mount -t vfat /dev/sda /mnt + +The MSC device is mounted in /dev directory + +The copy command is executed to test the Read/Write functionality + +cp /mnt/ /mnt/file_copy.txt + Debugging ========== 1. NuttX needs to be compiled in Cygwin environment on Windows. diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c index 0790b9b972..7e5fee5301 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c +++ b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_bringup.c @@ -32,8 +32,11 @@ #include #include +#include #include +#include +#include "rx65n_usbhost.h" #include "rx65n_rsk2mb.h" #include #ifdef CONFIG_LIB_BOARDCTL @@ -60,10 +63,165 @@ # include # include "rx65n_riic.h" #endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#define NSH_HAVE_USBHOST 1 + +/* USB Host */ + +#ifndef CONFIG_USBHOST +# undef NSH_HAVE_USBHOST +#endif + +#ifdef NSH_HAVE_USBHOST +# ifndef CONFIG_USBHOST_DEFPRIO +# define CONFIG_USBHOST_DEFPRIO 100 +# endif +# ifndef CONFIG_USBHOST_STACKSIZE +# ifdef CONFIG_USBHOST_HUB +# define CONFIG_USBHOST_STACKSIZE 1536 +# else +# define CONFIG_USBHOST_STACKSIZE 1024 +# endif +# endif +#endif + +#ifdef NSH_HAVE_USBHOST +static struct usbhost_connection_s *g_usbconn; +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_waiter + * + * Description: + * Wait for USB devices to be connected. + * + ****************************************************************************/ + +#ifdef NSH_HAVE_USBHOST +static int nsh_waiter(int argc, char *argv[]) +{ + struct usbhost_hubport_s *hport; + + syslog(LOG_INFO, "nsh_waiter: Running\n\r"); + for (; ; ) + { + /* Wait for the device to change state */ + + DEBUGVERIFY(CONN_WAIT(g_usbconn, &hport)); + + /* Did we just become connected? */ + + if (hport->connected && hport->port == 0) + { + /* Yes.. enumerate the newly connected device */ + + (void)CONN_ENUMERATE(g_usbconn, hport); + } + } + + /* Keep the compiler from complaining */ + + return 0; +} +#endif + +/**************************************************************************** + * Name: nsh_usbhostinitialize + * + * Description: + * Initialize SPI-based microSD. + * + ****************************************************************************/ + +#ifdef NSH_HAVE_USBHOST +static int nsh_usbhostinitialize(void) +{ + int pid; + int ret; + + /* First, register all of the class drivers needed to support the drivers + * that we care about: + */ + + syslog(LOG_INFO, "Register class drivers\n\r"); + +#ifdef CONFIG_USBHOST_MSC + /* Register the USB host Mass Storage Class */ + + printf ("USB Host MSC\n\r"); + ret = usbhost_msc_initialize(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the mass storage class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_CDCACM + /* Register the CDC/ACM serial class */ + + printf ("USB Host CDCACM \n\r"); + ret = usbhost_kbdinit(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the KBD class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_HIDKBD + /* Register the HID KBD class */ + + ret = usbhost_kbdinit(); + if (ret != OK) + { + syslog(LOG_ERR, + "ERROR: Failed to register the CDC/ACM serial class: %d\n", ret); + } +#endif + +#ifdef CONFIG_USBHOST_HUB + /* Initialize USB hub class support */ + + ret = usbhost_hub_initialize(); + if (ret < 0) + { + uerr("ERROR: usbhost_hub_initialize failed: %d\n", ret); + } +#endif + + /* Then get an instance of the USB host interface */ + + g_usbconn = rx65n_usbhost_initialize(0); + if (g_usbconn) + { + /* Start a thread to handle device connection. */ + + syslog(LOG_INFO, "Start nsh_waiter\n\r"); + + pid = kthread_create("usbhost", CONFIG_USBHOST_DEFPRIO, + CONFIG_USBHOST_STACKSIZE, + (main_t)nsh_waiter, (FAR char * const *)NULL); + syslog(LOG_INFO, "USBHost: Created pid = %d\n\r", pid); + return pid < 0 ? -ENOEXEC : OK; + } + + return -ENODEV; +} +#else +# define nsh_usbhostinitialize() (OK) +#endif + /**************************************************************************** * Name: rx65n_rspi_initialize * @@ -234,6 +392,11 @@ int rx65n_bringup(void) (void)rx65n_rspi_initialize(); #endif +#if defined(CONFIG_USBHOST) + ret = nsh_usbhostinitialize(); + printf ("USB Initialization done!!! with return value = %d\n\r", ret); +#endif + #if defined(CONFIG_CDCACM) && !defined(CONFIG_CDCACM_CONSOLE) /* Initialize CDCACM */ diff --git a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c index ca440b3651..bd374102e5 100644 --- a/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c +++ b/boards/renesas/rx65n/rx65n-rsk2mb/src/rx65n_gpio.c @@ -216,6 +216,33 @@ void r_usbdev_port_enable(void) } #endif +/**************************************************************************** + * Name: r_usb_port_enable + * + * Description: + * USB Enabling for RX65N RSK2MB + ****************************************************************************/ + +#if defined(CONFIG_ARCH_BOARD_RX65N_RSK2MB) +#if defined(CONFIG_USBHOST) +void r_usb_port_enable(void) +{ + /* Set VBUS pin for USB */ + + MPC.P16PFS.BYTE = 0x12u; + + /* PORT1.PMR.BYTE |= 0x40; */ + + PORT1.PMR.BIT.B6 = 1u; + + /* set USB0_OVRCURA pin */ + + MPC.P14PFS.BYTE = 0x12u; + PORT1.PMR.BIT.B4 = 1u; +} +#endif +#endif + /**************************************************************************** * Name: sci1_init_port *