]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/serial/sh/scif/v2_0/src/sh_scif_serial.c
Initial revision
[karo-tx-redboot.git] / packages / devs / serial / sh / scif / v2_0 / src / sh_scif_serial.c
1 //==========================================================================
2 //
3 //      io/serial/sh/scif/sh_scif_serial.c
4 //
5 //      SH Serial IRDA/SCIF 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 //####ECOSGPLCOPYRIGHTEND####
37 //==========================================================================
38 //#####DESCRIPTIONBEGIN####
39 //
40 // Author(s):   jskov
41 // Contributors:gthomas, jskov
42 // Date:        2000-04-04
43 // Purpose:     SH Serial IRDA/SCIF I/O module (interrupt driven version)
44 // Description: 
45 //
46 //####DESCRIPTIONEND####
47 //==========================================================================
48
49 #include <pkgconf/io_serial.h>
50 #include <pkgconf/io.h>
51
52 // FIXME: This is necessary since the SCI driver may be overriding
53 // CYGDAT_IO_SERIAL_DEVICE_HEADER. Need a better way to include two
54 // different drivers.
55 #include <pkgconf/io_serial_sh_scif.h>
56
57 #include <cyg/io/io.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/io/devtab.h>
60 #include <cyg/infra/diag.h>
61 #include <cyg/infra/cyg_ass.h>
62 #include <cyg/io/serial.h>
63
64 #include <cyg/hal/sh_regs.h>
65 #include <cyg/hal/hal_cache.h>
66
67 // Only compile driver if an inline file with driver details was selected.
68 #ifdef CYGDAT_IO_SERIAL_SH_SCIF_INL
69
70 #if defined(CYGPKG_HAL_SH_SH2)
71 // The SCIF controller register layout on the SH2
72 // The controller base is defined in the board specification file.
73 # define SCIF_SCSMR      0x00      // serial mode register
74 # define SCIF_SCBRR      0x02      // bit rate register     
75 # define SCIF_SCSCR      0x04      // serial control register
76 # define SCIF_SCFTDR     0x06      // transmit data register
77 # define SCIF_SC1SSR     0x08      // serial status register 1
78 # define SCIF_SCSSR      SCIF_SC1SSR
79 # define SCIF_SC2SSR     0x0a      // serial status register 2
80 # define SCIF_SCFRDR     0x0c      // receive data register   
81 # define SCIF_SCFCR      0x0e      // FIFO control            
82 # define SCIF_SCFDR      0x10      // FIFO data count register
83 # define SCIF_SCFER      0x12      // FIFO error register
84 # define SCIF_SCIMR      0x14      // IrDA mode register
85 # define HAL_READ(x,y)  HAL_READ_UINT8(x,y)
86 # define HAL_WRITE(x,y) HAL_WRITE_UINT8(x,y)  
87
88 #elif defined(CYGPKG_HAL_SH_SH3)
89 // The SCIF controller register layout on the SH3
90 // The controller base is defined in the board specification file.
91 # define SCIF_SCSMR      0x00      // serial mode register
92 # define SCIF_SCBRR      0x02      // bit rate register
93 # define SCIF_SCSCR      0x04      // serial control register
94 # define SCIF_SCFTDR     0x06      // transmit data register
95 # define SCIF_SCSSR      0x08      // serial status register
96 # define SCIF_SCFRDR     0x0a      // receive data register
97 # define SCIF_SCFCR      0x0c      // FIFO control
98 # define SCIF_SCFDR      0x0e      // FIFO data count register
99 # define HAL_READ(x,y)  HAL_READ_UINT8(x,y)
100 # define HAL_WRITE(x,y) HAL_WRITE_UINT8(x,y)  
101 #elif defined(CYGPKG_HAL_SH_SH4)
102 // The SCIF controller register layout on the SH4
103 // The controller base is defined in the board specification file.
104 # define SCIF_SCSMR      0x00      // serial mode register
105 # define SCIF_SCBRR      0x04      // bit rate register
106 # define SCIF_SCSCR      0x08      // serial control register
107 # define SCIF_SCFTDR     0x0C      // transmit data register
108 # define SCIF_SCSSR      0x10      // serial status register
109 # define SCIF_SCFRDR     0x14      // receive data register
110 # define SCIF_SCFCR      0x18      // FIFO control
111 # define SCIF_SCFDR      0x1C      // FIFO data count register
112 # define HAL_READ(x,y)  HAL_READ_UINT16(x,y)
113 # define HAL_WRITE(x,y) HAL_WRITE_UINT16(x,y)  
114 #else
115 # error "Unsupported variant"
116 #endif
117
118 static short select_word_length[] = {
119     -1,
120     -1,
121     CYGARC_REG_SCIF_SCSMR_CHR,               // 7 bits
122     0                                   // 8 bits
123 };
124
125 static short select_stop_bits[] = {
126     -1,
127     0,                                  // 1 stop bit
128     -1,
129     CYGARC_REG_SCIF_SCSMR_STOP               // 2 stop bits
130 };
131
132 static short select_parity[] = {
133     0,                                  // No parity
134     CYGARC_REG_SCIF_SCSMR_PE,                // Even parity
135     CYGARC_REG_SCIF_SCSMR_PE|CYGARC_REG_SCIF_SCSMR_OE, // Odd parity
136     -1,
137     -1
138 };
139
140 static unsigned short select_baud[] = {
141     0,    // Unused
142     CYGARC_SCBRR_CKSx(50)<<8 | CYGARC_SCBRR_N(50),
143     CYGARC_SCBRR_CKSx(75)<<8 | CYGARC_SCBRR_N(75),
144     CYGARC_SCBRR_CKSx(110)<<8 | CYGARC_SCBRR_N(110),
145     CYGARC_SCBRR_CKSx(134)<<8 | CYGARC_SCBRR_N(134),
146     CYGARC_SCBRR_CKSx(150)<<8 | CYGARC_SCBRR_N(150),
147     CYGARC_SCBRR_CKSx(200)<<8 | CYGARC_SCBRR_N(200),
148     CYGARC_SCBRR_CKSx(300)<<8 | CYGARC_SCBRR_N(300),
149     CYGARC_SCBRR_CKSx(600)<<8 | CYGARC_SCBRR_N(600),
150     CYGARC_SCBRR_CKSx(1200)<<8 | CYGARC_SCBRR_N(1200),
151     CYGARC_SCBRR_CKSx(1800)<<8 | CYGARC_SCBRR_N(1800),
152     CYGARC_SCBRR_CKSx(2400)<<8 | CYGARC_SCBRR_N(2400),
153     CYGARC_SCBRR_CKSx(3600)<<8 | CYGARC_SCBRR_N(3600),
154     CYGARC_SCBRR_CKSx(4800)<<8 | CYGARC_SCBRR_N(4800),
155     CYGARC_SCBRR_CKSx(7200)<<8 | CYGARC_SCBRR_N(7200),
156     CYGARC_SCBRR_CKSx(9600)<<8 | CYGARC_SCBRR_N(9600),
157     CYGARC_SCBRR_CKSx(14400)<<8 | CYGARC_SCBRR_N(14400),
158     CYGARC_SCBRR_CKSx(19200)<<8 | CYGARC_SCBRR_N(19200),
159     CYGARC_SCBRR_CKSx(38400)<<8 | CYGARC_SCBRR_N(38400),
160     CYGARC_SCBRR_CKSx(57600)<<8 | CYGARC_SCBRR_N(57600),
161     CYGARC_SCBRR_CKSx(115200)<<8 | CYGARC_SCBRR_N(115200),
162     CYGARC_SCBRR_CKSx(230400)<<8 | CYGARC_SCBRR_N(230400)
163 };
164
165 typedef struct sh_scif_info {
166     CYG_WORD          er_int_num,       // Error interrupt number
167 #ifdef CYGINT_IO_SERIAL_SH_SCIF_BR_INTERRUPT
168                       br_int_num,       // Break interrupt number
169 #endif
170                       rx_int_num,       // Receive interrupt number
171                       tx_int_num;       // Transmit interrupt number
172
173     CYG_ADDRWORD      ctrl_base;        // Base address of SCI controller
174
175     cyg_interrupt     serial_er_interrupt,
176 #ifdef CYGINT_IO_SERIAL_SH_SCIF_BR_INTERRUPT
177                       serial_br_interrupt,
178 #endif
179                       serial_rx_interrupt,
180                       serial_tx_interrupt;
181     cyg_handle_t      serial_er_interrupt_handle, 
182 #ifdef CYGINT_IO_SERIAL_SH_SCIF_BR_INTERRUPT
183                       serial_br_interrupt_handle, 
184 #endif
185                       serial_rx_interrupt_handle, 
186                       serial_tx_interrupt_handle;
187
188     volatile bool     tx_enabled;       // expect tx _serial_ interrupts
189 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
190     bool              irda_mode;
191 #endif
192 #ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX
193     bool              async_rxtx_mode;
194 #endif
195
196 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
197     cyg_bool          dma_enable;       // Set if DMA mode
198     cyg_uint32        dma_xmt_cr_flags; // CR flags for DMA mode
199     CYG_WORD          dma_xmt_int_num;  // DMA xmt completion interrupt
200     CYG_ADDRWORD      dma_xmt_base;     // Base address of DMA channel
201     int               dma_xmt_len;      // length transferred by DMA
202     cyg_interrupt     dma_xmt_interrupt;
203     cyg_handle_t      dma_xmt_interrupt_handle;
204     volatile cyg_bool dma_xmt_running;  // expect tx _dma_ interrupts
205 #endif
206 } sh_scif_info;
207
208 static bool sh_scif_init(struct cyg_devtab_entry *tab);
209 static bool sh_scif_putc(serial_channel *chan, unsigned char c);
210 static Cyg_ErrNo sh_scif_lookup(struct cyg_devtab_entry **tab, 
211                                    struct cyg_devtab_entry *sub_tab,
212                                    const char *name);
213 static unsigned char sh_scif_getc(serial_channel *chan);
214 static Cyg_ErrNo sh_scif_set_config(serial_channel *chan, cyg_uint32 key,
215                                      const void *xbuf, cyg_uint32 *len);
216 static void sh_scif_start_xmit(serial_channel *chan);
217 static void sh_scif_stop_xmit(serial_channel *chan);
218
219 static cyg_uint32 sh_scif_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
220 static void       sh_scif_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, 
221                                    cyg_addrword_t data);
222 static cyg_uint32 sh_scif_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
223 static void       sh_scif_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, 
224                                    cyg_addrword_t data);
225 static cyg_uint32 sh_scif_er_ISR(cyg_vector_t vector, cyg_addrword_t data);
226 static void       sh_scif_er_DSR(cyg_vector_t vector, cyg_ucount32 count, 
227                                    cyg_addrword_t data);
228
229 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
230 static cyg_uint32 sh_dma_xmt_ISR(cyg_vector_t vector, cyg_addrword_t data);
231 static void       sh_dma_xmt_DSR(cyg_vector_t vector, cyg_ucount32 count, 
232                                  cyg_addrword_t data);
233 #endif
234
235 static SERIAL_FUNS(sh_scif_funs, 
236                    sh_scif_putc, 
237                    sh_scif_getc,
238                    sh_scif_set_config,
239                    sh_scif_start_xmit,
240                    sh_scif_stop_xmit
241     );
242
243 // Get the board specification
244 #include CYGDAT_IO_SERIAL_SH_SCIF_INL
245
246 // Allow platform to define handling of additional config keys
247 #ifndef CYGPRI_DEVS_SH_SCIF_SET_CONFIG_PLF
248 # define CYGPRI_DEVS_SH_SCIF_SET_CONFIG_PLF
249 #endif
250
251 // Internal function to actually configure the hardware to desired baud rate,
252 // etc.
253 static bool
254 sh_scif_config_port(serial_channel *chan, cyg_serial_info_t *new_config, 
255                      bool init)
256 {
257     cyg_uint16 baud_divisor = select_baud[new_config->baud];
258     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
259     cyg_uint8 _scr, _smr;
260     cyg_uint16 _sr;
261     CYG_ADDRWORD base = sh_chan->ctrl_base;
262
263     // Check configuration request
264     if ((-1 == select_word_length[(new_config->word_length -
265                                   CYGNUM_SERIAL_WORD_LENGTH_5)])
266         || -1 == select_stop_bits[new_config->stop]
267         || -1 == select_parity[new_config->parity]
268         || baud_divisor == 0)
269         return false;
270
271     // Disable SCI interrupts while changing hardware
272     HAL_READ(base+SCIF_SCSCR, _scr);
273     HAL_WRITE(base+SCIF_SCSCR, 0);
274
275     // Reset FIFO.
276     HAL_WRITE(base+SCIF_SCFCR, 
277               CYGARC_REG_SCIF_SCFCR_TFRST|CYGARC_REG_SCIF_SCFCR_RFRST);
278
279 #ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX
280     sh_chan->async_rxtx_mode = false;
281 #endif
282 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
283     if (sh_chan->irda_mode) {
284         // In IrDA mode, the configuration is hardwired and the mode
285         // bits should not be set
286 #ifdef CYGARC_REG_SCIF_SCSMR_IRMOD
287         _smr = CYGARC_REG_SCIF_SCSMR_IRMOD;
288 #elif defined(SCIF_SCIMR)
289         _smr = 0;
290         HAL_WRITE_UINT8(base+SCIF_SCIMR, CYGARC_REG_SCIF_SCIMR_IRMOD);
291 #endif
292     } else
293 #endif
294     {
295         // Set databits, stopbits and parity.
296         _smr = select_word_length[(new_config->word_length -
297                                    CYGNUM_SERIAL_WORD_LENGTH_5)] | 
298             select_stop_bits[new_config->stop] |
299             select_parity[new_config->parity];
300 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
301 #ifdef SCIF_SCIMR
302         // Disable IrDA mode
303         HAL_WRITE(base+SCIF_SCIMR, 0);
304 #endif
305 #endif
306     }
307     HAL_WRITE(base+SCIF_SCSMR, _smr);
308
309     // Set baud rate.
310     _smr &= ~CYGARC_REG_SCIF_SCSMR_CKSx_MASK;
311     _smr |= baud_divisor >> 8;
312     HAL_WRITE(base+SCIF_SCSMR, _smr);
313     HAL_WRITE_UINT8(base+SCIF_SCBRR, baud_divisor & 0xff);
314
315     // FIXME: Should delay 1/<baud> second here.
316
317     // Clear the status register (read first).
318     HAL_READ_UINT16(base+SCIF_SCSSR, _sr);
319     HAL_WRITE_UINT16(base+SCIF_SCSSR, 0);
320
321     // Bring FIFO out of reset and set FIFO trigger marks
322     //
323     // Note that the RX FIFO size must be smaller when flow control is
324     // enabled. This due to observations made by running the flow2
325     // serial test. The automatic RTS de-assertion happens
326     // (apparently) when the FIFO fills past the trigger count -
327     // causing the sender to stop transmission. But there's a lag
328     // before transmission is stopped, and if the FIFO fills in that
329     // time, data will be lost. Thus, seeing as HW flow control is
330     // presumed used for prevention of data loss, set the trigger
331     // level so the sender has time to stop transmission before the
332     // FIFO fills up.
333     //
334     // The trigger setting of 8 allows test flow2 to complete without
335     // problems. It tests duplex data transmission at 115200
336     // baud. Depending on the lag time between the de-assertion of RTS
337     // and actual transmission stop, it may be necessary to reduce the
338     // trigger level further.
339 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
340     HAL_WRITE(base+SCIF_SCFCR, 
341                     CYGARC_REG_SCIF_SCFCR_RTRG_8|CYGARC_REG_SCIF_SCFCR_TTRG_8);
342 #else
343     HAL_WRITE(base+SCIF_SCFCR, 
344                     CYGARC_REG_SCIF_SCFCR_RTRG_14|CYGARC_REG_SCIF_SCFCR_TTRG_8);
345 #endif
346
347     if (init) {
348         // Always enable received and (for normal mode) transmitter
349         _scr = CYGARC_REG_SCIF_SCSCR_TE | CYGARC_REG_SCIF_SCSCR_RE;
350 #ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX
351         if (sh_chan->async_rxtx_mode)
352             _scr = CYGARC_REG_SCIF_SCSCR_RE;
353 #endif
354 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
355         if (sh_chan->irda_mode)
356             _scr = CYGARC_REG_SCIF_SCSCR_RE;
357 #endif
358
359         if (chan->in_cbuf.len != 0)
360             _scr |= CYGARC_REG_SCIF_SCSCR_RIE; // enable rx interrupts
361     }
362      
363     HAL_WRITE(base+SCIF_SCSCR, _scr);
364
365     if (new_config != &chan->config) {
366         chan->config = *new_config;
367     }
368     return true;
369 }
370
371 // Function to initialize the device.  Called at bootstrap time.
372 static bool 
373 sh_scif_init(struct cyg_devtab_entry *tab)
374 {
375     serial_channel *chan = (serial_channel *)tab->priv;
376     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
377 #ifdef CYGDBG_IO_INIT
378     diag_printf("SH SERIAL init - dev: %x.%d\n", 
379                 sh_chan->ctrl_base, sh_chan->rx_int_num);
380 #endif
381     // Really only required for interrupt driven devices
382     (chan->callbacks->serial_init)(chan);
383
384     if (chan->out_cbuf.len != 0) {
385         cyg_drv_interrupt_create(sh_chan->tx_int_num,
386                                  3,
387                                  (cyg_addrword_t)chan, // Data item passed to interrupt handler
388                                  sh_scif_tx_ISR,
389                                  sh_scif_tx_DSR,
390                                  &sh_chan->serial_tx_interrupt_handle,
391                                  &sh_chan->serial_tx_interrupt);
392         cyg_drv_interrupt_attach(sh_chan->serial_tx_interrupt_handle);
393         cyg_drv_interrupt_unmask(sh_chan->tx_int_num);
394         sh_chan->tx_enabled = false;
395     }
396     if (chan->in_cbuf.len != 0) {
397         // Receive interrupt
398         cyg_drv_interrupt_create(sh_chan->rx_int_num,
399                                  3,
400                                  (cyg_addrword_t)chan, // Data item passed to interrupt handler
401                                  sh_scif_rx_ISR,
402                                  sh_scif_rx_DSR,
403                                  &sh_chan->serial_rx_interrupt_handle,
404                                  &sh_chan->serial_rx_interrupt);
405         cyg_drv_interrupt_attach(sh_chan->serial_rx_interrupt_handle);
406         // Receive error interrupt
407         cyg_drv_interrupt_create(sh_chan->er_int_num,
408                                  3,
409                                  (cyg_addrword_t)chan, // Data item passed to interrupt handler
410                                  sh_scif_er_ISR,
411                                  sh_scif_er_DSR,
412                                  &sh_chan->serial_er_interrupt_handle,
413                                  &sh_chan->serial_er_interrupt);
414         cyg_drv_interrupt_attach(sh_chan->serial_er_interrupt_handle);
415 #ifdef CYGINT_IO_SERIAL_SH_SCIF_BR_INTERRUPT
416         // Break error interrupt
417         cyg_drv_interrupt_create(sh_chan->br_int_num,
418                                  3,
419                                  (cyg_addrword_t)chan, // Data item passed to interrupt handler
420                                  sh_scif_er_ISR,
421                                  sh_scif_er_DSR,
422                                  &sh_chan->serial_br_interrupt_handle,
423                                  &sh_chan->serial_br_interrupt);
424         cyg_drv_interrupt_attach(sh_chan->serial_br_interrupt_handle);
425 #endif
426         // This unmasks all interrupt sources.
427         cyg_drv_interrupt_unmask(sh_chan->rx_int_num);
428     }
429
430 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
431     // Assign DMA channel and interrupt if requested
432     if (sh_chan->dma_enable) {
433         // FIXME: Need a cleaner way to assign DMA channels
434         static int dma_channel = 0;
435 #if defined(CYGPKG_HAL_SH_SH2)
436         sh_chan->dma_xmt_int_num = dma_channel+CYGNUM_HAL_INTERRUPT_DMAC0_TE;
437 #elif defined(CYGPKG_HAL_SH_SH3)
438         sh_chan->dma_xmt_int_num = dma_channel+CYGNUM_HAL_INTERRUPT_DMAC_DEI0;
439 #else
440 # error "No interrupt defined for variant"
441 #endif
442         sh_chan->dma_xmt_base = (dma_channel*0x10)+CYGARC_REG_SAR0;
443         dma_channel++;
444
445         // Enable the DMA engines.
446         HAL_WRITE_UINT16(CYGARC_REG_DMAOR, CYGARC_REG_DMAOR_DME);
447
448         cyg_drv_interrupt_create(sh_chan->dma_xmt_int_num,
449                                  3,
450                                  (cyg_addrword_t)chan, // Data item passed to interrupt handler
451                                  sh_dma_xmt_ISR,
452                                  sh_dma_xmt_DSR,
453                                  &sh_chan->dma_xmt_interrupt_handle,
454                                  &sh_chan->dma_xmt_interrupt);
455         cyg_drv_interrupt_attach(sh_chan->dma_xmt_interrupt_handle);
456         cyg_drv_interrupt_unmask(sh_chan->dma_xmt_int_num);
457     }
458     sh_chan->dma_xmt_running = false;
459 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
460
461     sh_scif_config_port(chan, &chan->config, true);
462     return true;
463 }
464
465 // This routine is called when the device is "looked" up (i.e. attached)
466 static Cyg_ErrNo 
467 sh_scif_lookup(struct cyg_devtab_entry **tab,
468                   struct cyg_devtab_entry *sub_tab,
469                   const char *name)
470 {
471     serial_channel *chan = (serial_channel *)(*tab)->priv;
472
473     // Really only required for interrupt driven devices
474     (chan->callbacks->serial_init)(chan);
475     return ENOERR;
476 }
477
478 // Send a character to the device output buffer.
479 // Return 'true' if character is sent to device
480 static bool
481 sh_scif_putc(serial_channel *chan, unsigned char c)
482 {
483     cyg_uint16 _fdr, _sr;
484     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
485
486     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCFDR, _fdr);
487     if (((_fdr & CYGARC_REG_SCIF_SCFDR_TCOUNT_MASK) >> CYGARC_REG_SCIF_SCFDR_TCOUNT_shift) < 15) {
488 // Transmit FIFO has room for another char
489         HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCFTDR, c);
490         // Clear FIFO-empty/transmit end flags (read back sr first)
491         HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
492         HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR,
493                         CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~CYGARC_REG_SCIF_SCSSR_TDFE);
494         return true;
495     } else {
496 // No space
497         return false;
498     }
499 }
500
501 // Fetch a character from the device input buffer, waiting if necessary
502 // Note: Input is running wo FIFO enabled, so the counter is not checked here.
503 static unsigned char 
504 sh_scif_getc(serial_channel *chan)
505 {
506     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
507     unsigned char c;
508     cyg_uint16 _sr;
509
510     do {
511         HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
512     } while ((_sr & CYGARC_REG_SCIF_SCSSR_RDF) == 0);
513
514     HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, c);
515
516     // Clear buffer full flag (read back first)
517     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
518     HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, 
519                      CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~CYGARC_REG_SCIF_SCSSR_RDF);
520
521     return c;
522 }
523
524 // Set up the device characteristics; baud rate, etc.
525 static Cyg_ErrNo
526 sh_scif_set_config(serial_channel *chan, cyg_uint32 key,
527                     const void *xbuf, cyg_uint32 *len)
528 {
529     switch (key) {
530     case CYG_IO_SET_CONFIG_SERIAL_INFO:
531       {
532         cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
533         if ( *len < sizeof(cyg_serial_info_t) ) {
534             return -EINVAL;
535         }
536         *len = sizeof(cyg_serial_info_t);
537         if ( true != sh_scif_config_port(chan, config, false) )
538             return -EINVAL;
539       }
540       break;
541 #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
542     case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
543       {
544           sh_scif_info *ser_chan = (sh_scif_info *)chan->dev_priv;
545           cyg_addrword_t base = ser_chan->ctrl_base;
546           cyg_uint32 *f = (cyg_uint32 *)xbuf;
547           if ( *len < *f )
548               return -EINVAL;
549
550           if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX ) {
551               // Control RX RTC/CTS flow control by disabling/enabling
552               // RX interrupt.  When disabled, FIFO will fill up and
553               // clear RTS.
554               cyg_uint8 _scscr;
555               HAL_READ(base+SCIF_SCSCR, _scscr);
556               if (*f) // we should throttle
557                   _scscr &= ~CYGARC_REG_SCIF_SCSCR_RIE;
558               else // we should no longer throttle
559                   _scscr |= CYGARC_REG_SCIF_SCSCR_RIE;
560               HAL_WRITE(base+SCIF_SCSCR, _scscr);
561           }
562 #ifdef CYGHWR_SH_SCIF_FLOW_DSRDTR
563           if ( chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX ) {
564               // Control RX DSR/DTR flow control via platform specific macro
565               CYGHWR_SH_SCIF_FLOW_DSRDTR_RX(chan, *f);
566           }
567 #endif
568       }
569       break;
570     case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG:
571       {
572           // Handle CTS/RTS flag
573           if ( chan->config.flags & 
574                (CYGNUM_SERIAL_FLOW_RTSCTS_RX | CYGNUM_SERIAL_FLOW_RTSCTS_TX )){
575               cyg_uint8 _scfcr;
576               sh_scif_info *ser_chan = (sh_scif_info *)chan->dev_priv;
577               cyg_addrword_t base = ser_chan->ctrl_base;
578               cyg_uint8 *f = (cyg_uint8 *)xbuf;
579
580               HAL_READ(base+SCIF_SCFCR, _scfcr);
581               if (*f) // enable RTS/CTS flow control
582                   _scfcr |= CYGARC_REG_SCIF_SCFCR_MCE;
583               else // disable RTS/CTS flow control
584                   _scfcr &= ~CYGARC_REG_SCIF_SCFCR_MCE;
585               HAL_WRITE(base+SCIF_SCFCR, _scfcr);
586           }
587 #ifndef CYGHWR_SH_SCIF_FLOW_DSRDTR
588           // Clear DSR/DTR flag as it's not supported.
589           if (chan->config.flags &
590               (CYGNUM_SERIAL_FLOW_DSRDTR_RX|CYGNUM_SERIAL_FLOW_DSRDTR_TX)) {
591               chan->config.flags &= ~(CYGNUM_SERIAL_FLOW_DSRDTR_RX|
592                                       CYGNUM_SERIAL_FLOW_DSRDTR_TX);
593               return -EINVAL;
594           }
595 #else
596           return CYGHWR_SH_SCIF_FLOW_DSRDTR_CONFIG(chan);
597 #endif
598       }
599       break;
600 #endif
601
602     CYGPRI_DEVS_SH_SCIF_SET_CONFIG_PLF
603
604     default:
605         return -EINVAL;
606     }
607     return ENOERR;
608 }
609
610
611 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
612
613 // Must be called with serial interrupts disabled
614 static xmt_req_reply_t
615 sh_scif_start_dma_xmt(serial_channel *chan)
616 {
617     int chars_avail;
618     unsigned char* chars;
619     xmt_req_reply_t res;
620
621     // We can transfer the full buffer - ask how much to transfer
622     res = (chan->callbacks->data_xmt_req)(chan, chan->out_cbuf.len, 
623                                           &chars_avail, &chars);
624     if (CYG_XMT_OK == res) {
625         sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
626         cyg_uint32 dma_base = sh_chan->dma_xmt_base;
627         cyg_uint32 scr;
628
629         // Save the length so it can be used in the DMA DSR
630         sh_chan->dma_xmt_len = chars_avail;
631
632         // Flush cache for the area
633         HAL_DCACHE_FLUSH((cyg_haladdress)chars, chars_avail);
634
635         // Program DMA
636         HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR, 0); // disable and clear
637         HAL_WRITE_UINT32(dma_base+CYGARC_REG_SAR, (cyg_uint32)chars);
638         HAL_WRITE_UINT32(dma_base+CYGARC_REG_DAR, 
639                          (sh_chan->ctrl_base+SCIF_SCFTDR) & 0x0fffffff);
640         HAL_WRITE_UINT32(dma_base+CYGARC_REG_DMATCR, chars_avail);
641         // Source increments, dest static, byte transfer, enable
642         // interrupt on completion.
643         HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR,
644                          sh_chan->dma_xmt_cr_flags | CYGARC_REG_CHCR_SM0 \
645                          | CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
646
647         // Enable serial interrupts
648         HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, scr);
649         scr |= CYGARC_REG_SCIF_SCSCR_TIE;
650         HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, scr);
651     }
652
653     return res;
654 }
655
656 // must be called with serial interrupts masked
657 static void
658 sh_scif_stop_dma_xmt(serial_channel *chan)
659 {
660     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
661     cyg_uint32 dma_base = sh_chan->dma_xmt_base;
662     cyg_uint32 cr;
663
664     // Disable DMA engine and interrupt enable flag.  Should be safe
665     // to do since it's triggered by the serial interrupt which has
666     // already been disabled.
667     HAL_READ_UINT32(dma_base+CYGARC_REG_CHCR, cr);
668     cr &= ~(CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
669     HAL_WRITE_UINT32(dma_base+CYGARC_REG_CHCR, cr);
670
671     // Did transfer complete?
672     HAL_READ_UINT32(dma_base+CYGARC_REG_CHCR, cr);
673     if (0 == (cr & CYGARC_REG_CHCR_TE)) {
674         // Transfer incomplete. Report actually transferred amount of data
675         // back to the serial driver.
676         int chars_left;
677         HAL_READ_UINT32(dma_base+CYGARC_REG_DMATCR, chars_left);
678         CYG_ASSERT(chars_left > 0, "DMA incomplete, but no data left");
679         CYG_ASSERT(chars_left <= sh_chan->dma_xmt_len,
680                    "More data remaining than was attempted transferred");
681
682         (chan->callbacks->data_xmt_done)(chan, 
683                                          sh_chan->dma_xmt_len - chars_left);
684     }
685
686 #ifdef CYGDBG_USE_ASSERTS
687     {
688         cyg_uint32 dmaor;
689         HAL_READ_UINT32(CYGARC_REG_DMAOR, dmaor);
690         CYG_ASSERT(0== (dmaor & (CYGARC_REG_DMAOR_AE | CYGARC_REG_DMAOR_NMIF)),
691                    "DMA error");
692     }
693 #endif
694     
695     // The DMA engine is free again.
696     sh_chan->dma_xmt_running = false;
697 }
698
699 // Serial xmt DMA completion interrupt handler (ISR)
700 static cyg_uint32 
701 sh_dma_xmt_ISR(cyg_vector_t vector, cyg_addrword_t data)
702 {
703     serial_channel *chan = (serial_channel *)data;
704     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
705     cyg_uint32 _cr;
706
707     // mask serial interrupt
708     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _cr);
709     _cr &= ~CYGARC_REG_SCIF_SCSCR_TIE;      // Disable xmit interrupt
710     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _cr);
711
712     // mask DMA interrupt and disable engine
713     HAL_READ_UINT32(sh_chan->dma_xmt_base+CYGARC_REG_CHCR, _cr);
714     _cr &= ~(CYGARC_REG_CHCR_IE | CYGARC_REG_CHCR_DE);
715     HAL_WRITE_UINT32(sh_chan->dma_xmt_base+CYGARC_REG_CHCR, _cr);
716
717     return CYG_ISR_CALL_DSR;  // Cause DSR to be run
718 }
719
720 // Serial xmt DMA completion interrupt handler (DSR)
721 static void       
722 sh_dma_xmt_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
723 {
724     serial_channel *chan = (serial_channel *)data;
725     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
726
727     (chan->callbacks->data_xmt_done)(chan, sh_chan->dma_xmt_len);
728
729     // Try to load the engine again.
730     sh_chan->dma_xmt_running = 
731         (CYG_XMT_OK == sh_scif_start_dma_xmt(chan)) ? true : false;
732 }
733 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
734
735
736 // Enable the transmitter on the device
737 static void
738 sh_scif_start_xmit(serial_channel *chan)
739 {
740     cyg_uint8 _scr;
741     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
742     xmt_req_reply_t _block_status = CYG_XMT_DISABLED;
743
744     if (sh_chan->tx_enabled)
745         return;
746
747 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
748     // Check if the engine is already running. If so, return. Note
749     // that there will never be a race on this flag - the caller of
750     // this function is respecting a per-channel lock.
751     if (sh_chan->dma_xmt_running)
752         return;
753     // If the channel uses DMA, try to start a DMA job for this -
754     // but handle the case where the job doesn't start by falling
755     // back to the FIFO/interrupt based code.
756     if (sh_chan->dma_enable) {
757         _block_status = sh_scif_start_dma_xmt(chan);
758         CYG_ASSERT(_block_status != CYG_XMT_EMPTY, 
759                    "start_xmit called with empty buffers!");
760         sh_chan->dma_xmt_running = 
761             (CYG_XMT_OK == _block_status) ? true : false;
762     }
763 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
764
765     if (CYG_XMT_DISABLED == _block_status) {
766         // Mask interrupts while changing the CR since a rx
767         // interrupt or another thread doing the same in the
768         // middle of this would result in a bad CR state.
769         cyg_drv_isr_lock();
770         {
771             HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
772             _scr |= CYGARC_REG_SCIF_SCSCR_TIE;       // Enable xmit interrupt
773 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
774             if (sh_chan->irda_mode) {
775                 // Enable transmitter - this automatically disables
776                 // the receiver in the hardware.  Doing it explicitly
777                 // (like for async RX/TX below) causes more spurious
778                 // characters to be read when re-enabling the
779                 // receiver.
780                 _scr |= CYGARC_REG_SCIF_SCSCR_TE;
781             }
782 #endif
783 #ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX
784             if (sh_chan->async_rxtx_mode) {
785                 // Enable transmitter
786                 _scr |= CYGARC_REG_SCIF_SCSCR_TE;
787                 // Disable receiver
788                 _scr &= ~CYGARC_REG_SCIF_SCSCR_RE;
789             }
790 #endif
791             HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
792             sh_chan->tx_enabled = true;
793         }
794         cyg_drv_isr_unlock();
795     }
796 }
797
798 // Disable the transmitter on the device
799 static void 
800 sh_scif_stop_xmit(serial_channel *chan)
801 {
802     cyg_uint8 _scr;
803     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
804
805     // In IrDA and async mode the transmitter needs to be disabled, so
806     // wait for transmission to complete within reason: disable it
807     // after 0.1s
808     if (0
809 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
810         || sh_chan->irda_mode
811 #endif
812 #if defined(CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX)
813         || sh_chan->async_rxtx_mode
814 #endif
815         ) {
816         cyg_uint16 sr;
817         int i = 1000;
818         do {
819             HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, sr);
820             if (sr & CYGARC_REG_SCIF_SCSSR_TEND) break;
821             HAL_DELAY_US(100);
822         } while (i-- > 0);
823     }
824
825     // Mask interrupts while changing the CR since a rx interrupt or
826     // another thread doing the same in the middle of this would
827     // result in a bad CR state.
828     cyg_drv_isr_lock();
829     {
830             HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
831             _scr &= ~CYGARC_REG_SCIF_SCSCR_TIE;      // Disable xmit interrupt
832 #ifdef CYGINT_IO_SERIAL_SH_SCIF_IRDA
833             if (sh_chan->irda_mode) {
834 #ifdef CYGHWR_IO_SERIAL_SH_SCIF_IRDA_TXRX_COMPENSATION
835                 // In IrDA mode there will be generated spurious RX
836                 // events when the TX unit is switched on. Eat that
837                 // character.
838                 cyg_uint8 _junk;
839                 cyg_uint16 _sr;
840                 HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _junk);
841
842                 // Clear buffer full flag (read back first)
843                 HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
844                 HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, 
845                                  CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~(CYGARC_REG_SCIF_SCSSR_RDF|CYGARC_REG_SCIF_SCSSR_DR));
846 #endif
847                 // Disable transmitter
848                 _scr &= ~CYGARC_REG_SCIF_SCSCR_TE;
849             }
850 #endif
851 #ifdef CYGINT_IO_SERIAL_SH_SCIF_ASYNC_RXTX
852             if (sh_chan->async_rxtx_mode) {
853                 // Enable receiver again
854                 _scr |= CYGARC_REG_SCIF_SCSCR_RE;
855                 // Disable transmitter
856                 _scr &= ~CYGARC_REG_SCIF_SCSCR_TE;
857             }
858 #endif
859             HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
860     }
861     cyg_drv_isr_unlock();
862
863 #ifdef CYGINT_IO_SERIAL_SH_SCIF_DMA
864     // If the channel uses DMA, stop the DMA engine.
865     if (sh_chan->dma_xmt_running)
866         sh_scif_stop_dma_xmt(chan);
867     else // dangling else!
868 #endif // CYGINT_IO_SERIAL_SH_SCIF_DMA
869         sh_chan->tx_enabled = false;
870 }
871
872 // Serial I/O - low level tx interrupt handler (ISR)
873 static cyg_uint32 
874 sh_scif_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
875 {
876     serial_channel *chan = (serial_channel *)data;
877     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
878     cyg_uint8 _scr;
879
880     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
881     _scr &= ~CYGARC_REG_SCIF_SCSCR_TIE;      // mask out tx interrupts
882     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
883
884     return CYG_ISR_CALL_DSR;  // Cause DSR to be run
885 }
886
887 // Serial I/O - high level tx interrupt handler (DSR)
888 static void       
889 sh_scif_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
890 {
891     serial_channel *chan = (serial_channel *)data;
892     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
893     xmt_req_reply_t _block_status = CYG_XMT_DISABLED;
894     cyg_uint16 _fdr, _sr;
895     int _space, _chars_avail;
896     unsigned char* _chars;
897     CYG_ADDRWORD _base = sh_chan->ctrl_base;
898
899     // Always check if we're supposed to be enabled; the driver runs
900     // with DSRs disabled, and a DSR may have been posted (but not
901     // executed) before the interrupt was masked.
902     if (!sh_chan->tx_enabled)
903         return;
904
905 #ifdef CYGHWR_SH_SCIF_FLOW_DSRDTR
906     CYGHWR_SH_SCIF_FLOW_DSRDTR_TX(chan);
907 #endif
908
909     // How many chars can we stuff into the FIFO?
910     HAL_READ_UINT16(_base+SCIF_SCFDR, _fdr);
911     _space = 16 - ((_fdr & CYGARC_REG_SCIF_SCFDR_TCOUNT_MASK) >> CYGARC_REG_SCIF_SCFDR_TCOUNT_shift);
912
913     // Try to do the transfer most efficiently
914     _block_status = (chan->callbacks->data_xmt_req)(chan, _space,
915                                                     &_chars_avail, &_chars);
916     if (CYG_XMT_OK == _block_status) {
917         // Transfer the data in block(s).
918         do {
919             int i = _chars_avail;
920             while (i--) {
921                 HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SCFTDR, *_chars++);
922                 _space--;
923             }
924             (chan->callbacks->data_xmt_done)(chan, _chars_avail);
925         } while (_space > 0 && 
926                  (CYG_XMT_OK == (chan->callbacks->data_xmt_req)(chan, _space,
927                                                                 &_chars_avail,
928                                                                 &_chars)));
929     } else if (CYG_XMT_DISABLED == _block_status) {
930         // Transfer char-by-char, but stop if the transmitter
931         // gets disabled.
932         while (_space-- && sh_chan->tx_enabled)
933             (chan->callbacks->xmt_char)(chan);
934     }
935
936     // Clear FIFO-empty/transmit end flags (read back sr first)
937     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
938     HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR,
939                      CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~CYGARC_REG_SCIF_SCSSR_TDFE);
940
941     if (sh_chan->tx_enabled) {
942         cyg_uint8 _scr;
943         HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
944         _scr |= CYGARC_REG_SCIF_SCSCR_TIE;       // unmask tx interrupts
945         HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
946     }
947 }
948
949 // Serial I/O - low level RX interrupt handler (ISR)
950 static cyg_uint32 
951 sh_scif_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
952 {
953     serial_channel *chan = (serial_channel *)data;
954     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
955     cyg_uint8 _scr;
956
957     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
958     _scr &= ~CYGARC_REG_SCIF_SCSCR_RIE;      // mask rx interrupts
959     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
960     return CYG_ISR_CALL_DSR;            // Cause DSR to be run
961 }
962
963 // Serial I/O - high level rx interrupt handler (DSR)
964 static void       
965 sh_scif_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
966 {
967     serial_channel *chan = (serial_channel *)data;
968     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
969     cyg_uint8 _scr;
970     cyg_uint16 _fdr, _sr;
971     int _avail, _space_avail;
972     unsigned char* _space;
973     rcv_req_reply_t _block_status;
974
975     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCFDR, _fdr);
976     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
977
978     _avail = _fdr & CYGARC_REG_SCIF_SCFDR_RCOUNT_MASK;
979     if (_avail > 0) {
980         _block_status = (chan->callbacks->data_rcv_req)(chan, _avail, 
981                                                         &_space_avail, &_space);
982         if (CYG_RCV_OK == _block_status) {
983             // Transfer the data in block(s).
984             do {
985                 int i = _space_avail;
986                 while(i--) {
987                     cyg_uint8 _c;
988                     HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _c);
989                     *_space++ = _c;
990                     _avail--;
991                 }
992                 (chan->callbacks->data_rcv_done)(chan, _space_avail);
993             } while (_avail > 0 &&
994                      (CYG_RCV_OK == (chan->callbacks->data_rcv_req)(chan, _avail, 
995                                                                     &_space_avail,
996                                                                     &_space)));
997         } else {
998             // Transfer the data char-by-char both for CYG_RCV_FULL
999             // and CYG_RCV_DISABLED, leaving all policy decisions with
1000             // the IO driver.
1001             while(_avail--) {
1002                 cyg_uint8 _c;
1003                 HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SCFRDR, _c);
1004                 (chan->callbacks->rcv_char)(chan, _c);
1005             }
1006         }
1007     } else {
1008         CYG_ASSERT(_avail > 0, "No data to be read in RX DSR");
1009     }
1010
1011     // Clear buffer full flag (read back first)
1012     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _sr);
1013     HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, 
1014                      CYGARC_REG_SCIF_SCSSR_CLEARMASK & ~(CYGARC_REG_SCIF_SCSSR_RDF|CYGARC_REG_SCIF_SCSSR_DR));
1015
1016     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1017     _scr |= CYGARC_REG_SCIF_SCSCR_RIE;       // unmask rx interrupts
1018     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1019 }
1020
1021 // Serial I/O - low level error interrupt handler (ISR)
1022 static cyg_uint32 
1023 sh_scif_er_ISR(cyg_vector_t vector, cyg_addrword_t data)
1024 {
1025     serial_channel *chan = (serial_channel *)data;
1026     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
1027     cyg_uint8 _scr;
1028
1029     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1030     _scr &= ~CYGARC_REG_SCIF_SCSCR_RIE;      // mask rx interrupts
1031     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1032     return CYG_ISR_CALL_DSR;            // Cause DSR to be run
1033 }
1034
1035 // Serial I/O - high level error interrupt handler (DSR)
1036 static void       
1037 sh_scif_er_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
1038 {
1039     serial_channel *chan = (serial_channel *)data;
1040     sh_scif_info *sh_chan = (sh_scif_info *)chan->dev_priv;
1041     cyg_uint16 _ssr, _ssr_mask;
1042 #ifdef SCIF_SC2SSR
1043     cyg_uint8 _ssr2;
1044 #endif
1045     cyg_uint8 _scr;
1046 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
1047     cyg_serial_line_status_t stat;
1048 #endif
1049
1050     HAL_READ_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _ssr);
1051     _ssr_mask = CYGARC_REG_SCIF_SCSSR_CLEARMASK;
1052     // Clear the ER bit
1053     _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_ER;
1054
1055
1056 #ifdef SCIF_SC2SSR
1057     HAL_READ_UINT8(sh_chan->ctrl_base+SCIF_SC2SSR, _ssr2);
1058     if (_ssr2 & CYGARC_REG_SCIF_SC2SSR_ORER) {
1059         _ssr2 &= ~CYGARC_REG_SCIF_SC2SSR_ORER;
1060         HAL_WRITE_UINT8(sh_chan->ctrl_base+SCIF_SC2SSR, _ssr2);
1061         stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
1062         (chan->callbacks->indicate_status)(chan, &stat );
1063     }
1064 #endif
1065     if (_ssr & CYGARC_REG_SCIF_SCSSR_FER) {
1066         // _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_FER; // FER is read-only
1067 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
1068         stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
1069         (chan->callbacks->indicate_status)(chan, &stat );
1070 #endif
1071     }
1072     if (_ssr & CYGARC_REG_SCIF_SCSSR_PER) {
1073         // _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_PER; // PER is read-only
1074 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
1075         stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
1076         (chan->callbacks->indicate_status)(chan, &stat );
1077 #endif
1078     }
1079     if (_ssr & CYGARC_REG_SCIF_SCSSR_BRK) {
1080         _ssr_mask &= ~CYGARC_REG_SCIF_SCSSR_BRK;
1081 #ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
1082         stat.which = CYGNUM_SERIAL_STATUS_BREAK;
1083         (chan->callbacks->indicate_status)(chan, &stat );
1084 #endif
1085     }
1086     HAL_WRITE_UINT16(sh_chan->ctrl_base+SCIF_SCSSR, _ssr_mask);
1087
1088     HAL_READ(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1089     _scr |= CYGARC_REG_SCIF_SCSCR_RIE;       // unmask rx interrupts
1090     HAL_WRITE(sh_chan->ctrl_base+SCIF_SCSCR, _scr);
1091 }
1092
1093 #endif // ifdef CYGDAT_IO_SERIAL_SH_SCIF_INL