Mercurial > ecos
comparison packages/devs/serial/h8300/h8300h/current/src/h8300_sci_serial.c @ 208:e0c0827131d1 ecos
Merge from eCos master repository on 2002-05-20-20:11:54-BST
| author | jlarmour |
|---|---|
| date | Mon, 20 May 2002 22:19:26 +0000 |
| parents | |
| children | d2c90368aeef |
comparison
equal
deleted
inserted
replaced
| 207:74c807ddde34 | 208:e0c0827131d1 |
|---|---|
| 1 //========================================================================== | |
| 2 // | |
| 3 // h8300_sci_serial.c | |
| 4 // | |
| 5 // H8/300 Serial SCI I/O Interface Module (interrupt driven) | |
| 6 // | |
| 7 //========================================================================== | |
| 8 //####ECOSGPLCOPYRIGHTBEGIN#### | |
| 9 // ------------------------------------------- | |
| 10 // This file is part of eCos, the Embedded Configurable Operating System. | |
| 11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. | |
| 12 // | |
| 13 // eCos is free software; you can redistribute it and/or modify it under | |
| 14 // the terms of the GNU General Public License as published by the Free | |
| 15 // Software Foundation; either version 2 or (at your option) any later version. | |
| 16 // | |
| 17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY | |
| 18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 20 // for more details. | |
| 21 // | |
| 22 // You should have received a copy of the GNU General Public License along | |
| 23 // with eCos; if not, write to the Free Software Foundation, Inc., | |
| 24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | |
| 25 // | |
| 26 // As a special exception, if other files instantiate templates or use macros | |
| 27 // or inline functions from this file, or you compile this file and link it | |
| 28 // with other works to produce a work based on this file, this file does not | |
| 29 // by itself cause the resulting work to be covered by the GNU General Public | |
| 30 // License. However the source code for this file must still be made available | |
| 31 // in accordance with section (3) of the GNU General Public License. | |
| 32 // | |
| 33 // This exception does not invalidate any other reasons why a work based on | |
| 34 // this file might be covered by the GNU General Public License. | |
| 35 // | |
| 36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. | |
| 37 // at http://sources.redhat.com/ecos/ecos-license | |
| 38 // ------------------------------------------- | |
| 39 //####ECOSGPLCOPYRIGHTEND#### | |
| 40 //========================================================================== | |
| 41 //#####DESCRIPTIONBEGIN#### | |
| 42 // | |
| 43 // Author(s): jskov | |
| 44 // Contributors:gthomas, jskov | |
| 45 // Date: 1999-05-24 | |
| 46 // Purpose: H8/300 Serial I/O module (interrupt driven version) | |
| 47 // Description: | |
| 48 // | |
| 49 // Note: Since interrupt sources from the same SCI channel share the same | |
| 50 // interrupt level, there is no risk of races when altering the | |
| 51 // channel's control register from ISRs and DSRs. However, when | |
| 52 // altering the control register from user-level code, interrupts | |
| 53 // must be disabled while the register is being accessed. | |
| 54 // | |
| 55 // FIXME: Receiving in polled mode prevents duplex transfers from working for | |
| 56 // some reason. | |
| 57 //####DESCRIPTIONEND#### | |
| 58 //========================================================================== | |
| 59 | |
| 60 #include <pkgconf/io_serial.h> | |
| 61 #include <pkgconf/io.h> | |
| 62 | |
| 63 // FIXME: This is necessary since the SCIF driver may be overriding | |
| 64 // CYGDAT_IO_SERIAL_DEVICE_HEADER. Need a better way to include two | |
| 65 // different drivers. | |
| 66 #include <pkgconf/io_serial_h8300_sci.h> | |
| 67 | |
| 68 #include <cyg/io/io.h> | |
| 69 #include <cyg/hal/hal_intr.h> | |
| 70 #include <cyg/io/devtab.h> | |
| 71 #include <cyg/infra/diag.h> | |
| 72 #include <cyg/io/serial.h> | |
| 73 | |
| 74 #ifdef CYGDAT_IO_SERIAL_H8300_SCI | |
| 75 // The SCI controller register layout on the SH3/7708. | |
| 76 #define SCI_SCSMR 0 // serial mode register | |
| 77 #define SCI_SCBRR 1 // bit rate register | |
| 78 #define SCI_SCSCR 2 // serial control register | |
| 79 #define SCI_SCTDR 3 // transmit data register | |
| 80 #define SCI_SCSSR 4 // serial status register | |
| 81 #define SCI_SCRDR 5 // receive data register | |
| 82 #define SCI_SCSPTR -4 // serial port register | |
| 83 | |
| 84 static short select_word_length[] = { | |
| 85 -1, | |
| 86 -1, | |
| 87 CYGARC_REG_SCSMR_CHR, // 7 bits | |
| 88 0 // 8 bits | |
| 89 }; | |
| 90 | |
| 91 static short select_stop_bits[] = { | |
| 92 -1, | |
| 93 0, // 1 stop bit | |
| 94 -1, | |
| 95 CYGARC_REG_SCSMR_STOP // 2 stop bits | |
| 96 }; | |
| 97 | |
| 98 static short select_parity[] = { | |
| 99 0, // No parity | |
| 100 CYGARC_REG_SCSMR_PE, // Even parity | |
| 101 CYGARC_REG_SCSMR_PE|CYGARC_REG_SCSMR_OE, // Odd parity | |
| 102 -1, | |
| 103 -1 | |
| 104 }; | |
| 105 | |
| 106 static unsigned short select_baud[] = { | |
| 107 0, // Unused | |
| 108 CYGARC_SCBRR_CKSx(50)<<8 | CYGARC_SCBRR_N(50), | |
| 109 CYGARC_SCBRR_CKSx(75)<<8 | CYGARC_SCBRR_N(75), | |
| 110 CYGARC_SCBRR_CKSx(110)<<8 | CYGARC_SCBRR_N(110), | |
| 111 CYGARC_SCBRR_CKSx(134)<<8 | CYGARC_SCBRR_N(134), | |
| 112 CYGARC_SCBRR_CKSx(150)<<8 | CYGARC_SCBRR_N(150), | |
| 113 CYGARC_SCBRR_CKSx(200)<<8 | CYGARC_SCBRR_N(200), | |
| 114 CYGARC_SCBRR_CKSx(300)<<8 | CYGARC_SCBRR_N(300), | |
| 115 CYGARC_SCBRR_CKSx(600)<<8 | CYGARC_SCBRR_N(600), | |
| 116 CYGARC_SCBRR_CKSx(1200)<<8 | CYGARC_SCBRR_N(1200), | |
| 117 CYGARC_SCBRR_CKSx(1800)<<8 | CYGARC_SCBRR_N(1800), | |
| 118 CYGARC_SCBRR_CKSx(2400)<<8 | CYGARC_SCBRR_N(2400), | |
| 119 CYGARC_SCBRR_CKSx(3600)<<8 | CYGARC_SCBRR_N(3600), | |
| 120 CYGARC_SCBRR_CKSx(4800)<<8 | CYGARC_SCBRR_N(4800), | |
| 121 CYGARC_SCBRR_CKSx(7200)<<8 | CYGARC_SCBRR_N(7200), | |
| 122 CYGARC_SCBRR_CKSx(9600)<<8 | CYGARC_SCBRR_N(9600), | |
| 123 CYGARC_SCBRR_CKSx(14400)<<8 | CYGARC_SCBRR_N(14400), | |
| 124 CYGARC_SCBRR_CKSx(19200)<<8 | CYGARC_SCBRR_N(19200), | |
| 125 CYGARC_SCBRR_CKSx(38400)<<8 | CYGARC_SCBRR_N(38400), | |
| 126 CYGARC_SCBRR_CKSx(57600)<<8 | CYGARC_SCBRR_N(57600), | |
| 127 CYGARC_SCBRR_CKSx(115200)<<8 | CYGARC_SCBRR_N(115200), | |
| 128 CYGARC_SCBRR_CKSx(230400)<<8 | CYGARC_SCBRR_N(230400) | |
| 129 }; | |
| 130 | |
| 131 | |
| 132 typedef struct h8300_sci_info { | |
| 133 CYG_ADDRWORD data; // Pointer to data register | |
| 134 | |
| 135 CYG_WORD er_int_num, // Error interrupt number | |
| 136 rx_int_num, // Receive interrupt number | |
| 137 tx_int_num; // Transmit interrupt number | |
| 138 | |
| 139 CYG_ADDRWORD ctrl_base; // Base address of SCI controller | |
| 140 | |
| 141 cyg_interrupt serial_er_interrupt, | |
| 142 serial_rx_interrupt, | |
| 143 serial_tx_interrupt; | |
| 144 cyg_handle_t serial_er_interrupt_handle, | |
| 145 serial_rx_interrupt_handle, | |
| 146 serial_tx_interrupt_handle; | |
| 147 | |
| 148 bool tx_enabled; | |
| 149 } sh_sci_info; | |
| 150 | |
| 151 static bool h8300_serial_init(struct cyg_devtab_entry *tab); | |
| 152 static bool h8300_serial_putc(serial_channel *chan, unsigned char c); | |
| 153 static Cyg_ErrNo h8300_serial_lookup(struct cyg_devtab_entry **tab, | |
| 154 struct cyg_devtab_entry *sub_tab, | |
| 155 const char *name); | |
| 156 static unsigned char h8300_serial_getc(serial_channel *chan); | |
| 157 static Cyg_ErrNo h8300_serial_set_config(serial_channel *chan, cyg_uint32 key, | |
| 158 const void *xbuf, cyg_uint32 *len); | |
| 159 static void h8300_serial_start_xmit(serial_channel *chan); | |
| 160 static void h8300_serial_stop_xmit(serial_channel *chan); | |
| 161 | |
| 162 static cyg_uint32 h8300_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data); | |
| 163 static void h8300_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, | |
| 164 cyg_addrword_t data); | |
| 165 static cyg_uint32 h8300_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data); | |
| 166 static void h8300_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, | |
| 167 cyg_addrword_t data); | |
| 168 static cyg_uint32 h8300_serial_er_ISR(cyg_vector_t vector, cyg_addrword_t data); | |
| 169 static void h8300_serial_er_DSR(cyg_vector_t vector, cyg_ucount32 count, | |
| 170 cyg_addrword_t data); | |
| 171 | |
| 172 static SERIAL_FUNS(h8300_serial_funs, | |
| 173 h8300_serial_putc, | |
| 174 h8300_serial_getc, | |
| 175 h8300_serial_set_config, | |
| 176 h8300_serial_start_xmit, | |
| 177 h8300_serial_stop_xmit | |
| 178 ); | |
| 179 | |
| 180 | |
| 181 static h8300_sci_info h8300_serial_info = | |
| 182 { | |
| 183 NULL, | |
| 184 CYGNUM_HAL_INTERRUPT_ERI0, | |
| 185 CYGNUM_HAL_INTERRUPT_RXI0, | |
| 186 CYGNUM_HAL_INTERRUPT_TXI0, | |
| 187 CYGARC_REG_SMR0 | |
| 188 }; | |
| 189 | |
| 190 #if CYGNUM_IO_SERIAL_H8300_H8300H_SERIAL1_BUFSIZE > 0 | |
| 191 static unsigned char h8300_serial_out_buf[CYGNUM_IO_SERIAL_H8300_CQ7708_SERIAL1_BUFSIZE]; | |
| 192 static unsigned char h8300_serial_in_buf[CYGNUM_IO_SERIAL_H8300_CQ7708_SERIAL1_BUFSIZE]; | |
| 193 | |
| 194 static SERIAL_CHANNEL_USING_INTERRUPTS(h8300_serial_channel, | |
| 195 h8300_serial_funs, | |
| 196 h8300_serial_info, | |
| 197 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_H8300_H8300H_SERIAL1_BAUD), | |
| 198 CYG_SERIAL_STOP_DEFAULT, | |
| 199 CYG_SERIAL_PARITY_DEFAULT, | |
| 200 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 201 CYG_SERIAL_FLAGS_DEFAULT, | |
| 202 &h8300_serial_out_buf[0], | |
| 203 sizeof(h8300_serial_out_buf), | |
| 204 &h8300_serial_in_buf[0], | |
| 205 sizeof(h8300_serial_in_buf) | |
| 206 ); | |
| 207 #else | |
| 208 static SERIAL_CHANNEL(h8300_serial_channel, | |
| 209 h8300_serial_funs, | |
| 210 h8300_serial_info, | |
| 211 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_H8300_H8300H_SERIAL1_BAUD), | |
| 212 CYG_SERIAL_STOP_DEFAULT, | |
| 213 CYG_SERIAL_PARITY_DEFAULT, | |
| 214 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 215 CYG_SERIAL_FLAGS_DEFAULT | |
| 216 ); | |
| 217 #endif | |
| 218 | |
| 219 DEVTAB_ENTRY(h8300_serial_io, | |
| 220 CYGDAT_IO_SERIAL_H8300_H8300H_SERIAL1_NAME, | |
| 221 0, // Does not depend on a lower level interface | |
| 222 &cyg_io_serial_devio, | |
| 223 h8300_serial_init, | |
| 224 h8300_serial_lookup, // Serial driver may need initializing | |
| 225 &h8300_serial_channel | |
| 226 ); | |
| 227 | |
| 228 // Internal function to actually configure the hardware to desired baud rate, | |
| 229 // etc. | |
| 230 static bool | |
| 231 h8300_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, | |
| 232 bool init) | |
| 233 { | |
| 234 cyg_uint16 baud_divisor = select_baud[new_config->baud]; | |
| 235 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 236 cyg_uint8 _scr, _smr; | |
| 237 | |
| 238 // Check configuration request | |
| 239 if ((-1 == select_word_length[(new_config->word_length - | |
| 240 CYGNUM_SERIAL_WORD_LENGTH_5)]) | |
| 241 || -1 == select_stop_bits[new_config->stop] | |
| 242 || -1 == select_parity[new_config->parity] | |
| 243 || baud_divisor == 0) | |
| 244 return false; | |
| 245 | |
| 246 // Disable SCI interrupts while changing hardware | |
| 247 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 248 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, 0); | |
| 249 | |
| 250 // Set databits, stopbits and parity. | |
| 251 _smr = select_word_length[(new_config->word_length - | |
| 252 CYGNUM_SERIAL_WORD_LENGTH_5)] | | |
| 253 select_stop_bits[new_config->stop] | | |
| 254 select_parity[new_config->parity]; | |
| 255 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSMR, _smr); | |
| 256 | |
| 257 // Set baud rate. | |
| 258 _smr &= ~CYGARC_REG_SCSMR_CKSx_MASK; | |
| 259 _smr |= baud_divisor >> 8; | |
| 260 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSMR, _smr); | |
| 261 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCBRR, baud_divisor & 0xff); | |
| 262 | |
| 263 // Clear the status register. | |
| 264 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, 0); | |
| 265 | |
| 266 if (init) { | |
| 267 // Always enable transmitter and receiver. | |
| 268 _scr = CYGARC_REG_SCSCR_TE | CYGARC_REG_SCSCR_RE; | |
| 269 | |
| 270 if (chan->out_cbuf.len != 0) | |
| 271 _scr |= CYGARC_REG_SCSCR_TIE; // enable tx interrupts | |
| 272 | |
| 273 if (chan->in_cbuf.len != 0) | |
| 274 _scr |= CYGARC_REG_SCSCR_RIE; // enable rx interrupts | |
| 275 } | |
| 276 | |
| 277 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 278 | |
| 279 if (new_config != &chan->config) { | |
| 280 chan->config = *new_config; | |
| 281 } | |
| 282 return true; | |
| 283 } | |
| 284 | |
| 285 // Function to initialize the device. Called at bootstrap time. | |
| 286 static bool | |
| 287 h8300_serial_init(struct cyg_devtab_entry *tab) | |
| 288 { | |
| 289 serial_channel *chan = (serial_channel *)tab->priv; | |
| 290 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 291 #ifdef CYGDBG_IO_INIT | |
| 292 diag_printf("SH SERIAL init - dev: %x.%d\n", | |
| 293 h8300_chan->data, h8300_chan->rx_int_num); | |
| 294 #endif | |
| 295 // Really only required for interrupt driven devices | |
| 296 (chan->callbacks->serial_init)(chan); | |
| 297 | |
| 298 if (chan->out_cbuf.len != 0) { | |
| 299 cyg_drv_interrupt_create(h8300_chan->tx_int_num, | |
| 300 3, | |
| 301 (cyg_addrword_t)chan, // Data item passed to interrupt handler | |
| 302 h8300_serial_tx_ISR, | |
| 303 h8300_serial_tx_DSR, | |
| 304 &h8300_chan->serial_tx_interrupt_handle, | |
| 305 &h8300_chan->serial_tx_interrupt); | |
| 306 cyg_drv_interrupt_attach(h8300_chan->serial_tx_interrupt_handle); | |
| 307 cyg_drv_interrupt_unmask(h8300_chan->tx_int_num); | |
| 308 h8300_chan->tx_enabled = false; | |
| 309 } | |
| 310 if (chan->in_cbuf.len != 0) { | |
| 311 // Receive interrupt | |
| 312 cyg_drv_interrupt_create(h8300_chan->rx_int_num, | |
| 313 3, | |
| 314 (cyg_addrword_t)chan, // Data item passed to interrupt handler | |
| 315 h8300_serial_rx_ISR, | |
| 316 h8300_serial_rx_DSR, | |
| 317 &h8300_chan->serial_rx_interrupt_handle, | |
| 318 &h8300_chan->serial_rx_interrupt); | |
| 319 cyg_drv_interrupt_attach(h8300_chan->serial_rx_interrupt_handle); | |
| 320 // Receive error interrupt | |
| 321 cyg_drv_interrupt_create(h8300_chan->er_int_num, | |
| 322 3, | |
| 323 (cyg_addrword_t)chan, // Data item passed to interrupt handler | |
| 324 h8300_serial_er_ISR, | |
| 325 h8300_serial_er_DSR, | |
| 326 &h8300_chan->serial_er_interrupt_handle, | |
| 327 &h8300_chan->serial_er_interrupt); | |
| 328 cyg_drv_interrupt_attach(h8300_chan->serial_er_interrupt_handle); | |
| 329 // This unmasks both interrupt sources. | |
| 330 cyg_drv_interrupt_unmask(h8300_chan->rx_int_num); | |
| 331 } | |
| 332 h8300_serial_config_port(chan, &chan->config, true); | |
| 333 return true; | |
| 334 } | |
| 335 | |
| 336 // This routine is called when the device is "looked" up (i.e. attached) | |
| 337 static Cyg_ErrNo | |
| 338 h8300_serial_lookup(struct cyg_devtab_entry **tab, | |
| 339 struct cyg_devtab_entry *sub_tab, | |
| 340 const char *name) | |
| 341 { | |
| 342 serial_channel *chan = (serial_channel *)(*tab)->priv; | |
| 343 | |
| 344 // Really only required for interrupt driven devices | |
| 345 (chan->callbacks->serial_init)(chan); | |
| 346 return ENOERR; | |
| 347 } | |
| 348 | |
| 349 // Send a character to the device output buffer. | |
| 350 // Return 'true' if character is sent to device | |
| 351 static bool | |
| 352 h8300_serial_putc(serial_channel *chan, unsigned char c) | |
| 353 { | |
| 354 cyg_uint8 _ssr; | |
| 355 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 356 | |
| 357 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, _ssr); | |
| 358 if (_ssr & CYGARC_REG_SCSSR_TDRE) { | |
| 359 // Transmit buffer is empty | |
| 360 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCTDR, c); | |
| 361 // Clear empty flag. | |
| 362 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, | |
| 363 CYGARC_REG_SCSSR_CLEARMASK & ~CYGARC_REG_SCSSR_TDRE); | |
| 364 return true; | |
| 365 } else { | |
| 366 // No space | |
| 367 return false; | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 // Fetch a character from the device input buffer, waiting if necessary | |
| 372 static unsigned char | |
| 373 h8300_serial_getc(serial_channel *chan) | |
| 374 { | |
| 375 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 376 unsigned char c; | |
| 377 cyg_uint8 _ssr; | |
| 378 | |
| 379 do { | |
| 380 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, _ssr); | |
| 381 } while ((_ssr & CYGARC_REG_SCSSR_RDRF) == 0); | |
| 382 | |
| 383 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCRDR, c); | |
| 384 | |
| 385 // Clear buffer full flag. | |
| 386 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, | |
| 387 CYGARC_REG_SCSSR_CLEARMASK & ~CYGARC_REG_SCSSR_RDRF); | |
| 388 | |
| 389 return c; | |
| 390 } | |
| 391 | |
| 392 // Set up the device characteristics; baud rate, etc. | |
| 393 static Cyg_ErrNo | |
| 394 h8300_serial_set_config(serial_channel *chan, cyg_uint32 key, | |
| 395 const void *xbuf, cyg_uint32 *len) | |
| 396 { | |
| 397 switch (key) { | |
| 398 case CYG_IO_SET_CONFIG_SERIAL_INFO: | |
| 399 { | |
| 400 cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf; | |
| 401 if ( *len < sizeof(cyg_serial_info_t) ) { | |
| 402 return -EINVAL; | |
| 403 } | |
| 404 *len = sizeof(cyg_serial_info_t); | |
| 405 if ( true != h8300_serial_config_port(chan, config, false) ) | |
| 406 return -EINVAL; | |
| 407 } | |
| 408 break; | |
| 409 default: | |
| 410 return -EINVAL; | |
| 411 } | |
| 412 return ENOERR; | |
| 413 } | |
| 414 | |
| 415 // Enable the transmitter on the device | |
| 416 static void | |
| 417 h8300_serial_start_xmit(serial_channel *chan) | |
| 418 { | |
| 419 cyg_uint8 _scr; | |
| 420 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 421 | |
| 422 h8300_chan->tx_enabled = true; | |
| 423 | |
| 424 // Mask the interrupts (all sources of the unit) while changing | |
| 425 // the CR since a rx interrupt in the middle of this would result | |
| 426 // in a bad CR state. | |
| 427 cyg_drv_interrupt_mask(h8300_chan->rx_int_num); | |
| 428 | |
| 429 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 430 _scr |= CYGARC_REG_SCSCR_TIE; // Enable xmit interrupt | |
| 431 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 432 | |
| 433 cyg_drv_interrupt_unmask(h8300_chan->rx_int_num); | |
| 434 } | |
| 435 | |
| 436 // Disable the transmitter on the device | |
| 437 static void | |
| 438 h8300_serial_stop_xmit(serial_channel *chan) | |
| 439 { | |
| 440 cyg_uint8 _scr; | |
| 441 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 442 | |
| 443 h8300_chan->tx_enabled = false; | |
| 444 | |
| 445 // Mask the interrupts (all sources of the unit) while changing | |
| 446 // the CR since a rx interrupt in the middle of this would result | |
| 447 // in a bad CR state. | |
| 448 cyg_drv_interrupt_mask(h8300_chan->rx_int_num); | |
| 449 | |
| 450 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 451 _scr &= ~CYGARC_REG_SCSCR_TIE; // Disable xmit interrupt | |
| 452 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 453 | |
| 454 cyg_drv_interrupt_unmask(h8300_chan->rx_int_num); | |
| 455 } | |
| 456 | |
| 457 // Serial I/O - low level tx interrupt handler (ISR) | |
| 458 static cyg_uint32 | |
| 459 h8300_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data) | |
| 460 { | |
| 461 serial_channel *chan = (serial_channel *)data; | |
| 462 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 463 cyg_uint8 _scr; | |
| 464 | |
| 465 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 466 _scr &= ~CYGARC_REG_SCSCR_TIE; // mask out tx interrupts | |
| 467 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 468 | |
| 469 return CYG_ISR_CALL_DSR; // Cause DSR to be run | |
| 470 } | |
| 471 | |
| 472 // Serial I/O - high level tx interrupt handler (DSR) | |
| 473 static void | |
| 474 h8300_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) | |
| 475 { | |
| 476 serial_channel *chan = (serial_channel *)data; | |
| 477 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 478 | |
| 479 (chan->callbacks->xmt_char)(chan); | |
| 480 | |
| 481 if (h8300_chan->tx_enabled) { | |
| 482 cyg_uint8 _scr; | |
| 483 | |
| 484 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 485 _scr |= CYGARC_REG_SCSCR_TIE; // unmask tx interrupts | |
| 486 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 487 } | |
| 488 } | |
| 489 | |
| 490 // Serial I/O - low level RX interrupt handler (ISR) | |
| 491 static cyg_uint32 | |
| 492 h8300_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data) | |
| 493 { | |
| 494 serial_channel *chan = (serial_channel *)data; | |
| 495 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 496 cyg_uint8 _scr; | |
| 497 | |
| 498 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 499 _scr &= ~CYGARC_REG_SCSCR_RIE; // mask rx interrupts | |
| 500 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 501 return CYG_ISR_CALL_DSR; // Cause DSR to be run | |
| 502 } | |
| 503 | |
| 504 // Serial I/O - high level rx interrupt handler (DSR) | |
| 505 static void | |
| 506 h8300_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) | |
| 507 { | |
| 508 serial_channel *chan = (serial_channel *)data; | |
| 509 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 510 cyg_uint8 _ssr, _scr; | |
| 511 | |
| 512 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, _ssr); | |
| 513 if (_ssr & CYGARC_REG_SCSSR_RDRF) { | |
| 514 cyg_uint8 _c; | |
| 515 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCRDR, _c); | |
| 516 // Clear buffer full flag. | |
| 517 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, | |
| 518 CYGARC_REG_SCSSR_CLEARMASK & ~CYGARC_REG_SCSSR_RDRF); | |
| 519 | |
| 520 (chan->callbacks->rcv_char)(chan, _c); | |
| 521 } | |
| 522 | |
| 523 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 524 _scr |= CYGARC_REG_SCSCR_RIE; // unmask rx interrupts | |
| 525 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 526 } | |
| 527 | |
| 528 static volatile int h8300_serial_error_orer = 0; | |
| 529 static volatile int h8300_serial_error_fer = 0; | |
| 530 static volatile int h8300_serial_error_per = 0; | |
| 531 | |
| 532 // Serial I/O - low level error interrupt handler (ISR) | |
| 533 static cyg_uint32 | |
| 534 h8300_serial_er_ISR(cyg_vector_t vector, cyg_addrword_t data) | |
| 535 { | |
| 536 serial_channel *chan = (serial_channel *)data; | |
| 537 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 538 cyg_uint8 _scr; | |
| 539 | |
| 540 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 541 _scr &= ~CYGARC_REG_SCSCR_RIE; // mask rx interrupts | |
| 542 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 543 return CYG_ISR_CALL_DSR; // Cause DSR to be run | |
| 544 } | |
| 545 | |
| 546 // Serial I/O - high level error interrupt handler (DSR) | |
| 547 static void | |
| 548 h8300_serial_er_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) | |
| 549 { | |
| 550 serial_channel *chan = (serial_channel *)data; | |
| 551 h8300_sci_info *h8300_chan = (h8300_sci_info *)chan->dev_priv; | |
| 552 cyg_uint8 _ssr, _ssr2, _scr; | |
| 553 | |
| 554 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, _ssr); | |
| 555 _ssr2 = CYGARC_REG_SCSSR_CLEARMASK; | |
| 556 | |
| 557 if (_ssr & CYGARC_REG_SCSSR_ORER) { | |
| 558 _ssr2 &= ~CYGARC_REG_SCSSR_ORER; | |
| 559 h8300_serial_error_orer++; | |
| 560 } | |
| 561 if (_ssr & CYGARC_REG_SCSSR_FER) { | |
| 562 _ssr2 &= ~CYGARC_REG_SCSSR_FER; | |
| 563 h8300_serial_error_fer++; | |
| 564 } | |
| 565 if (_ssr & CYGARC_REG_SCSSR_PER) { | |
| 566 _ssr2 &= ~CYGARC_REG_SCSSR_PER; | |
| 567 h8300_serial_error_per++; | |
| 568 } | |
| 569 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSSR, _ssr2); | |
| 570 | |
| 571 HAL_READ_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 572 _scr |= CYGARC_REG_SCSCR_RIE; // unmask rx interrupts | |
| 573 HAL_WRITE_UINT8(h8300_chan->ctrl_base+SCI_SCSCR, _scr); | |
| 574 } | |
| 575 | |
| 576 #endif // ifdef CYGDAT_IO_SERIAL_H8300_SCI |
