diff options
Diffstat (limited to 'c/src/lib/libbsp/sparc/shared/tmtc/grtc.c')
-rw-r--r-- | c/src/lib/libbsp/sparc/shared/tmtc/grtc.c | 1998 |
1 files changed, 0 insertions, 1998 deletions
diff --git a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c b/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c deleted file mode 100644 index c01d7d8391..0000000000 --- a/c/src/lib/libbsp/sparc/shared/tmtc/grtc.c +++ /dev/null @@ -1,1998 +0,0 @@ -/* GRTC Telecommand decoder driver - * - * COPYRIGHT (c) 2007. - * Cobham Gaisler AB. - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include <bsp.h> -#include <rtems/libio.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <ctype.h> -#include <malloc.h> -#include <rtems/bspIo.h> - -#include <drvmgr/drvmgr.h> -#include <drvmgr/ambapp_bus.h> -#include <ambapp.h> -#include <bsp/grtc.h> - -/* map via rtems_interrupt_lock_* API: */ -#define SPIN_DECLARE(lock) RTEMS_INTERRUPT_LOCK_MEMBER(lock) -#define SPIN_INIT(lock, name) rtems_interrupt_lock_initialize(lock, name) -#define SPIN_LOCK(lock, level) rtems_interrupt_lock_acquire_isr(lock, &level) -#define SPIN_LOCK_IRQ(lock, level) rtems_interrupt_lock_acquire(lock, &level) -#define SPIN_UNLOCK(lock, level) rtems_interrupt_lock_release_isr(lock, &level) -#define SPIN_UNLOCK_IRQ(lock, level) rtems_interrupt_lock_release(lock, &level) -#define SPIN_IRQFLAGS(k) rtems_interrupt_lock_context k -#define SPIN_ISR_IRQFLAGS(k) SPIN_IRQFLAGS(k) - -/* turn on/off local CPU's interrupt to ensure HW timing - not SMP safe. */ -#define IRQ_LOCAL_DECLARE(_level) rtems_interrupt_level _level -#define IRQ_LOCAL_DISABLE(_level) rtems_interrupt_local_disable(_level) -#define IRQ_LOCAL_ENABLE(_level) rtems_interrupt_local_enable(_level) - -/* -#define DEBUG -#define DEBUGFUNCS -*/ - -#include <bsp/debug_defs.h> - -#ifdef DEBUG_ERROR -#define DEBUG_ERR_LOG(device,error) grtc_log_error(device,error) -#else -#define DEBUG_ERR_LOG(device,error) -#endif - -/* GRTC register map */ -struct grtc_regs { - volatile unsigned int grst; /* Global Reset Register (GRR 0x00) */ - volatile unsigned int gctrl; /* Global Control Register (GCR 0x04) */ - int unused0; - volatile unsigned int sir; /* Spacecraft Identifier Register (SIR 0x0c) */ - volatile unsigned int far; /* Frame Acceptance Report Register (FAR 0x10) */ - - volatile unsigned int clcw1; /* CLCW Register 1 (CLCWR1 0x14) */ - volatile unsigned int clcw2; /* CLCW Register 2 (CLCWR2 0x18) */ - volatile unsigned int phir; /* Physical Interface Register (PHIR 0x1c) */ - volatile unsigned int cor; /* Control Register (COR 0x20) */ - - volatile unsigned int str; /* Status Register (STR 0x24) */ - volatile unsigned int asr; /* Address Space Register (ASR 0x28) */ - volatile unsigned int rp; /* Receive Read Pointer Register (RRP 0x2c) */ - volatile unsigned int wp; /* Receive Write Pointer Register (RWP 0x30) */ - - int unused1[(0x60-0x34)/4]; - - volatile unsigned int pimsr; /* Pending Interrupt Masked Status Register (PIMSR 0x60) */ - volatile unsigned int pimr; /* Pending Interrupt Masked Register (PIMR 0x64) */ - volatile unsigned int pisr; /* Pending Interrupt Status Register (PISR 0x68) */ - volatile unsigned int pir; /* Pending Interrupt Register (PIR 0x6c) */ - volatile unsigned int imr; /* Interrupt Mask Register (IMR 0x70) */ - volatile unsigned int picr; /* Pending Interrupt Clear Register (PICR 0x74) */ -}; - -/* Security Byte */ -#define GRTC_SEB 0x55000000 - -/* Global Reset Register (GRR 0x00) */ -#define GRTC_GRR_SRST 0x1 -#define GRTC_GRR_SRST_BIT 0 - -/* Global Control Register (GCR 0x04) */ -#define GRTC_GCR_PSR_BIT 10 -#define GRTC_GCR_NRZM_BIT 11 -#define GRTC_GCR_PSS_BIT 12 - -#define GRTC_GCR_PSR (1<<GRTC_GCR_PSR_BIT) -#define GRTC_GCR_NRZM (1<<GRTC_GCR_NRZM_BIT) -#define GRTC_GCR_PSS (1<<GRTC_GCR_PSS_BIT) - -/* Spacecraft Identifier Register (SIR 0x0c) */ - - -/* Frame Acceptance Report Register (FAR 0x10) */ -#define GRTC_FAR_SCI_BIT 10 -#define GRTC_FAR_CSEC_BIT 11 -#define GRTC_FAR_CAC_BIT 12 -#define GRTC_FAR_SSD_BIT 13 - -#define GRTC_FAR_SCI (0x7<<GRTC_FAR_SCI_BIT) -#define GRTC_FAR_CSEC (0x7<<GRTC_FAR_CSEC_BIT) -#define GRTC_FAR_CAC (0x3f<<GRTC_FAR_CAC_BIT) -#define GRTC_FAR_SSD (1<<GRTC_FAR_SSD_BIT) - -/* CLCW Register 1 (CLCWR1 0x14) */ -/* CLCW Register 2 (CLCWR2 0x18) */ -#define GRTC_CLCW_RVAL_BIT 0 -#define GRTC_CLCW_RTYPE_BIT 8 -#define GRTC_CLCW_FBCO_BIT 9 -#define GRTC_CLCW_RTMI_BIT 11 -#define GRTC_CLCW_WAIT_BIT 12 -#define GRTC_CLCW_LOUT_BIT 13 -#define GRTC_CLCW_NBLO_BIT 14 -#define GRTC_CLCW_NRFA_BIT 15 -#define GRTC_CLCW_VCI_BIT 18 -#define GRTC_CLCW_CIE_BIT 24 -#define GRTC_CLCW_STAF_BIT 26 -#define GRTC_CLCW_VNUM_BIT 29 -#define GRTC_CLCW_CWTY_BIT 31 - -#define GRTC_CLCW_RVAL (0xff<<GRTC_CLCW_RVAL_BIT) -#define GRTC_CLCW_RTYPE (1<<GRTC_CLCW_RTYPE_BIT) -#define GRTC_CLCW_FBCO (0x3<<GRTC_CLCW_FBCO_BIT) -#define GRTC_CLCW_RTMI (0x3<<GRTC_CLCW_RTMI_BIT) -#define GRTC_CLCW_WAIT (1<<GRTC_CLCW_WAIT_BIT) -#define GRTC_CLCW_LOUT (1<<GRTC_CLCW_LOUT_BIT) -#define GRTC_CLCW_NBLO (1<<GRTC_CLCW_NBLO_BIT) -#define GRTC_CLCW_NRFA (1<<GRTC_CLCW_NRFA_BIT) -#define GRTC_CLCW_VCI (0x3f<<GRTC_CLCW_VCI_BIT) -#define GRTC_CLCW_CIE (0x3<<GRTC_CLCW_CIE_BIT) -#define GRTC_CLCW_STAF (0x3<<GRTC_CLCW_STAF_BIT) -#define GRTC_CLCW_VNUM (0x3<<GRTC_CLCW_VNUM_BIT) -#define GRTC_CLCW_CWTY (1<<GRTC_CLCW_CWTY_BIT) - -/* Physical Interface Register (PIR 0x1c) */ -#define GRTC_PIR_BLO_BIT 0 -#define GRTC_PIR_RFA_BIT 8 - -#define GRTC_PIR_BLO (0xff<<GRTC_PIR_BLO_BIT) -#define GRTC_PIR_RFA (0xff<<GRTC_PIR_RFA_BIT) - -/* Control Register (COR 0x20) */ -#define GRTC_COR_RE_BIT 0 -#define GRTC_COR_CRST_BIT 9 - -#define GRTC_COR_RE (1<<GRTC_COR_RE_BIT) -#define GRTC_COR_CRST (1<<GRTC_COR_CRST_BIT) - -/* Status Register (STR 0x24) */ -#define GRTC_STR_CR_BIT 0 -#define GRTC_STR_OV_BIT 4 -#define GRTC_STR_RFF_BIT 7 -#define GRTC_STR_RBF_BIT 10 - -#define GRTC_STR_CR (1<<GRTC_STR_CR_BIT) -#define GRTC_STR_OV (1<<GRTC_STR_OV_BIT) -#define GRTC_STR_RFF (1<<GRTC_STR_RFF_BIT) -#define GRTC_STR_RBF (1<<GRTC_STR_RBF_BIT) - -/* Address Space Register (ASR 0x28) */ -#define GRTC_ASR_RXLEN_BIT 0 -#define GRTC_ASR_BUFST_BIT 10 - -#define GRTC_ASR_RXLEN (0xff<<GRTC_ASR_RXLEN_BIT) -#define GRTC_ASR_BUFST (0x3fffff<<GRTC_ASR_BUFST_BIT) - -/* Receive Read Pointer Register (RRP 0x2c) */ -#define GRTC_RRP_PTR_BIT 0 - -#define GRTC_RRP_PTR (0xffffff<<GRTC_RRP_PTR_BIT) - -/* Receive Write Pointer Register (RWP 0x30) */ -#define GRTC_RWP_PTR_BIT 0 - -#define GRTC_RWP_PTR (0xffffff<<GRTC_RWP_PTR_BIT) - -/* Pending Interrupt Masked Status Register (PIMSR 0x60) */ -/* Pending Interrupt Masked Register (PIMR 0x64) */ -/* Pending Interrupt Status Register (PISR 0x68) */ -/* Pending Interrupt Register (PIR 0x6c) */ -/* Interrupt Mask Register (IMR 0x70) */ -/* Pending Interrupt Clear Register (PICR 0x74) */ -#define GRTC_INT_RFA_BIT 0 -#define GRTC_INT_BLO_BIT 1 -#define GRTC_INT_FAR_BIT 2 -#define GRTC_INT_CR_BIT 3 -#define GRTC_INT_RBF_BIT 4 -#define GRTC_INT_OV_BIT 5 -#define GRTC_INT_CS_BIT 6 - -#define GRTC_INT_RFA (1<<GRTC_INT_RFA_BIT) -#define GRTC_INT_BLO (1<<GRTC_INT_BLO_BIT) -#define GRTC_INT_FAR (1<<GRTC_INT_FAR_BIT) -#define GRTC_INT_CR (1<<GRTC_INT_CR_BIT) -#define GRTC_INT_OV (1<<GRTC_INT_OV_BIT) -#define GRTC_INT_CS (1<<GRTC_INT_CS_BIT) - -#define GRTC_INT_ALL (GRTC_INT_RFA|GRTC_INT_BLO|GRTC_INT_FAR|GRTC_INT_CR|GRTC_INT_OV|GRTC_INT_CS) - -#define READ_REG(address) (*(volatile unsigned int *)address) - -/* Driver functions */ -static rtems_device_driver grtc_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grtc_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); - -#define GRTC_DRIVER_TABLE_ENTRY { grtc_initialize, grtc_open, grtc_close, grtc_read, grtc_write, grtc_ioctl } - -static rtems_driver_address_table grtc_driver = GRTC_DRIVER_TABLE_ENTRY; - -enum { - FRM_STATE_NONE = 0, /* not started */ - FRM_STATE_HDR = 1, /* Reading Header (Frame length isn't known) */ - FRM_STATE_ALLOC = 2, /* Allocate Frame to hold data */ - FRM_STATE_PAYLOAD = 3, /* Reading Payload (Frame length is known) */ - FRM_STATE_FILLER = 4, /* Check filler */ - FRM_STATE_DROP = 5 /* error, drop data until end marker */ -}; - -/* Frame pool, all frames in pool have the same buffer length (frame mode only) */ -struct grtc_frame_pool { - unsigned int frame_len; /* Maximal length of frame (payload+hdr+crc..) */ - unsigned int frame_cnt; /* Current number of frames in pool (in frms) */ - struct grtc_frame *frms; /* Chain of frames in pool (this is the pool) */ -}; - -struct grtc_priv { - struct drvmgr_dev *dev; /* Driver manager device */ - char devName[32]; /* Device Name */ - struct grtc_regs *regs; /* TC Hardware Register MAP */ - int irq; /* IRQ number of TC core */ - SPIN_DECLARE(devlock); /* spin-lock of registers */ - - int major; /* Driver major */ - int minor; /* Device Minor */ - - int open; /* Device has been opened by user */ - int running; /* TC receiver running */ - int mode; /* RAW or FRAME mode */ - int overrun_condition; /* Overrun condition */ - int blocking; /* Blocking/polling mode */ - rtems_interval timeout; /* Timeout in blocking mode */ - int wait_for_nbytes;/* Number of bytes to wait for in blocking mode */ - - struct grtc_ioc_config config; - -/* RAW MODE ONLY */ - /* Buffer allocation (user provided or driver allocated using malloc) */ - void *buf; - void *buf_remote; - void *_buf; - int buf_custom; /* 0=no custom buffer, 1=custom buffer (don't free it...) */ - unsigned int len; - -/* FRAME MODE ONLY */ - /* Frame management when user provides buffers. */ - int pool_cnt; /* Number of Pools */ - struct grtc_frame_pool *pools; /* Array of pools */ - - struct grtc_list ready; /* Ready queue (received frames) */ - - /* Frame read data (Frame mode only) */ - int frame_state; - int filler; - unsigned int hdr[2]; /* 5 byte header */ - struct grtc_frame *frm; /* Frame currently beeing copied */ - int frmlen; - - struct grtc_ioc_stats stats; /* Statistics */ - - rtems_id sem_rx; - -#ifdef DEBUG_ERROR - /* Buffer read/write state */ - unsigned int rp; - unsigned int wp; - - /* Debugging */ - int last_error[128]; - int last_error_cnt; -#endif -}; - -/* Prototypes */ -static void grtc_hw_reset(struct grtc_priv *priv); -static void grtc_interrupt(void *arg); - -/* Common Global Variables */ -static rtems_id grtc_dev_sem; -static int grtc_driver_io_registered = 0; -static rtems_device_major_number grtc_driver_io_major = 0; - -/******************* Driver manager interface ***********************/ - -/* Driver prototypes */ -static int grtc_register_io(rtems_device_major_number *m); -static int grtc_device_init(struct grtc_priv *pDev); - -static int grtc_init2(struct drvmgr_dev *dev); -static int grtc_init3(struct drvmgr_dev *dev); - -static struct drvmgr_drv_ops grtc_ops = -{ - {NULL, grtc_init2, grtc_init3, NULL}, - NULL, - NULL, -}; - -static struct amba_dev_id grtc_ids[] = -{ - {VENDOR_GAISLER, GAISLER_GRTC}, - {0, 0} /* Mark end of table */ -}; - -static struct amba_drv_info grtc_drv_info = -{ - { - DRVMGR_OBJ_DRV, /* Driver */ - NULL, /* Next driver */ - NULL, /* Device list */ - DRIVER_AMBAPP_GAISLER_GRTC_ID, /* Driver ID */ - "GRTC_DRV", /* Driver Name */ - DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ - &grtc_ops, - NULL, /* Funcs */ - 0, /* No devices yet */ - sizeof(struct grtc_priv), - }, - &grtc_ids[0] -}; - -void grtc_register_drv (void) -{ - DBG("Registering GRTC driver\n"); - drvmgr_drv_register(&grtc_drv_info.general); -} - -static int grtc_init2(struct drvmgr_dev *dev) -{ - struct grtc_priv *priv; - - DBG("GRTC[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); - priv = dev->priv; - if ( !priv ) - return DRVMGR_NOMEM; - priv->dev = dev; - - /* This core will not find other cores, so we wait for init2() */ - - return DRVMGR_OK; -} - -static int grtc_init3(struct drvmgr_dev *dev) -{ - struct grtc_priv *priv; - char prefix[32]; - rtems_status_code status; - - priv = dev->priv; - - /* Do initialization */ - - if ( grtc_driver_io_registered == 0) { - /* Register the I/O driver only once for all cores */ - if ( grtc_register_io(&grtc_driver_io_major) ) { - /* Failed to register I/O driver */ - dev->priv = NULL; - return DRVMGR_FAIL; - } - - grtc_driver_io_registered = 1; - } - - /* I/O system registered and initialized - * Now we take care of device initialization. - */ - if ( grtc_device_init(priv) ) { - return DRVMGR_FAIL; - } - - /* Get Filesystem name prefix */ - prefix[0] = '\0'; - if ( drvmgr_get_dev_prefix(dev, prefix) ) { - /* Failed to get prefix, make sure of a unique FS name - * by using the driver minor. - */ - sprintf(priv->devName, "/dev/grtc%d", dev->minor_drv); - } else { - /* Got special prefix, this means we have a bus prefix - * And we should use our "bus minor" - */ - sprintf(priv->devName, "/dev/%sgrtc%d", prefix, dev->minor_bus); - } - - SPIN_INIT(&priv->devlock, priv->devName); - - /* Register Device */ - status = rtems_io_register_name(priv->devName, grtc_driver_io_major, dev->minor_drv); - if (status != RTEMS_SUCCESSFUL) { - return DRVMGR_FAIL; - } - - return DRVMGR_OK; -} - -/******************* Driver Implementation ***********************/ - -static int grtc_register_io(rtems_device_major_number *m) -{ - rtems_status_code r; - - if ((r = rtems_io_register_driver(0, &grtc_driver, m)) == RTEMS_SUCCESSFUL) { - DBG("GRTC driver successfully registered, major: %d\n", *m); - } else { - switch(r) { - case RTEMS_TOO_MANY: - printk("GRTC rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); - return -1; - case RTEMS_INVALID_NUMBER: - printk("GRTC rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); - return -1; - case RTEMS_RESOURCE_IN_USE: - printk("GRTC rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); - return -1; - default: - printk("GRTC rtems_io_register_driver failed\n"); - return -1; - } - } - return 0; -} - -static int grtc_device_init(struct grtc_priv *pDev) -{ - struct amba_dev_info *ambadev; - struct ambapp_core *pnpinfo; - - /* Get device information from AMBA PnP information */ - ambadev = (struct amba_dev_info *)pDev->dev->businfo; - if ( ambadev == NULL ) { - return -1; - } - pnpinfo = &ambadev->info; - pDev->irq = pnpinfo->irq; - pDev->regs = (struct grtc_regs *)pnpinfo->ahb_slv->start[0]; - pDev->minor = pDev->dev->minor_drv; - pDev->open = 0; - pDev->running = 0; - - /* Create Binary RX Semaphore with count = 0 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'C', '0' + pDev->minor), - 0, - RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ - RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &pDev->sem_rx) != RTEMS_SUCCESSFUL ) { - return -1; - } - - /* Reset Hardware before attaching IRQ handler */ - grtc_hw_reset(pDev); - - return 0; -} - -static void grtc_hw_reset(struct grtc_priv *priv) -{ - /* Reset Core */ - priv->regs->grst = GRTC_SEB | GRTC_GRR_SRST; -} - -static void grtc_hw_get_defaults(struct grtc_priv *pDev, struct grtc_ioc_config *config) -{ - unsigned int gcr = READ_REG(&pDev->regs->gctrl); - - config->psr_enable = (gcr & GRTC_GCR_PSR) ? 1:0; - config->nrzm_enable = (gcr & GRTC_GCR_NRZM) ? 1:0; - config->pss_enable = (gcr & GRTC_GCR_PSS) ? 1:0; - - config->crc_calc = 0; -} - -/* bufsize is given in bytes */ -static int __inline__ grtc_hw_data_avail_upper(unsigned int rrp, unsigned rwp, unsigned int bufsize) -{ - if ( rrp == rwp ) - return 0; - - if ( rwp > rrp ) { - return rwp-rrp; - } - - return (bufsize-rrp); -} - -/* bufsize is given in bytes */ -static int __inline__ grtc_hw_data_avail_lower(unsigned int rrp, unsigned rwp, unsigned int bufsize) -{ - if ( rrp == rwp ) - return 0; - - if ( rwp > rrp ) { - return 0; - } - - return rwp; -} - -/* bufsize is given in bytes */ -static int __inline__ grtc_hw_data_avail(unsigned int rrp, unsigned rwp, unsigned int bufsize) -{ - if ( rrp == rwp ) - return 0; - - if ( rwp > rrp ) { - return rwp-rrp; - } - - return rwp+(bufsize-rrp); -} - -/* Reads as much as possible but not more than 'max' bytes from the TC receive buffer. - * Number of bytes put into 'buf' is returned. - */ -static int grtc_hw_read_try(struct grtc_priv *pDev, char *buf, int max) -{ - struct grtc_regs *regs = pDev->regs; - unsigned int rp, wp, asr, bufmax, rrp, rwp; - unsigned int upper, lower; - unsigned int count, cnt, left; - - FUNCDBG(); - - if ( max < 1 ) - return 0; - - rp = READ_REG(®s->rp); - asr = READ_REG(®s->asr); - bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT; - bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */ - wp = READ_REG(®s->wp); - - /* Relative rp and wp */ - rrp = rp - (asr & GRTC_ASR_BUFST); - rwp = wp - (asr & GRTC_ASR_BUFST); - - lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax); - upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax); - - DBG("grtc_hw_read_try: AVAIL: Lower: %d, Upper: %d\n",lower,upper); - DBG("grtc_hw_read_try: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n", - rp,rrp,wp,rwp,bufmax,pDev->buffer); - - if ( (upper+lower) == 0 ) - return 0; - - /* Count bytes will be read */ - count = (upper+lower) > max ? max : (upper+lower); - left = count; - - /* Read from upper part of data buffer */ - if ( upper > 0 ){ - if ( left < upper ){ - cnt = left; - }else{ - cnt = upper; /* Read all upper data available */ - } - DBG("grtc_hw_read_try: COPYING %d from upper\n",cnt); - /* Convert from Remote address (RP) into CPU Local address */ - memcpy(buf, (void *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), cnt); - buf += cnt; - left -= cnt; - } - - /* Read from lower part of data buffer */ - if ( left > 0 ){ - if ( left < lower ){ - cnt = left; - }else{ - cnt = lower; /* Read all lower data available */ - } - DBG("grtc_hw_read_try: COPYING %d from lower\n",cnt); - memcpy(buf, (void *)pDev->buf, cnt); - buf += cnt; - left -= cnt; - } - - /* Update hardware RP pointer to tell hardware about new space available */ - if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){ - regs->rp = (rp+count-bufmax); - } else { - regs->rp = rp+count; - } - - return count; -} - -/* Reads as much as possible but not more than 'max' bytes from the TC receive buffer. - * Number of bytes put into 'buf' is returned. - */ -static int grtc_data_avail(struct grtc_priv *pDev) -{ - unsigned int rp, wp, asr, bufmax, rrp, rwp; - struct grtc_regs *regs = pDev->regs; - - FUNCDBG(); - - rp = READ_REG(®s->rp); - asr = READ_REG(®s->asr); - bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT; - bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */ - wp = READ_REG(®s->wp); - - /* Relative rp and wp */ - rrp = rp - (asr & GRTC_ASR_BUFST); - rwp = wp - (asr & GRTC_ASR_BUFST); - - return grtc_hw_data_avail(rrp,rwp,bufmax); -} - -static void *grtc_memalign(unsigned int boundary, unsigned int length, void *realbuf) -{ - *(int *)realbuf = (int)malloc(length+(~GRTC_ASR_BUFST)+1); - DBG("GRTC: Alloced %d (0x%x) bytes, requested: %d\n",length+(~GRTC_ASR_BUFST)+1,length+(~GRTC_ASR_BUFST)+1,length); - return (void *)(((*(unsigned int *)realbuf)+(~GRTC_ASR_BUFST)+1) & ~(boundary-1)); -} - -static int grtc_start(struct grtc_priv *pDev) -{ - struct grtc_regs *regs = pDev->regs; - unsigned int tmp; - - if ( !pDev->buf || (((unsigned int)pDev->buf & ~GRTC_ASR_BUFST) != 0) || - (pDev->len>(1024*0x100)) || (pDev->len<1024) || ((pDev->len & (1024-1)) != 0) - ) { - DBG("GRTC: start: buffer not properly allocated(0x%x,0x%x,0x%x,0x%x)\n",pDev->buf,pDev->len,((unsigned int)pDev->buf & ~GRTC_ASR_BUFST),(pDev->len & ~(1024-1))); - return RTEMS_NO_MEMORY; - } - - memset(pDev->buf,0,pDev->len); - - /* Software init */ - pDev->overrun_condition = 0; -#ifdef DEBUG_ERROR - pDev->last_error_cnt = 0; - memset(&pDev->last_error[0],0,128*sizeof(int)); -#endif - memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats)); - - /* Reset the receiver */ - regs->cor = GRTC_SEB | GRTC_COR_CRST; - if ( READ_REG(®s->cor) & GRTC_COR_CRST ){ - /* Reset Failed */ - DBG("GRTC: start: Reseting receiver failed\n"); - return RTEMS_IO_ERROR; - } - - /* make sure the RX semaphore is in the correct state when starting. - * In case of a previous overrun condition it could be in incorrect - * state (where rtems_semaphore_flush was used). - */ - rtems_semaphore_obtain(pDev->sem_rx, RTEMS_NO_WAIT, 0); - - /* Set operating modes */ - tmp = 0; - if ( pDev->config.psr_enable ) - tmp |= GRTC_GCR_PSR; - if ( pDev->config.nrzm_enable ) - tmp |= GRTC_GCR_NRZM; - if ( pDev->config.pss_enable ) - tmp |= GRTC_GCR_PSS; - regs->gctrl = GRTC_SEB | tmp; - - /* Clear any pending interrupt */ - tmp = READ_REG(®s->pir); - regs->picr = GRTC_INT_ALL; - - /* Unmask only the Overrun interrupt */ - regs->imr = GRTC_INT_OV; - - /* Set up DMA registers - * 1. Let hardware know about our DMA area (size and location) - * 2. Set DMA read/write posistions to zero. - */ - regs->asr = (unsigned int)pDev->buf_remote | ((pDev->len>>10)-1); - regs->rp = (unsigned int)pDev->buf_remote; - - /* Mark running before enabling the receiver, we could receive - * an interrupt directly after enabling the receiver and it would - * then interpret the interrupt as spurious (see interrupt handler) - */ - pDev->running = 1; - - /* Enable receiver */ - regs->cor = GRTC_SEB | GRTC_COR_RE; - - DBG("GRTC: STARTED\n"); - - return 0; -} - -static void grtc_stop(struct grtc_priv *pDev, int overrun) -{ - struct grtc_regs *regs = pDev->regs; - SPIN_IRQFLAGS(irqflags); - - SPIN_LOCK_IRQ(&pDev->devlock, irqflags); - - /* Disable the receiver */ - regs->cor = GRTC_SEB; - - /* disable all interrupts and clear them */ - regs->imr = 0; - READ_REG(®s->pir); - regs->picr = GRTC_INT_ALL; - - DBG("GRTC: STOPPED\n"); - - if (overrun) { - pDev->overrun_condition = 1; - } else { - pDev->running = 0; - } - - SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags); - - /* Flush semaphores in case a thread is stuck waiting for CLTUs (RX data) */ - rtems_semaphore_flush(pDev->sem_rx); -} - -/* Wait until 'count' bytes are available in receive buffer, or until - * the timeout expires. - */ -static int grtc_wait_data(struct grtc_priv *pDev, int count, rtems_interval timeout) -{ - int avail; - int ret; - SPIN_IRQFLAGS(irqflags); - - FUNCDBG(); - - if ( count < 1 ) - return 0; - - SPIN_LOCK_IRQ(&pDev->devlock, irqflags); - - /* Enable interrupts when receiving CLTUs, Also clear old pending CLTUs store - * interrupts. - */ - pDev->regs->picr = GRTC_INT_CS; - pDev->regs->imr = READ_REG(&pDev->regs->imr) | GRTC_INT_CS; - - avail = grtc_data_avail(pDev); - if ( avail < count ) { - /* Wait for interrupt. */ - - SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags); - - if ( timeout == 0 ){ - timeout = RTEMS_NO_TIMEOUT; - } - ret = rtems_semaphore_obtain(pDev->sem_rx,RTEMS_WAIT,timeout); - /* RTEMS_SUCCESSFUL = interrupt signaled data is available - * RTEMS_TIMEOUT = timeout expired, probably not enough data available - * RTEMS_UNSATISFIED = driver has been closed or an error (overrun) occured - * which should cancel this operation. - * RTEMS_OBJECT_WAS_DELETED, RTEMS_INVALID_ID = driver error. - */ - SPIN_LOCK_IRQ(&pDev->devlock, irqflags); - }else{ - ret = RTEMS_SUCCESSFUL; - } - - /* Disable interrupts when receiving CLTUs */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~GRTC_INT_CS; - - SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags); - - return ret; -} - -static rtems_device_driver grtc_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg) -{ - struct grtc_priv *pDev; - struct drvmgr_dev *dev; - - FUNCDBG(); - - if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) { - DBG("Wrong minor %d\n", minor); - return RTEMS_INVALID_NUMBER; - } - pDev = (struct grtc_priv *)dev->priv; - - /* Wait until we get semaphore */ - if ( rtems_semaphore_obtain(grtc_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){ - return RTEMS_INTERNAL_ERROR; - } - - /* Is device in use? */ - if ( pDev->open ){ - rtems_semaphore_release(grtc_dev_sem); - return RTEMS_RESOURCE_IN_USE; - } - - /* Mark device taken */ - pDev->open = 1; - - rtems_semaphore_release(grtc_dev_sem); - - DBG("grtc_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev); - - /* Set defaults */ - pDev->buf = NULL; - pDev->_buf = NULL; - pDev->buf_custom = 0; - pDev->buf_remote = 0; - pDev->len = 0; - pDev->timeout = 0; /* no timeout */ - pDev->blocking = 0; /* polling mode */ - pDev->mode = GRTC_MODE_RAW; /* Always default to Raw mode */ - pDev->ready.head = NULL; - pDev->ready.tail = NULL; - pDev->ready.cnt = 0; - - pDev->running = 0; - pDev->overrun_condition = 0; - - memset(&pDev->config,0,sizeof(pDev->config)); - - /* The core has been reset when we execute here, so it is possible - * to read out defualts from core. - */ - grtc_hw_get_defaults(pDev,&pDev->config); - - return RTEMS_SUCCESSFUL; -} - -static rtems_device_driver grtc_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - struct grtc_priv *pDev; - struct drvmgr_dev *dev; - - FUNCDBG(); - - if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NUMBER; - } - pDev = (struct grtc_priv *)dev->priv; - - if ( pDev->running ){ - grtc_stop(pDev, 0); - } - - /* Reset core */ - grtc_hw_reset(pDev); - - /* Mark not open */ - pDev->open = 0; - - return RTEMS_SUCCESSFUL; -} - -static rtems_device_driver grtc_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - struct grtc_priv *pDev; - struct drvmgr_dev *dev; - int count; - int left; - int timedout; - int err; - rtems_interval timeout; - rtems_libio_rw_args_t *rw_args; - - FUNCDBG(); - - if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NUMBER; - } - pDev = (struct grtc_priv *)dev->priv; - - if ( !pDev->running && !pDev->overrun_condition ) { - return RTEMS_RESOURCE_IN_USE; - } - - if ( pDev->mode != GRTC_MODE_RAW ) { - return RTEMS_NOT_DEFINED; - } - - rw_args = (rtems_libio_rw_args_t *) arg; - left = rw_args->count; - timedout = 0; - timeout = pDev->timeout; - -read_from_buffer: - /* Read maximally rw_args->count bytes from receive buffer */ - count = grtc_hw_read_try(pDev,rw_args->buffer,left); - - left -= count; - - DBG("READ %d bytes from DMA, left: %d\n",count,left); - - if ( !timedout && !pDev->overrun_condition && ((count < 1) || ((count < rw_args->count) && (pDev->blocking == GRTC_BLKMODE_COMPLETE))) ){ - /* didn't read anything (no data available) or we want to wait for all bytes requested. - * - * Wait for data to arrive only in blocking mode - */ - if ( pDev->blocking ) { - if ( (err=grtc_wait_data(pDev,left,timeout)) != RTEMS_SUCCESSFUL ){ - /* Some kind of error, closed, overrun etc. */ - if ( err == RTEMS_TIMEOUT ){ - /* Got a timeout, we try to read as much as possible */ - timedout = 1; - goto read_from_buffer; - } - return err; - } - goto read_from_buffer; - } - /* Non-blocking mode and no data read. */ - return RTEMS_TIMEOUT; - } - - /* Tell caller how much was read. */ - - DBG("READ returning %d bytes, left: %d\n",rw_args->count-left,left); - - rw_args->bytes_moved = rw_args->count - left; - if ( rw_args->bytes_moved == 0 ) { - if ( pDev->overrun_condition ) { - /* signal to the user that overrun has happend when - * no more data can be read out. - */ - return RTEMS_IO_ERROR; - } - return RTEMS_TIMEOUT; - } - - return RTEMS_SUCCESSFUL; -} - -static rtems_device_driver grtc_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - FUNCDBG(); - return RTEMS_NOT_IMPLEMENTED; -} - -static int grtc_pool_add_frms(struct grtc_frame *frms) -{ - struct grtc_frame *frm, *next; - - /* Add frames to pools */ - frm = frms; - while(frm){ - - if ( !frm->pool ) { - /* */ - DBG("GRTC: Frame not assigned to a pool\n"); - return -1; - } - next = frm->next; /* Remember next frame to process */ - - DBG("GRTC: adding frame 0x%x to pool %d (%d)\n",frm,frm->pool->frame_len,frm->pool->frame_cnt); - - /* Insert Frame into pool */ - frm->next = frm->pool->frms; - frm->pool->frms = frm; - frm->pool->frame_cnt++; - - frm = next; - } - - return 0; -} - -static struct grtc_frame *grtc_pool_get_frm(struct grtc_priv *pDev, int frame_len, int *error) -{ - struct grtc_frame *frm; - struct grtc_frame_pool *pool; - int i; - - /* Loop through all pools until a pool is found - * with a matching (or larger) frame length - */ - pool = pDev->pools; - for (i=0; i<pDev->pool_cnt; i++,pool++) { - if ( pool->frame_len >= frame_len ) { - /* Found a good pool ==> get frame */ - frm = pool->frms; - if ( !frm ) { - /* not enough frames available for this - * frame length, we try next - * - * If this is a severe error add your handling - * code here. - */ -#if 0 - if ( error ) - *error = 0; - return 0; -#endif - continue; - } - - /* Got a frame, the frame is taken out of the - * pool for usage. - */ - pool->frms = frm->next; - pool->frame_cnt--; - return frm; - } - } - - if ( error ) - *error = 1; - - /* Didn't find any frames */ - return NULL; -} - -/* Return number of bytes processed, Stops at the first occurance - * of the pattern given in 'pattern' - */ -static int grtc_scan(unsigned short *src, int max, unsigned char pattern, int *found) -{ - unsigned short tmp = 0; - unsigned int left = max; - - while ( (left>1) && (((tmp=*src) & 0x00ff) != pattern) ) { - src++; - left-=2; - } - if ( (tmp & 0xff) == pattern ) { - *found = 1; - } else { - *found = 0; - } - return max-left; -} - -static int grtc_copy(unsigned short *src, unsigned char *buf, int cnt) -{ - unsigned short tmp; - int left = cnt; - - while ( (left>0) && ((((tmp=*src) & 0x00ff) == 0x00) || ((tmp & 0x00ff) == 0x01)) ) { - *buf++ = tmp>>8; - src++; - left--; - } - - return cnt-left; -} - - -static int grtc_hw_find_frm(struct grtc_priv *pDev) -{ - struct grtc_regs *regs = pDev->regs; - unsigned int rp, wp, asr, bufmax, rrp, rwp; - unsigned int upper, lower; - unsigned int count, cnt; - int found; - - FUNCDBG(); - - rp = READ_REG(®s->rp); - asr = READ_REG(®s->asr); - wp = READ_REG(®s->wp); - - /* Quick Check for most common case where Start of frame is at next - * data byte. - */ - if ( rp != wp ) { - /* At least 1 byte in buffer */ - if ( ((*(unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf)) & 0x00ff) == 0x01 ) { - return 0; - } - } - - bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT; - bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */ - - /* Relative rp and wp */ - rrp = rp - (asr & GRTC_ASR_BUFST); - rwp = wp - (asr & GRTC_ASR_BUFST); - - lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax); - upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax); - - DBG("grtc_hw_find_frm: AVAIL: Lower: %d, Upper: %d\n",lower,upper); - DBG("grtc_hw_find_frm: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n", - rp,rrp,wp,rwp,bufmax,pDev->buf_remote); - - if ( (upper+lower) == 0 ) - return 1; - - /* Count bytes will be read */ - count = 0; - found = 0; - - /* Read from upper part of data buffer */ - if ( upper > 0 ){ - cnt = grtc_scan((unsigned short *)((rp - (unsigned int)pDev->buf_remote) + (unsigned int)pDev->buf), upper, 0x01, &found); - count = cnt; - if ( found ) { - DBG("grtc_hw_find_frm: SCANNED upper %d bytes until found\n",cnt); - goto out; - } - - DBG("grtc_hw_find_frm: SCANNED all upper %d bytes, not found\n",cnt); - } - - /* Read from lower part of data buffer */ - if ( lower > 0 ){ - cnt = grtc_scan((unsigned short *)pDev->buf, lower, 0x01, &found); - count += cnt; - - if ( found ) { - DBG("grtc_hw_find_frm: SCANNED lower %d bytes until found\n",cnt); - goto out; - } - - DBG("grtc_hw_find_frm: SCANNED all lower %d bytes, not found\n",cnt); - } - -out: - /* Update hardware RP pointer to tell hardware about new space available */ - if ( count > 0 ) { - if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){ - regs->rp = (rp+count-bufmax); - } else { - regs->rp = rp+count; - } - } - if ( found ) - return 0; - return 1; - -} - -static int grtc_check_ending(unsigned short *src, int max, int end) -{ - while ( max > 0 ) { - /* Check Filler */ - if ( *src != 0x5500 ) { - /* Filler is wrong */ - return -1; - } - src++; - max-=2; - } - - /* Check ending (at least */ - if ( end ) { - if ( (*src & 0x00ff) != 0x02 ) { - return -1; - } - } - - return 0; -} - -static int grtc_hw_check_ending(struct grtc_priv *pDev, int max) -{ - struct grtc_regs *regs = pDev->regs; - unsigned int rp, wp, asr, bufmax, rrp, rwp; - unsigned int upper, lower; - unsigned int count, cnt, left; - - FUNCDBG(); - - if ( max < 1 ) - return 0; - max = max*2; - max += 2; /* Check ending also (2 byte extra) */ - - rp = READ_REG(®s->rp); - asr = READ_REG(®s->asr); - bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT; - bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */ - wp = READ_REG(®s->wp); - - /* Relative rp and wp */ - rrp = rp - (asr & GRTC_ASR_BUFST); - rwp = wp - (asr & GRTC_ASR_BUFST); - - lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax); - upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax); - - DBG("grtc_hw_check_ending: AVAIL: Lower: %d, Upper: %d\n",lower,upper); - DBG("grtc_hw_check_ending: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n", - rp,rrp,wp,rwp,bufmax,pDev->buf_remote); - - if ( (upper+lower) < max ) - return 0; - - /* Count bytes will be read */ - count = max; - left = count; - - /* Read from upper part of data buffer */ - if ( upper > 0 ){ - if ( left <= upper ){ - cnt = left; - if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt-2, 1) ) { - return -1; - } - }else{ - cnt = upper; /* Read all upper data available */ - if ( grtc_check_ending((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), cnt, 0) ) { - return -1; - } - } - left -= cnt; - } - - /* Read from lower part of data buffer */ - if ( left > 0 ){ - cnt = left; - if ( grtc_check_ending((unsigned short *)pDev->buf, cnt-2, 1) ) { - return -1; - } - left -= cnt; - } - - /* Update hardware RP pointer to tell hardware about new space available */ - if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){ - regs->rp = (rp+count-bufmax); - } else { - regs->rp = rp+count; - } - - return 0; -} - -/* Copies Data from DMA area to buf, the control bytes are stripped. For - * every data byte, in the DMA area, one control byte is stripped. - */ -static int grtc_hw_copy(struct grtc_priv *pDev, unsigned char *buf, int max, int partial) -{ - struct grtc_regs *regs = pDev->regs; - unsigned int rp, wp, asr, bufmax, rrp, rwp; - unsigned int upper, lower; - unsigned int count, cnt, left; - int ret, tot, tmp; - - FUNCDBG(); - - if ( max < 1 ) - return 0; - - rp = READ_REG(®s->rp); - asr = READ_REG(®s->asr); - bufmax = (asr & GRTC_ASR_RXLEN) >> GRTC_ASR_RXLEN_BIT; - bufmax = (bufmax+1) << 10; /* Convert from 1kbyte blocks into bytes */ - wp = READ_REG(®s->wp); - - /* Relative rp and wp */ - rrp = rp - (asr & GRTC_ASR_BUFST); - rwp = wp - (asr & GRTC_ASR_BUFST); - - lower = grtc_hw_data_avail_lower(rrp,rwp,bufmax) >> 1; - upper = grtc_hw_data_avail_upper(rrp,rwp,bufmax) >> 1; - - DBG("grtc_hw_copy: AVAIL: Lower: %d, Upper: %d\n",lower,upper); - DBG("grtc_hw_copy: rp: 0x%x, rrp: 0x%x, wp: 0x%x, rwp: 0x%x, bufmax: %d\n, start: 0x%x\n", - rp,rrp,wp,rwp,bufmax,pDev->buf_remote); - - if ( (upper+lower) == 0 || (!partial && ((upper+lower)<max) ) ) - return 0; - - /* Count bytes will be read */ - count = (upper+lower) > max ? max : (upper+lower); - left = count; - tot = 0; - - /* Read from upper part of data buffer */ - if ( upper > 0 ){ - if ( left < upper ){ - cnt = left; - }else{ - cnt = upper; /* Read all upper data available */ - } - DBG("grtc_hw_copy: COPYING %d from upper\n",cnt); - if ( (tot=grtc_copy((unsigned short *)((rp-(unsigned int)pDev->buf_remote)+(unsigned int)pDev->buf), buf, cnt)) != cnt ) { - /* Failed to copy due to an receive error */ - DBG("grtc_hw_copy(upper): not all in DMA buffer (%d)\n",tot); - count = tot; - ret = -1; - goto out; - } - buf += cnt; - left -= cnt; - } - - /* Read from lower part of data buffer */ - if ( left > 0 ){ - if ( left < lower ){ - cnt = left; - }else{ - cnt = lower; /* Read all lower data available */ - } - DBG("grtc_hw_copy: COPYING %d from lower\n",cnt); - if ( (tmp=grtc_copy((unsigned short *)pDev->buf, buf, cnt)) != cnt ) { - /* Failed to copy due to an receive error */ - DBG("grtc_hw_copy(lower): not all in DMA buffer (%d)\n",tot); - count = tot+tmp; - ret = -1; - goto out; - } - buf += cnt; - left -= cnt; - } - ret = count; - -out: - count = count*2; - /* Update hardware RP pointer to tell hardware about new space available */ - if ( (rp+count) >= ((asr&GRTC_ASR_BUFST)+bufmax) ){ - regs->rp = (rp+count-bufmax); - } else { - regs->rp = rp+count; - } - - return ret; -} - -#ifdef DEBUG_ERROR -void grtc_log_error(struct grtc_priv *pDev, int err) -{ - /* Stop Receiver */ - *(volatile unsigned int *)&pDev->regs->cor = 0x55000000; - *(volatile unsigned int *)&pDev->regs->cor = 0x55000000; - pDev->last_error[pDev->last_error_cnt] = err; - if ( ++pDev->last_error_cnt > 128 ) - pDev->last_error_cnt = 0; -} -#endif - -/* Read one frame from DMA buffer - * - * Return Values - * Zero - nothing more to process - * 1 - more to process, no free frames - * 2 - more to process, frame received - * negative - more to process, frame dropped - */ -static int process_dma(struct grtc_priv *pDev) -{ - int ret, err; - int left, total_len; - unsigned char *dst; - struct grtc_frame *frm; - - switch( pDev->frame_state ) { - case FRM_STATE_NONE: - DBG2("FRAME_STATE_NONE\n"); - - /* Find Start of next frame by searching for 0x01 */ - ret = grtc_hw_find_frm(pDev); - if ( ret != 0 ) { - /* Frame start not found */ - return 0; - } - - /* Start of frame found, Try to copy header */ - pDev->frm = NULL; - pDev->frame_state = FRM_STATE_HDR; - - case FRM_STATE_HDR: - DBG2("FRAME_STATE_HDR\n"); - - /* Wait for all of header to be in place by setting partial to 0 */ - ret = grtc_hw_copy(pDev, (unsigned char *)pDev->hdr, 5, 0); - if ( ret < 0 ) { - /* Error copying header, restart scanning for new frame */ - DEBUG_ERR_LOG(pDev,1); - pDev->stats.err++; - pDev->stats.err_hdr++; - DBG("FRAME_STATE_HDR: copying failed %d\n",ret); - pDev->frame_state = FRM_STATE_NONE; - return -1; - } else if ( ret != 5 ) { - DBG("FRAME_STATE_HDR: no header (%d)\n",ret); - /* Not all bytes available, come back later */ - return 0; - } - - /* The complete header has been copied, parse it */ - pDev->frmlen = (((unsigned short *)pDev->hdr)[1] & 0x3ff)+1; - if ( pDev->frmlen < 5 ) { - /* Error: frame length is not correct */ - pDev->stats.err++; - pDev->stats.err_hdr++; - DBG("FRAME_STATE_HDR: frame length error: %d\n", pDev->frmlen); - pDev->frame_state = FRM_STATE_NONE; - return -1; - } - pDev->frame_state = FRM_STATE_ALLOC; - - case FRM_STATE_ALLOC: - DBG2("FRAME_STATE_ALLOC\n"); - /* Header has been read, allocate a frame to put payload and header into */ - - /* Allocate Frame matching Frame length */ - err = 0; - frm = grtc_pool_get_frm(pDev,pDev->frmlen,&err); - if ( !frm ) { - /* Couldn't find frame */ - DEBUG_ERR_LOG(pDev,2); - pDev->stats.dropped++; - DBG2("No free frames\n"); - if ( err == 0 ){ - /* Frame length exist in pool configuration, but no - * frames are available for that frame length. - */ - DEBUG_ERR_LOG(pDev,3); - pDev->stats.dropped_no_buf++; - return 1; - } else { - /* Frame length of incoming frame is larger than the - * frame length in any of the configured frame pools. - * - * This may be because of an corrupt header. We simply - * scan for the end of frame marker in the DMA buffer - * so we can drop the frame. - */ - DEBUG_ERR_LOG(pDev,4); - pDev->stats.dropped_too_long++; - pDev->frame_state = FRM_STATE_NONE; - return -2; - } - } - frm->len = 5; /* Only header currenlty in frame */ - - /* Copy Frame Header into frame structure */ - ((unsigned char*)&frm->hdr)[0] = ((unsigned char*)pDev->hdr)[0]; - ((unsigned char*)&frm->hdr)[1] = ((unsigned char*)pDev->hdr)[1]; - ((unsigned char*)&frm->hdr)[2] = ((unsigned char*)pDev->hdr)[2]; - ((unsigned char*)&frm->hdr)[3] = ((unsigned char*)pDev->hdr)[3]; - ((unsigned char*)&frm->hdr)[4] = ((unsigned char*)pDev->hdr)[4]; - - /* Calc Total and Filler byte count in frame */ - total_len = pDev->frmlen / 7; - total_len = total_len * 7; - if ( pDev->frmlen != total_len ) - total_len += 7; - - pDev->filler = total_len - pDev->frmlen; - - pDev->frame_state = FRM_STATE_PAYLOAD; - pDev->frm = frm; - - case FRM_STATE_PAYLOAD: - DBG2("FRAME_STATE_PAYLOAD\n"); - /* Parts of payload and the complete header has been read */ - frm = pDev->frm; - - dst = (unsigned char *)&frm->data[frm->len-5]; - left = pDev->frmlen-frm->len; - - ret = grtc_hw_copy(pDev,dst,left,1); - if ( ret < 0 ) { - DEBUG_ERR_LOG(pDev,5); - /* Error copying header, restart scanning for new frame */ - pDev->frame_state = FRM_STATE_NONE; - frm->next = NULL; - grtc_pool_add_frms(frm); - pDev->frm = NULL; - pDev->stats.err++; - pDev->stats.err_payload++; - return -1; - } else if ( ret != left ) { - /* Not all bytes available, come back later */ - frm->len += ret; - return 0; - } - frm->len += ret; - pDev->frame_state = FRM_STATE_FILLER; - - case FRM_STATE_FILLER: - DBG2("FRAME_STATE_FILLER\n"); - /* check filler data */ - frm = pDev->frm; - - ret = grtc_hw_check_ending(pDev,pDev->filler); - if ( ret != 0 ) { - /* Error in frame, drop frame */ - DEBUG_ERR_LOG(pDev,6); - pDev->frame_state = FRM_STATE_NONE; - frm->next = NULL; - grtc_pool_add_frms(frm); - pDev->frm = NULL; - pDev->stats.err++; - pDev->stats.err_ending++; - return -1; - } - - /* A complete frame received, put it into received frame queue */ - if ( pDev->ready.head ) { - /* Queue not empty */ - pDev->ready.tail->next = frm; - } else { - /* Queue empty */ - pDev->ready.head = frm; - } - pDev->ready.tail = frm; - frm->next = NULL; - pDev->ready.cnt++; - pDev->stats.frames_recv++; - - pDev->frame_state = FRM_STATE_NONE; - frm->next = NULL; - return 2; - -#if 0 - case FRM_STATE_DROP: - DBG2("FRAME_STATE_DROP\n"); - break; -#endif - - default: - printk("GRTC: internal error\n"); - pDev->frame_state = FRM_STATE_NONE; - break; - } - - return 0; -} - -static rtems_device_driver grtc_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) -{ - struct grtc_priv *pDev; - struct drvmgr_dev *dev; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; - unsigned int *data = ioarg->buffer; - int status,frm_len,i,ret; - struct grtc_ioc_buf_params *buf_arg; - struct grtc_ioc_config *cfg; - struct grtc_ioc_hw_status *hwregs; - struct grtc_ioc_pools_setup *pocfg; - struct grtc_ioc_assign_frm_pool *poassign; - struct grtc_frame *frm, *frms; - struct grtc_frame_pool *pool; - struct grtc_list *frmlist; - struct grtc_ioc_stats *stats; - unsigned int mem; - IRQ_LOCAL_DECLARE(oldLevel); - - FUNCDBG(); - - if ( drvmgr_get_dev(&grtc_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NUMBER; - } - pDev = (struct grtc_priv *)dev->priv; - - if (!ioarg) - return RTEMS_INVALID_NAME; - - ioarg->ioctl_return = 0; - switch(ioarg->command) { - case GRTC_IOC_START: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - } - if ( (status=grtc_start(pDev)) != RTEMS_SUCCESSFUL ){ - return status; - } - /* Register ISR and Unmask interrupt */ - drvmgr_interrupt_register(pDev->dev, 0, "grtc", grtc_interrupt, pDev); - - /* Read and write are now open... */ - break; - - case GRTC_IOC_STOP: - if ( !pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } - drvmgr_interrupt_unregister(pDev->dev, 0, grtc_interrupt, pDev); - grtc_stop(pDev, 0); - break; - - case GRTC_IOC_ISSTARTED: - if ( !pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } else if ( pDev->overrun_condition ) { - return RTEMS_IO_ERROR; - } - break; - - case GRTC_IOC_SET_BLOCKING_MODE: - if ( (unsigned int)data > GRTC_BLKMODE_COMPLETE ) { - return RTEMS_INVALID_NAME; - } - DBG("GRTC: Set blocking mode: %d\n",(unsigned int)data); - pDev->blocking = (unsigned int)data; - break; - - case GRTC_IOC_SET_TIMEOUT: - DBG("GRTC: Timeout: %d\n",(unsigned int)data); - pDev->timeout = (rtems_interval)data; - break; - - case GRTC_IOC_SET_BUF_PARAM: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - } - - buf_arg = (struct grtc_ioc_buf_params *)data; - if ( !buf_arg ) { - return RTEMS_INVALID_NAME; - } - - DBG("GRTC: IOC_SET_BUF_PARAM: Len: 0x%x, Custom Buffer: 0x%x\n",buf_arg->length,buf_arg->custom_buffer); - - /* Check alignment need, skip bit 0 since that bit only indicates remote address or not */ - if ( (unsigned int)buf_arg->custom_buffer & (~GRTC_BUF_MASK) & (~0x1) ) { - return RTEMS_INVALID_NAME; - } - - if ( buf_arg->length > 0x100 ){ - DBG("GRTC: Too big buffer requested\n"); - return RTEMS_INVALID_NAME; - } - - /* If current buffer allocated by driver we must free it */ - if ( !pDev->buf_custom && pDev->buf ){ - free(pDev->_buf); - pDev->_buf = NULL; - } - pDev->buf = NULL; - pDev->len = buf_arg->length*1024; - - if (pDev->len <= 0) - break; - mem = (unsigned int)buf_arg->custom_buffer; - pDev->buf_custom = mem; - - if (mem & 1) { - /* Remote address given, the address is as the GRTC - * core looks at it. Translate the base address into - * an address that the CPU can understand. - */ - pDev->buf_remote = (void *)(mem & ~0x1); - drvmgr_translate_check(pDev->dev, DMAMEM_TO_CPU, - (void *)pDev->buf_remote, - (void **)&pDev->buf, - pDev->len); - } else { - if (mem == 0) { - pDev->buf = grtc_memalign((~GRTC_ASR_BUFST)+1,pDev->len,&pDev->_buf); - DBG("grtc_ioctl: SETBUF: new buf: 0x%x(0x%x), Len: %d\n",pDev->buf,pDev->_buf,pDev->len); - if (!pDev->buf){ - pDev->len = 0; - pDev->buf_custom = 0; - pDev->_buf = NULL; - pDev->buf_remote = 0; - DBG("GRTC: Failed to allocate memory\n"); - return RTEMS_NO_MEMORY; - } - } else{ - pDev->buf = buf_arg->custom_buffer; - } - - /* Translate into a remote address so that GRTC core - * on a remote AMBA bus (for example over the PCI bus) - * gets a valid address - */ - drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA, - (void *)pDev->buf, - (void **)&pDev->buf_remote, - pDev->len); - } - break; - - case GRTC_IOC_GET_BUF_PARAM: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - } - - buf_arg = (struct grtc_ioc_buf_params *)data; - if ( !buf_arg ) { - return RTEMS_INVALID_NAME; - } - - buf_arg->length = pDev->len >> 10; /* Length in 1kByte blocks */ - if ( pDev->buf_custom ) - buf_arg->custom_buffer =(void *)pDev->buf; - else - buf_arg->custom_buffer = 0; /* Don't reveal internal driver buffer */ - break; - - case GRTC_IOC_SET_CONFIG: - cfg = (struct grtc_ioc_config *)data; - if ( !cfg ) { - return RTEMS_INVALID_NAME; - } - - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } - - pDev->config = *cfg; - break; - - case GRTC_IOC_GET_CONFIG: - cfg = (struct grtc_ioc_config *)data; - if ( !cfg ) { - return RTEMS_INVALID_NAME; - } - - *cfg = pDev->config; - break; - - case GRTC_IOC_GET_HW_STATUS: - hwregs = (struct grtc_ioc_hw_status *)data; - if ( !hwregs ) { - return RTEMS_INVALID_NAME; - } - /* We disable interrupt on the local CPU in order to get a - * snapshot of the registers. - */ - IRQ_LOCAL_DISABLE(oldLevel); - hwregs->sir = READ_REG(&pDev->regs->sir); - hwregs->far = READ_REG(&pDev->regs->far); - hwregs->clcw1 = READ_REG(&pDev->regs->clcw1); - hwregs->clcw2 = READ_REG(&pDev->regs->clcw2); - hwregs->phir = READ_REG(&pDev->regs->phir); - hwregs->str = READ_REG(&pDev->regs->str); - IRQ_LOCAL_ENABLE(oldLevel); - break; - - case GRTC_IOC_GET_STATS: - stats = (struct grtc_ioc_stats *)data; - if ( !stats ) { - return RTEMS_INVALID_NAME; - } - memcpy(stats,&pDev->stats,sizeof(struct grtc_ioc_stats)); - break; - - case GRTC_IOC_CLR_STATS: - memset(&pDev->stats,0,sizeof(struct grtc_ioc_stats)); - break; - - case GRTC_IOC_SET_MODE: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } - if ( (int)data == GRTC_MODE_FRAME ) { - pDev->mode = GRTC_MODE_FRAME; - } else if ( (int)data == GRTC_MODE_RAW ) { - pDev->mode = GRTC_MODE_RAW; - } else { - return RTEMS_INVALID_NAME; - } - break; - - case GRTC_IOC_POOLS_SETUP: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } - pocfg = (struct grtc_ioc_pools_setup *)data; - if ( (pDev->mode != GRTC_MODE_FRAME) || !pocfg ) { - return RTEMS_INVALID_NAME; - } - - /* Check that list is sorted */ - frm_len = 0; - for(i=0;i<pocfg->pool_cnt;i++){ - if ( pocfg->pool_frame_len[i] <= frm_len ) { - return RTEMS_INVALID_NAME; - } - frm_len = pocfg->pool_frame_len[i]; - } - - /* Ok, we trust user. The pool descriptions are allocated - * but not frames, that the user must do self. - */ - if ( pDev->pools ) { - free(pDev->pools); - } - pDev->pools = malloc(pocfg->pool_cnt * sizeof(struct grtc_frame_pool)); - if ( !pDev->pools ) { - pDev->pool_cnt = 0; - return RTEMS_NO_MEMORY; - } - pDev->pool_cnt = pocfg->pool_cnt; - for (i=0;i<pocfg->pool_cnt;i++) { - pDev->pools[i].frame_len = pocfg->pool_frame_len[i]; - pDev->pools[i].frame_cnt = 0; - pDev->pools[i].frms = NULL; - } - break; - - case GRTC_IOC_ASSIGN_FRM_POOL: - if ( pDev->running ) { - return RTEMS_RESOURCE_IN_USE; - } - - if ( (pDev->mode != GRTC_MODE_FRAME) ) { - return RTEMS_INVALID_NAME; - } - - poassign = (struct grtc_ioc_assign_frm_pool *)data; - if ( !poassign ) { - return RTEMS_INVALID_NAME; - } - - /* Find pool to assign the frames to */ - pool = NULL; - for(i=0; i<pDev->pool_cnt; i++) { - if ( pDev->pools[i].frame_len == poassign->frame_len ) { - pool = &pDev->pools[i]; - break; - } - } - if ( !pool ) { - /* No Pool matching frame length */ - return RTEMS_INVALID_NAME; - } - - /* Assign frames to pool */ - frm = poassign->frames; - while(frm){ - frm->pool = pool; /* Assign Frame to pool */ - frm = frm->next; - } - break; - - case GRTC_IOC_ADD_BUFF: - frms = (struct grtc_frame *)data; - - if ( (pDev->mode != GRTC_MODE_FRAME) ) { - return RTEMS_NOT_DEFINED; - } - if ( !frms ) { - return RTEMS_INVALID_NAME; - } - - /* Add frames to respicative pools */ - if ( grtc_pool_add_frms(frms) ) { - return RTEMS_INVALID_NAME; - } - break; - - /* Try to read as much data as possible from DMA area and - * put it into free frames. - * - * If receiver is in stopped mode, let user only read previously - * received frames. - */ - case GRTC_IOC_RECV: - - if ( (pDev->mode != GRTC_MODE_FRAME) ) { - return RTEMS_NOT_DEFINED; - } - - while ( pDev->running && ((ret=process_dma(pDev) == 2) || (ret == -1)) ) { - /* Frame received or dropped, process next frame */ - } - - /* Take frames out from ready queue and put them to user */ - frmlist = (struct grtc_list *)data; - if ( !frmlist ) { - return RTEMS_INVALID_NAME; - } - - frmlist->head = pDev->ready.head; - frmlist->tail = pDev->ready.tail; - frmlist->cnt = pDev->ready.cnt; - - /* Empty list */ - pDev->ready.head = NULL; - pDev->ready.tail = NULL; - pDev->ready.cnt = 0; - - if ((frmlist->cnt == 0) && pDev->overrun_condition) { - /* signal to the user that overrun has happend when - * no more data can be read out. - */ - return RTEMS_IO_ERROR; - } - break; - - case GRTC_IOC_GET_CLCW_ADR: - if ( !data ) { - return RTEMS_INVALID_NAME; - } - *data = (unsigned int)&pDev->regs->clcw1; - break; - - default: - return RTEMS_NOT_DEFINED; - } - return RTEMS_SUCCESSFUL; -} - -static void grtc_interrupt(void *arg) -{ - struct grtc_priv *pDev = arg; - struct grtc_regs *regs = pDev->regs; - unsigned int status; - SPIN_ISR_IRQFLAGS(irqflags); - - /* Clear interrupt by reading it */ - status = READ_REG(®s->pisr); - - /* Spurious Interrupt? */ - if ( !pDev->running ) - return; - - if ( status & GRTC_INT_OV ){ - /* Stop core (Disable receiver, interrupts), set overrun condition, - * Flush semaphore if thread waiting for data in grtc_wait_data(). - */ - grtc_stop(pDev, 1); - - /* No need to handle the reset of interrupts, we are still */ - goto out; - } - - if ( status & GRTC_INT_CS ){ - SPIN_LOCK(&pDev->devlock, irqflags); - - if ( (pDev->blocking==GRTC_BLKMODE_COMPLETE) && pDev->timeout ){ - /* Signal to thread only if enough data is available */ - if ( pDev->wait_for_nbytes > grtc_data_avail(pDev) ){ - /* Not enough data available */ - goto procceed_processing_interrupts; - } - - /* Enough data is available which means that we should - * wake up the thread sleeping. - */ - } - - /* Disable further CLTUs Stored interrupts, no point until - * thread waiting for them says it want to wait for more. - */ - regs->imr = READ_REG(®s->imr) & ~GRTC_INT_CS; - SPIN_UNLOCK(&pDev->devlock, irqflags); - - /* Signal Semaphore to wake waiting thread in read() */ - rtems_semaphore_release(pDev->sem_rx); - } - -procceed_processing_interrupts: - - if ( status & GRTC_INT_CR ){ - - } - - if ( status & GRTC_INT_FAR ){ - - } - - if ( status & GRTC_INT_BLO ){ - - } - - if ( status & GRTC_INT_RFA ){ - - } -out: - if ( status ) - regs->picr = status; -} - -static rtems_device_driver grtc_initialize( - rtems_device_major_number major, - rtems_device_minor_number unused, - void *arg - ) -{ - /* Device Semaphore created with count = 1 */ - if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'C'), - 1, - RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, - 0, - &grtc_dev_sem) != RTEMS_SUCCESSFUL ) { - return RTEMS_INTERNAL_ERROR; - } - - return RTEMS_SUCCESSFUL; -} |