source: rtems/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c @ db280d23

4.104.114.84.95
Last change on this file since db280d23 was db280d23, checked in by Ralf Corsepius <ralf.corsepius@…>, on 04/17/07 at 06:47:34

2007-04-17 Ralf Corsépius <ralf.corsepius@…>

  • mscan/mscan.c: Use size_t for message sizes. Remove absurd type cast.
  • Property mode set to 100644
File size: 50.2 KB
Line 
1/*===============================================================*\
2| Project: RTEMS generic MPC5200 BSP                              |
3+-----------------------------------------------------------------+
4|                    Copyright (c) 2005                           |
5|                    Embedded Brains GmbH                         |
6|                    Obere Lagerstr. 30                           |
7|                    D-82178 Puchheim                             |
8|                    Germany                                      |
9|                    rtems@embedded-brains.de                     |
10+-----------------------------------------------------------------+
11| The license and distribution terms for this file may be         |
12| found in the file LICENSE in this distribution or at            |
13|                                                                 |
14| http://www.rtems.com/license/LICENSE.                           |
15|                                                                 |
16+-----------------------------------------------------------------+
17| this file contains the MSCAN driver                             |
18\*===============================================================*/
19
20#include <stdio.h>
21#include <stdlib.h>
22#include <rtems.h>
23#include <rtems/error.h>
24#include <rtems/libio.h>
25#include <string.h>
26#include "../include/bsp.h"
27#include "../irq/irq.h"
28#include "../include/mpc5200.h"
29#include "../mscan/mscan_int.h"
30
31/* #define MSCAN_LOOPBACK */
32
33struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
34static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
35
36/* time segmant table  */
37uint8_t can_time_segment_table[CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1][NO_OF_TABLE_ENTRIES] = {
38
39/* Total no. of time quantas */   /* Time Segment 1*/    /* Time Segment 2 */     /* Sync: Jump width */
40{         7,                                4,                     2,                       1          },
41{         8,                                5,                     2,                       1          },
42{         9,                                6,                     2,                       2          },
43{        10,                                6,                     3,                       2          },
44{        11,                                7,                     3,                       2          },
45{        12,                                8,                     3,                       2          },
46{        13,                                8,                     4,                       2          },
47{        14,                                9,                     4,                       2          },
48{        15,                               10,                     4,                       2          },
49{        16,                               10,                     5,                       2          },
50{        17,                               11,                     5,                       2          },
51{        18,                               12,                     5,                       2          },
52{        19,                               12,                     6,                       2          },
53{        20,                               13,                     6,                       2          },
54{        21,                               14,                     6,                       2          },
55{        22,                               14,                     7,                       2          },
56{        23,                               15,                     7,                       2          },
57{        24,                               15,                     8,                       2          },
58{        25,                               16,                     8,                       2          }};
59
60
61/*
62 * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
63 */
64static struct can_message * get_tx_buffer(struct mscan_channel_info *chan)
65  {
66  /* define a temp. mess ptr. */
67  struct can_message * tmp_mess_ptr = NULL, *temp_head_ptr;
68
69  /* set temp. head pointer */
70  temp_head_ptr = chan->tx_ring_buf.head_ptr;
71
72  /* check buffer empty condition */
73  if(temp_head_ptr != chan->tx_ring_buf.tail_ptr)
74    {
75
76    /* current buffer head. ptr. */
77    tmp_mess_ptr = temp_head_ptr;
78
79    /* increment the head pointer */
80    temp_head_ptr++;
81
82    /* check for wrap around condition */
83    if(temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
84      {
85
86      /* set head ptr. to the begin of the ring buffer */
87      temp_head_ptr = chan->tx_ring_buf.buf_ptr;
88
89      }
90
91    /* end of crtical section restore head ptr. */
92    chan->tx_ring_buf.head_ptr = temp_head_ptr;
93    }
94
95  /* return the current head pointer */
96  return tmp_mess_ptr;
97  }
98
99/*
100 * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
101 */
102static struct can_message * fill_tx_buffer(struct mscan_channel_info *chan, struct can_message * mess_ptr)
103  {
104  /* define a temp. mess ptr. to the entry which follows the current tail entry */
105  struct can_message * tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
106
107  /* check for the wrap around condition */
108  if(tmp_mess_ptr >  chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
109    {
110        /* set temp. mess. ptr to the begin of the ring buffer */
111        tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
112    }
113
114  /* check buffer full condition */
115  if(tmp_mess_ptr == chan->tx_ring_buf.head_ptr)
116    {
117        /* return NULL in case buffer is full */
118        return NULL;
119    }
120  else
121    {
122        /* copy the can mess. to the tail of the buffer */
123    memcpy((void *)chan->tx_ring_buf.tail_ptr, (void *)mess_ptr, sizeof(struct can_message));
124
125    /* set new tail equal to temp. mess. ptr. */
126    chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
127    }
128
129  /* return the actual tail ptr. (next free entry) */
130  return chan->tx_ring_buf.tail_ptr;
131  }
132
133/*
134 * MPC5x00 MSCAN interrupt handler
135 */
136static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
137  {
138  rtems_status_code status;
139  mscan_handle *mscan_hdl = (mscan_handle *)handle;
140  struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
141  struct can_message rx_mess, *rx_mess_ptr, *tx_mess_ptr;
142  volatile struct mpc5200_mscan *mscan = chan->regs;
143  register uint8_t idx;
144
145  /*
146   handle tx ring buffer
147   */
148
149  /* loop over all 3 tx buffers */
150  for(idx = TFLG_TXE0; idx <= TFLG_TXE2; idx=idx<<1)
151    {
152
153    /* check for tx buffer vacation */
154    if((mscan->tflg) & idx)
155      {
156
157      /* try to get a message */
158      tx_mess_ptr = get_tx_buffer(chan);
159
160      /* check for new tx message */
161      if(tx_mess_ptr != NULL)
162        {
163
164        /* select the tx buffer */
165        mscan->bsel  = idx;
166
167        /* check for toucan interface */
168        if((mscan_hdl->toucan_callback) == NULL)
169          {
170
171          /* set tx id */
172                  mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
173                  mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
174                  mscan->txidr2 = 0;
175          mscan->txidr3 = 0;
176
177              }
178
179        /* fill in tx data if TOUCAN is activ an TOUCAN index have a match with the tx buffer or TOUCAN is disabled */
180        if(((mscan_hdl->toucan_callback) == NULL) || (((mscan_hdl->toucan_callback) != NULL) && ((tx_mess_ptr->toucan_tx_idx) == idx)))
181          {
182
183          /* insert dlc into mscan register */
184                  mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
185
186          /* skip data copy in case of RTR */
187          if(!(MSCAN_MESS_ID_HAS_RTR(tx_mess_ptr->mess_id)))
188            {
189            /* copy tx data to MSCAN registers */
190            switch(mscan->txdlr)
191              {
192              case 8:
193                mscan->txdsr7 = tx_mess_ptr->mess_data[7];
194              case 7:
195                mscan->txdsr6 = tx_mess_ptr->mess_data[6];
196              case 6:
197                mscan->txdsr5 = tx_mess_ptr->mess_data[5];
198              case 5:
199                mscan->txdsr4 = tx_mess_ptr->mess_data[4];
200              case 4:
201                mscan->txdsr3 = tx_mess_ptr->mess_data[3];
202              case 3:
203                mscan->txdsr2 = tx_mess_ptr->mess_data[2];
204              case 2:
205                mscan->txdsr1 = tx_mess_ptr->mess_data[1];
206              case 1:
207                mscan->txdsr0 = tx_mess_ptr->mess_data[0];
208                break;
209              default:
210                break;
211              }
212                    }
213
214          /* enable message buffer specific interrupt */
215              mscan->tier |= mscan->bsel;
216
217              /* start transfer */
218          mscan->tflg = mscan->bsel;
219
220          /* release counting semaphore of tx ring buffer */
221                  rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
222
223          }
224        else
225          {
226
227          /* refill the tx ring buffer with the message */
228          fill_tx_buffer(chan, tx_mess_ptr);
229
230              }
231            }
232          else
233            {
234                /* reset interrupt enable bit */
235            mscan->tier &= ~(idx);
236            }
237      }
238    }
239
240  /*
241   handle rx interrupts
242   */
243
244  /* check for rx interrupt source */
245  if(mscan->rier & RIER_RXFIE)
246    {
247
248    /* can messages received ? */
249    while(mscan->rflg & RFLG_RXF)
250      {
251
252      if(mscan_hdl->toucan_callback == NULL)
253        {
254
255        /* select temporary rx buffer */
256        rx_mess_ptr = &rx_mess;
257
258        }
259      else
260        {
261
262        /* check the rx fliter-match indicators (16-bit filter mode) */
263        /* in case of more than one hit, lower hit has priority */
264          idx = (mscan->idac) & 0x7;
265          switch(idx)
266          {
267
268          case 0:
269          case 1:
270          case 2:
271          case 3:
272            rx_mess_ptr =
273              (struct can_message *)&(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].can_rx_message[idx]);
274            break;
275
276          /* this case should never happen */
277                  default:
278            /* reset the rx indication flag */
279            mscan->rflg |= RFLG_RXF;
280
281            return;
282            break;
283              }
284
285        }
286
287      /* get rx ID */
288      rx_mess_ptr->mess_id = GET_IDR0(mscan->rxidr0) | GET_IDR1(mscan->rxidr1);
289
290      /* get rx len */
291      rx_mess_ptr->mess_len = ((mscan->rxdlr) & 0x0F);
292
293      /* get time stamp */
294      rx_mess_ptr->mess_time_stamp = ((mscan->rxtimh << 8) | (mscan->rxtiml));
295
296      /* skip data copy in case of RTR */
297      if(!(MSCAN_MESS_ID_HAS_RTR(rx_mess_ptr->mess_id)))
298
299        {
300
301         /* get the data */
302             switch(rx_mess_ptr->mess_len)
303               {
304               case 8:
305                 rx_mess_ptr->mess_data[7] = mscan->rxdsr7;
306               case 7:
307                 rx_mess_ptr->mess_data[6] = mscan->rxdsr6;
308               case 6:
309                 rx_mess_ptr->mess_data[5] = mscan->rxdsr5;
310               case 5:
311                 rx_mess_ptr->mess_data[4] = mscan->rxdsr4;
312               case 4:
313                 rx_mess_ptr->mess_data[3] = mscan->rxdsr3;
314               case 3:
315                 rx_mess_ptr->mess_data[2] = mscan->rxdsr2;
316               case 2:
317                 rx_mess_ptr->mess_data[1] = mscan->rxdsr1;
318               case 1:
319                 rx_mess_ptr->mess_data[0] = mscan->rxdsr0;
320               case 0:
321               default:
322                 break;
323               }
324            }
325
326      if(mscan_hdl->toucan_callback == NULL)
327        {
328
329        if((status = rtems_message_queue_send(chan->rx_qid, (void *)rx_mess_ptr, sizeof(struct can_message))) != RTEMS_SUCCESSFUL)
330                  {
331
332                  chan->int_rx_err++;
333
334          }
335
336            }
337      else
338        {
339
340        mscan_hdl->toucan_callback((int16_t)(((mscan->idac) & 0x7) + 3));
341
342            }
343
344      /* reset the rx indication flag */
345      mscan->rflg |= RFLG_RXF;
346
347      } /* end of while(mscan->rflg & RFLG_RXF) */
348
349    }
350
351    /* status change detected */
352    if(mscan->rflg & RFLG_CSCIF)
353      {
354
355      mscan->rflg |= RFLG_CSCIF;
356
357      if(mscan_hdl->toucan_callback != NULL)
358        {
359
360        mscan_hdl->toucan_callback((int16_t)(-1));
361
362        }
363
364      }
365
366  }
367
368
369/*
370 * Disable MSCAN ints.
371 */
372void mpc5200_mscan_int_disable(volatile struct mpc5200_mscan *mscan)
373  {
374
375  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
376  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
377  /*    [06]:CSCIE         0 : Status Change interrupt disabled     */
378  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
379  /*    [04]:RSTATE0       0 : Recv. Status Change int. ,Bit 0      */
380  /*                           -> 00 rx status change int. disabled */
381  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
382  /*    [02]:TSTAT0        0 : Transmit. Status Change int. , Bit 0 */
383  /*                           -> 00 tx status change int. disabled */
384  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
385  /*    [00]:RXFIE         0 : Recv. Full interrupt is disabled     */
386  mscan->rier &= ~(RIER_CSCIE | RIER_RXFIE);
387
388  /* TX Interrupt Enable on MSCAN_A/_B -----------------------------*/
389  /*    [07]:res.          0 : reserved                             */
390  /*    [06]:res.          0 : reserved                             */
391  /*    [05]:res.          0 : reserved                             */
392  /*    [04]:res.          0 : reserved                             */
393  /*    [03]:res.          0 : reserved                             */
394  /*    [02]:TSEG12        0 : TX2message buffer int. is disabled   */
395  /*    [01]:TSEG11        0 : TX1 message buffer int. is disabled  */
396  /*    [00]:TSEG10        0 : TX0 message buffer int. is disabled  */
397  mscan->tier &= ~(TIER_TXEI2 | TIER_TXEI1 | TIER_TXEI0);
398
399  return;
400
401  }
402
403
404/*
405 * Enable MSCAN ints.
406 */
407void mpc5200_mscan_int_enable(volatile struct mpc5200_mscan *mscan)
408  {
409
410  /* RX Interrupt Enable on MSCAN_A/_B -----------------------------*/
411  /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
412  /*    [06]:CSCIE         1 : Status Change interrupt enabled      */
413  /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
414  /*    [04]:RSTATE0       1 : Recv. Status Change int. ,Bit 0      */
415  /*                           -> 01 BusOff status changes enabled  */
416  /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
417  /*    [02]:TSTAT0        1 : Transmit. Status Change int. , Bit 0 */
418  /*                           -> 01 BusOff status changes enabled  */
419  /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
420  /*    [00]:RXFIE         1 : Recv. Full interrupt is enabled      */
421  mscan->rier |= (RIER_CSCIE  | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1));
422
423  return;
424
425  }
426
427/*
428 * Unmask MPC5x00 MSCAN_A interrupts
429 */
430void mpc5200_mscan_a_on(const rtems_irq_connect_data* ptr)
431  {
432  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
433
434  mpc5200_mscan_int_enable(mscan);
435
436  return;
437
438  }
439
440
441/*
442 * Mask MPC5x00 MSCAN_A interrupts
443 */
444void mpc5200_mscan_a_off(const rtems_irq_connect_data* ptr)
445  {
446  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
447
448  mpc5200_mscan_int_disable(mscan);
449
450  return;
451
452  }
453
454
455/*
456 *  Get MSCAN_A interrupt mask setting
457 */
458int mpc5200_mscan_a_isOn(const rtems_irq_connect_data* ptr)
459  {
460  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_A])->regs;
461
462  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
463    return RTEMS_SUCCESSFUL;
464  else
465    return RTEMS_UNSATISFIED;
466
467  return RTEMS_SUCCESSFUL;
468
469  }
470
471
472/*
473 * Unmask MPC5x00 MSCAN_B interrupts
474 */
475void mpc5200_mscan_b_on(const rtems_irq_connect_data* ptr)
476  {
477  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
478
479  mpc5200_mscan_int_enable(mscan);
480
481  return;
482
483  }
484
485
486/*
487 * Mask MPC5x00 MSCAN_B interrupts
488 */
489void mpc5200_mscan_b_off(const rtems_irq_connect_data* ptr)
490  {
491  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
492
493  mpc5200_mscan_int_disable(mscan);
494
495  return;
496
497  }
498
499
500/*
501 *  Get MSCAN_B interrupt mask setting
502 */
503int mpc5200_mscan_b_isOn(const rtems_irq_connect_data* ptr)
504  {
505  volatile struct mpc5200_mscan *mscan = (&chan_info[MSCAN_B])->regs;
506
507  if((mscan->rier & RIER_CSCIE) && (mscan->rier & RIER_RXFIE))
508    return RTEMS_SUCCESSFUL;
509  else
510    return RTEMS_UNSATISFIED;
511
512  return RTEMS_SUCCESSFUL;
513
514  }
515
516static mscan_handle mscan_a_handle =
517  {
518  MSCAN_A,
519  NULL
520  };
521
522
523static mscan_handle mscan_b_handle =
524  {
525  MSCAN_B,
526  NULL
527  };
528
529/*
530 * MPC5x00 MSCAN_A/_B irq data
531 */
532static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] =
533  {{
534  BSP_SIU_IRQ_MSCAN1,
535  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
536  (rtems_irq_hdl_param) &mscan_a_handle,
537  (rtems_irq_enable) mpc5200_mscan_a_on,
538  (rtems_irq_disable) mpc5200_mscan_a_off,
539  (rtems_irq_is_enabled) mpc5200_mscan_a_isOn
540  },
541  {
542  BSP_SIU_IRQ_MSCAN2,
543  (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
544  (rtems_irq_hdl_param) &mscan_b_handle,
545  (rtems_irq_enable) mpc5200_mscan_b_on,
546  (rtems_irq_disable) mpc5200_mscan_b_off,
547  (rtems_irq_is_enabled) mpc5200_mscan_b_isOn
548  }};
549
550
551/*
552 * Enter MSCAN sleep mode
553 */
554void mpc5200_mscan_enter_sleep_mode(volatile struct mpc5200_mscan *mscan)
555  {
556
557  /* Control Register 0 --------------------------------------------*/
558  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
559  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
560  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
561  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
562  /*    [03]:TIME        1 : Generate Timestamps                    */
563  /*    [02]:WUPE        1 : WakeUp Enabled                         */
564  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
565  /*    [00]:INITRQ      0 : No init. Mode Request                  */
566  /* select sleep mode */
567  mscan->ctl0 |= (CTL0_SLPRQ);
568
569  /* Control Register 1 --------------------------------------------*/
570  /*    [07]:CANE        0 : MSCAN Module is disabled               */
571  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
572  /*    [05]:LOOPB       0 : No Loopback                            */
573  /*    [04]:LISTEN      0 : Normal Operation                       */
574  /*    [03]:res         0 : reserved                               */
575  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
576  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
577  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
578  /* wait for sleep mode acknowledge */
579  while(!(mscan->ctl1 & CTL1_SLPAK));
580
581  return;
582
583  }
584
585
586/*
587 * Exit MSCAN sleep mode
588 */
589void mpc5200_mscan_exit_sleep_mode(volatile struct mpc5200_mscan *mscan)
590  {
591
592  /* Control Register 0 --------------------------------------------*/
593  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
594  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
595  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
596  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
597  /*    [03]:TIME        1 : Generate Timestamps                    */
598  /*    [02]:WUPE        1 : WakeUp Enabled                         */
599  /*    [01]:SLPRQ    0->1 : Sleep Mode Request                     */
600  /*    [00]:INITRQ      0 : No init. Mode Request                  */
601  /* select sleep mode */
602  mscan->ctl0 &= ~(CTL0_SLPRQ);
603
604  /* Control Register 1 --------------------------------------------*/
605  /*    [07]:CANE        0 : MSCAN Module is disabled               */
606  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
607  /*    [05]:LOOPB       0 : No Loopback                            */
608  /*    [04]:LISTEN      0 : Normal Operation                       */
609  /*    [03]:res         0 : reserved                               */
610  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
611  /*    [01]:SLPAK    0->1 : Sleep Mode Acknowledge (rd. only)      */
612  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
613  /* wait for sleep mode acknowledge */
614  while((mscan->ctl1 & CTL1_SLPAK));
615
616  return;
617
618  }
619
620
621/*
622 * Enter MSCAN init mode and disconnect from bus
623 */
624void mpc5200_mscan_enter_init_mode(volatile struct mpc5200_mscan *mscan)
625  {
626
627  /* Control Register 0 --------------------------------------------*/
628  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
629  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
630  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
631  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
632  /*    [03]:TIME        1 : Generate Timestamps                    */
633  /*    [02]:WUPE        0 : WakeUp disabled                        */
634  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
635  /*    [00]:INITRQ   0->1 : Init. Mode Request                     */
636  /* select init mode */
637  mscan->ctl0 |= (CTL0_INITRQ);
638
639  /* Control Register 1 --------------------------------------------*/
640  /*    [07]:CANE        0 : MSCAN Module is disabled               */
641  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
642  /*    [05]:LOOPB       0 : No Loopback                            */
643  /*    [04]:LISTEN      0 : Normal Operation                       */
644  /*    [03]:res         0 : reserved                               */
645  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
646  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
647  /*    [00]:INITAK   0->1 : Init. Mode Acknowledge (rd. only)      */
648  /* wait for init mode acknowledge */
649  while(!(mscan->ctl1 & CTL1_INITAK));
650
651  return;
652
653  }
654
655
656/*
657 * Exit MSCAN init mode
658 */
659void mpc5200_mscan_exit_init_mode(volatile struct mpc5200_mscan *mscan)
660  {
661
662  /* Control Register 0 --------------------------------------------*/
663  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
664  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
665  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
666  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
667  /*    [03]:TIME        1 : Generate Timestamps                    */
668  /*    [02]:WUPE        0 : WakeUp Disabled                        */
669  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
670  /*    [00]:INITRQ   1->0 : Init. Mode Request                     */
671  /* select normal mode */
672  mscan->ctl0 &= ~(CTL0_INITRQ);
673
674  /* Control Register 1 --------------------------------------------*/
675  /*    [07]:CANE        0 : MSCAN Module is disabled               */
676  /*    [06]:CLKSRC      1 : Clock Source -> IPB-Clock (33 MHz)     */
677  /*    [05]:LOOPB       0 : No Loopback                            */
678  /*    [04]:LISTEN      0 : Normal Operation                       */
679  /*    [03]:res         0 : reserved                               */
680  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
681  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
682  /*    [00]:INITAK   1->0 : Init. Mode Acknowledge (rd. only)      */
683  /* wait for normal mode acknowledge */
684  while(mscan->ctl1 & CTL1_INITAK);
685
686  return;
687
688  }
689
690
691/*
692 * MPC5x00 MSCAN wait for sync. with CAN bus
693 */
694void mpc5200_mscan_wait_sync(volatile struct mpc5200_mscan *mscan)
695  {
696
697  /* Control Register 0 --------------------------------------------*/
698  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
699  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
700  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
701  /*    [04]:SYNCH    0->1 : Synchronized, Status Bit (rd. only)    */
702  /*    [03]:TIME        1 : Generate Timestamps                    */
703  /*    [02]:WUPE        0 : WakeUp Disabled                        */
704  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
705  /*    [00]:INITRQ      0 : No init. Mode Request                  */
706  /* wait for MSCAN A_/_B bus synch. */
707
708#if 0 /* we don't have a need to wait for sync. */
709  while(!((mscan->ctl0) & CTL0_SYNCH));
710#endif
711  return;
712
713  }
714
715/* calculate the can clock prescaler value */
716uint8_t prescaler_calculation(uint32_t can_bit_rate, uint32_t can_clock_frq, uint8_t *tq_no) {
717
718/* local variables */
719uint8_t presc_val, tq_no_dev_min = 0;
720uint32_t bit_rate, bit_rate_dev, frq_tq, bit_rate_dev_min = 0xFFFFFFFF;
721
722/* loop through all values of time quantas */
723for(*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
724
725  /* calculate time quanta freq. */
726  frq_tq = *tq_no * can_bit_rate;
727
728  /* calculate the optimized prescal. val. */
729  presc_val = (can_clock_frq+frq_tq/2)/frq_tq;
730
731  /* calculate the bitrate */
732  bit_rate = can_clock_frq/(*tq_no * presc_val);
733
734  /* calculate the bitrate deviation */
735  if(can_bit_rate >= bit_rate)
736    {
737    /* calculate the bitrate deviation */
738    bit_rate_dev = can_bit_rate - bit_rate;
739    }
740  else
741    {
742    /* calculate the bitrate deviation */
743    bit_rate_dev = bit_rate - can_bit_rate;
744    }
745
746  /* check the deviation freq. */
747  if(bit_rate_dev == 0) {
748
749    /* return if best match (zero deviation) */
750   return (uint8_t)(presc_val);
751    }
752  else
753    {
754
755    /* check for minimum of bit rate deviation */
756    if(bit_rate_dev < bit_rate_dev_min) {
757
758      /* recognize the minimum freq. deviation */
759      bit_rate_dev_min = bit_rate_dev;
760
761      /* recognize the no. of time quantas */
762      tq_no_dev_min = *tq_no;
763          }
764        }
765  }
766
767  /* get the no of tq's */
768  *tq_no = tq_no_dev_min;
769
770  /* calculate time quanta freq. */
771  frq_tq = *tq_no * can_bit_rate;
772
773  /* return the optimized prescaler value */
774  return (uint8_t)((can_clock_frq+frq_tq/2)/frq_tq);
775}
776
777/*
778 * MPC5x00 MSCAN set up the bit timing
779 */
780void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan, uint32_t can_bit_rate, uint32_t can_clock_frq)
781{
782  uint32_t prescale_val = 0;
783  uint8_t tq_no, tseg_1, tseg_2, sseg;
784
785  /* get optimized prescaler value */
786  prescale_val = prescaler_calculation(can_bit_rate, can_clock_frq, &tq_no);
787
788  /* get time segment length from time segment table */
789  tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
790  tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
791  sseg    = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
792
793  /* Bus Timing Register 0 MSCAN_A/_B ------------------------------*/
794  /*    [07]:SJW1        1 : Synchronization jump width, Bit1       */
795  /*    [06]:SJW0        0 : Synchronization jump width, Bit0       */
796  /*                         SJW = 2 -> 3 Tq clock cycles           */
797  /*    [05]:BRP5        0 : Baud Rate Prescaler, Bit 5             */
798  /*    [04]:BRP4        0 : Baud Rate Prescaler, Bit 4             */
799  /*    [03]:BRP3        0 : Baud Rate Prescaler, Bit 3             */
800  /*    [02]:BRP2        1 : Baud Rate Prescaler, Bit 2             */
801  /*    [01]:BRP1        0 : Baud Rate Prescaler, Bit 1             */
802  /*    [00]:BRP0        1 : Baud Rate Prescaler, Bit 0             */
803  mscan->btr0 = (BTR0_SJW(sseg-1) | BTR0_BRP(prescale_val-1));
804
805  /* Bus Timing Register 1 MSCAN_A/_B ------------------------------*/
806  /*    [07]:SAMP        0 : One Sample per bit                     */
807  /*    [06]:TSEG22      0 : Time Segment 2, Bit 2                  */
808  /*    [05]:TSEG21      1 : Time Segment 2, Bit 1                  */
809  /*    [04]:TSEG20      0 : Time Segment 2, Bit 0                  */
810  /*                         -> PHASE_SEG2 = 3 Tq                   */
811  /*    [03]:TSEG13      0 : Time Segment 1, Bit 3                  */
812  /*    [02]:TSEG12      1 : Time Segment 1, Bit 2                  */
813  /*    [01]:TSEG11      1 : Time Segment 1, Bit 1                  */
814  /*    [00]:TSEG10      0 : Time Segment 1, Bit 0                  */
815  mscan->btr1 =  (BTR1_TSEG_22_20(tseg_2-1) | BTR1_TSEG_13_10(tseg_1-1));
816
817  return;
818
819  }
820
821
822/*
823 * MPC5x00 MSCAN perform settings in init mode
824 */
825void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *mscan)
826  {
827
828  /* perform all can bit time settings */
829  mpc5200_mscan_perform_bit_time_settings(mscan,CAN_BIT_RATE,IPB_CLOCK);
830
831  /* Control Register 1 --------------------------------------------*/
832  /*    [07]:CANE        0 : MSCAN Module is disabled               */
833  /*    [06]:CLKSRC      0 : Clock Source -> IPB_CLOCK (bsp.h)      */
834  /*    [05]:LOOPB       0 : No Loopback                            */
835  /*    [04]:LISTEN      0 : Normal Operation                       */
836  /*    [03]:res         0 : reserved                               */
837  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
838  /*    [01]:SLPAK    1->0 : Sleep Mode Acknowledge (rd. only)      */
839  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
840  /* Set CLK source, disable loopback & listen-only mode */
841#ifndef MSCAN_LOOPBACK
842  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC);
843#else
844  mscan->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC);
845  mscan->ctl1 |=  (CTL1_LOOPB);
846#endif
847
848  /* IPB clock                  -> IPB_CLOCK (bsp.h)                                                    */
849  /* bitrate                    -> CAN_BIT_RATE (mscan.h)                                               */
850  /* Max. no of Tq              -> CAN_MAX_NO_OF_TQ (mscan.h)                                           */
851  /* Prescaler value            -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */
852  /* SYNC_SEG                   ->  1 tq                                                                */
853  /* time segment 1             -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15 (mscan.h)    */
854  /* time segment 2             ->  8 tq (PHASE_SEG2)        , CAN_MAX_NO_OF_TQ_TSEG2 =  7 (mscan.h)    */
855  /* SJW                        ->  3 (fixed 0...3)          , CAN_MAX_NO_OF_TQ_SJW   =  2 (mscan.h)    */
856
857  /* ID Acceptance Control MSCAN_A/_B ------------------------------*/
858  /*    [07]:res.        0 : reserved                               */
859  /*    [06]:res.        0 : reserved                               */
860  /*    [05]:IDAM1       0 : ID acceptance control, Bit1            */
861  /*    [04]:IDAM0       1 : ID acceptance control, Bit0            */
862  /*                         -> filter 16 bit mode                  */
863  /*    [03]:res.        0 : reserved                               */
864  /*    [02]:IDHIT2      0 : ID acceptance hit indication, Bit 2    */
865  /*    [01]:IDHIT1      0 : ID acceptance hit indication, Bit 1    */
866  /*    [00]:IDHIT0      0 : ID acceptance hit indication, Bit 0    */
867  mscan->idac &= ~(IDAC_IDAM1);
868  mscan->idac |=  (IDAC_IDAM0);
869
870  /* initialize rx filter masks (16 bit), don't care including rtr */
871  mscan->idmr0  = SET_IDMR0(0x7FF);
872  mscan->idmr1  = SET_IDMR1(0x7FF);
873  mscan->idmr2  = SET_IDMR2(0x7FF);
874  mscan->idmr3  = SET_IDMR3(0x7FF);
875  mscan->idmr4  = SET_IDMR4(0x7FF);
876  mscan->idmr5  = SET_IDMR5(0x7FF);
877  mscan->idmr6  = SET_IDMR6(0x7FF);
878  mscan->idmr7  = SET_IDMR7(0x7FF);
879
880  /* Control Register 1 --------------------------------------------*/
881  /*    [07]:CANE     0->1 : MSCAN Module is enabled                */
882  /*    [06]:CLKSRC      1 : Clock Source -> IPB_CLOCK (bsp.h)      */
883  /*    [05]:LOOPB       0 : No Loopback                            */
884  /*    [04]:LISTEN      0 : Normal Operation                       */
885  /*    [03]:res         0 : reserved                               */
886  /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
887  /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
888  /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
889  /* enable MSCAN A_/_B */
890  mscan->ctl1 |= (CTL1_CANE);
891
892  return;
893
894  }
895
896
897/*
898 * MPC5x00 MSCAN perform settings in normal mode
899 */
900void mpc5200_mscan_perform_normal_mode_settings(volatile struct mpc5200_mscan *mscan)
901  {
902
903  /* Control Register 0 --------------------------------------------*/
904  /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
905  /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
906  /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
907  /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
908  /*    [03]:TIME        1 : Generate Timestamps                    */
909  /*    [02]:WUPE        0 : WakeUp Disabled                        */
910  /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
911  /*    [00]:INITRQ      0 : No init. Mode Request                  */
912  /* Disable wait mode, enable timestamps */
913  mscan->ctl0 &= ~(CTL0_CSWAI);
914  mscan->ctl0 |=  (CTL0_TIME);
915
916  return;
917
918  }
919
920rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, uint8_t mode)
921  {
922  struct mscan_channel_info *chan = NULL;
923  volatile struct mpc5200_mscan *mscan     = NULL;
924
925  switch(minor)
926    {
927
928    case MSCAN_A:
929    case MSCAN_B:
930      chan  = &chan_info[minor];
931      mscan = chan->regs;
932      break;
933
934    default:
935      return RTEMS_UNSATISFIED;
936      break;
937    }
938
939  if(chan->mode == mode)
940    return RTEMS_SUCCESSFUL;
941
942  switch(mode)
943    {
944
945    case MSCAN_INIT_NORMAL_MODE:
946      /* if not already set enter init mode */
947          mpc5200_mscan_enter_init_mode(mscan);
948          /* perform initialization which has to be done in init mode */
949      mpc5200_mscan_perform_init_mode_settings(mscan);
950      break;
951
952    case MSCAN_NORMAL_MODE:
953      /* if not already set enter init mode */
954      mpc5200_mscan_enter_init_mode(mscan);
955
956      if((chan->mode) == MSCAN_INITIALIZED_MODE)
957        {
958
959        /* perform initialization which has to be done in init mode */
960        mpc5200_mscan_perform_init_mode_settings(mscan);
961            }
962
963      if((chan->mode) == MSCAN_SLEEP_MODE)
964        {
965
966        /* exit sleep mode */
967            mpc5200_mscan_exit_sleep_mode(mscan);
968            }
969
970      /* exit init mode */
971      mpc5200_mscan_exit_init_mode(mscan);
972      /* enable ints. */
973      mpc5200_mscan_int_enable(mscan);
974      /* wait for bus sync. */
975      mpc5200_mscan_wait_sync(mscan);
976      break;
977
978    case MSCAN_SLEEP_MODE:
979      /* disable ints. */
980      mpc5200_mscan_int_disable(mscan);
981      /* exit sleep mode */
982          mpc5200_mscan_enter_sleep_mode(mscan);
983      break;
984
985    default:
986      return RTEMS_UNSATISFIED;
987      break;
988
989    }
990
991  /* set new channel mode */
992  chan->mode = mode;
993
994  return RTEMS_SUCCESSFUL;
995
996  }
997
998
999/*
1000 * initialization of channel info.
1001 */
1002rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtems_device_minor_number minor)
1003  {
1004  rtems_status_code status;
1005  struct mscan_channel_info *chan = &chan_info[minor];
1006
1007
1008  /* set registers according to MSCAN channel information */
1009  switch(minor)
1010    {
1011
1012    case MSCAN_A:
1013      chan->rx_qname = rtems_build_name ('C', 'N', 'A', 'Q');
1014      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'A', 'S');
1015
1016      /* register RTEMS device names for MSCAN A */
1017      if((status = rtems_io_register_name (MSCAN_A_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
1018            return status;
1019
1020      /* register RTEMS device names for MSCAN 0 */
1021      if((status = rtems_io_register_name (MSCAN_0_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
1022            return status;
1023
1024          /* allocate the space for MSCAN A tx ring buffer */
1025          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1026            {
1027        chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1028            }
1029          else
1030            {
1031                return RTEMS_UNSATISFIED;
1032            }
1033      break;
1034
1035    case MSCAN_B:
1036          chan->rx_qname = rtems_build_name ('C', 'N', 'B', 'Q');
1037      chan->tx_rb_sname = rtems_build_name ('C', 'N', 'B', 'S');
1038
1039          /* register RTEMS device names for MSCAN B */
1040          if((status = rtems_io_register_name (MSCAN_B_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1041            return status;
1042
1043      /* register RTEMS device names for MSCAN 1 */
1044          if((status = rtems_io_register_name (MSCAN_1_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
1045            return status;
1046
1047      /* allocate the space for MSCAN B tx ring buffer */
1048          if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
1049            {
1050                chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1051            }
1052          else
1053            {
1054                return RTEMS_UNSATISFIED;
1055            }
1056      break;
1057
1058    default:
1059      return RTEMS_UNSATISFIED;
1060      break;
1061    }
1062
1063  /* create RTEMS rx message queue */
1064  status = rtems_message_queue_create(chan->rx_qname,
1065                                             (uint32_t) NO_OF_MSCAN_RX_BUFF,
1066                                             (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)),
1067                                             (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
1068                                             (rtems_id *)&(chan->rx_qid));
1069
1070  /* create counting RTEMS tx ring buffer semaphore */
1071  status = rtems_semaphore_create(chan->tx_rb_sname,
1072                                 (uint32_t)(NO_OF_MSCAN_TX_BUFF),
1073                                  RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
1074                                 (rtems_task_priority)0,
1075                                 (rtems_id *)&(chan->tx_rb_sid));
1076
1077  /* Set up interrupts */
1078  if(!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
1079    rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %d\n", minor);
1080
1081  /* basic setup for channel info. struct. */
1082  chan->regs           = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]);
1083  chan->int_rx_err     = 0;
1084  chan->id_extended    = FALSE;
1085  chan->mode           = MSCAN_INITIALIZED_MODE;
1086  chan->tx_buf_no      = NO_OF_MSCAN_TX_BUFF;
1087
1088  return status;
1089
1090  }
1091
1092
1093/*
1094 * MPC5x00 MSCAN device initialization
1095 */
1096rtems_device_driver mscan_initialize(rtems_device_major_number major,
1097                                     rtems_device_minor_number minor,
1098                                     void *arg
1099                                    )
1100  {
1101  rtems_status_code status;
1102
1103  /* Initialization requested via RTEMS */
1104  if((status = mscan_channel_initialize(major,MSCAN_A)) != RTEMS_SUCCESSFUL)
1105    rtems_fatal_error_occurred(status);
1106
1107  if((status = mscan_channel_initialize(major,MSCAN_B)) != RTEMS_SUCCESSFUL)
1108    rtems_fatal_error_occurred(status);
1109
1110  if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
1111    rtems_fatal_error_occurred(status);
1112
1113  if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
1114    rtems_fatal_error_occurred(status);
1115
1116  return status;
1117
1118  }
1119
1120
1121/*
1122 * MPC5x00 MSCAN device open
1123 */
1124rtems_device_driver mscan_open( rtems_device_major_number major,
1125                                 rtems_device_minor_number minor,
1126                                 void * arg
1127                               )
1128  {
1129  rtems_status_code status = RTEMS_SUCCESSFUL;
1130  struct mscan_channel_info *chan = NULL;
1131
1132  switch(minor)
1133    {
1134
1135    case MSCAN_A:
1136    case MSCAN_B:
1137      chan = &chan_info[minor];
1138      break;
1139
1140    default:
1141      return RTEMS_UNSATISFIED;
1142      break;
1143    }
1144
1145
1146  /* check mode */
1147  if((chan->mode) == MSCAN_SLEEP_MODE)
1148    {
1149
1150    /* if not already set enter init mode */
1151    status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1152    }
1153
1154  return status;
1155
1156  }
1157
1158
1159/*
1160 * MPC5x00 MSCAN device close
1161 */
1162rtems_device_driver mscan_close( rtems_device_major_number major,
1163                                  rtems_device_minor_number minor,
1164                                  void * arg
1165                                )
1166  {
1167  rtems_status_code status;
1168  struct mscan_channel_info *chan = NULL;
1169
1170  switch(minor)
1171    {
1172
1173    case MSCAN_A:
1174    case MSCAN_B:
1175          chan = &chan_info[minor];
1176      break;
1177
1178    default:
1179      return RTEMS_UNSATISFIED;
1180      break;
1181    }
1182
1183  /* enter deep sleep mode */
1184  status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE);
1185
1186  return status;
1187
1188  }
1189
1190
1191/*
1192 * MPC5x00 MSCAN device read
1193 */
1194rtems_device_driver mscan_read( rtems_device_major_number major,
1195                                 rtems_device_minor_number minor,
1196                                 void * arg
1197                               )
1198  {
1199  rtems_status_code          status;
1200  size_t                     message_size = 0;
1201  rtems_libio_rw_args_t     *parms       = (rtems_libio_rw_args_t *)arg;
1202  struct mscan_rx_parms     *rx_parms    = (struct mscan_rx_parms *)(parms->buffer);
1203  struct can_message        *rx_mess     = (struct can_message *)(rx_parms->rx_mess);
1204  struct mscan_channel_info *chan        = NULL;
1205
1206  switch(minor)
1207    {
1208
1209    case MSCAN_A:
1210    case MSCAN_B:
1211          chan = &chan_info[minor];
1212      break;
1213
1214    default:
1215      return RTEMS_UNSATISFIED;
1216      break;
1217    }
1218
1219
1220  /* end init mode if it is first read */
1221  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
1222    {
1223
1224    /* if not already set enter init mode */
1225    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1226    }
1227
1228  if((status = rtems_message_queue_receive(chan->rx_qid,
1229                                          (void *)(rx_mess),
1230                                          &message_size,
1231                                          (uint32_t)(rx_parms->rx_flags),
1232                                          (rtems_interval)(rx_parms->rx_timeout)))
1233                                          != RTEMS_SUCCESSFUL)
1234    {
1235
1236    parms->bytes_moved = 0;
1237
1238    }
1239  else
1240    {
1241
1242    parms->bytes_moved = sizeof(struct can_message);
1243
1244    }
1245
1246  return status;
1247
1248  }
1249
1250
1251/*
1252 * MPC5x00 MSCAN device write
1253 */
1254rtems_device_driver mscan_write( rtems_device_major_number major,
1255                                 rtems_device_minor_number minor,
1256                                 void * arg
1257                                )
1258  {
1259  rtems_status_code status;
1260  rtems_libio_rw_args_t         *parms       = (rtems_libio_rw_args_t *)arg;
1261  struct mscan_tx_parms         *tx_parms    = (struct mscan_tx_parms *)(parms->buffer);
1262  struct can_message            *tx_mess     = (struct can_message *)(tx_parms->tx_mess);
1263  struct mscan_channel_info     *chan        = NULL;
1264  mscan_handle                  *mscan_hdl   = NULL;
1265  volatile struct mpc5200_mscan *mscan       = NULL;
1266
1267  switch(minor)
1268    {
1269    case MSCAN_A:
1270    case MSCAN_B:
1271          chan      = &chan_info[minor];
1272      mscan_hdl = mpc5200_mscan_irq_data[minor].handle;
1273      mscan     = chan->regs;
1274      break;
1275
1276    default:
1277      return RTEMS_UNSATISFIED;
1278      break;
1279    }
1280
1281  /* end init mode if it is first write */
1282  if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
1283    {
1284
1285    /* if not already set enter init mode */
1286    mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
1287    }
1288
1289  /* preset moved bytes */
1290  parms->bytes_moved = 0;
1291
1292  /* obtain counting semaphore of tx ring buffer */
1293  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1294                                       RTEMS_NO_WAIT,
1295                                          (rtems_interval)0))
1296                                        == RTEMS_SUCCESSFUL)
1297    {
1298
1299    /* append the TOUCAN tx_id to the mess. due to interrupt handling */
1300        tx_mess->toucan_tx_idx = tx_parms->tx_idx;
1301
1302    /* fill the tx ring buffer with the message */
1303    fill_tx_buffer(chan, tx_mess);
1304
1305    /* enable message buffer specific interrupt */
1306    mscan->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
1307
1308    /* calculate moved bytes */
1309    parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
1310
1311    }
1312
1313  return status;
1314
1315  }
1316
1317
1318/*
1319 * MPC5x00 MSCAN device control
1320 */
1321rtems_device_driver mscan_control( rtems_device_major_number major,
1322                                    rtems_device_minor_number minor,
1323                                    void * arg
1324                                  )
1325  {
1326  rtems_status_code status;
1327  uint16_t tx_id;
1328  rtems_libio_ioctl_args_t      *parms       = (rtems_libio_ioctl_args_t *)arg;
1329  struct mscan_ctrl_parms       *ctrl_parms  = (struct mscan_ctrl_parms *)(parms->buffer);
1330  struct mscan_channel_info     *chan        = NULL;
1331  mscan_handle                  *mscan_hdl   = NULL;
1332  volatile struct mpc5200_mscan *mscan       = NULL;
1333  uint8_t                       tx_buf_count = 0;
1334
1335  switch(minor)
1336    {
1337
1338    case MSCAN_A:
1339    case MSCAN_B:
1340          chan = &chan_info[minor];
1341      mscan_hdl  = mpc5200_mscan_irq_data[minor].handle;
1342      mscan = chan->regs;
1343      break;
1344
1345    default:
1346      return RTEMS_UNSATISFIED;
1347      break;
1348    }
1349
1350  switch(parms->command)
1351    {
1352
1353      /* TOUCAN callback initialization for MSCAN */
1354    case TOUCAN_MSCAN_INIT:
1355      mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc;
1356      break;
1357
1358    /* set rx buffer ID */
1359    case MSCAN_SET_RX_ID:
1360
1361      /* enter init mode */
1362      mpc5200_mscan_enter_init_mode(mscan);
1363
1364      switch(ctrl_parms->ctrl_reg_no)
1365        {
1366
1367        case RX_BUFFER_0:
1368          mscan->idar0  = SET_IDR0(ctrl_parms->ctrl_id);
1369          mscan->idar1  = SET_IDR1(ctrl_parms->ctrl_id);
1370          break;
1371
1372        case RX_BUFFER_1:
1373          mscan->idar2  = SET_IDR2(ctrl_parms->ctrl_id);
1374          mscan->idar3  = SET_IDR3(ctrl_parms->ctrl_id);
1375          break;
1376
1377        case RX_BUFFER_2:
1378          mscan->idar4  = SET_IDR4(ctrl_parms->ctrl_id);
1379          mscan->idar5  = SET_IDR5(ctrl_parms->ctrl_id);
1380          break;
1381
1382        case RX_BUFFER_3:
1383          mscan->idar6  = SET_IDR6(ctrl_parms->ctrl_id);
1384          mscan->idar7  = SET_IDR7(ctrl_parms->ctrl_id);
1385          break;
1386
1387        default:
1388        break;
1389
1390        }
1391
1392      /* exit init mode and perform further initialization which is required in the normal mode */
1393      mpc5200_mscan_exit_init_mode(mscan);
1394
1395      /* enable ints. */
1396      mpc5200_mscan_int_enable(mscan);
1397
1398      /* wait for bus sync. */
1399      mpc5200_mscan_wait_sync(mscan);
1400
1401      return RTEMS_SUCCESSFUL;
1402      break;
1403
1404    /* get rx buffer ID */
1405    case MSCAN_GET_RX_ID:
1406
1407      switch(ctrl_parms->ctrl_reg_no)
1408            {
1409
1410        case RX_BUFFER_0:
1411          ctrl_parms->ctrl_id = GET_IDR0(mscan->idar0) | GET_IDR1(mscan->idar1);
1412          break;
1413
1414        case RX_BUFFER_1:
1415          ctrl_parms->ctrl_id = GET_IDR2(mscan->idar2) | GET_IDR3(mscan->idar3);
1416          break;
1417
1418        case RX_BUFFER_2:
1419          ctrl_parms->ctrl_id = GET_IDR4(mscan->idar4) | GET_IDR5(mscan->idar5);
1420          break;
1421
1422        case RX_BUFFER_3:
1423          ctrl_parms->ctrl_id = GET_IDR6(mscan->idar6) | GET_IDR7(mscan->idar7);
1424          break;
1425
1426        default:
1427        break;
1428
1429        }
1430
1431      break;
1432
1433    /* set rx buffer ID mask */
1434    case MSCAN_SET_RX_ID_MASK:
1435
1436      /* enter init mode */
1437      mpc5200_mscan_enter_init_mode(mscan);
1438
1439      switch(ctrl_parms->ctrl_reg_no)
1440        {
1441
1442        case RX_BUFFER_0:
1443          mscan->idmr0  = SET_IDMR0(ctrl_parms->ctrl_id_mask);
1444          mscan->idmr1  = SET_IDMR1(ctrl_parms->ctrl_id_mask);
1445          break;
1446
1447        case RX_BUFFER_1:
1448          mscan->idmr2  = SET_IDMR2(ctrl_parms->ctrl_id_mask);
1449          mscan->idmr3  = SET_IDMR3(ctrl_parms->ctrl_id_mask);
1450          break;
1451
1452        case RX_BUFFER_2:
1453          mscan->idmr4  = SET_IDMR4(ctrl_parms->ctrl_id_mask);
1454          mscan->idmr5  = SET_IDMR5(ctrl_parms->ctrl_id_mask);
1455          break;
1456
1457        case RX_BUFFER_3:
1458          mscan->idmr6  = SET_IDMR6(ctrl_parms->ctrl_id_mask);
1459          mscan->idmr7  = SET_IDMR7(ctrl_parms->ctrl_id_mask);
1460          break;
1461
1462        default:
1463        break;
1464
1465        }
1466
1467      /* exit init mode and perform further initialization which is required in the normal mode */
1468      mpc5200_mscan_exit_init_mode(mscan);
1469
1470      /* enable ints. */
1471      mpc5200_mscan_int_enable(mscan);
1472
1473      /* wait for bus sync. */
1474      mpc5200_mscan_wait_sync(mscan);
1475
1476      break;
1477
1478    /* get rx buffer ID mask */
1479    case MSCAN_GET_RX_ID_MASK:
1480
1481      switch(ctrl_parms->ctrl_reg_no)
1482        {
1483
1484        case RX_BUFFER_0:
1485          ctrl_parms->ctrl_id_mask = (GET_IDMR0(mscan->idmr0) | GET_IDMR1(mscan->idmr1));
1486          break;
1487
1488        case RX_BUFFER_1:
1489          ctrl_parms->ctrl_id_mask = (GET_IDMR2(mscan->idmr2) | GET_IDMR3(mscan->idmr3));
1490          break;
1491
1492        case RX_BUFFER_2:
1493          ctrl_parms->ctrl_id_mask = (GET_IDMR4(mscan->idmr4) | GET_IDMR5(mscan->idmr5));
1494          break;
1495
1496        case RX_BUFFER_3:
1497          ctrl_parms->ctrl_id_mask = (GET_IDMR6(mscan->idmr6) | GET_IDMR7(mscan->idmr7));
1498          break;
1499
1500        default:
1501        break;
1502
1503        }
1504
1505    /* set tx buffer ID */
1506    case MSCAN_SET_TX_ID:
1507
1508      /* check for availability of tx buffer */
1509      if(!((mscan->tflg) & (uint8_t)(ctrl_parms->ctrl_reg_no)))
1510        {
1511
1512        /* do abort tx buf. request */
1513        mscan->tarq = (uint8_t)(ctrl_parms->ctrl_reg_no);
1514
1515        /* wait for abort tx buf. ack. */
1516        while((mscan->taak) & (uint8_t)(ctrl_parms->ctrl_reg_no));
1517
1518        }
1519
1520      /* select tx buf. */
1521      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1522
1523      /* set the tx id of selected buf. */
1524      tx_id = ctrl_parms->ctrl_id;
1525      mscan->txidr0 = SET_IDR0(tx_id);
1526      mscan->txidr1 = SET_IDR1(tx_id);
1527      mscan->txidr2 = 0;
1528      mscan->txidr3 = 0;
1529
1530      break;
1531
1532    /* get tx buffer ID */
1533    case MSCAN_GET_TX_ID:
1534
1535      /* select tx buf. */
1536      mscan->bsel   = (uint8_t)(ctrl_parms->ctrl_reg_no);
1537
1538      /* get tx id. of selected buf. */
1539      ctrl_parms->ctrl_id = GET_IDR0(mscan->txidr0) | GET_IDR1(mscan->txidr1);
1540
1541      break;
1542
1543    /* set can bitrate */
1544    case MSCAN_SET_BAUDRATE:
1545
1546      /* check bitrate settings */
1547      if(((ctrl_parms->ctrl_can_bitrate) >= CAN_BIT_RATE_MIN) && ((ctrl_parms->ctrl_can_bitrate) <= CAN_BIT_RATE_MAX)) {
1548
1549        /* enter init mode */
1550        mpc5200_mscan_enter_init_mode(mscan);
1551
1552        /* perform all can bit time settings */
1553        mpc5200_mscan_perform_bit_time_settings(mscan,(uint32_t)(ctrl_parms->ctrl_can_bitrate),IPB_CLOCK);
1554
1555        /* exit init mode and perform further initialization which is required in the normal mode */
1556        mpc5200_mscan_exit_init_mode(mscan);
1557
1558        /* enable ints. */
1559        mpc5200_mscan_int_enable(mscan);
1560
1561        /* wait for bus sync. */
1562        mpc5200_mscan_wait_sync(mscan);
1563
1564            return RTEMS_SUCCESSFUL;
1565            }
1566          else {
1567
1568             return RTEMS_UNSATISFIED;
1569             }
1570
1571      break;
1572
1573    case SET_TX_BUF_NO:
1574
1575      /* check for different settings of tx ring buffer */
1576      if((tx_buf_count = chan->tx_buf_no) != (uint8_t)(ctrl_parms->ctrl_tx_buf_no))
1577        {
1578
1579        /* preset the channel specific no of messages in the tx ring buffer */
1580        tx_buf_count = chan->tx_buf_no;
1581
1582        /* try to obtain all of the tx ring buffers */
1583        while(tx_buf_count > 0)
1584          {
1585
1586          /* obtain semaphore of all tx ring buffers */
1587                  if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
1588                                                           RTEMS_WAIT,
1589                                                          (rtems_interval)10))
1590                                                == RTEMS_SUCCESSFUL)
1591                {
1592
1593                    tx_buf_count--;
1594
1595                }
1596
1597          }
1598
1599        /* free the former tx ring buffer */
1600        free((void *)chan->tx_ring_buf.buf_ptr);
1601
1602        /* allocate the tx ring buffer with new size */
1603            if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*((uint8_t)(ctrl_parms->ctrl_tx_buf_no)+1))) != NULL)
1604              {
1605                  chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
1606              }
1607            else
1608              {
1609                  return RTEMS_UNSATISFIED;
1610              }
1611
1612        /* set the new amount of tx buffers */
1613        chan->tx_buf_no =  (uint8_t)(ctrl_parms->ctrl_tx_buf_no);
1614
1615        /* release the semaphore of all tx ring buffers */
1616        while(tx_buf_count < chan->tx_buf_no)
1617                  {
1618
1619                  /* obtain semaphore of all tx ring buffers */
1620              rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
1621
1622                  tx_buf_count++;
1623
1624                  }
1625
1626            }
1627          else
1628            {
1629
1630        return RTEMS_SUCCESSFUL;
1631
1632            }
1633      break;
1634
1635    default:
1636      break;
1637
1638    }
1639
1640  return RTEMS_SUCCESSFUL;
1641
1642  }
1643
Note: See TracBrowser for help on using the repository browser.