summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c')
-rw-r--r--c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c719
1 files changed, 498 insertions, 221 deletions
diff --git a/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c b/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c
index 857a160b9b..c107e9e37f 100644
--- a/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c
+++ b/c/src/lib/libbsp/powerpc/gen5200/mscan/mscan.c
@@ -30,8 +30,107 @@
/* #define MSCAN_LOOPBACK */
+volatile uint32_t tx_int_wr_count = 0;
+
struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
-static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
+volatile static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
+
+/* time segmant table */
+uint8_t can_time_segment_table[CAN_MAX_NO_OF_TQ - MIN_NO_OF_TQ + 1][NO_OF_TABLE_ENTRIES] = {
+
+/* Total no. of time quantas */ /* Time Segment 1*/ /* Time Segment 2 */ /* Sync: Jump width */
+{ 7, 4, 2, 1 },
+{ 8, 5, 2, 1 },
+{ 9, 6, 2, 2 },
+{ 10, 6, 3, 2 },
+{ 11, 7, 3, 2 },
+{ 12, 8, 3, 2 },
+{ 13, 8, 4, 2 },
+{ 14, 9, 4, 2 },
+{ 15, 10, 4, 2 },
+{ 16, 10, 5, 2 },
+{ 17, 11, 5, 2 },
+{ 18, 12, 5, 2 },
+{ 19, 12, 6, 2 },
+{ 20, 13, 6, 2 },
+{ 21, 14, 6, 2 },
+{ 22, 14, 7, 2 },
+{ 23, 15, 7, 2 },
+{ 24, 15, 8, 2 },
+{ 25, 16, 8, 2 }};
+
+
+/*
+ * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
+ */
+volatile static struct can_message * get_tx_buffer(struct mscan_channel_info *chan)
+ {
+ /* define a temp. mess ptr. */
+ volatile struct can_message * tmp_mess_ptr = NULL, *temp_head_ptr;
+
+ /* set temp. head pointer */
+ temp_head_ptr = chan->tx_ring_buf.head_ptr;
+
+ /* check buffer empty condition */
+ if(temp_head_ptr != chan->tx_ring_buf.tail_ptr)
+ {
+
+ /* current buffer head. ptr. */
+ tmp_mess_ptr = temp_head_ptr;
+
+ /* increment the head pointer */
+ temp_head_ptr++;
+
+ /* check for wrap around condition */
+ if(temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
+ {
+
+ /* set head ptr. to the begin of the ring buffer */
+ temp_head_ptr = chan->tx_ring_buf.buf_ptr;
+
+ }
+
+ /* end of crtical section restore head ptr. */
+ chan->tx_ring_buf.head_ptr = temp_head_ptr;
+ }
+
+ /* return the current head pointer */
+ return tmp_mess_ptr;
+ }
+
+/*
+ * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
+ */
+volatile static struct can_message * fill_tx_buffer(struct mscan_channel_info *chan, struct can_message * mess_ptr)
+ {
+ /* define a temp. mess ptr. to the entry which follows the current tail entry */
+ struct can_message * tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
+
+ /* check for the wrap around condition */
+ if(tmp_mess_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF)
+ {
+ /* set temp. mess. ptr to the begin of the ring buffer */
+ tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
+ }
+
+ /* check buffer full condition */
+ if(tmp_mess_ptr == chan->tx_ring_buf.head_ptr)
+ {
+ /* return NULL in case buffer is full */
+ return NULL;
+ }
+ else
+ {
+ /* copy the can mess. to the tail of the buffer */
+ memcpy((void *)chan->tx_ring_buf.tail_ptr, (void *)mess_ptr, sizeof(struct can_message));
+
+ /* set new tail equal to temp. mess. ptr. */
+ chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
+ }
+
+ /* return the actual tail ptr. (next free entry) */
+ return chan->tx_ring_buf.tail_ptr;
+ }
/*
* MPC5x00 MSCAN interrupt handler
@@ -41,24 +140,110 @@ static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
rtems_status_code status;
mscan_handle *mscan_hdl = (mscan_handle *)handle;
struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
- struct can_message rx_mess, *rx_mess_ptr;
+ struct can_message rx_mess, *rx_mess_ptr, *tx_mess_ptr;
volatile struct mpc5200_mscan *mscan = chan->regs;
+ register uint8_t idx;
/*
- handle tx interrupts
+ handle tx ring buffer
*/
- /* check and disable tx interrupt for message buffer 0 */
- if(mscan->tier & MSCAN_TX_BUFF0)
- mscan->tier &= ~(MSCAN_TX_BUFF0);
+ /* loop over all 3 tx buffers */
+ for(idx = TFLG_TXE0; idx <= TFLG_TXE2; idx=idx<<1)
+ {
+
+ /* check for tx buffer vacation */
+ if((mscan->tflg) & idx)
+ {
+
+ /* try to get a message */
+ tx_mess_ptr = get_tx_buffer(chan);
+
+ /* check for new tx message */
+ if(tx_mess_ptr != NULL)
+ {
+
+ /* select the tx buffer */
+ mscan->bsel = idx;
+
+ /* check for toucan interface */
+ if((mscan_hdl->toucan_callback) == NULL)
+ {
+
+ /* set tx id */
+ mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
+ mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
+ mscan->txidr2 = 0;
+ mscan->txidr3 = 0;
+
+ /* insert dlc into mscan register */
+ mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
+ }
+
+ /* select one free tx buffer if TOUCAN not registered) */
+ if(((mscan_hdl->toucan_callback) == NULL) || (((mscan_hdl->toucan_callback) != NULL) && ((tx_mess_ptr->toucan_tx_id) == idx)))
+ {
+
+ /* set tx id */
+ mscan->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
+ mscan->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
+ mscan->txidr2 = 0;
+ mscan->txidr3 = 0;
+
+ /* insert dlc into mscan register */
+ mscan->txdlr = (uint8_t)((tx_mess_ptr->mess_len) & 0x000F);
+
+ /* copy tx data to MSCAN registers */
+ switch(mscan->txdlr)
+ {
+ case 8:
+ mscan->txdsr7 = tx_mess_ptr->mess_data[7];
+ case 7:
+ mscan->txdsr6 = tx_mess_ptr->mess_data[6];
+ case 6:
+ mscan->txdsr5 = tx_mess_ptr->mess_data[5];
+ case 5:
+ mscan->txdsr4 = tx_mess_ptr->mess_data[4];
+ case 4:
+ mscan->txdsr3 = tx_mess_ptr->mess_data[3];
+ case 3:
+ mscan->txdsr2 = tx_mess_ptr->mess_data[2];
+ case 2:
+ mscan->txdsr1 = tx_mess_ptr->mess_data[1];
+ case 1:
+ mscan->txdsr0 = tx_mess_ptr->mess_data[0];
+ break;
+ default:
+ break;
+ }
+
+ /* enable message buffer specific interrupt */
+ mscan->tier |= mscan->bsel;
+
+ /* start transfer */
+ mscan->tflg = mscan->bsel;
+
+ /* release counting semaphore of tx ring buffer */
+ rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
+
+ tx_int_wr_count++;
- /* check and disable tx interrupt for message buffer 1 */
- if(mscan->tier & MSCAN_TX_BUFF1)
- mscan->tier &= ~(MSCAN_TX_BUFF1);
+ }
+ else
+ {
- /* check and disable tx interrupt for message buffer 2 */
- if(mscan->tier & MSCAN_TX_BUFF2)
- mscan->tier &= ~(MSCAN_TX_BUFF2);
+ /* refill the tx ring buffer with the message */
+ fill_tx_buffer(chan, tx_mess_ptr);
+
+ }
+ }
+ else
+ {
+ /* reset interrupt enable bit */
+ mscan->tier &= ~(idx);
+ }
+ }
+ }
/*
handle rx interrupts
@@ -84,24 +269,17 @@ static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
/* check the rx fliter-match indicators (16-bit filter mode) */
/* in case of more than one hit, lower hit has priority */
- switch((mscan->idac) & 0x7)
+ idx = (mscan->idac) & 0x7;
+ switch(idx)
{
case 0:
- rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[0]);
- break;
-
- case 1:
- rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[1]);
- break;
-
+ case 1:
case 2:
- rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[2]);
- break;
-
- case 3:
- rx_mess_ptr = (struct can_message *)&(mpc5200_mscan_rx_cntrl[MSCAN_A].can_rx_message[3]);
- break;
+ case 3:
+ rx_mess_ptr =
+ (struct can_message *)&(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].can_rx_message[idx]);
+ break;
/* this case should never happen */
default:
@@ -530,34 +708,71 @@ void mpc5200_mscan_wait_sync(volatile struct mpc5200_mscan *mscan)
/* [01]:SLPRQ 0 : No Sleep Mode Request */
/* [00]:INITRQ 0 : No init. Mode Request */
/* wait for MSCAN A_/_B bus synch. */
- while(!((mscan->ctl0) & CTL0_SYNCH));
+#if 0 /* we don't have a need to wait for sync. */
+ while(!((mscan->ctl0) & CTL0_SYNCH));
+#endif
return;
}
+/* calculate the can clock prescaler value */
+uint8_t prescaler_calculation(uint32_t can_bit_rate, uint32_t can_clock_frq, uint8_t *tq_no) {
+
+/* local variables */
+uint8_t tq_no_min_dev = 0;
+uint32_t frq_tq, frq_dev, frq_dev_min = 0xFFFFFFFF;
+
+/* loop through all values of time quantas */
+for(*tq_no = CAN_MAX_NO_OF_TQ; *tq_no >= MIN_NO_OF_TQ; (*tq_no)--) {
+
+ /* calculate time quanta freq. */
+ frq_tq = *tq_no * can_bit_rate;
+
+ /* calculate the deviation from requested tq freq. */
+ frq_dev = can_clock_frq%frq_tq;
+
+ /* check the deviation freq. */
+ if(frq_dev == 0) {
+
+ /* return if best match (zero deviation) */
+ return (uint8_t)(can_clock_frq/frq_tq);
+ }
+ else
+ {
+
+ /* check for minimum of freq. deviation */
+ if(frq_dev < frq_dev_min) {
+
+ /* recognize the minimum freq. deviation */
+ frq_dev_min = frq_dev;
+
+ /* recognize the no. of time quantas */
+ tq_no_min_dev = *tq_no;
+ }
+ }
+ }
+
+/* return the optimized prescaler value */
+ *tq_no = tq_no_min_dev;
+ return (uint8_t)(can_clock_frq/(tq_no_min_dev * can_bit_rate));
+}
/*
* MPC5x00 MSCAN set up the bit timing
*/
-void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan)
+void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *mscan, uint32_t can_bit_rate, uint32_t can_clock_frq)
{
uint32_t prescale_val = 0;
- uint32_t tq_num;
- uint32_t sync_seg,tseg1,tseg2;
-
- if(IPB_CLOCK%(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ))
- prescale_val = (IPB_CLOCK/(CAN_BIT_RATE * (CAN_MAX_NO_OF_TQ*2/3))) + 1;
- else
- prescale_val = IPB_CLOCK/(CAN_BIT_RATE* (CAN_MAX_NO_OF_TQ*2/3));
-
- tq_num = ((IPB_CLOCK/prescale_val)+CAN_BIT_RATE/2)/CAN_BIT_RATE;
- /*
- * XXX: make this table controlled according to MPC5200UM/Rev.3,Table 19-34
- */
- sync_seg = 2;
- tseg2 = (tq_num-sync_seg)/6;
- tseg1 = tq_num - sync_seg - tseg2;
+ uint8_t tq_no, tseg_1, tseg_2, sseg;
+
+ /* get optimized prescaler value */
+ prescale_val = prescaler_calculation(can_bit_rate, can_clock_frq, &tq_no);
+
+ /* get time segment length from time segment table */
+ tseg_1 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_1];
+ tseg_2 = can_time_segment_table[tq_no - MIN_NO_OF_TQ][TSEG_2];
+ sseg = can_time_segment_table[tq_no - MIN_NO_OF_TQ][SJW];
/* Bus Timing Register 0 MSCAN_A/_B ------------------------------*/
/* [07]:SJW1 1 : Synchronization jump width, Bit1 */
@@ -569,7 +784,7 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca
/* [02]:BRP2 1 : Baud Rate Prescaler, Bit 2 */
/* [01]:BRP1 0 : Baud Rate Prescaler, Bit 1 */
/* [00]:BRP0 1 : Baud Rate Prescaler, Bit 0 */
- mscan->btr0 |= (BTR0_SJW(sync_seg-1) | BTR0_BRP(prescale_val - 1));
+ mscan->btr0 = (BTR0_SJW(sseg-1) | BTR0_BRP(prescale_val-1));
/* Bus Timing Register 1 MSCAN_A/_B ------------------------------*/
/* [07]:SAMP 0 : One Sample per bit */
@@ -581,8 +796,7 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca
/* [02]:TSEG12 1 : Time Segment 1, Bit 2 */
/* [01]:TSEG11 1 : Time Segment 1, Bit 1 */
/* [00]:TSEG10 0 : Time Segment 1, Bit 0 */
- mscan->btr1 &= ~(BTR1_SAMP);
- mscan->btr1 |= (BTR1_TSEG_22_20(tseg2-1) | BTR1_TSEG_13_10(tseg1-1));
+ mscan->btr1 = (BTR1_TSEG_22_20(tseg_2-1) | BTR1_TSEG_13_10(tseg_1-1));
return;
@@ -594,7 +808,10 @@ void mpc5200_mscan_perform_bit_time_settings(volatile struct mpc5200_mscan *msca
*/
void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *mscan)
{
- mpc5200_mscan_perform_bit_time_settings(mscan);
+
+ /* perform all can bit time settings */
+ mpc5200_mscan_perform_bit_time_settings(mscan,CAN_BIT_RATE,IPB_CLOCK);
+
/* Control Register 1 --------------------------------------------*/
/* [07]:CANE 0 : MSCAN Module is disabled */
/* [06]:CLKSRC 0 : Clock Source -> IPB_CLOCK (bsp.h) */
@@ -634,25 +851,15 @@ void mpc5200_mscan_perform_init_mode_settings(volatile struct mpc5200_mscan *msc
mscan->idac &= ~(IDAC_IDAM1);
mscan->idac |= (IDAC_IDAM0);
- /* initialize rx filter masks: only accept exact matches */
- mscan->idmr0 = 0x00;
- mscan->idmr1 = 0x00;
- mscan->idmr2 = 0x00;
- mscan->idmr3 = 0x00;
- mscan->idmr4 = 0x00;
- mscan->idmr5 = 0x00;
- mscan->idmr6 = 0x00;
- mscan->idmr7 = 0x00;
-
- /* initialize rx filters: set to illegal values, so no matches occure */
- mscan->idar0 = 0xff;
- mscan->idar1 = 0xff;
- mscan->idar2 = 0xff;
- mscan->idar3 = 0xff;
- mscan->idar4 = 0xff;
- mscan->idar5 = 0xff;
- mscan->idar6 = 0xff;
- mscan->idar7 = 0xff;
+ /* initialize rx filter masks (16 bit) */
+ mscan->idmr0 = SET_IDMR0(0x07FF);
+ mscan->idmr1 = SET_IDMR1(0x07FF);
+ mscan->idmr2 = SET_IDMR2(0x07FF);
+ mscan->idmr3 = SET_IDMR3(0x07FF);
+ mscan->idmr4 = SET_IDMR4(0x07FF);
+ mscan->idmr5 = SET_IDMR5(0x07FF);
+ mscan->idmr6 = SET_IDMR6(0x07FF);
+ mscan->idmr7 = SET_IDMR7(0x07FF);
/* Control Register 1 --------------------------------------------*/
/* [07]:CANE 0->1 : MSCAN Module is enabled */
@@ -719,36 +926,44 @@ rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor, uint8_
switch(mode)
{
+ case MSCAN_INIT_NORMAL_MODE:
+ /* if not already set enter init mode */
+ mpc5200_mscan_enter_init_mode(mscan);
+ /* perform initialization which has to be done in init mode */
+ mpc5200_mscan_perform_init_mode_settings(mscan);
+ break;
+
case MSCAN_NORMAL_MODE:
/* if not already set enter init mode */
mpc5200_mscan_enter_init_mode(mscan);
if((chan->mode) == MSCAN_INITIALIZED_MODE)
+ {
+
/* perform initialization which has to be done in init mode */
mpc5200_mscan_perform_init_mode_settings(mscan);
- else
+ }
+
+ if((chan->mode) == MSCAN_SLEEP_MODE)
+ {
+
/* exit sleep mode */
mpc5200_mscan_exit_sleep_mode(mscan);
+ }
- /* exit init mode */
+ /* exit init mode */
mpc5200_mscan_exit_init_mode(mscan);
/* enable ints. */
mpc5200_mscan_int_enable(mscan);
/* wait for bus sync. */
mpc5200_mscan_wait_sync(mscan);
- return RTEMS_SUCCESSFUL;
break;
case MSCAN_SLEEP_MODE:
- /* enable ints. */
+ /* disable ints. */
mpc5200_mscan_int_disable(mscan);
- /* if not already set enter init mode */
- mpc5200_mscan_enter_init_mode(mscan);
/* exit sleep mode */
mpc5200_mscan_enter_sleep_mode(mscan);
- /* exit init mode */
- mpc5200_mscan_exit_init_mode(mscan);
- return RTEMS_SUCCESSFUL;
break;
default:
@@ -773,26 +988,55 @@ rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtem
rtems_status_code status;
struct mscan_channel_info *chan = &chan_info[minor];
+
/* set registers according to MSCAN channel information */
switch(minor)
{
case MSCAN_A:
chan->rx_qname = rtems_build_name ('C', 'N', 'A', 'Q');
+ chan->tx_rb_sname = rtems_build_name ('C', 'N', 'A', 'S');
/* register RTEMS device names for MSCAN A */
- if((status = rtems_io_register_name (MSCAN_A_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
+ if((status = rtems_io_register_name (MSCAN_A_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
+ return status;
+
+ /* register RTEMS device names for MSCAN 0 */
+ if((status = rtems_io_register_name (MSCAN_0_DEV_NAME, major, MSCAN_A)) != RTEMS_SUCCESSFUL)
return status;
+ /* allocate the space for MSCAN A tx ring buffer */
+ if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
+ {
+ chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
+ }
+ else
+ {
+ return RTEMS_UNSATISFIED;
+ }
break;
case MSCAN_B:
chan->rx_qname = rtems_build_name ('C', 'N', 'B', 'Q');
+ chan->tx_rb_sname = rtems_build_name ('C', 'N', 'B', 'S');
/* register RTEMS device names for MSCAN B */
if((status = rtems_io_register_name (MSCAN_B_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
return status;
+ /* register RTEMS device names for MSCAN 1 */
+ if((status = rtems_io_register_name (MSCAN_1_DEV_NAME, major, MSCAN_B)) != RTEMS_SUCCESSFUL)
+ return status;
+
+ /* allocate the space for MSCAN B tx ring buffer */
+ if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*(NO_OF_MSCAN_TX_BUFF+1))) != NULL)
+ {
+ chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
+ }
+ else
+ {
+ return RTEMS_UNSATISFIED;
+ }
break;
default:
@@ -800,27 +1044,30 @@ rtems_status_code mscan_channel_initialize(rtems_device_major_number major, rtem
break;
}
- /* create RTEMS rx message queue for MSCAN A */
- if((status = rtems_message_queue_create(chan->rx_qname,
- (uint32_t) NO_OF_MSCAN_A_RX_BUFF,
- (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)),
- (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
- (rtems_id *)&(chan->rx_qid)))
- != RTEMS_SUCCESSFUL)
- {
- return status;
-
- }
-
- /* Set up interrupts MSCAN A */
+ /* create RTEMS rx message queue */
+ status = rtems_message_queue_create(chan->rx_qname,
+ (uint32_t) NO_OF_MSCAN_RX_BUFF,
+ (uint32_t) MSCAN_MESSAGE_SIZE(sizeof(struct can_message)),
+ (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
+ (rtems_id *)&(chan->rx_qid));
+
+ /* create counting RTEMS tx ring buffer semaphore */
+ status = rtems_semaphore_create(chan->tx_rb_sname,
+ (uint32_t)(NO_OF_MSCAN_TX_BUFF),
+ RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
+ (rtems_task_priority)0,
+ (rtems_id *)&(chan->tx_rb_sid));
+
+ /* Set up interrupts */
if(!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %d\n", minor);
/* basic setup for channel info. struct. */
- chan->regs = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]);
- chan->int_rx_err = 0;
- chan->id_extended = FALSE;
- chan->mode = MSCAN_INITIALIZED_MODE;
+ chan->regs = (struct mpc5200_mscan *)&(mpc5200.mscan[minor]);
+ chan->int_rx_err = 0;
+ chan->id_extended = FALSE;
+ chan->mode = MSCAN_INITIALIZED_MODE;
+ chan->tx_buf_no = NO_OF_MSCAN_TX_BUFF;
return status;
@@ -844,10 +1091,10 @@ rtems_device_driver mscan_initialize(rtems_device_major_number major,
if((status = mscan_channel_initialize(major,MSCAN_B)) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status);
- if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
+ if((status = mpc5200_mscan_set_mode(MSCAN_A, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status);
- if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
+ if((status = mpc5200_mscan_set_mode(MSCAN_B, MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
rtems_fatal_error_occurred(status);
return status;
@@ -863,7 +1110,7 @@ rtems_device_driver mscan_open( rtems_device_major_number major,
void * arg
)
{
- rtems_status_code status;
+ rtems_status_code status = RTEMS_SUCCESSFUL;
struct mscan_channel_info *chan = NULL;
switch(minor)
@@ -879,8 +1126,14 @@ rtems_device_driver mscan_open( rtems_device_major_number major,
break;
}
- /* if not already set enter init mode */
- status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
+
+ /* check mode */
+ if((chan->mode) == MSCAN_SLEEP_MODE)
+ {
+
+ /* if not already set enter init mode */
+ status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
+ }
return status;
@@ -947,6 +1200,15 @@ rtems_device_driver mscan_read( rtems_device_major_number major,
break;
}
+
+ /* end init mode if it is first read */
+ if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
+ {
+
+ /* if not already set enter init mode */
+ mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
+ }
+
if((status = rtems_message_queue_receive(chan->rx_qid,
(void *)(rx_mess),
(uint32_t *)&message_size,
@@ -978,16 +1240,16 @@ rtems_device_driver mscan_write( rtems_device_major_number major,
void * arg
)
{
- rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *)arg;
- struct mscan_tx_parms *tx_parms = (struct mscan_tx_parms *)(parms->buffer);
- struct can_message *tx_mess = (struct can_message *)(tx_parms->tx_mess);
- struct mscan_channel_info *chan = NULL;
- mscan_handle *mscan_hdl = NULL;
- volatile struct mpc5200_mscan *mscan = NULL;
+ rtems_status_code status;
+ rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *)arg;
+ struct mscan_tx_parms *tx_parms = (struct mscan_tx_parms *)(parms->buffer);
+ struct can_message *tx_mess = (struct can_message *)(tx_parms->tx_mess);
+ struct mscan_channel_info *chan = NULL;
+ mscan_handle *mscan_hdl = NULL;
+ volatile struct mpc5200_mscan *mscan = NULL;
switch(minor)
{
-
case MSCAN_A:
case MSCAN_B:
chan = &chan_info[minor];
@@ -1000,118 +1262,39 @@ rtems_device_driver mscan_write( rtems_device_major_number major,
break;
}
- /* select one free tx buffer (TOUCAN not registered) */
- if((mscan_hdl->toucan_callback) == NULL)
- {
-
- if(mscan->tflg & MSCAN_TX_BUFF2)
- mscan->bsel = MSCAN_TX_BUFF2;
-
- if(mscan->tflg & MSCAN_TX_BUFF1)
- mscan->bsel = MSCAN_TX_BUFF1;
-
- if(mscan->tflg & MSCAN_TX_BUFF0)
- mscan->bsel = MSCAN_TX_BUFF0;
- }
- else
+ /* end init mode if it is first write */
+ if((chan->mode) == MSCAN_INIT_NORMAL_MODE)
{
- /* select a specific, preconfigured tx buffer (TOUCAN registered) */
- switch(tx_parms->tx_id)
- {
-
- case 0:
- if(mscan->tflg & MSCAN_TX_BUFF0)
- mscan->bsel = MSCAN_TX_BUFF0;
- break;
-
- case 1:
- if(mscan->tflg & MSCAN_TX_BUFF1)
- mscan->bsel = MSCAN_TX_BUFF1;
- break;
-
- case 2:
- if(mscan->tflg & MSCAN_TX_BUFF2)
- mscan->bsel = MSCAN_TX_BUFF2;
- break;
-
- default:
- break;
-
- }
-
+ /* if not already set enter init mode */
+ mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
}
- /* if no tx buffer is available, teminate the write request */
- if(!(mscan->bsel))
- {
-
- parms->bytes_moved = 0;
- return RTEMS_UNSATISFIED;
-
- }
+ /* preset moved bytes */
+ parms->bytes_moved = 0;
- /* prepare tx id and dlc (TOUCAN not initialized) */
- if((mscan_hdl->toucan_callback) == NULL)
+ /* obtain counting semaphore of tx ring buffer */
+ if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
+ RTEMS_NO_WAIT,
+ (rtems_interval)0))
+ == RTEMS_SUCCESSFUL)
{
- /* check for tx length */
- if((tx_mess->mess_len) & 0x000F)
- {
+ /* append the TOUCAN tx_id to the mess. due to interrupt handling */
+ tx_mess->toucan_tx_id = tx_parms->tx_id;
- /* set tx id */
- mscan->txidr0 = SET_IDR0(tx_mess->mess_id);
- mscan->txidr1 = SET_IDR1(tx_mess->mess_id);
- mscan->txidr2 = 0;
- mscan->txidr3 = 0;
+ /* fill the tx ring buffer with the message */
+ fill_tx_buffer(chan, tx_mess);
- /* insert dlc into mscan register */
- mscan->txdlr = (uint8_t)((tx_mess->mess_len) & 0x000F);
-
- }
- else
- {
+ /* enable message buffer specific interrupt */
+ mscan->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
- parms->bytes_moved = 0;
- return RTEMS_UNSATISFIED;
-
- }
-
- }
-
- /* copy tx data to MSCAN registers */
- switch(mscan->txdlr)
- {
-
- case 8:
- mscan->txdsr7 = tx_mess->mess_data[7];
- case 7:
- mscan->txdsr6 = tx_mess->mess_data[6];
- case 6:
- mscan->txdsr5 = tx_mess->mess_data[5];
- case 5:
- mscan->txdsr4 = tx_mess->mess_data[4];
- case 4:
- mscan->txdsr3 = tx_mess->mess_data[3];
- case 3:
- mscan->txdsr2 = tx_mess->mess_data[2];
- case 2:
- mscan->txdsr1 = tx_mess->mess_data[1];
- case 1:
- mscan->txdsr0 = tx_mess->mess_data[0];
- break;
- default:
- break;
+ /* calculate moved bytes */
+ parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
}
- /* enable message buffer specific interrupt */
- mscan->tier |= mscan->bsel;
-
- /* start transfer */
- mscan->tflg = mscan->bsel;
-
- return RTEMS_SUCCESSFUL;
+ return status;
}
@@ -1124,12 +1307,14 @@ rtems_device_driver mscan_control( rtems_device_major_number major,
void * arg
)
{
+ rtems_status_code status;
uint16_t tx_id;
- rtems_libio_ioctl_args_t *parms = (rtems_libio_ioctl_args_t *)arg;
- struct mscan_ctrl_parms *ctrl_parms = (struct mscan_ctrl_parms *)(parms->buffer);
- struct mscan_channel_info *chan = NULL;
- mscan_handle *mscan_hdl = NULL;
- volatile struct mpc5200_mscan *mscan = NULL;
+ rtems_libio_ioctl_args_t *parms = (rtems_libio_ioctl_args_t *)arg;
+ struct mscan_ctrl_parms *ctrl_parms = (struct mscan_ctrl_parms *)(parms->buffer);
+ struct mscan_channel_info *chan = NULL;
+ mscan_handle *mscan_hdl = NULL;
+ volatile struct mpc5200_mscan *mscan = NULL;
+ uint8_t tx_buf_count = 0;
switch(minor)
{
@@ -1239,23 +1424,23 @@ rtems_device_driver mscan_control( rtems_device_major_number major,
{
case RX_BUFFER_0:
- mscan->idmr0 = SET_IDR0(ctrl_parms->ctrl_id_mask);
- mscan->idmr1 = SET_IDR1(ctrl_parms->ctrl_id_mask);
+ mscan->idmr0 = SET_IDMR0(ctrl_parms->ctrl_id_mask);
+ mscan->idmr1 = SET_IDMR1(ctrl_parms->ctrl_id_mask);
break;
case RX_BUFFER_1:
- mscan->idmr2 = SET_IDR2(ctrl_parms->ctrl_id_mask);
- mscan->idmr3 = SET_IDR3(ctrl_parms->ctrl_id_mask);
+ mscan->idmr2 = SET_IDMR2(ctrl_parms->ctrl_id_mask);
+ mscan->idmr3 = SET_IDMR3(ctrl_parms->ctrl_id_mask);
break;
case RX_BUFFER_2:
- mscan->idmr4 = SET_IDR4(ctrl_parms->ctrl_id_mask);
- mscan->idmr5 = SET_IDR5(ctrl_parms->ctrl_id_mask);
+ mscan->idmr4 = SET_IDMR4(ctrl_parms->ctrl_id_mask);
+ mscan->idmr5 = SET_IDMR5(ctrl_parms->ctrl_id_mask);
break;
case RX_BUFFER_3:
- mscan->idmr6 = SET_IDR6(ctrl_parms->ctrl_id_mask);
- mscan->idmr7 = SET_IDR7(ctrl_parms->ctrl_id_mask);
+ mscan->idmr6 = SET_IDMR6(ctrl_parms->ctrl_id_mask);
+ mscan->idmr7 = SET_IDMR7(ctrl_parms->ctrl_id_mask);
break;
default:
@@ -1281,19 +1466,19 @@ rtems_device_driver mscan_control( rtems_device_major_number major,
{
case RX_BUFFER_0:
- ctrl_parms->ctrl_id_mask = GET_IDR0(mscan->idmr0) | GET_IDR1(mscan->idmr1);
+ ctrl_parms->ctrl_id_mask = GET_IDMR0(mscan->idmr0) | GET_IDMR1(mscan->idmr1);
break;
case RX_BUFFER_1:
- ctrl_parms->ctrl_id_mask = GET_IDR2(mscan->idmr2) | GET_IDR3(mscan->idmr3);
+ ctrl_parms->ctrl_id_mask = GET_IDMR2(mscan->idmr2) | GET_IDMR3(mscan->idmr3);
break;
case RX_BUFFER_2:
- ctrl_parms->ctrl_id_mask = GET_IDR4(mscan->idmr4) | GET_IDR5(mscan->idmr5);
+ ctrl_parms->ctrl_id_mask = GET_IDMR4(mscan->idmr4) | GET_IDMR5(mscan->idmr5);
break;
case RX_BUFFER_3:
- ctrl_parms->ctrl_id_mask = GET_IDR6(mscan->idmr6) | GET_IDR7(mscan->idmr7);
+ ctrl_parms->ctrl_id_mask = GET_IDMR6(mscan->idmr6) | GET_IDMR7(mscan->idmr7);
break;
default:
@@ -1339,6 +1524,98 @@ rtems_device_driver mscan_control( rtems_device_major_number major,
break;
+ /* set can bitrate */
+ case MSCAN_SET_BAUDRATE:
+
+ /* check bitrate settings */
+ if(((ctrl_parms->ctrl_can_bitrate) >= CAN_BIT_RATE_MIN) && ((ctrl_parms->ctrl_can_bitrate) <= CAN_BIT_RATE_MAX)) {
+
+ /* enter init mode */
+ mpc5200_mscan_enter_init_mode(mscan);
+
+ /* perform all can bit time settings */
+ mpc5200_mscan_perform_bit_time_settings(mscan,(uint32_t)(ctrl_parms->ctrl_can_bitrate),IPB_CLOCK);
+
+ /* exit init mode and perform further initialization which is required in the normal mode */
+ mpc5200_mscan_exit_init_mode(mscan);
+
+ /* enable ints. */
+ mpc5200_mscan_int_enable(mscan);
+
+ /* wait for bus sync. */
+ mpc5200_mscan_wait_sync(mscan);
+
+ return RTEMS_SUCCESSFUL;
+ }
+ else {
+
+ return RTEMS_UNSATISFIED;
+ }
+
+ break;
+
+ case SET_TX_BUF_NO:
+
+ /* check for different settings of tx ring buffer */
+ if((tx_buf_count = chan->tx_buf_no) != (uint8_t)(ctrl_parms->ctrl_tx_buf_no))
+ {
+
+ /* preset the channel specific no of messages in the tx ring buffer */
+ tx_buf_count = chan->tx_buf_no;
+
+ /* try to obtain all of the tx ring buffers */
+ while(tx_buf_count > 0)
+ {
+
+ /* obtain semaphore of all tx ring buffers */
+ if((status = rtems_semaphore_obtain((rtems_id)(chan->tx_rb_sid),
+ RTEMS_WAIT,
+ (rtems_interval)10))
+ == RTEMS_SUCCESSFUL)
+ {
+
+ tx_buf_count--;
+
+ }
+
+ }
+
+ /* free the former tx ring buffer */
+ free((void *)chan->tx_ring_buf.buf_ptr);
+
+ /* allocate the tx ring buffer with new size */
+ if(((chan->tx_ring_buf.buf_ptr) = malloc(sizeof(struct can_message)*((uint8_t)(ctrl_parms->ctrl_tx_buf_no)+1))) != NULL)
+ {
+ chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr = chan->tx_ring_buf.buf_ptr;
+ }
+ else
+ {
+ return RTEMS_UNSATISFIED;
+ }
+
+ /* set the new amount of tx buffers */
+ chan->tx_buf_no = (uint8_t)(ctrl_parms->ctrl_tx_buf_no);
+
+ /* release the semaphore of all tx ring buffers */
+ while(tx_buf_count < chan->tx_buf_no)
+ {
+
+ /* obtain semaphore of all tx ring buffers */
+ rtems_semaphore_release((rtems_id)(chan->tx_rb_sid));
+
+ tx_buf_count++;
+
+ }
+
+ }
+ else
+ {
+
+ return RTEMS_SUCCESSFUL;
+
+ }
+ break;
+
default:
break;