source: rtems/c/src/lib/libbsp/sparc/shared/can/satcan.c @ 4a7d1026

4.115
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

  • Property mode set to 100644
File size: 20.0 KB
Line 
1/*
2 *  SatCAN FPGA driver
3 *
4 *  COPYRIGHT (c) 2008.
5 *  Cobham Gaisler AB.
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.org/license/LICENSE.
10 */
11
12#include <rtems/libio.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <bsp.h>
17#include <rtems/bspIo.h> /* printk */
18
19#include <bsp/satcan.h>
20#include <ambapp.h>
21
22#ifndef GAISLER_SATCAN
23#define GAISLER_SATCAN 0x080
24#endif
25
26#if !defined(SATCAN_DEVNAME)
27 #undef SATCAN_DEVNAME
28 #define SATCAN_DEVNAME "/dev/satcan"
29#endif
30
31/* Enable debug output? */
32/* #define DEBUG */
33
34#ifdef DEBUG
35#define DBG(x...) printk(x)
36#else
37#define DBG(x...)
38#endif
39
40
41/* Defines related to DMA */
42#define ALIGN_2KMEM 32*1024
43#define ALIGN_8KMEM 128*1024
44
45#define OFFSET_2K_LOW_POS 15
46#define OFFSET_8K_LOW_POS 17
47
48#define DMA_2K_DATA_SELECT (1 << 14)
49#define DMA_8K_DATA_SELECT (1 << 16)
50
51#define DMA_2K_DATA_OFFSET 16*1024
52#define DMA_8K_DATA_OFFSET 64*1024
53
54/* Core register structures and defines */
55
56/* Indexes to SatCAN registers in satcan array are declared in satcan.h*/
57/* Fields for some of the SatCAN FPGA registers */
58
59/* CmdReg0 */
60#define CAN_TODn_Int_sel   (1 << 5)
61
62/* CmdReg1 */
63#define Sel_2k_8kN         (1 << 0)
64
65/* Read FIFO */
66#define FIFO_Full          (1 << 8)
67#define FIFO_Empty         (1 << 9)
68
69/* DMA Ch_Enable */
70#define DMA_AutoInitDmaTx  (1 << 3)
71#define DMA_EnTx2          (1 << 2)
72#define DMA_EnTx1          (1 << 1)
73#define DMA_EnRx           (1 << 0)
74
75/* SatCAN wrapper register fields */
76#define CTRL_BT_P     9
77#define CTRL_NODENO_P 5
78#define CTRL_DIS      (1 << 2)
79#define CTRL_DPS_P    1
80#define CTRL_RST      (1 << 0)
81
82#define IRQ_AHB       (1 << 8)
83#define IRQ_PPS       (1 << 7)
84#define IRQ_M5        (1 << 6)
85#define IRQ_M4        (1 << 5)
86#define IRQ_M3        (1 << 4)
87#define IRQ_M2        (1 << 3)
88#define IRQ_M1        (1 << 2)
89#define IRQ_SYNC      (1 << 1)
90#define IRQ_CAN       (1 << 0)
91
92#define MSK_AHB       (1 << 8)
93#define MSK_PPS       (1 << 7)
94#define MSK_M5        (1 << 6)
95#define MSK_M4        (1 << 5)
96#define MSK_M3        (1 << 4)
97#define MSK_M2        (1 << 3)
98#define MSK_M1        (1 << 2)
99#define MSK_SYNC      (1 << 1)
100#define MSK_CAN       (1 << 0)
101
102
103
104struct satcan_regs {
105        volatile unsigned int satcan[32];
106        volatile unsigned int ctrl;
107        volatile unsigned int irqpend;
108        volatile unsigned int irqmask;
109        volatile unsigned int membase;
110};
111
112
113struct satcan_priv {
114        /* config */
115        void           *dmaptr;
116        unsigned char  *alptr;
117        satcan_config  *cfg;
118       
119        /* driver state */
120        rtems_id       devsem;
121        rtems_id       txsem;
122        int            open;
123        int            txactive;
124        int            dmaen;
125        int            doff;
126        rtems_interval timeout;
127        int            dmamode;
128};
129
130static struct satcan_regs *regs;
131static struct satcan_priv *priv;
132
133static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
134static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
135static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
136static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
137static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg);
138static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number unused, void *arg);
139
140
141/*
142 * almalloc: allocate memory area of size sz aligned on sz boundary
143 * alptr: Utilized to return aligned pointer
144 * ptr:   Unaligned pointer
145 * sz:    Size of memory area
146 */
147static void almalloc(unsigned char **alptr, void **ptr, int sz)
148{
149  *ptr = calloc(1,2*sz);
150  *alptr = (unsigned char *) (((int)*ptr+sz) & ~(sz-1));
151}
152
153static rtems_isr satcan_interrupt_handler(rtems_vector_number v)
154{
155        unsigned int irq;
156        unsigned int fifo;
157       
158        irq = regs->irqpend;
159       
160        if (irq & IRQ_AHB && priv->cfg->ahb_irq_callback) {
161                priv->cfg->ahb_irq_callback();
162        }
163        if (irq & IRQ_PPS && priv->cfg->pps_irq_callback) {
164                priv->cfg->pps_irq_callback();
165        }
166        if (irq & IRQ_M5 && priv->cfg->m5_irq_callback) {
167                priv->cfg->m5_irq_callback();
168        }
169        if (irq & IRQ_M4 && priv->cfg->m4_irq_callback) {
170                priv->cfg->m4_irq_callback();
171        }
172        if (irq & IRQ_M3 && priv->cfg->m3_irq_callback) {
173                priv->cfg->m3_irq_callback();
174        }
175        if (irq & IRQ_M2 && priv->cfg->m2_irq_callback) {
176                priv->cfg->m2_irq_callback();
177        }
178        if (irq & IRQ_M1 && priv->cfg->m1_irq_callback) {
179                priv->cfg->m1_irq_callback();
180        }
181        if (irq & IRQ_SYNC && priv->cfg->sync_irq_callback) {
182                priv->cfg->sync_irq_callback();
183        }
184        if (irq & IRQ_CAN) {
185                fifo = regs->satcan[SATCAN_FIFO];
186                if (!(fifo & FIFO_Empty) && priv->txactive &&
187                    (((fifo & 0xff) == SATCAN_IRQ_EOD1) || ((fifo & 0xff) == SATCAN_IRQ_EOD2))) {
188                        rtems_semaphore_release(priv->txsem);
189                }
190                if (priv->cfg->can_irq_callback)
191                        priv->cfg->can_irq_callback(fifo);
192        }
193}
194
195
196
197static rtems_device_driver satcan_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
198{
199        rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t*)arg;
200        int *value;
201        rtems_interval *timeout;
202        satcan_regmod *regmod;
203
204        DBG("SatCAN:  IOCTL %d\n\r", ioarg->command);
205
206        ioarg->ioctl_return = 0;
207        switch(ioarg->command) {
208        case SATCAN_IOC_DMA_2K:
209                DBG("SatCAN: ioctl: setting 2K DMA mode\n\r");
210                free(priv->dmaptr);
211                almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
212                if (priv->dmaptr == NULL) {
213                        printk("SatCAN: Failed to allocate DMA memory\n\r");
214                        return RTEMS_NO_MEMORY;
215                }
216
217                regs->membase = (unsigned int)priv->alptr;
218                regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_2K_LOW_POS;
219                regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] | Sel_2k_8kN;
220                break;
221
222        case SATCAN_IOC_DMA_8K:
223                DBG("SatCAN: ioctl: setting 8K DMA mode\n\r");
224                free(priv->dmaptr);
225                almalloc(&priv->alptr, &priv->dmaptr, ALIGN_8KMEM);
226                if (priv->dmaptr == NULL) {
227                        printk("SatCAN: Failed to allocate DMA memory\n\r");
228                        return RTEMS_NO_MEMORY;
229                }
230               
231                regs->membase = (unsigned int)priv->alptr;
232                regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> OFFSET_8K_LOW_POS;
233                regs->satcan[SATCAN_CMD1] = regs->satcan[SATCAN_CMD1] & ~Sel_2k_8kN;
234                break;
235               
236        case SATCAN_IOC_GET_REG:
237                /* Get regmod structure from argument */
238                regmod = (satcan_regmod*)ioarg->buffer;
239                DBG("SatCAN: ioctl: getting register %d\n\r", regmod->reg);
240                if (regmod->reg < 0)
241                        return RTEMS_INVALID_NAME;
242                else if (regmod->reg <= SATCAN_FILTER_STOP)
243                        regmod->val = regs->satcan[regmod->reg];
244                else if (regmod->reg == SATCAN_WCTRL)
245                        regmod->val = regs->ctrl;
246                else if (regmod->reg == SATCAN_WIPEND)
247                        regmod->val = regs->irqpend;
248                else if (regmod->reg == SATCAN_WIMASK)
249                        regmod->val = regs->irqmask;
250                else if (regmod->reg == SATCAN_WAHBADDR)
251                        regmod->val = regs->membase;
252                else
253                        return RTEMS_INVALID_NAME;
254                break;
255
256        case SATCAN_IOC_SET_REG:
257                /* Get regmod structure from argument */
258                regmod = (satcan_regmod*)ioarg->buffer;
259                DBG("SatCAN: ioctl: setting register %d, value %x\n\r",
260                    regmod->reg, regmod->val);
261                if (regmod->reg < 0)
262                        return RTEMS_INVALID_NAME;
263                else if (regmod->reg <= SATCAN_FILTER_STOP)
264                        regs->satcan[regmod->reg] = regmod->val;
265                else if (regmod->reg == SATCAN_WCTRL)
266                        regs->ctrl = regmod->val;
267                else if (regmod->reg == SATCAN_WIPEND)
268                        regs->irqpend = regmod->val;
269                else if (regmod->reg == SATCAN_WIMASK)
270                        regs->irqmask = regmod->val;
271                else if (regmod->reg == SATCAN_WAHBADDR)
272                        regs->membase = regmod->val;
273                else
274                        return RTEMS_INVALID_NAME;
275                break;
276
277        case SATCAN_IOC_OR_REG:
278                /* Get regmod structure from argument */
279                regmod = (satcan_regmod*)ioarg->buffer;
280                DBG("SatCAN: ioctl: or:ing register %d, with value %x\n\r",
281                    regmod->reg, regmod->val);
282                if (regmod->reg < 0)
283                        return RTEMS_INVALID_NAME;
284                else if (regmod->reg <= SATCAN_FILTER_STOP)
285                        regs->satcan[regmod->reg] |= regmod->val;
286                else if (regmod->reg == SATCAN_WCTRL)
287                        regs->ctrl |= regmod->val;
288                else if (regmod->reg == SATCAN_WIPEND)
289                        regs->irqpend |= regmod->val;
290                else if (regmod->reg == SATCAN_WIMASK)
291                        regs->irqmask |= regmod->val;
292                else if (regmod->reg == SATCAN_WAHBADDR)
293                        regs->membase |= regmod->val;
294                else
295                        return RTEMS_INVALID_NAME;
296                break;
297
298        case SATCAN_IOC_AND_REG:
299                /* Get regmod structure from argument */
300                regmod = (satcan_regmod*)ioarg->buffer;
301                DBG("SatCAN: ioctl: masking register %d, with value %x\n\r",
302                    regmod->reg, regmod->val);
303                if (regmod->reg < 0)
304                        return RTEMS_INVALID_NAME;
305                else if (regmod->reg <= SATCAN_FILTER_STOP)
306                        regs->satcan[regmod->reg] &= regmod->val;
307                else if (regmod->reg == SATCAN_WCTRL)
308                        regs->ctrl &= regmod->val;
309                else if (regmod->reg == SATCAN_WIPEND)
310                        regs->irqpend &= regmod->val;
311                else if (regmod->reg == SATCAN_WIMASK)
312                        regs->irqmask &= regmod->val;
313                else if (regmod->reg == SATCAN_WAHBADDR)
314                        regs->membase &= regmod->val;
315                else
316                        return RTEMS_INVALID_NAME;
317                break;
318
319        case SATCAN_IOC_EN_TX1_DIS_TX2:
320                priv->dmaen = SATCAN_DMA_ENABLE_TX1;
321                break;
322
323        case SATCAN_IOC_EN_TX2_DIS_TX1:
324                priv->dmaen = SATCAN_DMA_ENABLE_TX2;
325                break;
326
327        case SATCAN_IOC_GET_DMA_MODE:
328                value = (int*)ioarg->buffer;
329                *value = priv->dmamode;
330                break;
331               
332        case SATCAN_IOC_SET_DMA_MODE:
333                value = (int*)ioarg->buffer;
334                if (*value != SATCAN_DMA_MODE_USER && *value != SATCAN_DMA_MODE_SYSTEM) {
335                        DBG("SatCAN: ioctl: invalid DMA mode\n\r");
336                        return RTEMS_INVALID_NAME;
337                }
338                priv->dmamode = *value;
339                break;
340
341        case SATCAN_IOC_ACTIVATE_DMA:
342                if (priv->dmamode != SATCAN_DMA_MODE_USER) {
343                        DBG("SatCAN: ioctl: ACTIVATE_DMA: not in user mode\n\r");
344                        return RTEMS_INVALID_NAME;
345                }
346                value = (int*)ioarg->buffer;
347                if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
348                        DBG("SatCAN: ioctl: ACTIVATE_DMA: Illegal channel\n\r");
349                        return RTEMS_INVALID_NAME;
350                }
351                regs->satcan[SATCAN_DMA] |= *value << 1;
352                break;
353
354        case SATCAN_IOC_DEACTIVATE_DMA:
355                if (priv->dmamode != SATCAN_DMA_MODE_USER) {
356                        DBG("SatCAN: ioctl: DEACTIVATE_DMA: not in user mode\n\r");
357                        return RTEMS_INVALID_NAME;
358                }
359                value = (int*)ioarg->buffer;
360                if (*value != SATCAN_DMA_ENABLE_TX1 && *value != SATCAN_DMA_ENABLE_TX2) {
361                        DBG("SatCAN: ioctl: DEACTIVATE_DMA: Illegal channel\n\r");
362                        return RTEMS_INVALID_NAME;
363                }
364                regs->satcan[SATCAN_DMA] &= ~(*value << 1);
365                break; 
366
367        case SATCAN_IOC_GET_DOFFSET:
368                value = (int*)ioarg->buffer;
369                *value = priv->doff;
370                break;
371       
372        case SATCAN_IOC_SET_DOFFSET:
373                value = (int*)ioarg->buffer;
374                priv->doff = *value;
375                break;
376               
377        case SATCAN_IOC_GET_TIMEOUT:
378                timeout = (rtems_interval*)ioarg->buffer;
379                *timeout = priv->timeout;
380                break;
381
382        case SATCAN_IOC_SET_TIMEOUT:
383                timeout = (rtems_interval*)ioarg->buffer;
384                priv->timeout = *timeout;
385                break;
386
387        default:
388                return RTEMS_NOT_DEFINED;
389        }
390
391        return RTEMS_SUCCESSFUL;
392}
393
394static rtems_device_driver satcan_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
395{
396        int i;
397        int doff;
398        int msgindex;
399        int messages;
400        rtems_libio_rw_args_t *rw_args=(rtems_libio_rw_args_t *) arg;
401        satcan_msg *msgs;
402        rtems_status_code status;
403       
404        DBG("SatCAN: Writing %d bytes from %p\n\r",rw_args->count,rw_args->buffer);
405
406        if ((rw_args->count < sizeof(satcan_msg)) || (!rw_args->buffer)) {
407                DBG("SatCAN: write: returning EINVAL\n\r");
408                return RTEMS_INVALID_NAME; /* EINVAL */
409        }
410
411        messages = rw_args->count / sizeof(satcan_msg);
412        msgs = (satcan_msg*)rw_args->buffer;
413
414        /* Check that size matches any number of satcan_msg */
415        if (rw_args->count % sizeof(satcan_msg)) {
416                DBG("SatCAN: write: count can not be evenly divided with satcan_msg size\n\r");
417                return RTEMS_INVALID_NAME; /* EINVAL */
418        }
419
420
421        /* DMA channel must be set if we are in system DMA mode */
422        DBG("SatCAN: write: dma channel select is %x\n\r", priv->dmaen);
423        if (!priv->dmaen && priv->dmamode == SATCAN_DMA_MODE_SYSTEM)
424                return RTEMS_INVALID_NAME; /* EINVAL */
425
426        /* DMA must not be active */
427        if (regs->satcan[SATCAN_DMA] & (DMA_EnTx1 | DMA_EnTx2 | DMA_AutoInitDmaTx)) {
428                DBG("SatCAN: write: DMA was active\n\r");
429                rw_args->bytes_moved = 0;
430                return RTEMS_IO_ERROR; /* EIO */
431        }               
432
433        doff = regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_OFFSET : DMA_8K_DATA_OFFSET;
434
435        for (msgindex = 0; msgindex < messages; msgindex++) {
436                /* Place header in DMA area */
437                for (i = 0; i < SATCAN_HEADER_SIZE; i++) {
438                        priv->alptr[priv->doff+8*msgindex+i] = msgs[msgindex].header[i];
439                }
440
441                /* Place data in DMA area */
442                for (i = 0; i < SATCAN_PAYLOAD_SIZE; i++)
443                        priv->alptr[priv->doff+doff+8*msgindex+i] = msgs[msgindex].payload[i];
444        }
445
446        if ((priv->dmaen & SATCAN_DMA_ENABLE_TX1) ||  priv->dmamode == SATCAN_DMA_MODE_USER) {
447                regs->satcan[SATCAN_DMA_TX_1_CUR] = 0;
448                regs->satcan[SATCAN_DMA_TX_1_END] = messages<<3;
449        }
450
451        if ((priv->dmaen & SATCAN_DMA_ENABLE_TX2) || priv->dmamode == SATCAN_DMA_MODE_USER) {
452                regs->satcan[SATCAN_DMA_TX_2_CUR] = 0;
453                regs->satcan[SATCAN_DMA_TX_2_END] = messages<<3;
454        }
455
456        /* If we are in DMA user mode we are done here, otherwise we block */
457        if (priv->dmamode == SATCAN_DMA_MODE_SYSTEM) {
458                priv->txactive = 1;
459
460                /* Enable DMA */
461                regs->satcan[SATCAN_DMA] |= priv->dmaen << 1;
462               
463                /* Wait for TX interrupt */
464                status = rtems_semaphore_obtain(priv->txsem, RTEMS_WAIT, priv->timeout);
465               
466                priv->txactive = 0;
467
468                /* Disable activated Tx DMA */
469                regs->satcan[SATCAN_DMA] &= ~(priv->dmaen << 1);
470
471                if (status != RTEMS_SUCCESSFUL) {
472                        rw_args->bytes_moved = 0;
473                        return status;
474                }
475        }
476
477        rw_args->bytes_moved = rw_args->count;
478       
479        return RTEMS_SUCCESSFUL;
480}
481
482static rtems_device_driver satcan_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
483{
484        char *buf;
485        int i;
486        int canid;
487        int messages;
488        rtems_libio_rw_args_t *rw_args = (rtems_libio_rw_args_t*)arg;
489        satcan_msg *ret;
490
491        /* Check that there is room for the return */
492        if (rw_args->count < sizeof(satcan_msg)) {
493                DBG("SatCAN: read: length of buffer must be at least %d, current is %d\n\r",
494                    sizeof(satcan_msg) + sizeof(int), rw_args->count);
495                return RTEMS_INVALID_NAME; /* -EINVAL */
496        }
497       
498        /* Check that size matches any number of satcan_msg */
499        if (rw_args->count % sizeof(satcan_msg)) {
500                DBG("SatCAN: read: count can not be evenly divided with satcan_msg size\n\r");
501                return RTEMS_INVALID_NAME; /* EINVAL */
502        }
503       
504        messages = rw_args->count / sizeof(satcan_msg);
505        ret = (satcan_msg*)rw_args->buffer;
506
507        DBG("SatCAN: read: reading %d messages to %p\n\r", messages, ret);
508       
509        for (i = 0; i < messages; i++) {
510                canid = (ret[i].header[1] << 8) | ret[i].header[0];
511       
512                /* Copy message header from DMA header area to buffer */
513                buf = (char*)((int)priv->alptr | (canid << 3));
514                memcpy(ret[i].header, buf, SATCAN_HEADER_SIZE);
515
516                DBG("SatCAN: read: copied header from %p to %p\n\r", buf, ret[i].header);
517
518                /* Clear New Message Marker */
519                buf[SATCAN_HEADER_NMM_POS] = 0;
520               
521                /* Copy message payload from DMA data area to buffer */
522                buf = (char*)((int)buf |
523                              (regs->satcan[SATCAN_CMD1] & Sel_2k_8kN ? DMA_2K_DATA_SELECT : DMA_8K_DATA_SELECT));
524                memcpy(ret[i].payload, buf, SATCAN_PAYLOAD_SIZE);
525       
526                DBG("SatCAN: read: copied payload from %p to %p\n\r", buf, ret[i].payload);
527        }
528        rw_args->bytes_moved = rw_args->count;
529
530        return RTEMS_SUCCESSFUL;
531}
532
533
534static rtems_device_driver satcan_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
535{
536        DBG("SatCAN: Closing %d\n\r",minor);
537
538        if (priv->open) {
539                regs->irqmask = 0;
540                regs->satcan[SATCAN_INT_EN] = 0;
541                regs->satcan[SATCAN_RX] = 0;
542                regs->satcan[SATCAN_DMA] = 0;
543                priv->open = 0;
544                priv->dmaen = 0;
545                priv->doff = 0;
546                priv->timeout = RTEMS_NO_TIMEOUT;
547                priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
548        }
549
550        return RTEMS_SUCCESSFUL;
551}
552
553
554static rtems_device_driver satcan_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
555{
556        DBG("SatCAN: Opening %d\n\r",minor);
557       
558        rtems_semaphore_obtain(priv->devsem,RTEMS_WAIT, RTEMS_NO_TIMEOUT);
559        if (priv->open) {
560                rtems_semaphore_release(priv->devsem);
561                return RTEMS_RESOURCE_IN_USE; /* EBUSY */
562        }
563        priv->open = 1;
564        rtems_semaphore_release(priv->devsem);
565
566        /* Enable AHB and CAN IRQs in wrapper and EOD1, EOD2 and CAN critical  IRQs in SatCAN core */
567        regs->irqmask = MSK_AHB | MSK_CAN;
568        regs->satcan[SATCAN_INT_EN] = ((1 << SATCAN_IRQ_EOD1) | (1 << SATCAN_IRQ_EOD2) |
569                                       (1 << SATCAN_IRQ_CRITICAL));
570
571        /* Select can_int as IRQ source */
572        regs->satcan[SATCAN_CMD0] = CAN_TODn_Int_sel;
573        /* CAN RX DMA Enable */
574        regs->satcan[SATCAN_DMA] = 1;
575        /* CAN RX Enable */
576        regs->satcan[SATCAN_RX] = 1;
577
578        DBG("SatCAN: Opening %d success\n\r",minor);
579
580        return RTEMS_SUCCESSFUL;
581}
582
583static rtems_device_driver satcan_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
584{
585        struct ambapp_ahb_info d;
586        char fs_name[20];
587        rtems_status_code status;
588
589        DBG("SatCAN: Initialize..\n\r");
590
591        strcpy(fs_name, SATCAN_DEVNAME);
592
593        /* Find core and initialize register pointer */
594        if (!ambapp_find_ahbslv(&ambapp_plb, VENDOR_GAISLER, GAISLER_SATCAN, &d)) {
595                printk("SatCAN: Failed to find SatCAN core\n\r");
596                return -1;
597        }
598
599        status = rtems_io_register_name(fs_name, major, minor);
600        if (RTEMS_SUCCESSFUL != status)
601                rtems_fatal_error_occurred(status);
602
603        regs = (struct satcan_regs*)d.start[0];
604               
605        /* Set node number and DPS */
606        regs->ctrl |= ((priv->cfg->nodeno & 0xf) << 5) | (priv->cfg->dps << 1);
607
608        /* Reset core */
609        regs->ctrl |= CTRL_RST;
610
611        /* Allocate DMA area */
612        almalloc(&priv->alptr, &priv->dmaptr, ALIGN_2KMEM);
613        if (priv->dmaptr == NULL) {
614                printk("SatCAN: Failed to allocate DMA memory\n\r");
615                free(priv->cfg);
616                free(priv);
617                return -1;
618        }
619       
620        /* Wait until core reset has completed */
621        while (regs->ctrl & CTRL_RST)
622                ;
623
624        /* Initialize core registers, default is 2K messages */
625        regs->membase = (unsigned int)priv->alptr;
626        regs->satcan[SATCAN_RAM_BASE] = (unsigned int)priv->alptr >> 15;
627       
628        DBG("regs->membase = %x\n\r", (unsigned int)priv->alptr);
629        DBG("regs->satcan[SATCAN_RAM_BASE] = %x\n\r", (unsigned int)priv->alptr >> 15);
630
631        status = rtems_semaphore_create(
632                rtems_build_name('S', 'd', 'v', '0'),
633                1,
634                RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
635                RTEMS_NO_PRIORITY_CEILING,
636                0,
637                &priv->devsem);
638        if (status != RTEMS_SUCCESSFUL) {
639                printk("SatCAN: Failed to create dev semaphore (%d)\n\r", status);
640                free(priv->cfg);
641                free(priv);
642                return RTEMS_UNSATISFIED;
643        }
644        status = rtems_semaphore_create(
645                rtems_build_name('S', 't', 'x', '0'),
646                0,
647                RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | \
648                RTEMS_NO_PRIORITY_CEILING,
649                0,
650                &priv->txsem);
651        if (status != RTEMS_SUCCESSFUL) {
652          printk("SatCAN: Failed to create tx semaphore (%d)\n\r", status);
653          free(priv->cfg);
654          free(priv);
655          return RTEMS_UNSATISFIED;
656        }
657
658        priv->txactive = 0;
659        priv->open = 0;
660        priv->dmaen = 0;
661        priv->doff = 0;
662        priv->timeout = RTEMS_NO_TIMEOUT;
663        priv->dmamode = SATCAN_DMA_MODE_SYSTEM;
664
665        /* Register interrupt handler */
666        set_vector(satcan_interrupt_handler, d.irq+0x10, 2);
667
668        return RTEMS_SUCCESSFUL;
669}
670
671
672
673#define SATCAN_DRIVER_TABLE_ENTRY { satcan_initialize, satcan_open, satcan_close, satcan_read, satcan_write, satcan_ioctl }
674
675static rtems_driver_address_table satcan_driver = SATCAN_DRIVER_TABLE_ENTRY;
676
677int satcan_register(satcan_config *conf)
678{
679        rtems_status_code r;
680        rtems_device_major_number m;
681
682        DBG("SatCAN: satcan_register called\n\r");
683
684        /* Create private structure */
685        if ((priv = malloc(sizeof(struct satcan_priv))) == NULL) {
686                printk("SatCAN driver could not allocate memory for priv structure\n\r");
687                return -1;
688        }
689
690        DBG("SatCAN: Creating local copy of config structure\n\r");
691        if ((priv->cfg = malloc(sizeof(satcan_config))) == NULL) {
692                printk("SatCAN driver could not allocate memory for cfg structure\n\r");
693                return 1;
694        }
695        memcpy(priv->cfg, conf, sizeof(satcan_config));
696
697        if ((r = rtems_io_register_driver(0, &satcan_driver, &m)) == RTEMS_SUCCESSFUL) {
698                DBG("SatCAN driver successfully registered, major: %d\n\r", m);
699        } else {
700                switch(r) {
701                case RTEMS_TOO_MANY:
702                        printk("SatCAN rtems_io_register_driver failed: RTEMS_TOO_MANY\n\r"); break;
703                case RTEMS_INVALID_NUMBER: 
704                        printk("SatCAN rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n\r"); break;
705                case RTEMS_RESOURCE_IN_USE:
706                        printk("SatCAN rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n\r"); break;
707                default:
708                        printk("SatCAN rtems_io_register_driver failed\n\r");
709                }
710                return 1;
711        }
712
713        return 0;
714}
Note: See TracBrowser for help on using the repository browser.