From: Martin Aberg <mab...@gaisler.com> This commit preserves all driver services, using a function based user interface instead of the I/O interface.
The messages count parameter is now number of CAN messages instead of number of bytes. --- c/src/lib/libbsp/sparc/shared/can/grcan.c | 661 +++++++++++++------------- c/src/lib/libbsp/sparc/shared/include/grcan.h | 131 ++++- 2 files changed, 436 insertions(+), 356 deletions(-) diff --git a/c/src/lib/libbsp/sparc/shared/can/grcan.c b/c/src/lib/libbsp/sparc/shared/can/grcan.c index 46599dc..d1573b2 100644 --- a/c/src/lib/libbsp/sparc/shared/can/grcan.c +++ b/c/src/lib/libbsp/sparc/shared/can/grcan.c @@ -10,7 +10,6 @@ */ #include <bsp.h> -#include <rtems/libio.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -23,6 +22,9 @@ #include <drvmgr/ambapp_bus.h> #include <ambapp.h> +/* Maximum number of GRCAN devices supported by driver */ +#define GRCAN_COUNT_MAX 8 + #define WRAP_AROUND_TX_MSGS 1 #define WRAP_AROUND_RX_MSGS 2 #define GRCAN_MSG_SIZE sizeof(struct grcan_msg) @@ -137,15 +139,6 @@ struct grcan_priv { rtems_id rx_sem, tx_sem, txempty_sem, dev_sem; }; -static rtems_device_driver grcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); -static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); - -#define GRCAN_DRIVER_TABLE_ENTRY { grcan_initialize, grcan_open, grcan_close, grcan_read, grcan_write, grcan_ioctl } - static void __inline__ grcan_hw_reset(struct grcan_regs *regs); static unsigned int grcan_hw_read_try( @@ -209,15 +202,12 @@ static unsigned int __inline__ _grcan_read_nocache(unsigned int address) } #endif - -static rtems_driver_address_table grcan_driver = GRCAN_DRIVER_TABLE_ENTRY; -static int grcan_driver_io_registered = 0; -static rtems_device_major_number grcan_driver_io_major = 0; +static int grcan_count = 0; +static struct grcan_priv *priv_tab[GRCAN_COUNT_MAX]; /******************* Driver manager interface ***********************/ /* Driver prototypes */ -int grcan_register_io(rtems_device_major_number *m); int grcan_device_init(struct grcan_priv *pDev); int grcan_init2(struct drvmgr_dev *dev); @@ -265,6 +255,8 @@ int grcan_init2(struct drvmgr_dev *dev) struct grcan_priv *priv; DBG("GRCAN[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); + if (GRCAN_COUNT_MAX <= grcan_count) + return DRVMGR_ENORES; priv = dev->priv = malloc(sizeof(struct grcan_priv)); if ( !priv ) return DRVMGR_NOMEM; @@ -280,24 +272,10 @@ int grcan_init3(struct drvmgr_dev *dev) { struct grcan_priv *priv; char prefix[32]; - rtems_status_code status; priv = dev->priv; - /* Do initialization */ - - if ( grcan_driver_io_registered == 0) { - /* Register the I/O driver only once for all cores */ - if ( grcan_register_io(&grcan_driver_io_major) ) { - /* Failed to register I/O driver */ - dev->priv = NULL; - return DRVMGR_FAIL; - } - - grcan_driver_io_registered = 1; - } - - /* I/O system registered and initialized + /* * Now we take care of device initialization. */ @@ -305,6 +283,9 @@ int grcan_init3(struct drvmgr_dev *dev) return DRVMGR_FAIL; } + priv_tab[grcan_count] = priv; + grcan_count++; + /* Get Filesystem name prefix */ prefix[0] = '\0'; if ( drvmgr_get_dev_prefix(dev, prefix) ) { @@ -319,42 +300,9 @@ int grcan_init3(struct drvmgr_dev *dev) sprintf(priv->devName, "/dev/%sgrcan%d", prefix, dev->minor_bus); } - /* Register Device */ - status = rtems_io_register_name(priv->devName, grcan_driver_io_major, dev->minor_drv); - if (status != RTEMS_SUCCESSFUL) { - return DRVMGR_FAIL; - } - return DRVMGR_OK; } -/******************* Driver Implementation ***********************/ - -int grcan_register_io(rtems_device_major_number *m) -{ - rtems_status_code r; - - if ((r = rtems_io_register_driver(0, &grcan_driver, m)) == RTEMS_SUCCESSFUL) { - DBG("GRCAN driver successfully registered, major: %d\n", *m); - } else { - switch(r) { - case RTEMS_TOO_MANY: - printk("GRCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); - return -1; - case RTEMS_INVALID_NUMBER: - printk("GRCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); - return -1; - case RTEMS_RESOURCE_IN_USE: - printk("GRCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); - return -1; - default: - printk("GRCAN rtems_io_register_driver failed\n"); - return -1; - } - } - return 0; -} - int grcan_device_init(struct grcan_priv *pDev) { struct amba_dev_info *ambadev; @@ -428,7 +376,7 @@ static void __inline__ grcan_hw_reset(struct grcan_regs *regs) regs->ctrl = GRCAN_CTRL_RESET; } -static rtems_device_driver grcan_start(struct grcan_priv *pDev) +static rtems_device_driver grcan_hw_start(struct grcan_priv *pDev) { /* * tmp is set but never used. GCC gives a warning for this @@ -503,7 +451,7 @@ static rtems_device_driver grcan_start(struct grcan_priv *pDev) return RTEMS_SUCCESSFUL; } -static void grcan_stop(struct grcan_priv *pDev) +static void grcan_hw_stop(struct grcan_priv *pDev) { FUNCDBG(); @@ -1210,39 +1158,34 @@ static void grcan_free_buffers(struct grcan_priv *pDev, int rx, int tx) } } -static rtems_device_driver grcan_initialize( - rtems_device_major_number major, - rtems_device_minor_number unused, - void *arg - ) +int grcan_dev_count(void) { - return RTEMS_SUCCESSFUL; + return grcan_count; } -static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +void *grcan_open(int dev_no) { struct grcan_priv *pDev; - rtems_device_driver ret; - struct drvmgr_dev *dev; + void *ret; union drvmgr_key_value *value; FUNCDBG(); - if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { - DBG("Wrong minor %d\n", minor); - return RTEMS_INVALID_NAME; + if (grcan_count == 0 || (grcan_count <= dev_no)) { + return NULL; } - pDev = (struct grcan_priv *)dev->priv; + + pDev = priv_tab[dev_no]; /* Wait until we get semaphore */ if (rtems_semaphore_obtain(pDev->dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL) { - return RTEMS_INTERNAL_ERROR; + return NULL; } /* is device busy/taken? */ if ( pDev->open ) { - ret=RTEMS_RESOURCE_IN_USE; + ret = NULL; goto out; } @@ -1297,33 +1240,27 @@ static rtems_device_driver grcan_open(rtems_device_major_number major, rtems_dev grcan_calc_timing(GRCAN_DEFAULT_BAUD,pDev->corefreq_hz,GRCAN_SAMPLING_POINT,&pDev->config.timing); if ( grcan_alloc_buffers(pDev,1,1) ) { - ret=RTEMS_NO_MEMORY; + ret = NULL; goto out; } /* Clear statistics */ memset(&pDev->stats,0,sizeof(struct grcan_stats)); - ret = RTEMS_SUCCESSFUL; + ret = pDev; out: rtems_semaphore_release(pDev->dev_sem); return ret; } -static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +int grcan_close(void *d) { - struct grcan_priv *pDev; - struct drvmgr_dev *dev; + struct grcan_priv *pDev = d; FUNCDBG(); - if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; - } - pDev = (struct grcan_priv *)dev->priv; - if ( pDev->started ) - grcan_stop(pDev); + grcan_hw_stop(pDev); grcan_hw_reset(pDev->regs); @@ -1332,34 +1269,26 @@ static rtems_device_driver grcan_close(rtems_device_major_number major, rtems_de /* Mark Device as closed */ pDev->open = 0; - return RTEMS_SUCCESSFUL; + return 0; } -static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +int grcan_read(void *d, CANMsg *msg, size_t ucount) { - struct grcan_priv *pDev; - struct drvmgr_dev *dev; - rtems_libio_rw_args_t *rw_args; + struct grcan_priv *pDev = d; CANMsg *dest; unsigned int count, left; int req_cnt; FUNCDBG(); - if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; - } - pDev = (struct grcan_priv *)dev->priv; - - rw_args = (rtems_libio_rw_args_t *) arg; - dest = (CANMsg *) rw_args->buffer; - req_cnt = rw_args->count / sizeof(CANMsg); + dest = msg; + req_cnt = ucount; if ( (!dest) || (req_cnt<1) ) - return RTEMS_INVALID_NAME; + return -1; if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; + return -2; /*FUNCDBG("grcan_read [%i,%i]: buf: 0x%x len: %i\n",major, minor, (unsigned int)rw_args->buffer,rw_args->count);*/ @@ -1367,15 +1296,13 @@ static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_dev if ( !( pDev->rxblock && pDev->rxcomplete && (count!=req_cnt) ) ){ if ( count > 0 ) { /* Successfully received messages (at least one) */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + return count; } /* nothing read, shall we block? */ if ( !pDev->rxblock ) { /* non-blocking mode */ - rw_args->bytes_moved = 0; - return RTEMS_TIMEOUT; + return -3; } } @@ -1401,8 +1328,7 @@ static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_dev * the device driver has been closed by another * thread. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_UNSATISFIED; + return count; } /* Try read bytes from circular buffer */ @@ -1413,51 +1339,40 @@ static rtems_device_driver grcan_read(rtems_device_major_number major, rtems_dev req_cnt-count); } /* no need to unmask IRQ as IRQ Handler do that for us. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + return count; } -static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +int grcan_write(void *d, CANMsg *msg, size_t ucount) { - struct grcan_priv *pDev; - struct drvmgr_dev *dev; - rtems_libio_rw_args_t *rw_args; + struct grcan_priv *pDev = d; CANMsg *source; unsigned int count, left; int req_cnt; DBGC(DBG_TX,"\n"); - if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; - } - pDev = (struct grcan_priv *)dev->priv; - if ( !pDev->started || pDev->config.silent || pDev->flushing ) - return RTEMS_RESOURCE_IN_USE; + return -2; - rw_args = (rtems_libio_rw_args_t *) arg; - req_cnt = rw_args->count / sizeof(CANMsg); - source = (CANMsg *) rw_args->buffer; + req_cnt = ucount; + source = (CANMsg *) msg; /* check proper length and buffer pointer */ if (( req_cnt < 1) || (source == NULL) ){ - return RTEMS_INVALID_NAME; + return -1; } count = grcan_hw_write_try(pDev,pDev->regs,source,req_cnt); if ( !(pDev->txblock && pDev->txcomplete && (count!=req_cnt)) ) { if ( count > 0 ) { /* Successfully transmitted chars (at least one char) */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + return count; } /* nothing written, shall we block? */ if ( !pDev->txblock ) { /* non-blocking mode */ - rw_args->bytes_moved = 0; - return RTEMS_TIMEOUT; + return -3; } } @@ -1488,8 +1403,7 @@ static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_de * thread. To avoid deadlock we return directly * with error status. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_UNSATISFIED; + return count; } if ( pDev->txerror ){ @@ -1509,230 +1423,309 @@ static rtems_device_driver grcan_write(rtems_device_major_number major, rtems_de } /* no need to unmask IRQ as IRQ Handler do that for us. */ - rw_args->bytes_moved = count * sizeof(CANMsg); - return RTEMS_SUCCESSFUL; + return count; } -static rtems_device_driver grcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) +int grcan_start(void *d) { - struct grcan_priv *pDev; - struct drvmgr_dev *dev; - rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; - unsigned int *data = ioarg->buffer; - struct grcan_timing timing; - unsigned int speed; - struct grcan_selection *selection; - int tmp,ret; + struct grcan_priv *pDev = d; rtems_device_driver status; - struct grcan_stats *stats; - struct grcan_filter *filter; - IRQ_GLOBAL_PREPARE(oldLevel); FUNCDBG(); - if ( drvmgr_get_dev(&grcan_drv_info.general, minor, &dev) ) { - return RTEMS_INVALID_NAME; + if ( pDev->started ) + return -1; + + if ( (status=grcan_hw_start(pDev)) != RTEMS_SUCCESSFUL ){ + return -2; } - pDev = (struct grcan_priv *)dev->priv; - if (!ioarg) - return RTEMS_INVALID_NAME; + /* Read and write are now open... */ + pDev->started = 1; - ioarg->ioctl_return = 0; - switch(ioarg->command) { - case GRCAN_IOC_START: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + /* Register interrupt routine and enable IRQ at IRQ ctrl */ + drvmgr_interrupt_register(pDev->dev, 0, "grcan", grcan_interrupt, pDev); - if ( (status=grcan_start(pDev)) != RTEMS_SUCCESSFUL ){ - return status; - } - /* Read and write are now open... */ - pDev->started = 1; + return 0; +} - /* Register interrupt routine and enable IRQ at IRQ ctrl */ - drvmgr_interrupt_register(dev, 0, "grcan", grcan_interrupt, pDev); +int grcan_stop(void *d) +{ + struct grcan_priv *pDev = d; - break; + FUNCDBG(); - case GRCAN_IOC_STOP: - if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; + if ( !pDev->started ) + return -1; - /* Disable interrupts */ - drvmgr_interrupt_unregister(dev, 0, grcan_interrupt, pDev); + /* Disable interrupts */ + drvmgr_interrupt_unregister(pDev->dev, 0, grcan_interrupt, pDev); - grcan_stop(pDev); - pDev->started = 0; - break; + grcan_hw_stop(pDev); + pDev->started = 0; - case GRCAN_IOC_ISSTARTED: - if ( !pDev->started ) - return RTEMS_RESOURCE_IN_USE; - break; + return 0; +} - case GRCAN_IOC_FLUSH: - if ( !pDev->started || pDev->flushing || pDev->config.silent ) - return RTEMS_RESOURCE_IN_USE; +int grcan_isstarted(void *d) +{ + struct grcan_priv *pDev = d; - pDev->flushing = 1; - tmp = grcan_tx_flush(pDev); - pDev->flushing = 0; - if ( tmp ) { - /* The wait has been aborted, probably due to - * the device driver has been closed by another - * thread. - */ - return RTEMS_UNSATISFIED; - } - break; + FUNCDBG(); -#if 0 - /* Set physical link */ - case GRCAN_IOC_SET_LINK: -#ifdef REDUNDANT_CHANNELS - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ + return pDev->started; +} - /* switch HW channel */ - pDev->channel = (unsigned int)ioargs->buffer; -#else - return RTEMS_NOT_IMPLEMENTED; -#endif - break; -#endif +int grcan_flush(void *d) +{ + struct grcan_priv *pDev = d; + int tmp; - case GRCAN_IOC_SET_SILENT: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - pDev->config.silent = (int)ioarg->buffer; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_ABORT: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - pDev->config.abort = (int)ioarg->buffer; - /* This Configuration parameter doesn't need HurriCANe reset - * ==> no pDev->config_changed = 1; - */ - break; - - case GRCAN_IOC_SET_SELECTION: - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; - - selection = (struct grcan_selection *)ioarg->buffer; - if ( !selection ) - return RTEMS_INVALID_NAME; - - pDev->config.selection = *selection; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_RXBLOCK: - pDev->rxblock = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_TXBLOCK: - pDev->txblock = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_TXCOMPLETE: - pDev->txcomplete = (int)ioarg->buffer; - break; - - case GRCAN_IOC_SET_RXCOMPLETE: - pDev->rxcomplete = (int)ioarg->buffer; - break; - - case GRCAN_IOC_GET_STATS: - stats = (struct grcan_stats *)ioarg->buffer; - if ( !stats ) - return RTEMS_INVALID_NAME; - *stats = pDev->stats; - break; - - case GRCAN_IOC_CLR_STATS: - IRQ_GLOBAL_DISABLE(oldLevel); - memset(&pDev->stats,0,sizeof(struct grcan_stats)); - IRQ_GLOBAL_ENABLE(oldLevel); - break; - - case GRCAN_IOC_SET_SPEED: - /* cannot change speed during run mode */ - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - - /* get speed rate from argument */ - speed = (unsigned int)ioarg->buffer; - ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing); - if ( ret ) - return RTEMS_INVALID_NAME; /* EINVAL */ - - /* save timing/speed */ - pDev->config.timing = timing; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_BTRS: - /* Set BTR registers manually - * Read GRCAN/HurriCANe Manual. + FUNCDBG(); + + if ( !pDev->started || pDev->flushing || pDev->config.silent ) + return -1; + + pDev->flushing = 1; + tmp = grcan_tx_flush(pDev); + pDev->flushing = 0; + if ( tmp ) { + /* The wait has been aborted, probably due to + * the device driver has been closed by another + * thread. */ - if ( pDev->started ) - return RTEMS_RESOURCE_IN_USE; /* EBUSY */ - if ( !ioarg->buffer ) - return RTEMS_INVALID_NAME; - - pDev->config.timing = *(struct grcan_timing *)ioarg->buffer; - pDev->config_changed = 1; - break; - - case GRCAN_IOC_SET_AFILTER: - filter = (struct grcan_filter *)ioarg->buffer; - if ( !filter ){ - /* Disable filtering - let all messages pass */ - pDev->afilter.mask = 0x0; - pDev->afilter.code = 0x0; - }else{ - /* Save filter */ - pDev->afilter = *filter; - } - /* Set hardware acceptance filter */ - grcan_hw_accept(pDev->regs,&pDev->afilter); - break; - - case GRCAN_IOC_SET_SFILTER: - filter = (struct grcan_filter *)ioarg->buffer; - if ( !filter ){ - /* disable TX/RX SYNC filtering */ - pDev->sfilter.mask = 0xffffffff; - pDev->sfilter.mask = 0; - - /* disable Sync interrupt */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); - }else{ - /* Save filter */ - pDev->sfilter = *filter; + return -1; + } - /* Enable Sync interrupt */ - pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); - } - /* Set Sync RX/TX filter */ - grcan_hw_sync(pDev->regs,&pDev->sfilter); - break; - - case GRCAN_IOC_GET_STATUS: - if ( !data ) - return RTEMS_INVALID_NAME; - /* Read out the statsu register from the GRCAN core */ - data[0] = READ_REG(&pDev->regs->stat); - break; - - default: - return RTEMS_NOT_DEFINED; + return 0; +} + +int grcan_set_silent(void* d, int silent) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( pDev->started ) + return -1; + + pDev->config.silent = silent; + pDev->config_changed = 1; + + return 0; +} + +int grcan_set_abort(void* d, int abort) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( pDev->started ) + return -1; + + pDev->config.abort = abort; + /* This Configuration parameter doesn't need HurriCANe reset + * ==> no pDev->config_changed = 1; + */ + + return 0; +} + +int grcan_set_selection(void *d, const struct grcan_selection *selection) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( pDev->started ) + return -1; + + if ( !selection ) + return -2; + + pDev->config.selection = *selection; + pDev->config_changed = 1; + + return 0; +} + +int grcan_set_rxblock(void *d, int block) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + pDev->rxblock = block; + + return 0; +} + +int grcan_set_txblock(void *d, int block) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + pDev->txblock = block; + + return 0; +} + +int grcan_set_txcomplete(void *d, int complete) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + pDev->txcomplete = complete; + + return 0; +} + +int grcan_set_rxcomplete(void *d, int complete) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + pDev->rxcomplete = complete; + + return 0; +} + +int grcan_get_stats(void *d, struct grcan_stats *stats) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( !stats ) + return -1; + + *stats = pDev->stats; + + return 0; +} + +int grcan_clr_stats(void *d) +{ + struct grcan_priv *pDev = d; + IRQ_GLOBAL_PREPARE(oldLevel); + + FUNCDBG(); + + IRQ_GLOBAL_DISABLE(oldLevel); + memset(&pDev->stats,0,sizeof(struct grcan_stats)); + IRQ_GLOBAL_ENABLE(oldLevel); + + return 0; +} + +int grcan_set_speed(void *d, unsigned int speed) +{ + struct grcan_priv *pDev = d; + struct grcan_timing timing; + int ret; + + FUNCDBG(); + + /* cannot change speed during run mode */ + if ( pDev->started ) + return -1; + + /* get speed rate from argument */ + ret = grcan_calc_timing(speed, pDev->corefreq_hz, GRCAN_SAMPLING_POINT, &timing); + if ( ret ) + return -2; + + /* save timing/speed */ + pDev->config.timing = timing; + pDev->config_changed = 1; + + return 0; +} + +int grcan_set_btrs(void *d, const struct grcan_timing *timing) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + /* Set BTR registers manually + * Read GRCAN/HurriCANe Manual. + */ + if ( pDev->started ) + return -1; + + if ( !timing ) + return -2; + + pDev->config.timing = *timing; + pDev->config_changed = 1; + + return 0; +} + +int grcan_set_afilter(void *d, const struct grcan_filter *filter) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( !filter ){ + /* Disable filtering - let all messages pass */ + pDev->afilter.mask = 0x0; + pDev->afilter.code = 0x0; + }else{ + /* Save filter */ + pDev->afilter = *filter; } - return RTEMS_SUCCESSFUL; + /* Set hardware acceptance filter */ + grcan_hw_accept(pDev->regs,&pDev->afilter); + + return 0; +} + +int grcan_set_sfilter(void *d, const struct grcan_filter *filter) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( !filter ){ + /* disable TX/RX SYNC filtering */ + pDev->sfilter.mask = 0xffffffff; + pDev->sfilter.mask = 0; + + /* disable Sync interrupt */ + pDev->regs->imr = READ_REG(&pDev->regs->imr) & ~(GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); + }else{ + /* Save filter */ + pDev->sfilter = *filter; + + /* Enable Sync interrupt */ + pDev->regs->imr = READ_REG(&pDev->regs->imr) | (GRCAN_RXSYNC_IRQ|GRCAN_TXSYNC_IRQ); + } + /* Set Sync RX/TX filter */ + grcan_hw_sync(pDev->regs,&pDev->sfilter); + + return 0; +} + +int grcan_get_status(void* d, unsigned int *data) +{ + struct grcan_priv *pDev = d; + + FUNCDBG(); + + if ( !data ) + return -1; + + /* Read out the statsu register from the GRCAN core */ + data[0] = READ_REG(&pDev->regs->stat); + + return 0; } /* Handle the IRQ */ @@ -1763,7 +1756,7 @@ static void grcan_interrupt(void *arg) * to read/write until user has called ioctl(fd,START,0). */ pDev->started = 0; - grcan_stop(pDev); /* this mask all IRQ sources */ + grcan_hw_stop(pDev); /* this mask all IRQ sources */ status=0x1ffff; /* clear all interrupts */ goto out; } diff --git a/c/src/lib/libbsp/sparc/shared/include/grcan.h b/c/src/lib/libbsp/sparc/shared/include/grcan.h index 5f4da5d..c391aa3 100644 --- a/c/src/lib/libbsp/sparc/shared/include/grcan.h +++ b/c/src/lib/libbsp/sparc/shared/include/grcan.h @@ -156,34 +156,121 @@ typedef struct { #define GRCAN_STAT_RXERRCNT 0xff00 #define GRCAN_STAT_TXERRCNT 0xff0000 -/* IOCTL Commands controlling operational +/* + * Return number of GRCAN devices available to driver + */ +extern int grcan_dev_count(void); + +/* + * Open a GRCAN device + * + * dev_no: Device number to open + * return: Device handle to use with all other grcan_ API functions. The + * function returns NULL if device can not be opened. + */ +extern void *grcan_open(int dev_no); + +/* + * Close a GRCAN device + * + * return: This function always returns 0 (success) + */ +extern int grcan_close(void *d); + +/* + * Receive CAN messages + * + * Multiple CAN messages can be received in one call. + * + * d: Device handle + * msg: Pointer to receive messages + * count: Number of CAN messages to receive + * + * return: + * >=0: Number of CAN messages received. This can be less than the + * count parameter. + * -1: count parameter less than size of struct grcan_msg or NULL msg. + * -2: Device not in started mode + * -3: Timeout in non-blocking mode + * -4: A blocking read was interrupted by a Bus-off error. Device has + * left started mode. + */ +extern int grcan_read( + void *d, + CANMsg *msg, + size_t count +); + +/* + * Transmit CAN messages + * + * Multiple CAN messages can be transmit in one call. + * + * d: Device handle + * msg: Pointer to messages to transmit + * count: Number of CAN messages to transmit + * + * return: + * >=0: Number of CAN messages transmitted. This can be less than the + * count parameter. + * -1: count parameter less than size of struct grcan_msg + * -2: Device not in started mode + * -3: Timeout in non-blocking mode + * -4: Bus-off error. Device has left started mode + */ +extern int grcan_write( + void *d, + CANMsg *msg, + size_t count +); + +/* The remaining functions return 0 on success and non-zero on failure. */ + +/* Functions controlling operational * mode */ -#define GRCAN_IOC_START 1 /* Bring the link up after open or bus-off */ -#define GRCAN_IOC_STOP 2 /* stop to change baud rate/config or closing down */ -#define GRCAN_IOC_ISSTARTED 3 /* return RTEMS_SUCCESSFUL when started, othervise EBUSY */ -#define GRCAN_IOC_FLUSH 4 /* Waits until all TX messages has been sent */ +/* Bring the link up after open or bus-off */ +extern int grcan_start(void *d); +/* stop to change baud rate/config or closing down */ +extern int grcan_stop(void *d); +/* return 1 when started, othervise 0 */ +extern int grcan_isstarted(void *d); +/* Wait until all TX messages have been sent */ +extern int grcan_flush(void *d); -/* IOCTL Commands that require connection +/* Functions that require connection * to be stopped */ -#define GRCAN_IOC_SET_SILENT 16 /* enable silent mode read only state */ -#define GRCAN_IOC_SET_ABORT 17 /* enable/disable stopping link on AHB Error */ -#define GRCAN_IOC_SET_SELECTION 18 /* Set Enable0,Enable1,Selection */ -#define GRCAN_IOC_SET_SPEED 19 /* Set baudrate by using driver's baud rate timing calculation routines */ -#define GRCAN_IOC_SET_BTRS 20 /* Set baudrate by specifying the timing registers manually */ - -/* IOCTL Commands can be called whenever */ -#define GRCAN_IOC_SET_RXBLOCK 32 /* Enable/disable Blocking on reception (until at least one message has been received) */ -#define GRCAN_IOC_SET_TXBLOCK 33 /* Enable/disable Blocking on transmission (until at least one message has been transmitted) */ -#define GRCAN_IOC_SET_TXCOMPLETE 34 /* Enable/disable Blocking until all requested messages has been sent */ -#define GRCAN_IOC_SET_RXCOMPLETE 35 /* Enable/disable Blocking until all requested has been received */ -#define GRCAN_IOC_GET_STATS 36 /* Get Statistics */ -#define GRCAN_IOC_CLR_STATS 37 /* Clear Statistics */ -#define GRCAN_IOC_SET_AFILTER 38 /* Set Acceptance filters, provide pointer to "struct grcan_filter" or NULL to disable filtering (let all messages pass) */ -#define GRCAN_IOC_SET_SFILTER 40 /* Set Sync Messages RX/TX filters, NULL disables the IRQ completely */ -#define GRCAN_IOC_GET_STATUS 41 /* Get status register of GRCAN core */ +/* enable silent mode read only state */ +extern int grcan_set_silent(void *d, int silent); +/* enable/disable stopping link on AHB Error */ +extern int grcan_set_abort(void *d, int abort); +/* Set Enable0,Enable1,Selection */ +extern int grcan_set_selection(void *d, const struct grcan_selection *selection); +/* Set baudrate by using driver's baud rate timing calculation routines */ +extern int grcan_set_speed(void *d, unsigned int hz); +/* Set baudrate by specifying the timing registers manually */ +extern int grcan_set_btrs(void *d, const struct grcan_timing *timing); +/* Functions can be called whenever */ +/* Enable/disable Blocking on reception (until at least one message has been received) */ +int grcan_set_rxblock(void* d, int block); +/* Enable/disable Blocking on transmission (until at least one message has been transmitted) */ +int grcan_set_txblock(void* d, int block); +/* Enable/disable Blocking until all requested messages has been sent */ +int grcan_set_txcomplete(void* d, int complete); +/* Enable/disable Blocking until all requested has been received */ +int grcan_set_rxcomplete(void* d, int complete); +/* Get statistics */ +extern int grcan_get_stats(void *d, struct grcan_stats *stats); +/* Clear statistics */ +extern int grcan_clr_stats(void *d); +/* Set Acceptance filters, provide pointer to "struct grcan_filter" or NULL to disable filtering (let all messages pass) */ +extern int grcan_set_afilter(void *d, const struct grcan_filter *filter); +/* Set Sync Messages RX/TX filters, NULL disables the IRQ completely */ +extern int grcan_set_sfilter(void *d, const struct grcan_filter *filter); +/* Get status register of GRCAN core */ +extern int grcan_get_status(void *d, unsigned int *status); void grcan_register_drv(void); -- 2.7.4 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel