comparison packages/devs/serial/mips/jmr3904/current/src/tx3904_serial.c @ 82:6736c52df507 ecos-sw-2000-04-14

Merge from eCos master repository on 2000-04-14-13:35:46-BST
author jlarmour
date Tue, 18 Apr 2000 21:51:55 +0000
parents
children 6ed91473a1cd
comparison
equal deleted inserted replaced
81:89fef2181d7d 82:6736c52df507
1 //==========================================================================
2 //
3 // tx3904_serial.c
4 //
5 // Serial device driver for TX3904 on-chip serial devices
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Red Hat eCos Public License
12 // Version 1.1 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://www.redhat.com/
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Configurable Operating System,
22 // released September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Red Hat.
25 // Portions created by Red Hat are
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
27 // All Rights Reserved.
28 // -------------------------------------------
29 //
30 //####COPYRIGHTEND####
31 //==========================================================================
32 //#####DESCRIPTIONBEGIN####
33 //
34 // Author(s): nickg
35 // Contributors: nickg
36 // Date: 1999-03-3
37 // Purpose: TX3904 serial device driver
38 // Description: TX3904 serial device driver
39 //
40 //####DESCRIPTIONEND####
41 //
42 //==========================================================================
43
44 #include <pkgconf/hal.h>
45 #include <pkgconf/io_serial.h>
46 #include <cyg/hal/hal_io.h>
47 #include <cyg/hal/hal_intr.h>
48
49 #include <cyg/io/io.h>
50 #include <cyg/io/devtab.h>
51 #include <cyg/io/serial.h>
52
53 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904
54
55 cyg_bool cyg_hal_is_break(char *buf, int size);
56 void cyg_hal_user_break( CYG_ADDRWORD *regs );
57
58 //-------------------------------------------------------------------------
59
60 extern void diag_printf(const char *fmt, ...);
61
62 //-------------------------------------------------------------------------
63 // Forward definitions
64
65 static bool tx3904_serial_init(struct cyg_devtab_entry *tab);
66 static bool tx3904_serial_putc(serial_channel *chan, unsigned char c);
67 static Cyg_ErrNo tx3904_serial_lookup(struct cyg_devtab_entry **tab,
68 struct cyg_devtab_entry *sub_tab,
69 const char *name);
70 static unsigned char tx3904_serial_getc(serial_channel *chan);
71 static bool tx3904_serial_set_config(serial_channel *chan, cyg_serial_info_t *config);
72 static void tx3904_serial_start_xmit(serial_channel *chan);
73 static void tx3904_serial_stop_xmit(serial_channel *chan);
74
75 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
76 static cyg_uint32 tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs);
77 static void tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
78 #endif
79
80
81 //-------------------------------------------------------------------------
82 // TX3904 serial line control register values:
83
84 // Offsets to serial control registers from base
85 #define SERIAL_CR 0x00
86 #define SERIAL_SR 0x04
87 #define SERIAL_ICR 0x08
88 #define SERIAL_ISR 0x0C
89 #define SERIAL_FCR 0x10
90 #define SERIAL_BRG 0x14
91 #define SERIAL_TXB 0x20
92 #define SERIAL_RXB 0x30
93
94 // Status register bits
95 #define ISR_RXRDY 0x01
96 #define ISR_TXRDY 0x02
97 #define ISR_ERROR 0x04
98
99 // Control register bits
100 #define LCR_SB1 0x0000
101 #define LCR_SB1_5 0x0000
102 #define LCR_SB2 0x0004
103 #define LCR_PN 0x0000 // Parity mode - none
104 #define LCR_PS 0x0000 // Forced "space" parity
105 #define LCR_PM 0x0000 // Forced "mark" parity
106 #define LCR_PE 0x0018 // Parity mode - even
107 #define LCR_PO 0x0010 // Parity mode - odd
108 #define LCR_WL5 0x0001 // not supported - use 7bit
109 #define LCR_WL6 0x0001 // not supported - use 7bit
110 #define LCR_WL7 0x0001 // 7 bit chars
111 #define LCR_WL8 0x0000 // 8 bit chars
112
113 #define LCR_BRG 0x0020 // Select baud rate generator
114
115 #define ICR_RXE 0x0001 // receive enable
116 #define ICR_TXE 0x0002 // transmit enable
117
118 //-------------------------------------------------------------------------
119 // Tables to map input values to hardware settings
120
121 static unsigned char select_word_length[] = {
122 LCR_WL5, // 5 bits / word (char)
123 LCR_WL6,
124 LCR_WL7,
125 LCR_WL8
126 };
127
128 static unsigned char select_stop_bits[] = {
129 0,
130 LCR_SB1, // 1 stop bit
131 LCR_SB1_5, // 1.5 stop bit
132 LCR_SB2 // 2 stop bits
133 };
134
135 static unsigned char select_parity[] = {
136 LCR_PN, // No parity
137 LCR_PE, // Even parity
138 LCR_PO, // Odd parity
139 LCR_PM, // Mark parity
140 LCR_PS, // Space parity
141 };
142
143 // The values in this table plug straight into the BRG register
144 // in the serial driver hardware. They comprise a baud rate divisor
145 // in the bottom 8 bits and a clock selector in the top 8 bits.
146 // These figures all come from Toshiba.
147
148 #if (CYGHWR_HAL_MIPS_CPU_FREQ == 50)
149
150 static unsigned short select_baud[] = {
151 0, // Unused
152 0, // 50
153 0, // 75
154 0, // 110
155 0, // 134.5
156 0, // 150
157 0, // 200
158 0, // 300
159 0x0300|20, // 600
160 0x0300|10, // 1200
161 0, // 1800
162 0x0300|05, // 2400
163 0, // 3600
164 0x0300|10, // 4800
165 0, // 7200
166 0x0200|05, // 9600
167 0, // 14400
168 0x0100|10, // 19200
169 0x0100|05, // 38400
170 0, // 57600
171 0, // 115200
172 0, // 230400
173 };
174
175 #elif (CYGHWR_HAL_MIPS_CPU_FREQ == 66)
176
177 static unsigned short select_baud[] = {
178 0, // Unused
179 0, // 50
180 0, // 75
181 0, // 110
182 0, // 134.5
183 0, // 150
184 0, // 200
185 0, // 300
186 0x0300|27, // 600
187 0x0200|54, // 1200
188 0, // 1800
189 0x0200|27, // 2400
190 0, // 3600
191 0x0100|54, // 4800
192 0, // 7200
193 0x0100|27, // 9600
194 0, // 14400
195 0x0000|54, // 19200
196 0x0000|27, // 38400
197 0, // 57600
198 0, // 115200
199 0, // 230400
200 };
201
202 #else
203
204 #error Unsupported CPU frequency
205
206 #endif
207
208 //-------------------------------------------------------------------------
209 // Info for each serial device controlled
210
211 typedef struct tx3904_serial_info {
212 CYG_ADDRWORD base;
213 CYG_WORD int_num;
214 cyg_interrupt interrupt;
215 cyg_handle_t interrupt_handle;
216 cyg_uint8 input_char;
217 cyg_bool input_char_valid;
218 cyg_bool output_ready;
219 cyg_uint16 cur_baud;
220 } tx3904_serial_info;
221
222 //-------------------------------------------------------------------------
223 // Callback functions exported by this driver
224
225 static SERIAL_FUNS(tx3904_serial_funs,
226 tx3904_serial_putc,
227 tx3904_serial_getc,
228 tx3904_serial_set_config,
229 tx3904_serial_start_xmit,
230 tx3904_serial_stop_xmit
231 );
232
233 //-------------------------------------------------------------------------
234 // Hardware info for each serial line
235
236 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
237 static tx3904_serial_info tx3904_serial_info0 = {
238 0xFFFFF300,
239 CYGNUM_HAL_INTERRUPT_SIO_0
240 };
241 #if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
242 static unsigned char tx3904_serial_out_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
243 static unsigned char tx3904_serial_in_buf0[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE];
244 #endif
245 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
246
247 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
248 static tx3904_serial_info tx3904_serial_info1 = {
249 0xFFFFF400,
250 CYGNUM_HAL_INTERRUPT_SIO_1
251 };
252 #if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
253 static unsigned char tx3904_serial_out_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
254 static unsigned char tx3904_serial_in_buf1[CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE];
255 #endif
256 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
257
258 //-------------------------------------------------------------------------
259 // Channel descriptions:
260
261 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
262 #define SIZEOF_BUF(_x_) 0
263 #else
264 #define SIZEOF_BUF(_x_) sizeof(_x_)
265 #endif
266
267 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
268 #if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BUFSIZE > 0
269 static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel0,
270 tx3904_serial_funs,
271 tx3904_serial_info0,
272 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
273 CYG_SERIAL_STOP_DEFAULT,
274 CYG_SERIAL_PARITY_DEFAULT,
275 CYG_SERIAL_WORD_LENGTH_DEFAULT,
276 CYG_SERIAL_FLAGS_DEFAULT,
277 &tx3904_serial_out_buf0[0],
278 SIZEOF_BUF(tx3904_serial_out_buf0),
279 &tx3904_serial_in_buf0[0],
280 SIZEOF_BUF(tx3904_serial_in_buf0)
281 );
282 #else
283 static SERIAL_CHANNEL(tx3904_serial_channel0,
284 tx3904_serial_funs,
285 tx3904_serial_info0,
286 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL0_BAUD),
287 CYG_SERIAL_STOP_DEFAULT,
288 CYG_SERIAL_PARITY_DEFAULT,
289 CYG_SERIAL_WORD_LENGTH_DEFAULT,
290 CYG_SERIAL_FLAGS_DEFAULT
291 );
292 #endif
293 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
294
295 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
296 #if CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BUFSIZE > 0
297 static SERIAL_CHANNEL_USING_INTERRUPTS(tx3904_serial_channel1,
298 tx3904_serial_funs,
299 tx3904_serial_info1,
300 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
301 CYG_SERIAL_STOP_DEFAULT,
302 CYG_SERIAL_PARITY_DEFAULT,
303 CYG_SERIAL_WORD_LENGTH_DEFAULT,
304 CYG_SERIAL_FLAGS_DEFAULT,
305 &tx3904_serial_out_buf1[0],
306 SIZEOF_BUF(tx3904_serial_out_buf1),
307 &tx3904_serial_in_buf1[0],
308 SIZEOF_BUF(tx3904_serial_in_buf1)
309 );
310 #else
311 static SERIAL_CHANNEL(tx3904_serial_channel1,
312 tx3904_serial_funs,
313 tx3904_serial_info1,
314 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_TX39_JMR3904_SERIAL1_BAUD),
315 CYG_SERIAL_STOP_DEFAULT,
316 CYG_SERIAL_PARITY_DEFAULT,
317 CYG_SERIAL_WORD_LENGTH_DEFAULT,
318 CYG_SERIAL_FLAGS_DEFAULT
319 );
320 #endif
321 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
322
323 //-------------------------------------------------------------------------
324 // And finally, the device table entries:
325
326 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
327 DEVTAB_ENTRY(tx3904_serial_io0,
328 CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL0_NAME,
329 0, // Does not depend on a lower level interface
330 &cyg_io_serial_devio,
331 tx3904_serial_init,
332 tx3904_serial_lookup, // Serial driver may need initializing
333 &tx3904_serial_channel0
334 );
335 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
336
337 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
338 DEVTAB_ENTRY(tx3904_serial_io1,
339 CYGDAT_IO_SERIAL_TX39_JMR3904_SERIAL1_NAME,
340 0, // Does not depend on a lower level interface
341 &cyg_io_serial_devio,
342 tx3904_serial_init,
343 tx3904_serial_lookup, // Serial driver may need initializing
344 &tx3904_serial_channel1
345 );
346 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL1
347
348 // ------------------------------------------------------------------------
349 // Delay for some number of character times. This is based on the baud
350 // rate currently set. We use the numbers that plug in to the BRG
351 // clock select and divider to control two loops. The innermost delay
352 // loop uses a count that is derived from dividing the CPU frequency
353 // by the BRG granularity (and we then add 1 to compensate for any
354 // rounding). This gives the number of cycles that the innermost loop
355 // must consume. For the sake of simplicity we assume that this loop
356 // will take 1 cycle per loop, which is roughly true in optimized
357 // code.
358
359 void delay_char_time(tx3904_serial_info *tx3904_chan, int n)
360 {
361 static cyg_uint16 clock_val[4] = { 4, 16, 64, 256 };
362 cyg_uint16 baud_val = select_baud[tx3904_chan->cur_baud];
363 cyg_count32 clock_loop = clock_val[baud_val>>8];
364 cyg_count32 div_loop = baud_val & 0xFF;
365 cyg_count32 bit_time = ((CYGHWR_HAL_MIPS_CPU_FREQ_ACTUAL)/(2457600)) + 1;
366
367 n *= 11; // allow for start and stop bits and 8 data bits
368
369 while( n-- )
370 {
371 cyg_count32 i,j,k;
372
373 for( i = 0; i < clock_loop; i++ )
374 for( j = 0; j < div_loop; j++ )
375 for( k = 0; k < bit_time; k++ )
376 continue;
377 }
378 }
379
380 //-------------------------------------------------------------------------
381
382 static bool
383 tx3904_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
384 {
385 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
386 cyg_uint16 cr = 0;
387 cyg_uint16 icr = 0;
388 cyg_uint16 baud_divisor = select_baud[new_config->baud];
389
390 if (baud_divisor == 0)
391 return false; // Invalid baud rate selected
392
393 // set up other config values:
394
395 cr |= select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
396 cr |= select_stop_bits[new_config->stop];
397 cr |= select_parity[new_config->parity];
398
399 // Source transfer clock from BRG
400 cr |= LCR_BRG;
401
402 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
403 // Enable RX interrupts only at present
404 #ifdef CYGPKG_IO_SERIAL_TX39_JMR3904_SERIAL0
405 if ((chan->out_cbuf.len != 0) || (chan == &tx3904_serial_channel0)) {
406 #else
407 if (chan->out_cbuf.len != 0) {
408 #endif
409 icr |= ICR_RXE;
410 }
411 #endif
412
413 // Avoid any interrupts while we are fiddling with the line parameters.
414 cyg_drv_interrupt_mask(tx3904_chan->int_num);
415
416
417 // In theory we should wait here for the transmitter to drain the
418 // FIFO so we dont change the line parameters with characters
419 // unsent. Unfortunately the TX39 serial devices do not allow us
420 // to discover when the FIFO is empty.
421
422 delay_char_time(tx3904_chan, 8);
423
424 // Disable device entirely.
425 // HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, 0);
426 // HAL_WRITE_UINT8(tx3904_chan->base+SERIAL_ICR, 0);
427
428 // Reset the FIFOs
429
430 HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 7);
431 HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_FCR, 0);
432
433 // Set up baud rate
434
435 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_BRG, baud_divisor );
436
437 // Write CR into hardware
438 HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_CR, cr);
439
440 // Write ICR into hardware
441 HAL_WRITE_UINT16(tx3904_chan->base+SERIAL_ICR, icr);
442
443 // Re-enable interrupts.
444 cyg_drv_interrupt_unmask(tx3904_chan->int_num);
445
446 // Save current baud rate
447 tx3904_chan->cur_baud = new_config->baud;
448
449 if (new_config != &chan->config) {
450 chan->config = *new_config;
451 }
452 return true;
453 }
454
455 //-------------------------------------------------------------------------
456 // Function to initialize the device. Called at bootstrap time.
457
458 bool tx3904_serial_init(struct cyg_devtab_entry *tab)
459 {
460 serial_channel *chan = (serial_channel *)tab->priv;
461 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
462
463 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
464
465 tx3904_chan->cur_baud = CYGNUM_SERIAL_BAUD_38400;
466
467 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
468 if (chan->out_cbuf.len != 0) {
469 // Install and enable the interrupt
470 cyg_drv_interrupt_create(tx3904_chan->int_num,
471 4, // Priority
472 (cyg_addrword_t)chan, // Data item passed to interrupt handler
473 (cyg_ISR_t *)tx3904_serial_ISR,
474 tx3904_serial_DSR,
475 &tx3904_chan->interrupt_handle,
476 &tx3904_chan->interrupt);
477 cyg_drv_interrupt_attach(tx3904_chan->interrupt_handle);
478 cyg_drv_interrupt_unmask(tx3904_chan->int_num);
479 }
480 #endif
481
482 tx3904_serial_config_port(chan, &chan->config, true);
483
484 return true;
485 }
486
487 //-------------------------------------------------------------------------
488 // This routine is called when the device is "looked" up (i.e. attached)
489
490 static Cyg_ErrNo
491 tx3904_serial_lookup(struct cyg_devtab_entry **tab,
492 struct cyg_devtab_entry *sub_tab,
493 const char *name)
494 {
495 serial_channel *chan = (serial_channel *)(*tab)->priv;
496 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
497 return ENOERR;
498 }
499
500 //-------------------------------------------------------------------------
501 // Return 'true' if character is sent to device
502
503 bool
504 tx3904_serial_putc(serial_channel *chan, unsigned char c)
505 {
506 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
507 cyg_uint16 isr;
508
509 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
510
511 if( isr & ISR_TXRDY )
512 {
513 HAL_WRITE_UINT8( tx3904_chan->base+SERIAL_TXB, c );
514
515 isr &= ~ISR_TXRDY;
516
517 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
518
519 return true;
520 }
521 else return false;
522 }
523
524 //-------------------------------------------------------------------------
525
526 unsigned char
527 tx3904_serial_getc(serial_channel *chan)
528 {
529 unsigned char c;
530 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
531 cyg_uint16 isr;
532
533 do
534 {
535 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
536
537 // Eliminate any RX errors
538 if( isr & ISR_ERROR )
539 {
540 cyg_uint16 sr = 0;
541
542 isr &= ISR_ERROR;
543
544 // HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
545
546 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, sr );
547 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
548 }
549
550 } while( (isr & ISR_RXRDY) != ISR_RXRDY );
551
552 HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, c );
553
554 isr &= ~ISR_RXRDY;
555
556 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
557
558 return c;
559 }
560
561 //-------------------------------------------------------------------------
562
563 bool
564 tx3904_serial_set_config(serial_channel *chan, cyg_serial_info_t *config)
565 {
566 return tx3904_serial_config_port(chan, config, false);
567 }
568
569 //-------------------------------------------------------------------------
570 // Enable the transmitter on the device
571
572 static void
573 tx3904_serial_start_xmit(serial_channel *chan)
574 {
575 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
576 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
577 cyg_uint16 icr;
578
579 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
580
581 icr |= ICR_TXE;
582
583 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
584 #endif
585 }
586
587 //-------------------------------------------------------------------------
588 // Disable the transmitter on the device
589
590 static void
591 tx3904_serial_stop_xmit(serial_channel *chan)
592 {
593 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
594 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
595 cyg_uint16 icr;
596
597 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
598
599 icr &= ~ICR_TXE;
600
601 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ICR, icr );
602 #endif
603 }
604
605 //-------------------------------------------------------------------------
606 // Serial I/O - low level interrupt handlers (ISR)
607
608 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
609
610 static cyg_uint32
611 tx3904_serial_ISR(cyg_vector_t vector, cyg_addrword_t data, cyg_addrword_t *regs)
612 {
613 serial_channel *chan = (serial_channel *)data;
614 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
615 cyg_uint8 isr;
616 cyg_uint32 result = 0;
617
618 cyg_drv_interrupt_mask(tx3904_chan->int_num);
619 cyg_drv_interrupt_acknowledge(tx3904_chan->int_num);
620
621 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
622
623 // Eliminate any RX errors
624 if( isr & ISR_ERROR )
625 {
626 cyg_uint16 sr = 0;
627
628 isr &= ~ISR_ERROR;
629
630 HAL_READ_UINT16( tx3904_chan->base+SERIAL_SR, sr );
631
632 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_SR, 0 );
633 }
634
635 // Check for a TX interrupt and set the flag if so.
636 if( isr & ISR_TXRDY )
637 {
638 isr &= ~ISR_TXRDY;
639
640 tx3904_chan->output_ready = true;
641
642 result |= CYG_ISR_CALL_DSR; // Cause DSR to be run
643 }
644
645
646 // Check here for an RX interrupt and fetch the character. If it
647 // is a ^C then call into GDB stub to handle it.
648
649 if( isr & ISR_RXRDY )
650 {
651 cyg_uint8 rxb;
652 HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
653
654 isr &= ~ISR_RXRDY;
655
656 if( cyg_hal_is_break( &rxb , 1 ) )
657 cyg_hal_user_break( regs );
658 else
659 {
660 tx3904_chan->input_char = rxb;
661 tx3904_chan->input_char_valid = true;
662 result |= CYG_ISR_CALL_DSR; // Cause DSR to be run
663 }
664
665 }
666
667 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
668
669 return result;
670 }
671
672
673 #endif
674
675 //-------------------------------------------------------------------------
676 // Serial I/O - high level interrupt handler (DSR)
677
678 #ifndef CYGPKG_IO_SERIAL_TX39_JMR3904_POLLED_MODE
679
680 static void
681 tx3904_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
682 {
683 serial_channel *chan = (serial_channel *)data;
684 tx3904_serial_info *tx3904_chan = (tx3904_serial_info *)chan->dev_priv;
685 cyg_uint8 isr;
686
687 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
688
689 if( tx3904_chan->input_char_valid )
690 {
691 (chan->callbacks->rcv_char)(chan, tx3904_chan->input_char);
692
693 tx3904_chan->input_char_valid = false;
694
695 #if 0
696 // And while we are here, pull any further characters out of the
697 // FIFO. This should help to reduce the interrupt rate.
698
699 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
700
701 while( isr & ISR_RXRDY )
702 {
703 cyg_uint8 rxb;
704 HAL_READ_UINT8( tx3904_chan->base+SERIAL_RXB, rxb );
705
706 (chan->callbacks->rcv_char)(chan, rxb);
707
708 isr &= ~ISR_RXRDY;
709
710 HAL_WRITE_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
711 HAL_READ_UINT16( tx3904_chan->base+SERIAL_ISR, isr );
712 }
713 #endif
714
715 }
716
717 if( tx3904_chan->output_ready )
718 {
719 (chan->callbacks->xmt_char)(chan);
720
721 tx3904_chan->output_ready = false;
722 }
723
724 cyg_drv_interrupt_unmask(tx3904_chan->int_num);
725 }
726
727 #endif
728 #endif // CYGPKG_IO_SERIAL_TX39_JMR3904
729
730 //-------------------------------------------------------------------------
731 // EOF tx3904_serial.c