1 //==========================================================================
3 // ec555_serial_with_ints.c
5 // PowerPC 5xx EC555 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: EC555 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 EC555 board
66 #ifdef CYGPKG_IO_SERIAL_POWERPC_EC555
68 #include "ec555_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_EC555_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_EC555_SERIAL_A_BUFSIZE > 0
127 static unsigned char mpc555_serial_out_buf0[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BUFSIZE];
128 static unsigned char mpc555_serial_in_buf0[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_A_BUFSIZE];
130 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel0,
133 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_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_EC555_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_EC555_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_EC555_SERIAL_A
161 #ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_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_EC555_SERIAL_B_BUFSIZE > 0
169 static unsigned char mpc555_serial_out_buf1[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BUFSIZE];
170 static unsigned char mpc555_serial_in_buf1[CYGNUM_IO_SERIAL_POWERPC_EC555_SERIAL_B_BUFSIZE];
172 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel1,
175 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_POWERPC_EC555_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_EC555_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_EC555_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_EC555_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 receiver interrupts. Some rom monitor might be listening to 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);
222 #ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_A // Do not waist time on unused hardware
223 if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
224 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TX);
225 // Don't waist time on unused interrupts
226 // if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
227 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_TXC);
228 // Don't waist time on unused interrupts
229 // if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
230 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI0_IDLE);
233 HAL_READ_UINT16(CYGARC_REG_IMM_SC2SR, status);
234 HAL_READ_UINT16(CYGARC_REG_IMM_SCC2R1, control);
235 if((status & CYGARC_REG_IMM_SCxSR_RDRF) && (control & CYGARC_REG_IMM_SCCxR1_RIE))
236 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RX);
238 #ifdef CYGPKG_IO_SERIAL_POWERPC_EC555_SERIAL_B // Do not waist time on unused hardware
239 if((status & CYGARC_REG_IMM_SCxSR_TDRE) && (control & CYGARC_REG_IMM_SCCxR1_TIE))
240 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TX);
241 // Don't waist time on unused interrupts
242 // if((status & CYGARC_REG_IMM_SCxSR_TC) && (control & CYGARC_REG_IMM_SCCxR1_TCIE))
243 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXC);
244 // Don't waist time on unused interrupts
245 // if((status & CYGARC_REG_IMM_SCxSR_IDLE) && (control & CYGARC_REG_IMM_SCCxR1_ILIE))
246 // return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_IDLE);
249 // The driver doesn't use the queue operation of the hardware (It would need different code for serial 1 and 2
250 // since oly one port supports queue mode). So the following is not needed.
251 // Leave it there. It is easyer for later implementations to remove the comments than finding
252 // out how the hardware works again.
253 HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1SR, status);
254 HAL_READ_UINT16(CYGARC_REG_IMM_QSCI1CR, control);
255 if((status & CYGARC_REG_IMM_QSCI1SR_QTHF) && (control & CYGARC_REG_IMM_QSCI1CR_QTHFI))
256 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQTHF);
257 if((status & CYGARC_REG_IMM_QSCI1SR_QBHF) && (control & CYGARC_REG_IMM_QSCI1CR_QBHFI))
258 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_RXQBHF);
259 if((status & CYGARC_REG_IMM_QSCI1SR_QTHE) && (control & CYGARC_REG_IMM_QSCI1CR_QTHEI))
260 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQTHE);
261 if((status & CYGARC_REG_IMM_QSCI1SR_QBHE) && (control & CYGARC_REG_IMM_QSCI1CR_QBHEI))
262 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SCI1_TXQBHE);
267 HAL_READ_UINT16(CYGARC_REG_IMM_SPSR, status);
268 HAL_READ_UINT16(CYGARC_REG_IMM_SPCR2, control);
269 if((status & CYGARC_REG_IMM_SPSR_SPIF) && (control & CYGARC_REG_IMM_SPCR2_SPIFIE))
270 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_FI);
272 HAL_READ_UINT16(CYGARC_REG_IMM_SPCR3, control);
273 if((status & CYGARC_REG_IMM_SPSR_MODF) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
274 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_MODF);
276 if((status & CYGARC_REG_IMM_SPSR_HALTA) && (control & CYGARC_REG_IMM_SPCR3_HMIE))
277 return hal_call_isr(CYGNUM_HAL_INTERRUPT_IMB3_SPI_HALTA);
285 //--------------------------------------------------------------------------------
286 // Internal function to actually configure the hardware to desired baud rate, etc.
287 //--------------------------------------------------------------------------------
288 static bool mpc555_serial_config_port(serial_channel * chan, cyg_serial_info_t * new_config, bool init)
290 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)(chan->dev_priv);
292 cyg_addrword_t port = mpc555_chan->base;
293 cyg_uint16 baud_rate = select_baud[new_config->baud];
294 unsigned char frame_length = 1; // The start bit
296 cyg_uint16 old_isrstate;
300 return false; // Invalid baud rate selected
302 if((new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_7) &&
303 (new_config->word_length != CYGNUM_SERIAL_WORD_LENGTH_8))
304 return false; // Invalid word length selected
306 if((new_config->parity != CYGNUM_SERIAL_PARITY_NONE) &&
307 (new_config->parity != CYGNUM_SERIAL_PARITY_EVEN) &&
308 (new_config->parity != CYGNUM_SERIAL_PARITY_ODD))
309 return false; // Invalid parity selected
311 if((new_config->stop != CYGNUM_SERIAL_STOP_1) &&
312 (new_config->stop != CYGNUM_SERIAL_STOP_2))
313 return false; // Invalid stop bits selected
315 frame_length += select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
316 frame_length += select_stop_bits[new_config->stop];
317 frame_length += select_parity[new_config->parity];
319 if((frame_length != 10) && (frame_length != 11))
320 return false; // Invalid frame format selected
322 // Disable port interrupts while changing hardware
323 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
324 old_isrstate = sccxr;
325 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_LOOPS);
326 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WOMS);
327 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILT);
328 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
329 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
330 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
331 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_WAKE);
332 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TE);
333 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RE);
334 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RWU);
335 old_isrstate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_SBK);
336 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TIE);
337 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_TCIE);
338 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_RIE);
339 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_ILIE);
340 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
342 // Set databits, stopbits and parity.
343 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
345 if(frame_length == 11)
346 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_M;
348 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
350 switch(new_config->parity)
352 case CYGNUM_SERIAL_PARITY_NONE:
353 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
355 case CYGNUM_SERIAL_PARITY_EVEN:
356 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
357 sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
359 case CYGNUM_SERIAL_PARITY_ODD:
360 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
361 sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PT;
366 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
369 baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_OTHR);
370 baud_rate &= ~((cyg_uint16)MPC555_SERIAL_SCCxR0_LINKBD);
371 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
372 sccxr &= ~(MPC555_SERIAL_SCCxR0_SCxBR);
374 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
377 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
378 sccxr |= MPC555_SERIAL_SCCxR1_TE;
379 sccxr |= MPC555_SERIAL_SCCxR1_RE;
380 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
383 { // enable the receiver interrupt
384 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
385 sccxr |= MPC555_SERIAL_SCCxR1_RIE;
386 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
388 else // Restore the old interrupt state
390 HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
391 sccxr |= old_isrstate;
392 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
395 if(new_config != &chan->config)
396 chan->config = *new_config;
401 //--------------------------------------------------------------
402 // Function to initialize the device. Called at bootstrap time.
403 //--------------------------------------------------------------
404 static hal_mpc5xx_arbitration_data arbiter;
406 static bool mpc555_serial_init(struct cyg_devtab_entry * tab)
408 serial_channel * chan = (serial_channel *)tab->priv;
409 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
411 if(!mpc555_serial_config_port(chan, &chan->config, true))
414 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
415 if(chan->out_cbuf.len != 0)
417 arbiter.priority = CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI;
419 arbiter.arbiter = hal_arbitration_isr_qsci;
421 // Install the arbitration isr, Make sure that is is not installed twice
422 hal_mpc5xx_remove_arbitration_isr(CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI);
423 hal_mpc5xx_install_arbitration_isr(&arbiter);
425 // Create the Tx interrupt, do not enable it yet
426 cyg_drv_interrupt_create(mpc555_chan->tx_interrupt_num,
427 mpc555_chan->tx_interrupt_priority,
428 (cyg_addrword_t)chan, // Data item passed to interrupt handler
429 mpc555_serial_tx_ISR,
430 mpc555_serial_tx_DSR,
431 &mpc555_chan->tx_interrupt_handle,
432 &mpc555_chan->tx_interrupt);
433 cyg_drv_interrupt_attach(mpc555_chan->tx_interrupt_handle);
435 // Create the Rx interrupt, this can be safely unmasked now
436 cyg_drv_interrupt_create(mpc555_chan->rx_interrupt_num,
437 mpc555_chan->rx_interrupt_priority,
438 (cyg_addrword_t)chan,
439 mpc555_serial_rx_ISR,
440 mpc555_serial_rx_DSR,
441 &mpc555_chan->rx_interrupt_handle,
442 &mpc555_chan->rx_interrupt);
443 cyg_drv_interrupt_attach(mpc555_chan->rx_interrupt_handle);
444 cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
450 //----------------------------------------------------------------------
451 // This routine is called when the device is "looked" up (i.e. attached)
452 //----------------------------------------------------------------------
453 static Cyg_ErrNo mpc555_serial_lookup(struct cyg_devtab_entry ** tab,
454 struct cyg_devtab_entry * sub_tab,
457 serial_channel * chan = (serial_channel *)(*tab)->priv;
458 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
463 //----------------------------------------------
464 // Send a character to the device output buffer.
465 // Return 'true' if character is sent to device
466 //----------------------------------------------
467 static bool mpc555_serial_putc(serial_channel * chan, unsigned char c)
469 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
470 cyg_addrword_t port = mpc555_chan->base;
475 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
476 if(scsr & MPC555_SERIAL_SCxSR_TDRE)
477 { // Ok, we have space, write the character and return success
478 scdr = (cyg_uint16)c;
479 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
483 // We cannot write to the transmitter, return failure
487 //---------------------------------------------------------------------
488 // Fetch a character from the device input buffer, waiting if necessary
489 //---------------------------------------------------------------------
490 static unsigned char mpc555_serial_getc(serial_channel * chan)
493 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
494 cyg_addrword_t port = mpc555_chan->base;
500 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
501 } while(!(scsr & MPC555_SERIAL_SCxSR_RDRF));
503 // Ok, data is received, read it out and return
504 HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
505 c = (unsigned char)scdr;
510 //---------------------------------------------------
511 // Set up the device characteristics; baud rate, etc.
512 //---------------------------------------------------
513 static bool mpc555_serial_set_config(serial_channel * chan, cyg_uint32 key,
514 const void *xbuf, cyg_uint32 * len)
517 case CYG_IO_SET_CONFIG_SERIAL_INFO:
519 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
520 if(*len < sizeof(cyg_serial_info_t)) {
523 *len = sizeof(cyg_serial_info_t);
524 if(true != mpc555_serial_config_port(chan, config, false))
534 //-------------------------------------
535 // Enable the transmitter on the device
536 //-------------------------------------
537 static void mpc555_serial_start_xmit(serial_channel * chan)
539 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
541 mpc555_chan->tx_interrupt_enable = true;
542 cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
544 // No need to call xmt_char, this will generate an interrupt immediately.
547 //--------------------------------------
548 // Disable the transmitter on the device
549 //--------------------------------------
550 static void mpc555_serial_stop_xmit(serial_channel * chan)
552 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
555 mpc555_chan->tx_interrupt_enable = false;
556 cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
557 cyg_drv_dsr_unlock();
560 //-----------------------------------------
561 // The low level transmit interrupt handler
562 //-----------------------------------------
563 static cyg_uint32 mpc555_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
565 serial_channel * chan = (serial_channel *)data;
566 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
568 cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
569 cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_num);
571 return CYG_ISR_CALL_DSR; // cause the DSR to run
574 //----------------------------------------
575 // The low level receive interrupt handler
576 //----------------------------------------
577 static cyg_uint32 mpc555_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
579 serial_channel * chan = (serial_channel *)data;
580 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
582 cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_num);
583 cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_num);
585 return CYG_ISR_CALL_DSR; // cause the DSR to run
588 //------------------------------------------
589 // The high level transmit interrupt handler
590 //------------------------------------------
591 static void mpc555_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
593 serial_channel * chan = (serial_channel *)data;
594 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
596 (chan->callbacks->xmt_char)(chan);
597 if(mpc555_chan->tx_interrupt_enable)
598 cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
601 //-----------------------------------------
602 // The high level receive interrupt handler
603 //-----------------------------------------
604 #define MPC555_SERIAL_SCxSR_ERRORS (MPC555_SERIAL_SCxSR_OR | \
605 MPC555_SERIAL_SCxSR_NF | \
606 MPC555_SERIAL_SCxSR_FE | \
607 MPC555_SERIAL_SCxSR_PF)
609 static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
611 serial_channel * chan = (serial_channel *)data;
612 mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
613 cyg_addrword_t port = mpc555_chan->base;
617 // Allways read out the received character, in order to clear receiver flags
618 HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
620 HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
621 if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
623 scsr &= ~((cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS);
624 HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
628 (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
631 cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
634 #endif // CYGPKG_IO_SERIAL_POWERPC_EC555
636 // EOF ec555_serial_with_ints.c