Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:06

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  *  SatCAN FPGA driver
0005  * 
0006  *  COPYRIGHT (c) 2008.
0007  *  Cobham Gaisler AB.
0008  *
0009  * Redistribution and use in source and binary forms, with or without
0010  * modification, are permitted provided that the following conditions
0011  * are met:
0012  * 1. Redistributions of source code must retain the above copyright
0013  *    notice, this list of conditions and the following disclaimer.
0014  * 2. Redistributions in binary form must reproduce the above copyright
0015  *    notice, this list of conditions and the following disclaimer in the
0016  *    documentation and/or other materials provided with the distribution.
0017  *
0018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0028  * POSSIBILITY OF SUCH DAMAGE.
0029  */
0030 
0031 #include <rtems/libio.h>
0032 #include <stdlib.h>
0033 #include <stdio.h>
0034 #include <string.h>
0035 #include <bsp.h>
0036 #include <rtems/bspIo.h> /* printk */
0037 
0038 #include <grlib/satcan.h>
0039 #include <grlib/ambapp.h>
0040 
0041 #include <grlib/grlib_impl.h>
0042 
0043 #ifndef GAISLER_SATCAN
0044 #define GAISLER_SATCAN 0x080
0045 #endif
0046 
0047 #if !defined(SATCAN_DEVNAME) 
0048  #undef SATCAN_DEVNAME
0049  #define SATCAN_DEVNAME "/dev/satcan"
0050 #endif
0051 
0052 /* Enable debug output? */
0053 /* #define DEBUG */ 
0054 
0055 #ifdef DEBUG
0056 #define DBG(x...) printk(x)
0057 #else
0058 #define DBG(x...) 
0059 #endif
0060 
0061 
0062 /* Defines related to DMA */
0063 #define ALIGN_2KMEM 32*1024
0064 #define ALIGN_8KMEM 128*1024
0065 
0066 #define OFFSET_2K_LOW_POS 15
0067 #define OFFSET_8K_LOW_POS 17
0068 
0069 #define DMA_2K_DATA_SELECT (1 << 14)
0070 #define DMA_8K_DATA_SELECT (1 << 16)
0071 
0072 #define DMA_2K_DATA_OFFSET 16*1024
0073 #define DMA_8K_DATA_OFFSET 64*1024
0074 
0075 /* Core register structures and defines */
0076 
0077 /* Indexes to SatCAN registers in satcan array are declared in satcan.h*/
0078 /* Fields for some of the SatCAN FPGA registers */
0079 
0080 /* CmdReg0 */
0081 #define CAN_TODn_Int_sel   (1 << 5)
0082 
0083 /* CmdReg1 */
0084 #define Sel_2k_8kN         (1 << 0)
0085 
0086 /* Read FIFO */
0087 #define FIFO_Full          (1 << 8)
0088 #define FIFO_Empty         (1 << 9)
0089 
0090 /* DMA Ch_Enable */
0091 #define DMA_AutoInitDmaTx  (1 << 3)
0092 #define DMA_EnTx2          (1 << 2)
0093 #define DMA_EnTx1          (1 << 1)
0094 #define DMA_EnRx           (1 << 0)
0095 
0096 /* SatCAN wrapper register fields */
0097 #define CTRL_BT_P     9
0098 #define CTRL_NODENO_P 5
0099 #define CTRL_DIS      (1 << 2)
0100 #define CTRL_DPS_P    1
0101 #define CTRL_RST      (1 << 0)
0102 
0103 #define IRQ_AHB       (1 << 8)
0104 #define IRQ_PPS       (1 << 7)
0105 #define IRQ_M5        (1 << 6)
0106 #define IRQ_M4        (1 << 5)
0107 #define IRQ_M3        (1 << 4)
0108 #define IRQ_M2        (1 << 3)
0109 #define IRQ_M1        (1 << 2)
0110 #define IRQ_SYNC      (1 << 1)
0111 #define IRQ_CAN       (1 << 0)
0112 
0113 #define MSK_AHB       (1 << 8)
0114 #define MSK_PPS       (1 << 7)
0115 #define MSK_M5        (1 << 6)
0116 #define MSK_M4        (1 << 5)
0117 #define MSK_M3        (1 << 4)
0118 #define MSK_M2        (1 << 3)
0119 #define MSK_M1        (1 << 2)
0120 #define MSK_SYNC      (1 << 1)
0121 #define MSK_CAN       (1 << 0)
0122 
0123 
0124 
0125 struct satcan_regs {
0126     volatile unsigned int satcan[32];
0127     volatile unsigned int ctrl;
0128     volatile unsigned int irqpend;
0129     volatile unsigned int irqmask;
0130     volatile unsigned int membase;
0131 };
0132 
0133 
0134 struct satcan_priv {
0135     /* config */
0136     void           *dmaptr;
0137     unsigned char  *alptr;
0138     satcan_config  *cfg;
0139     
0140     /* driver state */
0141     rtems_id       devsem;
0142     rtems_id       txsem;
0143     int            open;
0144     int            txactive;
0145     int            dmaen;
0146     int            doff;
0147     rtems_interval timeout;
0148     int            dmamode;
0149 };
0150 
0151 static struct satcan_regs *regs;
0152 static struct satcan_priv *priv;
0153 
0154 static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0155 static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0156 static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0157 static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0158 static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
0159 static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
0160 
0161 
0162 /*
0163  * almalloc: allocate memory area of size sz aligned on sz boundary 
0164  * alptr: Utilized to return aligned pointer
0165  * ptr:   Unaligned pointer
0166  * sz:    Size of memory area
0167  */
0168 static void almalloc(unsigned char **alptr, void **ptr, int sz)
0169 {
0170   *ptr = rtems_calloc(1,2*sz);
0171   *alptr = (unsigned char *) (((int)*ptr+sz) & ~(sz-1));
0172 }
0173 
0174 static rtems_isr satcan_interrupt_handler(void *v)
0175 {
0176     unsigned int irq;
0177     unsigned int fifo;
0178     
0179     irq = regs->irqpend;
0180     
0181     if (irq & IRQ_AHB && priv->cfg->ahb_irq_callback) {
0182         priv->cfg->ahb_irq_callback();
0183     }
0184     if (irq & IRQ_PPS && priv->cfg->pps_irq_callback) {
0185         priv->cfg->pps_irq_callback();
0186     }
0187     if (irq & IRQ_M5 && priv->cfg->m5_irq_callback) {
0188         priv->cfg->m5_irq_callback();
0189     }
0190     if (irq & IRQ_M4 && priv->cfg->m4_irq_callback) {
0191         priv->cfg->m4_irq_callback();
0192     }
0193     if (irq & IRQ_M3 && priv->cfg->m3_irq_callback) {
0194         priv->cfg->m3_irq_callback();
0195     }
0196     if (irq & IRQ_M2 && priv->cfg->m2_irq_callback) {
0197         priv->cfg->m2_irq_callback();
0198     }
0199     if (irq & IRQ_M1 && priv->cfg->m1_irq_callback) {
0200         priv->cfg->m1_irq_callback();
0201     }
0202     if (irq & IRQ_SYNC && priv->cfg->sync_irq_callback) {
0203         priv->cfg->sync_irq_callback();
0204     }
0205     if (irq & IRQ_CAN) {
0206         fifo = regs->satcan[SATCAN_FIFO];
0207         if (!(fifo & FIFO_Empty) && priv->txactive &&
0208             (((fifo & 0xff) == SATCAN_IRQ_EOD1) || ((fifo & 0xff) == SATCAN_IRQ_EOD2))) { 
0209             rtems_semaphore_release(priv->txsem);
0210         }
0211         if (priv->cfg->can_irq_callback)
0212             priv->cfg->can_irq_callback(fifo);
0213     }
0214 }
0215 
0216 
0217 
0218 static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0219 {
0220     rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
0221     int *value;
0222     rtems_interval *timeout;
0223     satcan_regmod *regmod;
0224 
0225     DBG("SatCAN:  IOCTL %d\n\r", ioarg->command);
0226 
0227     ioarg->ioctl_return = 0;
0228     switch(ioarg->command) {
0229     case SATCAN_IOC_DMA_2K:
0230         DBG("SatCAN: ioctl: setting 2K DMA mode\n\r");
0231         free(priv->dmaptr);
0232         almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
0233         if (priv->dmaptr == NULL) {
0234             printk("SatCAN: Failed to allocate DMA memory\n\r");
0235             return RTEMS_NO_MEMORY;
0236         }
0237 
0238         regs->membase = (unsigned int)priv->alptr;
0239         regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_2K_LOW_POS;
0240         regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] | Sel_2k_8kN;
0241         break;
0242 
0243     case SATCAN_IOC_DMA_8K:
0244         DBG("SatCAN: ioctl: setting 8K DMA mode\n\r");
0245         free(priv->dmaptr);
0246         almalloc(&priv->alptr, &priv->dmaptr, ALIGN_8KMEM);
0247         if (priv->dmaptr == NULL) {
0248             printk("SatCAN: Failed to allocate DMA memory\n\r");
0249             return RTEMS_NO_MEMORY;
0250         }
0251         
0252         regs->membase = (unsigned int)priv->alptr;
0253         regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_8K_LOW_POS;
0254         regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] & ~Sel_2k_8kN;
0255         break;
0256         
0257     case SATCAN_IOC_GET_REG:
0258         /* Get regmod structure from argument */
0259         regmod = (satcan_regmod*)ioarg->buffer;
0260         DBG("SatCAN: ioctl: getting register %d\n\r", regmod->reg);
0261         if (regmod->reg <= SATCAN_FILTER_STOP)
0262             regmod->val = regs->satcan[regmod->reg];
0263         else if (regmod->reg == SATCAN_WCTRL)
0264             regmod->val = regs->ctrl;
0265         else if (regmod->reg == SATCAN_WIPEND)
0266             regmod->val = regs->irqpend;
0267         else if (regmod->reg == SATCAN_WIMASK)
0268             regmod->val = regs->irqmask;
0269         else if (regmod->reg == SATCAN_WAHBADDR)
0270             regmod->val = regs->membase;
0271         else
0272             return RTEMS_INVALID_NAME;
0273         break;
0274 
0275     case SATCAN_IOC_SET_REG:
0276         /* Get regmod structure from argument */
0277         regmod = (satcan_regmod*)ioarg->buffer;
0278         DBG("SatCAN: ioctl: setting register %d, value %x\n\r", 
0279             regmod->reg, regmod->val);
0280         if (regmod->reg <= SATCAN_FILTER_STOP)
0281             regs->satcan[regmod->reg] = regmod->val;
0282         else if (regmod->reg == SATCAN_WCTRL)
0283             regs->ctrl = regmod->val;
0284         else if (regmod->reg == SATCAN_WIPEND)
0285             regs->irqpend = regmod->val;
0286         else if (regmod->reg == SATCAN_WIMASK)
0287             regs->irqmask = regmod->val;
0288         else if (regmod->reg == SATCAN_WAHBADDR)
0289             regs->membase = regmod->val;
0290         else
0291             return RTEMS_INVALID_NAME;
0292         break;
0293 
0294     case SATCAN_IOC_OR_REG:
0295         /* Get regmod structure from argument */
0296         regmod = (satcan_regmod*)ioarg->buffer;
0297         DBG("SatCAN: ioctl: or:ing register %d, with value %x\n\r",
0298             regmod->reg, regmod->val);
0299         if (regmod->reg <= SATCAN_FILTER_STOP)
0300             regs->satcan[regmod->reg] |= regmod->val;
0301         else if (regmod->reg == SATCAN_WCTRL)
0302             regs->ctrl |= regmod->val;
0303         else if (regmod->reg == SATCAN_WIPEND)
0304             regs->irqpend |= regmod->val;
0305         else if (regmod->reg == SATCAN_WIMASK)
0306             regs->irqmask |= regmod->val;
0307         else if (regmod->reg == SATCAN_WAHBADDR)
0308             regs->membase |= regmod->val;
0309         else
0310             return RTEMS_INVALID_NAME;
0311         break;
0312 
0313     case SATCAN_IOC_AND_REG:
0314         /* Get regmod structure from argument */
0315         regmod = (satcan_regmod*)ioarg->buffer;
0316         DBG("SatCAN: ioctl: masking register %d, with value %x\n\r",
0317             regmod->reg, regmod->val);
0318         if (regmod->reg <= SATCAN_FILTER_STOP)
0319             regs->satcan[regmod->reg] &= regmod->val;
0320         else if (regmod->reg == SATCAN_WCTRL)
0321             regs->ctrl &= regmod->val;
0322         else if (regmod->reg == SATCAN_WIPEND)
0323             regs->irqpend &= regmod->val;
0324         else if (regmod->reg == SATCAN_WIMASK)
0325             regs->irqmask &= regmod->val;
0326         else if (regmod->reg == SATCAN_WAHBADDR)
0327             regs->membase &= regmod->val;
0328         else
0329             return RTEMS_INVALID_NAME;
0330         break;
0331 
0332     case SATCAN_IOC_EN_TX1_DIS_TX2:
0333         priv->dmaen = SATCAN_DMA_ENABLE_TX1;
0334         break;
0335 
0336     case SATCAN_IOC_EN_TX2_DIS_TX1:
0337         priv->dmaen = SATCAN_DMA_ENABLE_TX2;
0338         break;
0339 
0340     case SATCAN_IOC_GET_DMA_MODE:
0341         value = (int*)ioarg->buffer;
0342         *value = priv->dmamode;
0343         break;
0344         
0345     case SATCAN_IOC_SET_DMA_MODE:
0346         value = (int*)ioarg->buffer;
0347         if (*value != SATCAN_DMA_MODE_USER && *value != SATCAN_DMA_MODE_SYSTEM) {
0348             DBG("SatCAN: ioctl: invalid DMA mode\n\r");
0349             return RTEMS_INVALID_NAME;
0350         }
0351         priv->dmamode = *value;
0352         break;
0353 
0354     case SATCAN_IOC_ACTIVATE_DMA:
0355         if (priv->dmamode != SATCAN_DMA_MODE_USER) {
0356             DBG("SatCAN: ioctl: ACTIVATE_DMA: not in user mode\n\r");
0357             return RTEMS_INVALID_NAME;
0358         }
0359         value = (int*)ioarg->buffer;
0360         if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
0361             DBG("SatCAN: ioctl: ACTIVATE_DMA: Illegal channel\n\r");
0362             return RTEMS_INVALID_NAME;
0363         }
0364         regs->satcan[SATCAN_DMA] |= *value << 1;
0365         break;
0366 
0367     case SATCAN_IOC_DEACTIVATE_DMA:
0368         if (priv->dmamode != SATCAN_DMA_MODE_USER) {
0369             DBG("SatCAN: ioctl: DEACTIVATE_DMA: not in user mode\n\r");
0370             return RTEMS_INVALID_NAME;
0371         }
0372         value = (int*)ioarg->buffer;
0373         if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
0374             DBG("SatCAN: ioctl: DEACTIVATE_DMA: Illegal channel\n\r");
0375             return RTEMS_INVALID_NAME;
0376         }
0377         regs->satcan[SATCAN_DMA] &= ~(*value << 1);
0378         break;  
0379 
0380     case SATCAN_IOC_GET_DOFFSET:
0381         value = (int*)ioarg->buffer;
0382         *value = priv->doff;
0383         break;
0384     
0385     case SATCAN_IOC_SET_DOFFSET:
0386         value = (int*)ioarg->buffer;
0387         priv->doff = *value;
0388         break;
0389         
0390     case SATCAN_IOC_GET_TIMEOUT:
0391         timeout = (rtems_interval*)ioarg->buffer;
0392         *timeout = priv->timeout;
0393         break;
0394 
0395     case SATCAN_IOC_SET_TIMEOUT:
0396         timeout = (rtems_interval*)ioarg->buffer;
0397         priv->timeout = *timeout;
0398         break;
0399 
0400     default:
0401         return RTEMS_NOT_DEFINED;
0402     }
0403 
0404     return RTEMS_SUCCESSFUL;
0405 }
0406 
0407 static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0408 {
0409     int i;
0410     int doff;
0411     int msgindex;
0412     int messages;
0413     rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
0414     satcan_msg *msgs;
0415     rtems_status_code status;
0416     
0417     DBG("SatCAN: Writing %d bytes from %p\n\r",rw_args->count,rw_args->buffer);
0418 
0419     if ((rw_args->count < sizeof(satcan_msg)) || (!rw_args->buffer)) {
0420         DBG("SatCAN: write: returning EINVAL\n\r");
0421         return RTEMS_INVALID_NAME; /* EINVAL */
0422     }
0423 
0424     messages = rw_args->count / sizeof(satcan_msg);
0425     msgs = (satcan_msg*)rw_args->buffer;
0426 
0427     /* Check that size matches any number of satcan_msg */
0428     if (rw_args->count % sizeof(satcan_msg)) {
0429         DBG("SatCAN: write: count can not be evenly divided with satcan_msg size\n\r");
0430         return RTEMS_INVALID_NAME; /* EINVAL */
0431     }
0432 
0433 
0434     /* DMA channel must be set if we are in system DMA mode */
0435     DBG("SatCAN: write: dma channel select is %x\n\r", priv->dmaen);
0436     if (!priv->dmaen && priv->dmamode == SATCAN_DMA_MODE_SYSTEM)
0437         return RTEMS_INVALID_NAME; /* EINVAL */
0438 
0439     /* DMA must not be active */
0440     if (regs->satcan[SATCAN_DMA] & (DMA_EnTx1 | DMA_EnTx2 | DMA_AutoInitDmaTx)) {
0441         DBG("SatCAN: write: DMA was active\n\r");
0442         rw_args->bytes_moved = 0;
0443         return RTEMS_IO_ERROR; /* EIO */
0444     }       
0445 
0446     doff = regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_OFFSET : DMA_8K_DATA_OFFSET;
0447 
0448     for (msgindex = 0; msgindex < messages; msgindex++) {
0449         /* Place header in DMA area */
0450         for (i = 0; i < SATCAN_HEADER_SIZE; i++) {
0451             priv->alptr[priv->doff+8*msgindex+i] = msgs[msgindex].header[i];
0452         }
0453 
0454         /* Place data in DMA area */
0455         for (i = 0; i < SATCAN_PAYLOAD_SIZE; i++)
0456             priv->alptr[priv->doff+doff+8*msgindex+i] = msgs[msgindex].payload[i];
0457     }
0458 
0459     if ((priv->dmaen & SATCAN_DMA_ENABLE_TX1) ||  priv->dmamode == SATCAN_DMA_MODE_USER) {
0460         regs->satcan[SATCAN_DMA_TX_1_CUR] = 0;
0461         regs->satcan[SATCAN_DMA_TX_1_END] = messages<<3; 
0462     }
0463 
0464     if ((priv->dmaen & SATCAN_DMA_ENABLE_TX2) || priv->dmamode == SATCAN_DMA_MODE_USER) {
0465         regs->satcan[SATCAN_DMA_TX_2_CUR] = 0;
0466         regs->satcan[SATCAN_DMA_TX_2_END] = messages<<3; 
0467     }
0468 
0469     /* If we are in DMA user mode we are done here, otherwise we block */
0470     if (priv->dmamode == SATCAN_DMA_MODE_SYSTEM) {
0471         priv->txactive = 1;
0472 
0473         /* Enable DMA */
0474         regs->satcan[SATCAN_DMA] |= priv->dmaen << 1;
0475         
0476         /* Wait for TX interrupt */
0477         status = rtems_semaphore_obtain(priv->txsem, RTEMS_WAIT, priv->timeout);
0478         
0479         priv->txactive = 0;
0480 
0481         /* Disable activated Tx DMA */
0482         regs->satcan[SATCAN_DMA] &= ~(priv->dmaen << 1);
0483 
0484         if (status != RTEMS_SUCCESSFUL) {
0485             rw_args->bytes_moved = 0;
0486             return status;
0487         }
0488     }
0489 
0490     rw_args->bytes_moved = rw_args->count;
0491     
0492     return RTEMS_SUCCESSFUL;
0493 }
0494 
0495 static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0496 {
0497     char *buf;
0498     int i;
0499     int canid;
0500     int messages;
0501     rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
0502     satcan_msg *ret;
0503 
0504     /* Check that there is room for the return */
0505     if (rw_args->count < sizeof(satcan_msg)) {
0506         DBG("SatCAN: read: length of buffer must be at least %d, current is %d\n\r",
0507             sizeof(satcan_msg) + sizeof(int), rw_args->count);
0508         return RTEMS_INVALID_NAME; /* -EINVAL */
0509     }
0510     
0511     /* Check that size matches any number of satcan_msg */
0512     if (rw_args->count % sizeof(satcan_msg)) {
0513         DBG("SatCAN: read: count can not be evenly divided with satcan_msg size\n\r");
0514         return RTEMS_INVALID_NAME; /* EINVAL */
0515     }
0516     
0517     messages = rw_args->count / sizeof(satcan_msg);
0518     ret = (satcan_msg*)rw_args->buffer;
0519 
0520     DBG("SatCAN: read: reading %d messages to %p\n\r", messages, ret);
0521     
0522     for (i = 0; i < messages; i++) {
0523         canid = (ret[i].header[1] << 8) | ret[i].header[0];
0524     
0525         /* Copy message header from DMA header area to buffer */
0526         buf = (char*)((int)priv->alptr | (canid << 3));
0527         memcpy(ret[i].header, buf, SATCAN_HEADER_SIZE);
0528 
0529         DBG("SatCAN: read: copied header from %p to %p\n\r", buf, ret[i].header);
0530 
0531         /* Clear New Message Marker */
0532         buf[SATCAN_HEADER_NMM_POS] = 0;
0533         
0534         /* Copy message payload from DMA data area to buffer */
0535         buf = (char*)((int)buf | 
0536                   (regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_SELECT : DMA_8K_DATA_SELECT));
0537         memcpy(ret[i].payload, buf, SATCAN_PAYLOAD_SIZE);
0538     
0539         DBG("SatCAN: read: copied payload from %p to %p\n\r", buf, ret[i].payload);
0540     }
0541     rw_args->bytes_moved = rw_args->count;
0542 
0543     return RTEMS_SUCCESSFUL;
0544 }
0545 
0546 
0547 static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0548 {
0549     DBG("SatCAN: Closing %d\n\r",minor);
0550 
0551     if (priv->open) {
0552         regs->irqmask = 0;
0553         regs->satcan[SATCAN_INT_EN] = 0;
0554         regs->satcan[SATCAN_RX] = 0;
0555         regs->satcan[SATCAN_DMA] = 0;
0556         priv->open = 0;
0557         priv->dmaen = 0;
0558         priv->doff = 0;
0559         priv->timeout = RTEMS_NO_TIMEOUT;
0560         priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
0561     }
0562 
0563     return RTEMS_SUCCESSFUL;
0564 }
0565 
0566 
0567 static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0568 {
0569     DBG("SatCAN: Opening %d\n\r",minor);
0570     
0571     rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0572     if (priv->open) {
0573         rtems_semaphore_release(priv->devsem);
0574         return RTEMS_RESOURCE_IN_USE; /* EBUSY */
0575     }
0576     priv->open = 1;
0577     rtems_semaphore_release(priv->devsem);
0578 
0579     /* Enable AHB and CAN IRQs in wrapper and EOD1, EOD2 and CAN critical  IRQs in SatCAN core */
0580     regs->irqmask = MSK_AHB | MSK_CAN;
0581     regs->satcan[SATCAN_INT_EN] = ((1 << SATCAN_IRQ_EOD1) | (1 << SATCAN_IRQ_EOD2) |
0582                        (1 << SATCAN_IRQ_CRITICAL));
0583 
0584     /* Select can_int as IRQ source */
0585     regs->satcan[SATCAN_CMD0] = CAN_TODn_Int_sel;
0586     /* CAN RX DMA Enable */
0587     regs->satcan[SATCAN_DMA] = 1;
0588     /* CAN RX Enable */
0589     regs->satcan[SATCAN_RX] = 1;
0590 
0591     DBG("SatCAN: Opening %d success\n\r",minor);
0592 
0593     return RTEMS_SUCCESSFUL;
0594 }
0595 
0596 static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0597 {
0598     struct ambapp_ahb_info d;
0599     char fs_name[20];
0600     rtems_status_code status;
0601 
0602     DBG("SatCAN: Initialize..\n\r");
0603 
0604     strcpy(fs_name, SATCAN_DEVNAME);
0605 
0606     /* Find core and initialize register pointer */
0607     if (!ambapp_find_ahbslv(ambapp_plb(), VENDOR_GAISLER, GAISLER_SATCAN, &d)) {
0608         printk("SatCAN: Failed to find SatCAN core\n\r");
0609         return -1;
0610     }
0611 
0612     status = rtems_io_register_name(fs_name, major, minor);
0613     if (RTEMS_SUCCESSFUL != status)
0614         rtems_fatal_error_occurred(status);
0615 
0616     regs = (struct satcan_regs*)d.start[0];
0617         
0618     /* Set node number and DPS */
0619     regs->ctrl |= ((priv->cfg->nodeno & 0xf) << 5) | (priv->cfg->dps << 1);
0620 
0621     /* Reset core */
0622     regs->ctrl |= CTRL_RST;
0623 
0624     /* Allocate DMA area */
0625     almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
0626     if (priv->dmaptr == NULL) {
0627         printk("SatCAN: Failed to allocate DMA memory\n\r");
0628         free(priv->cfg);
0629         free(priv);
0630         return -1; 
0631     }
0632     
0633     /* Wait until core reset has completed */
0634     while (regs->ctrl & CTRL_RST)
0635         ;
0636 
0637     /* Initialize core registers, default is 2K messages */
0638     regs->membase = (unsigned int)priv->alptr;
0639     regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> 15;
0640     
0641     DBG("regs->membase = %x\n\r", (unsigned int)priv->alptr);
0642     DBG("regs->satcan[SATCAN_RAM_BASE] = %x\n\r", (unsigned int)priv->alptr >> 15);
0643 
0644     status = rtems_semaphore_create(
0645         rtems_build_name('S', 'd', 'v', '0'),
0646         1,
0647         RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
0648         RTEMS_NO_PRIORITY_CEILING,
0649         0, 
0650         &priv->devsem);
0651     if (status != RTEMS_SUCCESSFUL) {
0652         printk("SatCAN: Failed to create dev semaphore (%d)\n\r", status);
0653         free(priv->cfg);
0654         free(priv);
0655         return RTEMS_UNSATISFIED;
0656     }
0657     status = rtems_semaphore_create(
0658         rtems_build_name('S', 't', 'x', '0'),
0659         0, 
0660         RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
0661         RTEMS_NO_PRIORITY_CEILING,
0662         0, 
0663         &priv->txsem);
0664     if (status != RTEMS_SUCCESSFUL) {
0665       printk("SatCAN: Failed to create tx semaphore (%d)\n\r", status);
0666       free(priv->cfg);
0667       free(priv);
0668       return RTEMS_UNSATISFIED;
0669     }
0670 
0671     priv->txactive = 0;
0672     priv->open = 0;
0673     priv->dmaen = 0;
0674     priv->doff = 0;
0675     priv->timeout = RTEMS_NO_TIMEOUT;
0676     priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
0677 
0678     /* Register interrupt handler */
0679     rtems_interrupt_handler_install(d.common.irq, "satcan",
0680             RTEMS_INTERRUPT_SHARED,
0681             satcan_interrupt_handler, NULL);
0682 
0683     return RTEMS_SUCCESSFUL;
0684 }
0685 
0686 
0687 
0688 #define SATCAN_DRIVER_TABLE_ENTRY { satcan_initialize, satcan_open, satcan_close, satcan_read, satcan_write, satcan_ioctl }
0689 
0690 static rtems_driver_address_table satcan_driver = SATCAN_DRIVER_TABLE_ENTRY;
0691 
0692 int satcan_register(satcan_config *conf)
0693 {
0694     rtems_status_code r;
0695     rtems_device_major_number m;
0696 
0697     DBG("SatCAN: satcan_register called\n\r");
0698 
0699     /* Create private structure */
0700     if ((priv = grlib_malloc(sizeof(*priv))) == NULL) {
0701         printk("SatCAN driver could not allocate memory for priv structure\n\r");
0702         return -1;
0703     }
0704 
0705     DBG("SatCAN: Creating local copy of config structure\n\r");
0706     if ((priv->cfg = grlib_malloc(sizeof(*priv->cfg))) == NULL) {
0707         printk("SatCAN driver could not allocate memory for cfg structure\n\r");
0708         return 1;
0709     }
0710     memcpy(priv->cfg, conf, sizeof(satcan_config));
0711 
0712     if ((r = rtems_io_register_driver(0, &satcan_driver, &m)) == RTEMS_SUCCESSFUL) {
0713         DBG("SatCAN driver successfully registered, major: %d\n\r", m);
0714     } else {
0715         switch(r) {
0716         case RTEMS_TOO_MANY:
0717             printk("SatCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
0718         case RTEMS_INVALID_NUMBER:  
0719             printk("SatCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
0720         case RTEMS_RESOURCE_IN_USE:
0721             printk("SatCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
0722         default:
0723             printk("SatCAN rtems_io_register_driver failed\n\r");
0724         }
0725         return 1;
0726     }
0727 
0728     return 0;
0729 }