Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:53

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * RTEMS generic MPC5200 BSP
0005  *
0006  * This file contains the MSCAN driver.
0007  */
0008 
0009 /*
0010  * Copyright (c) 2005 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include <stdio.h>
0035 #include <stdlib.h>
0036 #include <rtems.h>
0037 #include <rtems/error.h>
0038 #include <rtems/libio.h>
0039 #include <string.h>
0040 
0041 #include <bsp.h>
0042 #include <bsp/fatal.h>
0043 #include <bsp/irq.h>
0044 #include "../mscan/mscan_int.h"
0045 
0046 /* #define MSCAN_LOOPBACK */
0047 
0048 struct mpc5200_rx_cntrl mpc5200_mscan_rx_cntrl[MPC5200_CAN_NO];
0049 static struct mscan_channel_info chan_info[MPC5200_CAN_NO];
0050 
0051 /*
0052  * MPC5x00 MSCAN tx ring buffer function to get a can message buffer from the head of the tx ring buffer
0053  */
0054 static struct can_message *get_tx_buffer(struct mscan_channel_info *chan)
0055 {
0056   /* define a temp. mess ptr. */
0057   struct can_message *tmp_mess_ptr = NULL,
0058     *temp_head_ptr;
0059 
0060   /* set temp. head pointer */
0061   temp_head_ptr = chan->tx_ring_buf.head_ptr;
0062 
0063   /* check buffer empty condition */
0064   if (temp_head_ptr != chan->tx_ring_buf.tail_ptr) {
0065 
0066     /* current buffer head. ptr. */
0067     tmp_mess_ptr = temp_head_ptr;
0068 
0069     /* increment the head pointer */
0070     temp_head_ptr++;
0071 
0072     /* check for wrap around condition */
0073     if (temp_head_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) {
0074 
0075       /* set head ptr. to the begin of the ring buffer */
0076       temp_head_ptr = chan->tx_ring_buf.buf_ptr;
0077 
0078     }
0079 
0080     /* end of crtical section restore head ptr. */
0081     chan->tx_ring_buf.head_ptr = temp_head_ptr;
0082   }
0083 
0084   /* return the current head pointer */
0085   return tmp_mess_ptr;
0086 }
0087 
0088 /*
0089  * MPC5x00 MSCAN tx ring buffer function to write a can message buffer to the tail of the tx ring buffer
0090  */
0091 static struct can_message *fill_tx_buffer(struct mscan_channel_info *chan,
0092                                           struct can_message *mess_ptr)
0093 {
0094   /* define a temp. mess ptr. to the entry which follows the current tail entry */
0095   struct can_message *tmp_mess_ptr = chan->tx_ring_buf.tail_ptr + 1;
0096 
0097   /* check for the wrap around condition */
0098   if (tmp_mess_ptr > chan->tx_ring_buf.buf_ptr + NO_OF_MSCAN_TX_BUFF) {
0099     /* set temp. mess. ptr to the begin of the ring buffer */
0100     tmp_mess_ptr = chan->tx_ring_buf.buf_ptr;
0101   }
0102 
0103   /* check buffer full condition */
0104   if (tmp_mess_ptr == chan->tx_ring_buf.head_ptr) {
0105     /* return NULL in case buffer is full */
0106     return NULL;
0107   } else {
0108     /* copy the can mess. to the tail of the buffer */
0109     memcpy((void *) chan->tx_ring_buf.tail_ptr, (void *) mess_ptr,
0110            sizeof (struct can_message));
0111 
0112     /* set new tail equal to temp. mess. ptr. */
0113     chan->tx_ring_buf.tail_ptr = tmp_mess_ptr;
0114   }
0115 
0116   /* return the actual tail ptr. (next free entry) */
0117   return chan->tx_ring_buf.tail_ptr;
0118 }
0119 
0120 /*
0121  * MPC5x00 MSCAN interrupt handler
0122  */
0123 static void mpc5200_mscan_interrupt_handler(rtems_irq_hdl_param handle)
0124 {
0125   rtems_status_code status;
0126   mscan_handle *mscan_hdl = (mscan_handle *) handle;
0127   struct mscan_channel_info *chan = &chan_info[mscan_hdl->mscan_channel];
0128   struct can_message rx_mess,
0129    *rx_mess_ptr,
0130    *tx_mess_ptr;
0131   mscan *m = chan->regs;
0132   register uint8_t idx;
0133 
0134   /*
0135      handle tx ring buffer
0136    */
0137 
0138   /* loop over all 3 tx buffers */
0139   for (idx = TFLG_TXE0; idx <= TFLG_TXE2; idx = idx << 1) {
0140 
0141     /* check for tx buffer vacation */
0142     if ((m->tflg) & idx) {
0143 
0144       /* try to get a message */
0145       tx_mess_ptr = get_tx_buffer(chan);
0146 
0147       /* check for new tx message */
0148       if (tx_mess_ptr != NULL) {
0149 
0150         /* select the tx buffer */
0151         m->bsel = idx;
0152 
0153         /* check for toucan interface */
0154         if ((mscan_hdl->toucan_callback) == NULL) {
0155 
0156           /* set tx id */
0157           m->txidr0 = SET_IDR0(tx_mess_ptr->mess_id);
0158           m->txidr1 = SET_IDR1(tx_mess_ptr->mess_id);
0159           m->txidr2 = 0;
0160           m->txidr3 = 0;
0161 
0162         }
0163 
0164         /* fill in tx data if TOUCAN is activ an TOUCAN index have a match with the tx buffer or TOUCAN is disabled */
0165         if (((mscan_hdl->toucan_callback) == NULL)
0166             || (((mscan_hdl->toucan_callback) != NULL)
0167                 && ((tx_mess_ptr->toucan_tx_idx) == idx))) {
0168 
0169           /* insert dlc into m register */
0170           m->txdlr = (uint8_t) ((tx_mess_ptr->mess_len) & 0x000F);
0171 
0172           /* skip data copy in case of RTR */
0173           if (!(MSCAN_MESS_ID_HAS_RTR(tx_mess_ptr->mess_id))) {
0174             /* copy tx data to MSCAN registers */
0175             switch (m->txdlr) {
0176               case 8:
0177                 m->txdsr7 = tx_mess_ptr->mess_data[7];
0178               case 7:
0179                 m->txdsr6 = tx_mess_ptr->mess_data[6];
0180               case 6:
0181                 m->txdsr5 = tx_mess_ptr->mess_data[5];
0182               case 5:
0183                 m->txdsr4 = tx_mess_ptr->mess_data[4];
0184               case 4:
0185                 m->txdsr3 = tx_mess_ptr->mess_data[3];
0186               case 3:
0187                 m->txdsr2 = tx_mess_ptr->mess_data[2];
0188               case 2:
0189                 m->txdsr1 = tx_mess_ptr->mess_data[1];
0190               case 1:
0191                 m->txdsr0 = tx_mess_ptr->mess_data[0];
0192                 break;
0193               default:
0194                 break;
0195             }
0196           }
0197 
0198           /* enable message buffer specific interrupt */
0199           m->tier |= m->bsel;
0200 
0201           /* start transfer */
0202           m->tflg = m->bsel;
0203 
0204           /* release counting semaphore of tx ring buffer */
0205           rtems_semaphore_release((rtems_id) (chan->tx_rb_sid));
0206 
0207         } else {
0208 
0209           /* refill the tx ring buffer with the message */
0210           fill_tx_buffer(chan, tx_mess_ptr);
0211 
0212         }
0213       } else {
0214         /* reset interrupt enable bit */
0215         m->tier &= ~(idx);
0216       }
0217     }
0218   }
0219 
0220   /*
0221      handle rx interrupts
0222    */
0223 
0224   /* check for rx interrupt source */
0225   if (m->rier & RIER_RXFIE) {
0226 
0227     /* can messages received ? */
0228     while (m->rflg & RFLG_RXF) {
0229 
0230       if (mscan_hdl->toucan_callback == NULL) {
0231 
0232         /* select temporary rx buffer */
0233         rx_mess_ptr = &rx_mess;
0234 
0235       } else {
0236 
0237         /* check the rx fliter-match indicators (16-bit filter mode) */
0238         /* in case of more than one hit, lower hit has priority */
0239         idx = (m->idac) & 0x7;
0240         switch (idx) {
0241 
0242           case 0:
0243           case 1:
0244           case 2:
0245           case 3:
0246             rx_mess_ptr =
0247               (struct can_message *)
0248               &(mpc5200_mscan_rx_cntrl[mscan_hdl->mscan_channel].
0249                 can_rx_message[idx]);
0250             break;
0251 
0252             /* this case should never happen */
0253           default:
0254             /* reset the rx indication flag */
0255             m->rflg |= RFLG_RXF;
0256 
0257             return;
0258             break;
0259         }
0260 
0261       }
0262 
0263       /* get rx ID */
0264       rx_mess_ptr->mess_id = GET_IDR0(m->rxidr0) | GET_IDR1(m->rxidr1);
0265 
0266       /* get rx len */
0267       rx_mess_ptr->mess_len = ((m->rxdlr) & 0x0F);
0268 
0269       /* get time stamp */
0270       rx_mess_ptr->mess_time_stamp = ((m->rxtimh << 8) | (m->rxtiml));
0271 
0272       /* skip data copy in case of RTR */
0273       if (!(MSCAN_MESS_ID_HAS_RTR(rx_mess_ptr->mess_id)))
0274       {
0275 
0276         /* get the data */
0277         switch (rx_mess_ptr->mess_len) {
0278           case 8:
0279             rx_mess_ptr->mess_data[7] = m->rxdsr7;
0280           case 7:
0281             rx_mess_ptr->mess_data[6] = m->rxdsr6;
0282           case 6:
0283             rx_mess_ptr->mess_data[5] = m->rxdsr5;
0284           case 5:
0285             rx_mess_ptr->mess_data[4] = m->rxdsr4;
0286           case 4:
0287             rx_mess_ptr->mess_data[3] = m->rxdsr3;
0288           case 3:
0289             rx_mess_ptr->mess_data[2] = m->rxdsr2;
0290           case 2:
0291             rx_mess_ptr->mess_data[1] = m->rxdsr1;
0292           case 1:
0293             rx_mess_ptr->mess_data[0] = m->rxdsr0;
0294           case 0:
0295           default:
0296             break;
0297         }
0298       }
0299 
0300       if (mscan_hdl->toucan_callback == NULL) {
0301 
0302         if ((status =
0303              rtems_message_queue_send(chan->rx_qid, (void *) rx_mess_ptr,
0304                                       sizeof (struct can_message))) !=
0305             RTEMS_SUCCESSFUL) {
0306 
0307           chan->int_rx_err++;
0308 
0309         }
0310 
0311       } else {
0312 
0313         mscan_hdl->toucan_callback((int16_t) (((m->idac) & 0x7) + 3));
0314 
0315       }
0316 
0317       /* reset the rx indication flag */
0318       m->rflg |= RFLG_RXF;
0319 
0320     }                           /* end of while(m->rflg & RFLG_RXF) */
0321 
0322   }
0323 
0324   /* status change detected */
0325   if (m->rflg & RFLG_CSCIF) {
0326 
0327     m->rflg |= RFLG_CSCIF;
0328 
0329     if (mscan_hdl->toucan_callback != NULL) {
0330 
0331       mscan_hdl->toucan_callback((int16_t) (-1));
0332 
0333     }
0334 
0335   }
0336 
0337 }
0338 
0339 /**
0340  * @brief Enables some interrupts for the MSCAN module @a m.
0341  *
0342  * Enabled interrupts:
0343  *  - Receiver or transmitter enters or leaves bus off state
0344  *  - Receiver buffer full
0345  */
0346 static void mscan_interrupts_enable(mscan *m)
0347 {
0348 
0349   /* RX Interrupt Enable on MSCAN_A/_B ----------------------------- */
0350   /*    [07]:WUPIE         0 : WakeUp interrupt disabled            */
0351   /*    [06]:CSCIE         1 : Status Change interrupt enabled      */
0352   /*    [05]:RSTATE1       0 : Recv. Status Change int. ,Bit 1      */
0353   /*    [04]:RSTATE0       1 : Recv. Status Change int. ,Bit 0      */
0354   /*                           -> 01 BusOff status changes enabled  */
0355   /*    [03]:TSTAT1        0 : Transmit. Status Change int. , Bit 1 */
0356   /*    [02]:TSTAT0        1 : Transmit. Status Change int. , Bit 0 */
0357   /*                           -> 01 BusOff status changes enabled  */
0358   /*    [01]:OVRIE         0 : Overrun Interrupt is disabled        */
0359   /*    [00]:RXFIE         1 : Recv. Full interrupt is enabled      */
0360   m->rier |= (RIER_CSCIE | RIER_RXFIE | RIER_RSTAT(1) | RIER_TSTAT(1));
0361 
0362   return;
0363 
0364 }
0365 
0366 /*
0367  * Unmask MPC5x00 MSCAN_A interrupts
0368  */
0369 static void mpc5200_mscan_a_on(const rtems_irq_connect_data * ptr)
0370 {
0371   mscan *m = (&chan_info[MSCAN_A])->regs;
0372 
0373   mscan_interrupts_enable(m);
0374 
0375   return;
0376 
0377 }
0378 
0379 /*
0380  * Mask MPC5x00 MSCAN_A interrupts
0381  */
0382 static void mpc5200_mscan_a_off(const rtems_irq_connect_data * ptr)
0383 {
0384   mscan *m = (&chan_info[MSCAN_A])->regs;
0385 
0386   mscan_interrupts_disable(m);
0387 
0388   return;
0389 
0390 }
0391 
0392 /*
0393  *  Get MSCAN_A interrupt mask setting
0394  */
0395 static int mpc5200_mscan_a_isOn(const rtems_irq_connect_data * ptr)
0396 {
0397   mscan *m = (&chan_info[MSCAN_A])->regs;
0398 
0399   if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE))
0400     return RTEMS_SUCCESSFUL;
0401   else
0402     return RTEMS_UNSATISFIED;
0403 
0404   return RTEMS_SUCCESSFUL;
0405 
0406 }
0407 
0408 /*
0409  * Unmask MPC5x00 MSCAN_B interrupts
0410  */
0411 static void mpc5200_mscan_b_on(const rtems_irq_connect_data * ptr)
0412 {
0413   mscan *m = (&chan_info[MSCAN_B])->regs;
0414 
0415   mscan_interrupts_enable(m);
0416 
0417   return;
0418 
0419 }
0420 
0421 /*
0422  * Mask MPC5x00 MSCAN_B interrupts
0423  */
0424 static void mpc5200_mscan_b_off(const rtems_irq_connect_data * ptr)
0425 {
0426   mscan *m = (&chan_info[MSCAN_B])->regs;
0427 
0428   mscan_interrupts_disable(m);
0429 
0430   return;
0431 
0432 }
0433 
0434 /*
0435  *  Get MSCAN_B interrupt mask setting
0436  */
0437 static int mpc5200_mscan_b_isOn(const rtems_irq_connect_data * ptr)
0438 {
0439   mscan *m = (&chan_info[MSCAN_B])->regs;
0440 
0441   if ((m->rier & RIER_CSCIE) && (m->rier & RIER_RXFIE))
0442     return RTEMS_SUCCESSFUL;
0443   else
0444     return RTEMS_UNSATISFIED;
0445 
0446   return RTEMS_SUCCESSFUL;
0447 
0448 }
0449 
0450 static mscan_handle mscan_a_handle = {
0451   MSCAN_A,
0452   NULL
0453 };
0454 
0455 static mscan_handle mscan_b_handle = {
0456   MSCAN_B,
0457   NULL
0458 };
0459 
0460 /*
0461  * MPC5x00 MSCAN_A/_B irq data
0462  */
0463 static rtems_irq_connect_data mpc5200_mscan_irq_data[MPC5200_CAN_NO] = {
0464   {
0465     BSP_SIU_IRQ_MSCAN1,
0466     (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
0467     (rtems_irq_hdl_param) & mscan_a_handle,
0468     (rtems_irq_enable) mpc5200_mscan_a_on,
0469     (rtems_irq_disable) mpc5200_mscan_a_off,
0470     (rtems_irq_is_enabled) mpc5200_mscan_a_isOn
0471   }, {
0472     BSP_SIU_IRQ_MSCAN2,
0473     (rtems_irq_hdl) mpc5200_mscan_interrupt_handler,
0474     (rtems_irq_hdl_param) & mscan_b_handle,
0475     (rtems_irq_enable) mpc5200_mscan_b_on,
0476     (rtems_irq_disable) mpc5200_mscan_b_off,
0477     (rtems_irq_is_enabled) mpc5200_mscan_b_isOn
0478   }
0479 };
0480 
0481 /*
0482  * MPC5x00 MSCAN wait for sync. with CAN bus
0483  */
0484 void mpc5200_mscan_wait_sync(mscan *m)
0485 {
0486 
0487   /* Control Register 0 -------------------------------------------- */
0488   /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
0489   /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
0490   /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
0491   /*    [04]:SYNCH    0->1 : Synchronized, Status Bit (rd. only)    */
0492   /*    [03]:TIME        1 : Generate Timestamps                    */
0493   /*    [02]:WUPE        0 : WakeUp Disabled                        */
0494   /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
0495   /*    [00]:INITRQ      0 : No init. Mode Request                  */
0496   /* wait for MSCAN A_/_B bus synch. */
0497 
0498 #if 0                           /* we don't have a need to wait for sync. */
0499   while (!((m->ctl0) & CTL0_SYNCH));
0500 #endif
0501   return;
0502 
0503 }
0504 
0505 /*
0506  * MPC5x00 MSCAN perform settings in init mode
0507  */
0508 static void mpc5200_mscan_perform_initialization_mode_settings(mscan *m)
0509 {
0510   mscan_context context;
0511 
0512   /* perform all can bit time settings */
0513   (void) mscan_set_bit_rate(m, MSCAN_BIT_RATE_DEFAULT);
0514 
0515   /* Enter initialization mode */
0516   mscan_initialization_mode_enter( m, &context);
0517 
0518   /* Control Register 1 -------------------------------------------- */
0519   /*    [07]:CANE        0 : MSCAN Module is disabled               */
0520   /*    [06]:CLKSRC      0 : Clock Source -> IPB_CLOCK (bsp.h)      */
0521   /*    [05]:LOOPB       0 : No Loopback                            */
0522   /*    [04]:LISTEN      0 : Normal Operation                       */
0523   /*    [03]:res         0 : reserved                               */
0524   /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
0525   /*    [01]:SLPAK    1->0 : Sleep Mode Acknowledge (rd. only)      */
0526   /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
0527   /* Set CLK source, disable loopback & listen-only mode */
0528 #ifndef MSCAN_LOOPBACK
0529   m->ctl1 &= ~(CTL1_LISTEN | CTL1_LOOPB | CTL1_CLKSRC);
0530 #else
0531   m->ctl1 &= ~(CTL1_LISTEN | CTL1_CLKSRC);
0532   m->ctl1 |= (CTL1_LOOPB);
0533 #endif
0534 
0535   /* IPB clock       -> IPB_CLOCK                                                            */
0536   /* bitrate         -> CAN_BIT_RATE                                                         */
0537   /* Max. no of Tq   -> CAN_MAX_NO_OF_TQ                                                     */
0538   /* Prescaler value -> prescale_val = ROUND_UP(IPB_CLOCK/(CAN_BIT_RATE * CAN_MAX_NO_OF_TQ)) */
0539   /* SYNC_SEG        ->  1 tq                                                                */
0540   /* time segment 1  -> 16 tq (PROP_SEG+PHASE_SEG), CAN_MAX_NO_OF_TQ_TSEG1 = 15              */
0541   /* time segment 2  ->  8 tq (PHASE_SEG2)        , CAN_MAX_NO_OF_TQ_TSEG2 =  7              */
0542   /* SJW             ->  3 (fixed 0...3)          , CAN_MAX_NO_OF_TQ_SJW   =  2              */
0543 
0544   /* ID Acceptance Control MSCAN_A/_B ------------------------------ */
0545   /*    [07]:res.        0 : reserved                               */
0546   /*    [06]:res.        0 : reserved                               */
0547   /*    [05]:IDAM1       0 : ID acceptance control, Bit1            */
0548   /*    [04]:IDAM0       1 : ID acceptance control, Bit0            */
0549   /*                         -> filter 16 bit mode                  */
0550   /*    [03]:res.        0 : reserved                               */
0551   /*    [02]:IDHIT2      0 : ID acceptance hit indication, Bit 2    */
0552   /*    [01]:IDHIT1      0 : ID acceptance hit indication, Bit 1    */
0553   /*    [00]:IDHIT0      0 : ID acceptance hit indication, Bit 0    */
0554   m->idac &= ~(IDAC_IDAM1);
0555   m->idac |= (IDAC_IDAM0);
0556 
0557   /* initialize rx filter masks (16 bit), don't care including rtr */
0558   m->idmr0 = SET_IDMR0(0x7FF);
0559   m->idmr1 = SET_IDMR1(0x7FF);
0560   m->idmr2 = SET_IDMR2(0x7FF);
0561   m->idmr3 = SET_IDMR3(0x7FF);
0562   m->idmr4 = SET_IDMR4(0x7FF);
0563   m->idmr5 = SET_IDMR5(0x7FF);
0564   m->idmr6 = SET_IDMR6(0x7FF);
0565   m->idmr7 = SET_IDMR7(0x7FF);
0566 
0567   /* Control Register 1 -------------------------------------------- */
0568   /*    [07]:CANE     0->1 : MSCAN Module is enabled                */
0569   /*    [06]:CLKSRC      1 : Clock Source -> IPB_CLOCK (bsp.h)      */
0570   /*    [05]:LOOPB       0 : No Loopback                            */
0571   /*    [04]:LISTEN      0 : Normal Operation                       */
0572   /*    [03]:res         0 : reserved                               */
0573   /*    [02]:WUPM        0 : No protect. from spurious WakeUp       */
0574   /*    [01]:SLPAK       0 : Sleep Mode Acknowledge (rd. only)      */
0575   /*    [00]:INITAK      0 : Init. Mode Acknowledge (rd. only)      */
0576   /* enable MSCAN A_/_B */
0577   m->ctl1 |= (CTL1_CANE);
0578 
0579   /* Leave initialization mode */
0580   mscan_initialization_mode_leave( m, &context);
0581 
0582   return;
0583 
0584 }
0585 
0586 /*
0587  * MPC5x00 MSCAN perform settings in normal mode
0588  */
0589 void mpc5200_mscan_perform_normal_mode_settings(mscan
0590                                                 *m)
0591 {
0592 
0593   /* Control Register 0 -------------------------------------------- */
0594   /*    [07]:RXFRM       0 : Recv. Frame, Flag Bit (rd.&clear only) */
0595   /*    [06]:RXACT       0 : Recv. Active, Status Bit (rd. only)    */
0596   /*    [05]:CSWAI       0 : CAN Stops in Wait Mode                 */
0597   /*    [04]:SYNCH       0 : Synchronized, Status Bit (rd. only)    */
0598   /*    [03]:TIME        1 : Generate Timestamps                    */
0599   /*    [02]:WUPE        0 : WakeUp Disabled                        */
0600   /*    [01]:SLPRQ       0 : No Sleep Mode Request                  */
0601   /*    [00]:INITRQ      0 : No init. Mode Request                  */
0602   /* Disable wait mode, enable timestamps */
0603   m->ctl0 &= ~(CTL0_CSWAI);
0604   m->ctl0 |= (CTL0_TIME);
0605 
0606   return;
0607 
0608 }
0609 
0610 rtems_status_code mpc5200_mscan_set_mode(rtems_device_minor_number minor,
0611                                          uint8_t mode)
0612 {
0613   struct mscan_channel_info *chan = NULL;
0614   mscan *m = NULL;
0615 
0616   switch (minor) {
0617 
0618     case MSCAN_A:
0619     case MSCAN_B:
0620       chan = &chan_info[minor];
0621       m = chan->regs;
0622       break;
0623 
0624     default:
0625       return RTEMS_UNSATISFIED;
0626       break;
0627   }
0628 
0629   if (chan->mode == mode)
0630     return RTEMS_SUCCESSFUL;
0631 
0632   switch (mode) {
0633 
0634     case MSCAN_INIT_NORMAL_MODE:
0635       /* perform initialization which has to be done in init mode */
0636       mpc5200_mscan_perform_initialization_mode_settings(m);
0637       break;
0638 
0639     case MSCAN_NORMAL_MODE:
0640       if ((chan->mode) == MSCAN_INITIALIZED_MODE) {
0641         /* perform initialization which has to be done in init mode */
0642         mpc5200_mscan_perform_initialization_mode_settings(m);
0643       }
0644 
0645       if ((chan->mode) == MSCAN_SLEEP_MODE) {
0646 
0647         /* exit sleep mode */
0648         mscan_sleep_mode_leave(m);
0649       }
0650       /* enable ints. */
0651       mscan_interrupts_enable(m);
0652       /* wait for bus sync. */
0653       mpc5200_mscan_wait_sync(m);
0654       break;
0655 
0656     case MSCAN_SLEEP_MODE:
0657       /* disable ints. */
0658       mscan_interrupts_disable(m);
0659       /* knter sleep mode */
0660       mscan_sleep_mode_enter(m);
0661       break;
0662 
0663     default:
0664       return RTEMS_UNSATISFIED;
0665       break;
0666 
0667   }
0668 
0669   /* set new channel mode */
0670   chan->mode = mode;
0671 
0672   return RTEMS_SUCCESSFUL;
0673 
0674 }
0675 
0676 /*
0677  * initialization of channel info.
0678  */
0679 rtems_status_code mscan_channel_initialize(rtems_device_major_number major,
0680                                            rtems_device_minor_number minor)
0681 {
0682   rtems_status_code status;
0683   struct mscan_channel_info *chan = &chan_info[minor];
0684 
0685   /* set registers according to MSCAN channel information */
0686   switch (minor) {
0687 
0688     case MSCAN_A:
0689       chan->rx_qname = rtems_build_name('C', 'N', 'A', 'Q');
0690       chan->tx_rb_sname = rtems_build_name('C', 'N', 'A', 'S');
0691 
0692       /* register RTEMS device names for MSCAN A */
0693       if ((status =
0694            rtems_io_register_name(MSCAN_A_DEV_NAME, major,
0695                                   MSCAN_A)) != RTEMS_SUCCESSFUL)
0696         return status;
0697 
0698       /* register RTEMS device names for MSCAN 0 */
0699       if ((status =
0700            rtems_io_register_name(MSCAN_0_DEV_NAME, major,
0701                                   MSCAN_A)) != RTEMS_SUCCESSFUL)
0702         return status;
0703 
0704       /* allocate the space for MSCAN A tx ring buffer */
0705       if (((chan->tx_ring_buf.buf_ptr) =
0706            malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) !=
0707           NULL) {
0708         chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
0709           chan->tx_ring_buf.buf_ptr;
0710       } else {
0711         return RTEMS_UNSATISFIED;
0712       }
0713       break;
0714 
0715     case MSCAN_B:
0716       chan->rx_qname = rtems_build_name('C', 'N', 'B', 'Q');
0717       chan->tx_rb_sname = rtems_build_name('C', 'N', 'B', 'S');
0718 
0719       /* register RTEMS device names for MSCAN B */
0720       if ((status =
0721            rtems_io_register_name(MSCAN_B_DEV_NAME, major,
0722                                   MSCAN_B)) != RTEMS_SUCCESSFUL)
0723         return status;
0724 
0725       /* register RTEMS device names for MSCAN 1 */
0726       if ((status =
0727            rtems_io_register_name(MSCAN_1_DEV_NAME, major,
0728                                   MSCAN_B)) != RTEMS_SUCCESSFUL)
0729         return status;
0730 
0731       /* allocate the space for MSCAN B tx ring buffer */
0732       if (((chan->tx_ring_buf.buf_ptr) =
0733            malloc(sizeof (struct can_message) * (NO_OF_MSCAN_TX_BUFF + 1))) !=
0734           NULL) {
0735         chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
0736           chan->tx_ring_buf.buf_ptr;
0737       } else {
0738         return RTEMS_UNSATISFIED;
0739       }
0740       break;
0741 
0742     default:
0743       return RTEMS_UNSATISFIED;
0744       break;
0745   }
0746 
0747   /* create RTEMS rx message queue */
0748   status =
0749     rtems_message_queue_create(chan->rx_qname, (uint32_t) NO_OF_MSCAN_RX_BUFF,
0750                                (uint32_t)
0751                                MSCAN_MESSAGE_SIZE(sizeof (struct can_message)),
0752                                (rtems_attribute) RTEMS_LOCAL | RTEMS_FIFO,
0753                                (rtems_id *) & (chan->rx_qid));
0754 
0755   /* create counting RTEMS tx ring buffer semaphore */
0756   status =
0757     rtems_semaphore_create(chan->tx_rb_sname, (uint32_t) (NO_OF_MSCAN_TX_BUFF),
0758                            RTEMS_COUNTING_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY
0759                            | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL,
0760                            (rtems_task_priority) 0,
0761                            (rtems_id *) & (chan->tx_rb_sid));
0762 
0763   /* Set up interrupts */
0764   if (!BSP_install_rtems_irq_handler(&(mpc5200_mscan_irq_data[minor])))
0765     rtems_panic("Can't attach MPC5x00 MSCAN interrupt handler %ld\n", minor);
0766 
0767   /* basic setup for channel info. struct. */
0768   chan->regs = (mscan *) &(mpc5200.mscan[minor]);
0769   chan->int_rx_err = 0;
0770   chan->id_extended = FALSE;
0771   chan->mode = MSCAN_INITIALIZED_MODE;
0772   chan->tx_buf_no = NO_OF_MSCAN_TX_BUFF;
0773 
0774   return status;
0775 
0776 }
0777 
0778 /*
0779  * MPC5x00 MSCAN device initialization
0780  */
0781 rtems_device_driver mscan_initialize(rtems_device_major_number major,
0782                                      rtems_device_minor_number minor, void *arg)
0783 {
0784   rtems_status_code status;
0785 
0786   /* Initialization requested via RTEMS */
0787   if ((status = mscan_channel_initialize(major, MSCAN_A)) != RTEMS_SUCCESSFUL)
0788     bsp_fatal(MPC5200_FATAL_MSCAN_A_INIT);
0789 
0790   if ((status = mscan_channel_initialize(major, MSCAN_B)) != RTEMS_SUCCESSFUL)
0791     bsp_fatal(MPC5200_FATAL_MSCAN_B_INIT);
0792 
0793   if ((status =
0794        mpc5200_mscan_set_mode(MSCAN_A,
0795                               MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
0796     bsp_fatal(MPC5200_FATAL_MSCAN_A_SET_MODE);
0797 
0798   if ((status =
0799        mpc5200_mscan_set_mode(MSCAN_B,
0800                               MSCAN_INIT_NORMAL_MODE)) != RTEMS_SUCCESSFUL)
0801     bsp_fatal(MPC5200_FATAL_MSCAN_B_SET_MODE);
0802 
0803   return status;
0804 
0805 }
0806 
0807 /*
0808  * MPC5x00 MSCAN device open
0809  */
0810 rtems_device_driver mscan_open(rtems_device_major_number major,
0811                                rtems_device_minor_number minor, void *arg)
0812 {
0813   rtems_status_code status = RTEMS_SUCCESSFUL;
0814   struct mscan_channel_info *chan = NULL;
0815 
0816   switch (minor) {
0817 
0818     case MSCAN_A:
0819     case MSCAN_B:
0820       chan = &chan_info[minor];
0821       break;
0822 
0823     default:
0824       return RTEMS_UNSATISFIED;
0825       break;
0826   }
0827 
0828   /* check mode */
0829   if ((chan->mode) == MSCAN_SLEEP_MODE) {
0830 
0831     /* if not already set enter init mode */
0832     status = mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
0833   }
0834 
0835   return status;
0836 
0837 }
0838 
0839 /*
0840  * MPC5x00 MSCAN device close
0841  */
0842 rtems_device_driver mscan_close(rtems_device_major_number major,
0843                                 rtems_device_minor_number minor, void *arg)
0844 {
0845   rtems_status_code status;
0846 
0847   switch (minor) {
0848 
0849     case MSCAN_A:
0850     case MSCAN_B:
0851       break;
0852 
0853     default:
0854       return RTEMS_UNSATISFIED;
0855       break;
0856   }
0857 
0858   /* enter deep sleep mode */
0859   status = mpc5200_mscan_set_mode(minor, MSCAN_SLEEP_MODE);
0860 
0861   return status;
0862 
0863 }
0864 
0865 /*
0866  * MPC5x00 MSCAN device read
0867  */
0868 rtems_device_driver mscan_read(rtems_device_major_number major,
0869                                rtems_device_minor_number minor, void *arg)
0870 {
0871   rtems_status_code status;
0872   size_t message_size = 0;
0873   rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg;
0874   struct mscan_rx_parms *rx_parms = (struct mscan_rx_parms *) (parms->buffer);
0875   struct can_message *rx_mess = (struct can_message *) (rx_parms->rx_mess);
0876   struct mscan_channel_info *chan = NULL;
0877 
0878   switch (minor) {
0879 
0880     case MSCAN_A:
0881     case MSCAN_B:
0882       chan = &chan_info[minor];
0883       break;
0884 
0885     default:
0886       return RTEMS_UNSATISFIED;
0887       break;
0888   }
0889 
0890   /* end init mode if it is first read */
0891   if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) {
0892 
0893     /* if not already set enter init mode */
0894     mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
0895   }
0896 
0897   if ((status =
0898        rtems_message_queue_receive(chan->rx_qid, (void *) (rx_mess),
0899                                    &message_size,
0900                                    (uint32_t) (rx_parms->rx_flags),
0901                                    (rtems_interval) (rx_parms->rx_timeout)))
0902       != RTEMS_SUCCESSFUL) {
0903 
0904     parms->bytes_moved = 0;
0905 
0906   } else {
0907 
0908     parms->bytes_moved = sizeof (struct can_message);
0909 
0910   }
0911 
0912   return status;
0913 
0914 }
0915 
0916 /*
0917  * MPC5x00 MSCAN device write
0918  */
0919 rtems_device_driver mscan_write(rtems_device_major_number major,
0920                                 rtems_device_minor_number minor, void *arg)
0921 {
0922   rtems_status_code status;
0923   rtems_libio_rw_args_t *parms = (rtems_libio_rw_args_t *) arg;
0924   struct mscan_tx_parms *tx_parms = (struct mscan_tx_parms *) (parms->buffer);
0925   struct can_message *tx_mess = (struct can_message *) (tx_parms->tx_mess);
0926   struct mscan_channel_info *chan = NULL;
0927   mscan *m = NULL;
0928 
0929   switch (minor) {
0930     case MSCAN_A:
0931     case MSCAN_B:
0932       chan = &chan_info[minor];
0933       m = chan->regs;
0934       break;
0935 
0936     default:
0937       return RTEMS_UNSATISFIED;
0938       break;
0939   }
0940 
0941   /* end init mode if it is first write */
0942   if ((chan->mode) == MSCAN_INIT_NORMAL_MODE) {
0943 
0944     /* if not already set enter init mode */
0945     mpc5200_mscan_set_mode(minor, MSCAN_NORMAL_MODE);
0946   }
0947 
0948   /* preset moved bytes */
0949   parms->bytes_moved = 0;
0950 
0951   /* obtain counting semaphore of tx ring buffer */
0952   if ((status =
0953        rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_NO_WAIT,
0954                               (rtems_interval) 0))
0955       == RTEMS_SUCCESSFUL) {
0956 
0957     /* append the TOUCAN tx_id to the mess. due to interrupt handling */
0958     tx_mess->toucan_tx_idx = tx_parms->tx_idx;
0959 
0960     /* fill the tx ring buffer with the message */
0961     fill_tx_buffer(chan, tx_mess);
0962 
0963     /* enable message buffer specific interrupt */
0964     m->tier |= (TIER_TXEI0 | TIER_TXEI1 | TIER_TXEI2);
0965 
0966     /* calculate moved bytes */
0967     parms->bytes_moved = (tx_mess->mess_len) & 0x000F;
0968 
0969   }
0970 
0971   return status;
0972 
0973 }
0974 
0975 /*
0976  * MPC5x00 MSCAN device control
0977  */
0978 rtems_device_driver mscan_control(rtems_device_major_number major,
0979                                   rtems_device_minor_number minor, void *arg)
0980 {
0981   rtems_status_code status;
0982   uint16_t tx_id;
0983   rtems_libio_ioctl_args_t *parms = (rtems_libio_ioctl_args_t *) arg;
0984   struct mscan_ctrl_parms *ctrl_parms =
0985     (struct mscan_ctrl_parms *) (parms->buffer);
0986   struct mscan_channel_info *chan = NULL;
0987   mscan_handle *mscan_hdl = NULL;
0988   mscan *m = NULL;
0989   mscan_context context;
0990   uint8_t tx_buf_count = 0;
0991 
0992   switch (minor) {
0993 
0994     case MSCAN_A:
0995     case MSCAN_B:
0996       chan = &chan_info[minor];
0997       mscan_hdl = mpc5200_mscan_irq_data[minor].handle;
0998       m = chan->regs;
0999       break;
1000 
1001     default:
1002       return RTEMS_UNSATISFIED;
1003       break;
1004   }
1005 
1006   switch (parms->command) {
1007 
1008       /* TOUCAN callback initialization for MSCAN */
1009     case TOUCAN_MSCAN_INIT:
1010       mscan_hdl->toucan_callback = ctrl_parms->toucan_cb_fnc;
1011       break;
1012 
1013       /* set rx buffer ID */
1014     case MSCAN_SET_RX_ID:
1015 
1016       /* enter init mode */
1017       mscan_initialization_mode_enter(m, &context);
1018 
1019       switch (ctrl_parms->ctrl_reg_no) {
1020 
1021         case RX_BUFFER_0:
1022           m->idar0 = SET_IDR0(ctrl_parms->ctrl_id);
1023           m->idar1 = SET_IDR1(ctrl_parms->ctrl_id);
1024           break;
1025 
1026         case RX_BUFFER_1:
1027           m->idar2 = SET_IDR2(ctrl_parms->ctrl_id);
1028           m->idar3 = SET_IDR3(ctrl_parms->ctrl_id);
1029           break;
1030 
1031         case RX_BUFFER_2:
1032           m->idar4 = SET_IDR4(ctrl_parms->ctrl_id);
1033           m->idar5 = SET_IDR5(ctrl_parms->ctrl_id);
1034           break;
1035 
1036         case RX_BUFFER_3:
1037           m->idar6 = SET_IDR6(ctrl_parms->ctrl_id);
1038           m->idar7 = SET_IDR7(ctrl_parms->ctrl_id);
1039           break;
1040 
1041         default:
1042           break;
1043 
1044       }
1045 
1046       /* exit init mode and perform further initialization which is required in the normal mode */
1047       mscan_initialization_mode_leave(m, &context);
1048 
1049       /* enable ints. */
1050       mscan_interrupts_enable(m);
1051 
1052       /* wait for bus sync. */
1053       mpc5200_mscan_wait_sync(m);
1054 
1055       return RTEMS_SUCCESSFUL;
1056       break;
1057 
1058       /* get rx buffer ID */
1059     case MSCAN_GET_RX_ID:
1060 
1061       switch (ctrl_parms->ctrl_reg_no) {
1062 
1063         case RX_BUFFER_0:
1064           ctrl_parms->ctrl_id = GET_IDR0(m->idar0) | GET_IDR1(m->idar1);
1065           break;
1066 
1067         case RX_BUFFER_1:
1068           ctrl_parms->ctrl_id = GET_IDR2(m->idar2) | GET_IDR3(m->idar3);
1069           break;
1070 
1071         case RX_BUFFER_2:
1072           ctrl_parms->ctrl_id = GET_IDR4(m->idar4) | GET_IDR5(m->idar5);
1073           break;
1074 
1075         case RX_BUFFER_3:
1076           ctrl_parms->ctrl_id = GET_IDR6(m->idar6) | GET_IDR7(m->idar7);
1077           break;
1078 
1079         default:
1080           break;
1081 
1082       }
1083 
1084       break;
1085 
1086       /* set rx buffer ID mask */
1087     case MSCAN_SET_RX_ID_MASK:
1088 
1089       /* enter init mode */
1090       mscan_initialization_mode_enter(m, &context);
1091 
1092       switch (ctrl_parms->ctrl_reg_no) {
1093 
1094         case RX_BUFFER_0:
1095           m->idmr0 = SET_IDMR0(ctrl_parms->ctrl_id_mask);
1096           m->idmr1 = SET_IDMR1(ctrl_parms->ctrl_id_mask);
1097           break;
1098 
1099         case RX_BUFFER_1:
1100           m->idmr2 = SET_IDMR2(ctrl_parms->ctrl_id_mask);
1101           m->idmr3 = SET_IDMR3(ctrl_parms->ctrl_id_mask);
1102           break;
1103 
1104         case RX_BUFFER_2:
1105           m->idmr4 = SET_IDMR4(ctrl_parms->ctrl_id_mask);
1106           m->idmr5 = SET_IDMR5(ctrl_parms->ctrl_id_mask);
1107           break;
1108 
1109         case RX_BUFFER_3:
1110           m->idmr6 = SET_IDMR6(ctrl_parms->ctrl_id_mask);
1111           m->idmr7 = SET_IDMR7(ctrl_parms->ctrl_id_mask);
1112           break;
1113 
1114         default:
1115           break;
1116 
1117       }
1118 
1119       /* exit init mode and perform further initialization which is required in the normal mode */
1120       mscan_initialization_mode_leave(m, &context);
1121 
1122       /* enable ints. */
1123       mscan_interrupts_enable(m);
1124 
1125       /* wait for bus sync. */
1126       mpc5200_mscan_wait_sync(m);
1127 
1128       break;
1129 
1130       /* get rx buffer ID mask */
1131     case MSCAN_GET_RX_ID_MASK:
1132 
1133       switch (ctrl_parms->ctrl_reg_no) {
1134 
1135         case RX_BUFFER_0:
1136           ctrl_parms->ctrl_id_mask =
1137             (GET_IDMR0(m->idmr0) | GET_IDMR1(m->idmr1));
1138           break;
1139 
1140         case RX_BUFFER_1:
1141           ctrl_parms->ctrl_id_mask =
1142             (GET_IDMR2(m->idmr2) | GET_IDMR3(m->idmr3));
1143           break;
1144 
1145         case RX_BUFFER_2:
1146           ctrl_parms->ctrl_id_mask =
1147             (GET_IDMR4(m->idmr4) | GET_IDMR5(m->idmr5));
1148           break;
1149 
1150         case RX_BUFFER_3:
1151           ctrl_parms->ctrl_id_mask =
1152             (GET_IDMR6(m->idmr6) | GET_IDMR7(m->idmr7));
1153           break;
1154 
1155         default:
1156           break;
1157 
1158       }
1159 
1160       /* set tx buffer ID */
1161     case MSCAN_SET_TX_ID:
1162 
1163       /* check for availability of tx buffer */
1164       if (!((m->tflg) & (uint8_t) (ctrl_parms->ctrl_reg_no))) {
1165 
1166         /* do abort tx buf. request */
1167         m->tarq = (uint8_t) (ctrl_parms->ctrl_reg_no);
1168 
1169         /* wait for abort tx buf. ack. */
1170         while ((m->taak) & (uint8_t) (ctrl_parms->ctrl_reg_no));
1171 
1172       }
1173 
1174       /* select tx buf. */
1175       m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no);
1176 
1177       /* set the tx id of selected buf. */
1178       tx_id = ctrl_parms->ctrl_id;
1179       m->txidr0 = SET_IDR0(tx_id);
1180       m->txidr1 = SET_IDR1(tx_id);
1181       m->txidr2 = 0;
1182       m->txidr3 = 0;
1183 
1184       break;
1185 
1186       /* get tx buffer ID */
1187     case MSCAN_GET_TX_ID:
1188 
1189       /* select tx buf. */
1190       m->bsel = (uint8_t) (ctrl_parms->ctrl_reg_no);
1191 
1192       /* get tx id. of selected buf. */
1193       ctrl_parms->ctrl_id = GET_IDR0(m->txidr0) | GET_IDR1(m->txidr1);
1194 
1195       break;
1196 
1197       /* set can bitrate */
1198     case MSCAN_SET_BAUDRATE:
1199       /* perform all can bit time settings */
1200       if (!mscan_set_bit_rate(m, ctrl_parms->ctrl_can_bitrate)) {
1201         return RTEMS_UNSATISFIED;
1202       }
1203 
1204       /* enable ints. */
1205       mscan_interrupts_enable(m);
1206 
1207       /* wait for bus sync. */
1208       mpc5200_mscan_wait_sync(m);
1209 
1210       break;
1211 
1212     case SET_TX_BUF_NO:
1213 
1214       /* check for different settings of tx ring buffer */
1215       if ((tx_buf_count =
1216            chan->tx_buf_no) != (uint8_t) (ctrl_parms->ctrl_tx_buf_no)) {
1217 
1218         /* preset the channel specific no of messages in the tx ring buffer */
1219         tx_buf_count = chan->tx_buf_no;
1220 
1221         /* try to obtain all of the tx ring buffers */
1222         while (tx_buf_count > 0) {
1223 
1224           /* obtain semaphore of all tx ring buffers */
1225           if ((status =
1226                rtems_semaphore_obtain((rtems_id) (chan->tx_rb_sid), RTEMS_WAIT,
1227                                       (rtems_interval) 10))
1228               == RTEMS_SUCCESSFUL) {
1229 
1230             tx_buf_count--;
1231 
1232           }
1233 
1234         }
1235 
1236         /* free the former tx ring buffer */
1237         free((void *) chan->tx_ring_buf.buf_ptr);
1238 
1239         /* allocate the tx ring buffer with new size */
1240         if (((chan->tx_ring_buf.buf_ptr) =
1241              malloc(sizeof (struct can_message) *
1242                     ((uint8_t) (ctrl_parms->ctrl_tx_buf_no) + 1))) != NULL) {
1243           chan->tx_ring_buf.head_ptr = chan->tx_ring_buf.tail_ptr =
1244             chan->tx_ring_buf.buf_ptr;
1245         } else {
1246           return RTEMS_UNSATISFIED;
1247         }
1248 
1249         /* set the new amount of tx buffers */
1250         chan->tx_buf_no = (uint8_t) (ctrl_parms->ctrl_tx_buf_no);
1251 
1252         /* release the semaphore of all tx ring buffers */
1253         while (tx_buf_count < chan->tx_buf_no) {
1254 
1255           /* obtain semaphore of all tx ring buffers */
1256           rtems_semaphore_release((rtems_id) (chan->tx_rb_sid));
1257 
1258           tx_buf_count++;
1259 
1260         }
1261 
1262       } else {
1263 
1264         return RTEMS_SUCCESSFUL;
1265 
1266       }
1267       break;
1268 
1269     default:
1270       break;
1271 
1272   }
1273 
1274   return RTEMS_SUCCESSFUL;
1275 
1276 }