]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/serial/powerpc/cme555/v2_0/src/cme555_serial_with_ints.c
Initial revision
[karo-tx-redboot.git] / packages / devs / serial / powerpc / cme555 / v2_0 / src / cme555_serial_with_ints.c
1 //==========================================================================
2 //
3 //      cme555_serial_with_ints.c
4 //
5 //      PowerPC 5xx CME555 Serial I/O Interface Module (interrupt driven)
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 //
43 // Author(s):   Bob Koninckx
44 // Contributors:
45 // Date:        2002-04-25
46 // Purpose:     CME555 Serial I/O module (interrupt driven version)
47 // Description: 
48 //
49 //   
50 //####DESCRIPTIONEND####
51 //==========================================================================
52 //----------------------------------
53 // Includes and forward declarations
54 //----------------------------------
55 #include <pkgconf/io_serial.h>
56 #include <pkgconf/io.h>
57
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>
64
65 // Only build this driver for the MPC555 based CME555 board
66 #ifdef CYGPKG_IO_SERIAL_POWERPC_CME555
67
68 #include "cme555_serial.h"
69
70 //-----------------
71 // Type definitions
72 //-----------------
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
84 } mpc555_serial_info;
85
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,
93                                       const char * name);
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);
99
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);
105
106 //-------------------------------------------
107 // Register the device driver with the kernel
108 //-------------------------------------------
109 static SERIAL_FUNS(mpc555_serial_funs, 
110                    mpc555_serial_putc, 
111                    mpc555_serial_getc,
112                    mpc555_serial_set_config,
113                    mpc555_serial_start_xmit,
114                    mpc555_serial_stop_xmit);
115
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,
125                                                  false};
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];
129
130 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel0,
131                                        mpc555_serial_funs,
132                                        mpc555_serial_info0,
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));
142 #else 
143 static SERIAL_CHANNEL(mpc555_serial_channel0,
144                       mpc555_serial_funs,
145                       mpc555_serial_info0,
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);
151 #endif
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,
156              mpc555_serial_init,
157              mpc555_serial_lookup,
158              &mpc555_serial_channel0);
159 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_A
160
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,
167                                                  false};
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];
171
172 static SERIAL_CHANNEL_USING_INTERRUPTS(mpc555_serial_channel1,
173                                        mpc555_serial_funs,
174                                        mpc555_serial_info1,
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));
184 #else
185 static SERIAL_CHANNEL(mpc555_serial_channel1,
186                       mpc555_serial_funs,
187                       mpc555_serial_info1,
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);
193 #endif
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,
198              mpc555_serial_init,
199              mpc555_serial_lookup,
200              &mpc555_serial_channel1);
201 #endif // ifdef CYGPKG_IO_SERIAL_POWERPC_CME555_SERIAL_B
202
203 //-----------------------------
204 // Device driver implementation
205 //-----------------------------
206
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
210 //
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)
213 {
214   cyg_uint16 status;
215   cyg_uint16 control;
216
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);
230 #endif
231
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);
245
246 #if 0
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);
261
262   cyg_uint16 status;
263   cyg_uint16 control;
264
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);
269
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);
273
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);
276 #endif
277   
278 #endif
279
280   return 0;
281 }
282
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)
287 {
288   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)(chan->dev_priv);
289
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
293
294   cyg_uint16 old_isrstate;
295   cyg_uint16 sccxr;
296
297   if(!baud_rate)
298     return false;    // Invalid baud rate selected
299
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
303
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
308
309   if((new_config->stop != CYGNUM_SERIAL_STOP_1) &&
310      (new_config->stop != CYGNUM_SERIAL_STOP_2))
311     return false;    // Invalid stop bits selected
312
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];
316
317   if((frame_length != 10) && (frame_length != 11))
318     return false;    // Invalid frame format selected
319
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);
339
340   // Set databits, stopbits and parity.
341   HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
342
343   if(frame_length == 11)
344     sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_M;
345   else
346     sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_M);
347
348   switch(new_config->parity)
349   {
350     case CYGNUM_SERIAL_PARITY_NONE:
351       sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PE);
352       break;
353     case CYGNUM_SERIAL_PARITY_EVEN:
354       sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
355       sccxr &= ~((cyg_uint16)MPC555_SERIAL_SCCxR1_PT);
356       break;
357     case CYGNUM_SERIAL_PARITY_ODD:
358       sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PE;
359       sccxr |= (cyg_uint16)MPC555_SERIAL_SCCxR1_PT;
360       break;
361     default:
362       break;
363   }
364   HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
365
366   // Set baud rate.
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);
371   sccxr |= baud_rate;
372   HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR0, sccxr);
373
374   // Enable the device
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);
379
380   if(init) 
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);
385   } 
386   else // Restore the old interrupt state
387   {
388     HAL_READ_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
389     sccxr |= old_isrstate;
390     HAL_WRITE_UINT16(port + MPC555_SERIAL_SCCxR1, sccxr);
391   }
392
393   if(new_config != &chan->config) 
394     chan->config = *new_config;
395
396   return true;
397 }
398
399 //--------------------------------------------------------------
400 // Function to initialize the device.  Called at bootstrap time.
401 //--------------------------------------------------------------
402 static hal_mpc5xx_arbitration_data arbiter;
403
404 static bool mpc555_serial_init(struct cyg_devtab_entry * tab)
405 {
406    serial_channel * chan = (serial_channel *)tab->priv;
407    mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
408
409    if(!mpc555_serial_config_port(chan, &chan->config, true))
410      return false;
411
412    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
413    if(chan->out_cbuf.len != 0)
414    { 
415      arbiter.priority = CYGNUM_HAL_ISR_SOURCE_PRIORITY_QSCI;
416      arbiter.data     = 0;
417      arbiter.arbiter  = hal_arbitration_isr_qsci;
418      
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); 
422
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);
432
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);
443     }
444
445     return true;
446 }
447
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,
453                                       const char * name)
454 {
455   serial_channel * chan = (serial_channel *)(*tab)->priv;
456   (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
457
458   return ENOERR;
459 }
460
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)
466 {
467   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
468   cyg_addrword_t port = mpc555_chan->base;
469
470   cyg_uint16 scsr;
471   cyg_uint16 scdr;
472
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);
478     return true;
479   }  
480   else
481     // We cannot write to the transmitter, return failure
482     return false;
483 }
484
485 //---------------------------------------------------------------------
486 // Fetch a character from the device input buffer, waiting if necessary
487 //---------------------------------------------------------------------
488 static unsigned char mpc555_serial_getc(serial_channel * chan)
489 {
490   unsigned char c;
491   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
492   cyg_addrword_t port = mpc555_chan->base;
493
494   cyg_uint16 scsr;
495   cyg_uint16 scdr;
496
497   do {
498     HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
499   } while(!(scsr & MPC555_SERIAL_SCxSR_RDRF));
500
501   // Ok, data is received, read it out and return
502   HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
503   c = (unsigned char)scdr;
504
505   return c;
506 }
507
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)
513 {
514   switch(key) {
515   case CYG_IO_SET_CONFIG_SERIAL_INFO:
516     {
517       cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
518       if(*len < sizeof(cyg_serial_info_t)) {
519         return -EINVAL;
520       }
521       *len = sizeof(cyg_serial_info_t);
522       if(true != mpc555_serial_config_port(chan, config, false))
523         return -EINVAL;
524     }
525     break;
526   default:
527     return -EINVAL;
528   }
529   return ENOERR;
530 }
531
532 //-------------------------------------
533 // Enable the transmitter on the device
534 //-------------------------------------
535 static void mpc555_serial_start_xmit(serial_channel * chan)
536 {
537   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
538
539   mpc555_chan->tx_interrupt_enable = true;
540   cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
541
542   // No need to call xmt_char, this will generate an interrupt immediately.
543 }
544
545 //--------------------------------------
546 // Disable the transmitter on the device
547 //--------------------------------------
548 static void mpc555_serial_stop_xmit(serial_channel * chan)
549 {
550   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
551
552   cyg_drv_dsr_lock();
553   mpc555_chan->tx_interrupt_enable = false;
554   cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
555   cyg_drv_dsr_unlock();
556 }
557
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)
562 {
563   serial_channel * chan = (serial_channel *)data;
564   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
565
566   cyg_drv_interrupt_mask(mpc555_chan->tx_interrupt_num);
567   cyg_drv_interrupt_acknowledge(mpc555_chan->tx_interrupt_num);
568
569   return CYG_ISR_CALL_DSR; // cause the DSR to run
570 }
571
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)
576 {
577   serial_channel * chan = (serial_channel *)data;
578   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
579
580   cyg_drv_interrupt_mask(mpc555_chan->rx_interrupt_num);
581   cyg_drv_interrupt_acknowledge(mpc555_chan->rx_interrupt_num);
582
583   return CYG_ISR_CALL_DSR; // cause the DSR to run
584 }
585
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)
590 {
591   serial_channel * chan = (serial_channel *)data;
592   mpc555_serial_info * mpc555_chan = (mpc555_serial_info *)chan->dev_priv;
593
594   (chan->callbacks->xmt_char)(chan);
595   if(mpc555_chan->tx_interrupt_enable)
596     cyg_drv_interrupt_unmask(mpc555_chan->tx_interrupt_num);
597 }
598
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)
606
607 static void mpc555_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
608 {
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;
612   cyg_uint16 scdr;
613   cyg_uint16 scsr;
614
615   // Allways read out the received character, in order to clear receiver flags
616   HAL_READ_UINT16(port + MPC555_SERIAL_SCxDR, scdr);
617
618   HAL_READ_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
619   if(scsr & (cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS)
620   {
621     scsr &= ~((cyg_uint16)MPC555_SERIAL_SCxSR_ERRORS);
622     HAL_WRITE_UINT16(port + MPC555_SERIAL_SCxSR, scsr);
623   }
624   else
625   {
626     (chan->callbacks->rcv_char)(chan, (cyg_uint8)scdr);
627   }
628
629   cyg_drv_interrupt_unmask(mpc555_chan->rx_interrupt_num);
630 }
631
632 #endif // CYGPKG_IO_SERIAL_POWERPC_CME555
633
634 // EOF cmd555_serial_with_ints.c