1 //==========================================================================
3 // cme555_serial_with_ints.c
5 // PowerPC 5xx CME555 Serial I/O Interface Module (interrupt driven)
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): Bob Koninckx
46 // Purpose: CME555 Serial I/O module (interrupt driven version)
50 //####DESCRIPTIONEND####
51 //==========================================================================
52 //----------------------------------
53 // Includes and forward declarations
54 //----------------------------------
55 #include <pkgconf/io_serial.h>
56 #include <pkgconf/io.h>
58 #include <cyg/io/io.h>
59 #include <cyg/hal/hal_intr.h>
60 #include <cyg/hal/hal_arbiter.h>
61 #include <cyg/io/devtab.h>
62 #include <cyg/infra/diag.h>
63 #include <cyg/io/serial.h>
65 // Only build this driver for the MPC555 based CME555 board
66 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555
68 #include "cme555_serial.h"
73 typedef struct mpc555_serial_info {
74 CYG_ADDRWORD base; // The base address of the serial port
75 CYG_WORD tx_interrupt_num; // trivial
76 CYG_WORD rx_interrupt_num; // trivial
77 cyg_priority_t tx_interrupt_priority; // trivial
78 cyg_priority_t rx_interrupt_priority; // trivial
79 bool tx_interrupt_enable; // tells if the transmit interrupt may be re-enabled
80 cyg_interrupt tx_interrupt; // the tx interrupt object
81 cyg_handle_t tx_interrupt_handle; // the tx interrupt handle
82 cyg_interrupt rx_interrupt; // the rx interrupt object
83 cyg_handle_t rx_interrupt_handle; // the rx interrupt handle
86 //--------------------
87 // Function prototypes
88 //--------------------
89 static bool mpc555_serial_init(struct cyg_devtab_entry * tab);
90 static bool mpc555_serial_putc(serial_channel * chan, unsigned char c);
91 static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab,
92 struct cyg_devtab_entry * sub_tab,
94 static unsigned char mpc555_serial_getc(serial_channel *chan);
95 static Cyg_ErrNo mpc555_serial_set_config(serial_channel *chan, cyg_uint32 key,
96 const void *xbuf, cyg_uint32 *len);
97 static void mpc555_serial_start_xmit(serial_channel *chan);
98 static void mpc555_serial_stop_xmit(serial_channel *chan);
100 // The interrupt servers
101 static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
102 static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
103 static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
104 static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
106 //-------------------------------------------
107 // Register the device driver with the kernel
108 //-------------------------------------------
109 static SERIAL_FUNS(mpc555_serial_funs,
112 mpc555_serial_set_config,
113 mpc555_serial_start_xmit,
114 mpc555_serial_stop_xmit);
116 //-------------------
117 // Device driver data
118 //-------------------
119 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_A
120 static mpc555_serial_info mpc555_serial_info0 = {MPC555_SERIAL_BASE_A,
121 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX,
122 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX,
123 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX_PRIORITY,
124 CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX_PRIORITY,
126 #if CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_A_BUFSIZE > 0
127 static unsigned char mpc555_serial_out_buf0[CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_A_BUFSIZE];
128 static unsigned char mpc555_serial_in_buf0[CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_A_BUFSIZE];
130 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel0,
133 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_A_BAUD),
134 CYG_SERIAL_STOP_DEFAULT,
135 CYG_SERIAL_PARITY_DEFAULT,
136 CYG_SERIAL_WORD_LENGTH_DEFAULT,
137 CYG_SERIAL_FLAGS_DEFAULT,
138 &mpc555_serial_out_buf0[0],
139 sizeof(mpc555_serial_out_buf0),
140 &mpc555_serial_in_buf0[0],
141 sizeof(mpc555_serial_in_buf0));
143 static SERIAL_CHANNEL(mpc555_serial_channel0,
146 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_A_BAUD),
147 CYG_SERIAL_STOP_DEFAULT,
148 CYG_SERIAL_PARITY_DEFAULT,
149 CYG_SERIAL_WORD_LENGTH_DEFAULT,
150 CYG_SERIAL_FLAGS_DEFAULT);
152 DEVTAB_ENTRY(mpc555_serial_io0,
153 CYGDAT_IO_SERIAL_POWERPC_CME555_SERIAL_A_NAME,
154 0, // does not depend on a lower level device driver
155 &cyg_io_serial_devio,
157 mpc555_serial_lookup,
158 &mpc555_serial_channel0);
159 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_A
161 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_B
162 static mpc555_serial_info mpc555_serial_info1 = {MPC555_SERIAL_BASE_B,
163 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX,
164 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX,
165 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX_PRIORITY,
166 CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX_PRIORITY,
168 #if CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_B_BUFSIZE > 0
169 static unsigned char mpc555_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_B_BUFSIZE];
170 static unsigned char mpc555_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_B_BUFSIZE];
172 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel1,
175 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_B_BAUD),
176 CYG_SERIAL_STOP_DEFAULT,
177 CYG_SERIAL_PARITY_DEFAULT,
178 CYG_SERIAL_WORD_LENGTH_DEFAULT,
179 CYG_SERIAL_FLAGS_DEFAULT,
180 &mpc555_serial_out_buf1[0],
181 sizeof(mpc555_serial_out_buf1),
182 &mpc555_serial_in_buf1[0],
183 sizeof(mpc555_serial_in_buf1));
185 static SERIAL_CHANNEL(mpc555_serial_channel1,
188 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_CME555_SERIAL_B_BAUD),
189 CYG_SERIAL_STOP_DEFAULT,
190 CYG_SERIAL_PARITY_DEFAULT,
191 CYG_SERIAL_WORD_LENGTH_DEFAULT,
192 CYG_SERIAL_FLAGS_DEFAULT);
194 DEVTAB_ENTRY(mpc555_serial_io1,
195 CYGDAT_IO_SERIAL_POWERPC_CME555_SERIAL_B_NAME,
196 0, // does not depend on a lower level device driver
197 &cyg_io_serial_devio,
199 mpc555_serial_lookup,
200 &mpc555_serial_channel1);
201 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_B
203 //-----------------------------
204 // Device driver implementation
205 //-----------------------------
207 // The arbitration isr.
208 // I think this is the best place to implement it. The device driver is the only place
209 // in the code where the knowledge is present about how the hardware is used
211 // Always check receive interrupts. Some rom monitor might be waiting for CTRL-C
212 static cyg_uint32 hal_arbitration_isr_qsci(CYG_ADDRWORD a_vector, CYG_ADDRWORD a_data)
217 HAL_READ_UINT16(CYGARC_REG_IMM_SC1SR, status);
218 HAL_READ_UINT16(CYGARC_REG_IMM_SCC1R1, control);
219 if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
220 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_RX);
221 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_A // Do not waist time on unused hardware
222 if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
223 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX);
224 // Don't waist time on unused interrupts
225 // if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
226 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC);
227 // Don't waist time on unused interrupts
228 // if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
229 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE);
232 HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, status);
233 HAL_READ_UINT16(CYGARC_REG_IMM_SCC2R1, control);
234 if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
235 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
236 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_B // Do not waist time on unused hardware
237 if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
238 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX);
239 // Don't waist time on unused interrupts
240 // if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
241 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC);
242 // Don't waist time on unused interrupts
243 // if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
244 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE);
247 // The driver doesn't use the queue operation of the hardware (It would need different code for serial 1 and 2
248 // since oly one port supports queue mode). So the following is not needed.
249 // Leave it there. It is easyer for later implementations to remove the comments than finding
250 // out how the hardware works again.
251 HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, status);
252 HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, control);
253 if((status & CYGARC_REG_IMM_QSCI1SR_QTHF) && (control & CYGARC_REG_IMM_QSCI1CR_QTHFI))
254 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF);
255 if((status & CYGARC_REG_IMM_QSCI1SR_QBHF) && (control & CYGARC_REG_IMM_QSCI1CR_QBHFI))
256 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF);
257 if((status & CYGARC_REG_IMM_QSCI1SR_QTHE) && (control & CYGARC_REG_IMM_QSCI1CR_QTHEI))
258 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE);
259 if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
260 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
265 HAL_READ_UINT16(CYGARC_REG_IMM_SPSR, status);
266 HAL_READ_UINT16(CYGARC_REG_IMM_SPCR2, control);
267 if((status & CYGARC_REG_IMM_SPSR_SPIF) && (control & CYGARC_REG_IMM_SPCR2_SPIFIE))
268 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_FI);
270 HAL_READ_UINT16(CYGARC_REG_IMM_SPCR3, control);
271 if((status & CYGARC_REG_IMM_SPSR_MODF) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
272 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_MODF);
274 if((status & CYGARC_REG_IMM_SPSR_HALTA) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
275 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
283 //--------------------------------------------------------------------------------
284 // Internal function to actually configure the hardware to desired baud rate, etc.
285 //--------------------------------------------------------------------------------
286 static bool mpc555_serial_config_port(serial_channel * chan, cyg_serial_info_t * new_config, bool init)
288 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)(chan->dev_priv);
290 cyg_addrword_t port = mpc555_chan->base;
291 cyg_uint16 baud_rate = select_baud[new_config->baud];
292 unsigned char frame_length = 1; // The start bit
294 cyg_uint16 old_isrstate;
298 return false; // Invalid baud rate selected
300 if((new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_7) &&
301 (new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_8))
302 return false; // Invalid word length selected
304 if((new_config->parity != CYGNUM_SERIAL_PARITY_NONE) &&
305 (new_config->parity != CYGNUM_SERIAL_PARITY_EVEN) &&
306 (new_config->parity != CYGNUM_SERIAL_PARITY_ODD))
307 return false; // Invalid parity selected
309 if((new_config->stop != CYGNUM_SERIAL_STOP_1) &&
310 (new_config->stop != CYGNUM_SERIAL_STOP_2))
311 return false; // Invalid stop bits selected
313 frame_length += select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
314 frame_length += select_stop_bits[new_config->stop];
315 frame_length += select_parity[new_config->parity];
317 if((frame_length != 10) && (frame_length != 11))
318 return false; // Invalid frame format selected
320 // Disable port interrupts while changing hardware
321 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
322 old_isrstate = sccxr;
323 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_LOOPS);
324 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WOMS);
325 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILT);
326 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
327 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
328 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
329 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WAKE);
330 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TE);
331 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RE);
332 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RWU);
333 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_SBK);
334 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TIE);
335 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TCIE);
336 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RIE);
337 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILIE);
338 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
340 // Set databits, stopbits and parity.
341 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
343 if(frame_length == 11)
344 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_M;
346 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
348 switch(new_config->parity)
350 case CYGNUM_SERIAL_PARITY_NONE:
351 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
353 case CYGNUM_SERIAL_PARITY_EVEN:
354 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
355 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
357 case CYGNUM_SERIAL_PARITY_ODD:
358 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
359 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PT;
364 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
367 baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_OTHR);
368 baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_LINKBD);
369 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
370 sccxr &= ~(MPC555_SERIAL_SCCxR0_SCxBR);
372 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
375 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
376 sccxr |= MPC555_SERIAL_SCCxR1_TE;
377 sccxr |= MPC555_SERIAL_SCCxR1_RE;
378 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
381 { // enable the receiver interrupt
382 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
383 sccxr |= MPC555_SERIAL_SCCxR1_RIE;
384 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
386 else // Restore the old interrupt state
388 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
389 sccxr |= old_isrstate;
390 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
393 if(new_config != &chan->config)
394 chan->config = *new_config;
399 //--------------------------------------------------------------
400 // Function to initialize the device. Called at bootstrap time.
401 //--------------------------------------------------------------
402 static hal_mpc5xx_arbitration_data arbiter;
404 static bool mpc555_serial_init(struct cyg_devtab_entry * tab)
406 serial_channel * chan = (serial_channel *)tab->priv;
407 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
409 if(!mpc555_serial_config_port(chan, &chan->config, true))
412 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
413 if(chan->out_cbuf.len != 0)
415 arbiter.priority = CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI;
417 arbiter.arbiter = hal_arbitration_isr_qsci;
419 // Install the arbitration isr, Make sure that is is not installed twice
420 hal_mpc5xx_remove_arbitration_isr(CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);
421 hal_mpc5xx_install_arbitration_isr(&arbiter);
423 // Create the Tx interrupt, do not enable it yet
424 cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_num,
425 mpc555_chan->tx_interrupt_priority,
426 (cyg_addrword_t)chan, // Data item passed to interrupt handler
427 mpc555_serial_tx_ISR,
428 mpc555_serial_tx_DSR,
429 &mpc555_chan->tx_interrupt_handle,
430 &mpc555_chan->tx_interrupt);
431 cyg_drv_interrupt_attach(mpc555_chan->tx_interrupt_handle);
433 // Create the Rx interrupt, this can be safely unmasked now
434 cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_num,
435 mpc555_chan->rx_interrupt_priority,
436 (cyg_addrword_t)chan,
437 mpc555_serial_rx_ISR,
438 mpc555_serial_rx_DSR,
439 &mpc555_chan->rx_interrupt_handle,
440 &mpc555_chan->rx_interrupt);
441 cyg_drv_interrupt_attach(mpc555_chan->rx_interrupt_handle);
442 cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
448 //----------------------------------------------------------------------
449 // This routine is called when the device is "looked" up (i.e. attached)
450 //----------------------------------------------------------------------
451 static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab,
452 struct cyg_devtab_entry * sub_tab,
455 serial_channel * chan = (serial_channel *)(*tab)->priv;
456 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
461 //----------------------------------------------
462 // Send a character to the device output buffer.
463 // Return 'true' if character is sent to device
464 //----------------------------------------------
465 static bool mpc555_serial_putc(serial_channel * chan, unsigned char c)
467 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
468 cyg_addrword_t port = mpc555_chan->base;
473 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
474 if(scsr & MPC555_SERIAL_SCxSR_TDRE)
475 { // Ok, we have space, write the character and return success
476 scdr = (cyg_uint16)c;
477 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
481 // We cannot write to the transmitter, return failure
485 //---------------------------------------------------------------------
486 // Fetch a character from the device input buffer, waiting if necessary
487 //---------------------------------------------------------------------
488 static unsigned char mpc555_serial_getc(serial_channel * chan)
491 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
492 cyg_addrword_t port = mpc555_chan->base;
498 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
499 } while(!(scsr & MPC555_SERIAL_SCxSR_RDRF));
501 // Ok, data is received, read it out and return
502 HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
503 c = (unsigned char)scdr;
508 //---------------------------------------------------
509 // Set up the device characteristics; baud rate, etc.
510 //---------------------------------------------------
511 static bool mpc555_serial_set_config(serial_channel * chan, cyg_uint32 key,
512 const void *xbuf, cyg_uint32 * len)
515 case CYG_IO_SET_CONFIG_SERIAL_INFO:
517 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
518 if(*len < sizeof(cyg_serial_info_t)) {
521 *len = sizeof(cyg_serial_info_t);
522 if(true != mpc555_serial_config_port(chan, config, false))
532 //-------------------------------------
533 // Enable the transmitter on the device
534 //-------------------------------------
535 static void mpc555_serial_start_xmit(serial_channel * chan)
537 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
539 mpc555_chan->tx_interrupt_enable = true;
540 cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
542 // No need to call xmt_char, this will generate an interrupt immediately.
545 //--------------------------------------
546 // Disable the transmitter on the device
547 //--------------------------------------
548 static void mpc555_serial_stop_xmit(serial_channel * chan)
550 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
553 mpc555_chan->tx_interrupt_enable = false;
554 cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
555 cyg_drv_dsr_unlock();
558 //-----------------------------------------
559 // The low level transmit interrupt handler
560 //-----------------------------------------
561 static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
563 serial_channel * chan = (serial_channel *)data;
564 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
566 cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
567 cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_num);
569 return CYG_ISR_CALL_DSR; // cause the DSR to run
572 //----------------------------------------
573 // The low level receive interrupt handler
574 //----------------------------------------
575 static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
577 serial_channel * chan = (serial_channel *)data;
578 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
580 cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_num);
581 cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_num);
583 return CYG_ISR_CALL_DSR; // cause the DSR to run
586 //------------------------------------------
587 // The high level transmit interrupt handler
588 //------------------------------------------
589 static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
591 serial_channel * chan = (serial_channel *)data;
592 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
594 (chan->callbacks->xmt_char)(chan);
595 if(mpc555_chan->tx_interrupt_enable)
596 cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
599 //-----------------------------------------
600 // The high level receive interrupt handler
601 //-----------------------------------------
602 #define MPC555_SERIAL_SCxSR_ERRORS (MPC555_SERIAL_SCxSR_OR | \
603 MPC555_SERIAL_SCxSR_NF | \
604 MPC555_SERIAL_SCxSR_FE | \
605 MPC555_SERIAL_SCxSR_PF)
607 static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
609 serial_channel * chan = (serial_channel *)data;
610 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
611 cyg_addrword_t port = mpc555_chan->base;
615 // Allways read out the received character, in order to clear receiver flags
616 HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
618 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
619 if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
621 scsr &= ~((cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS);
622 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
626 (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
629 cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
632 #endif // CYGPKG_IO_SERIAL_POWERPC_CME555
634 // EOF cmd555_serial_with_ints.c