Mercurial > ecos-v2_0-branch
annotate packages/io/serial/current/src/mips/tx3904_serial.c @ 66:bf00f99aec69 ecos-sw-2000-02-02
Merge from eCos master repository on 2000-02-02-19:16:44-GMT
| author | jlarmour |
|---|---|
| date | Wed, 02 Feb 2000 19:57:02 +0000 |
| parents | c38311975d4f |
| children |
| rev | line source |
|---|---|
| 2 | 1 //========================================================================== |
| 2 // | |
| 3 // tx3904_serial.c | |
| 4 // | |
| 5 // Serial device driver for TX3904 on-chip serial devices | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####COPYRIGHTBEGIN#### | |
|
64
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
9 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
10 // ------------------------------------------- |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
11 // The contents of this file are subject to the Red Hat eCos Public License |
|
66
bf00f99aec69
Merge from eCos master repository on 2000-02-02-19:16:44-GMT
jlarmour
parents:
64
diff
changeset
|
12 // Version 1.1 (the "License"); you may not use this file except in |
|
64
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
13 // compliance with the License. You may obtain a copy of the License at |
|
66
bf00f99aec69
Merge from eCos master repository on 2000-02-02-19:16:44-GMT
jlarmour
parents:
64
diff
changeset
|
14 // http://www.redhat.com/ |
|
64
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
15 // |
|
66
bf00f99aec69
Merge from eCos master repository on 2000-02-02-19:16:44-GMT
jlarmour
parents:
64
diff
changeset
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
64
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
18 // License for the specific language governing rights and limitations under |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
19 // the License. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
20 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
21 // The Original Code is eCos - Embedded Configurable Operating System, |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
22 // released September 30, 1998. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
23 // |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
24 // The Initial Developer of the Original Code is Red Hat. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
25 // Portions created by Red Hat are |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
26 // Copyright (C) 1998, 1999, 2000 Red Hat, Inc. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
27 // All Rights Reserved. |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
28 // ------------------------------------------- |
|
c38311975d4f
Merge from eCos master repository on 2000-01-28-04:28:11-GMT
jlarmour
parents:
62
diff
changeset
|
29 // |
| 2 | 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 | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
2
diff
changeset
|
330 &cyg_io_serial_devio, |
| 2 | 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 | |
|
62
7a6ac9edc838
Merge from eCos master repository on 2000-01-24-19:43:49-GMT
jlarmour
parents:
2
diff
changeset
|
341 &cyg_io_serial_devio, |
| 2 | 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 |
