Mercurial > ecos
annotate packages/io/serial/current/src/arm/pid_serial_with_ints.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 // io/serial/arm/pid_serial_with_ints.c | |
| 4 // | |
| 5 // ARM PID Serial I/O Interface Module (interrupt driven) | |
| 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 // | |
|
18
7253dcc42a09
Merge from eCos master repository on 1999-06-25-15:31:50-BST
jlarmour
parents:
6
diff
changeset
|
34 // Author(s): gthomas |
|
7253dcc42a09
Merge from eCos master repository on 1999-06-25-15:31:50-BST
jlarmour
parents:
6
diff
changeset
|
35 // Contributors: gthomas |
|
7253dcc42a09
Merge from eCos master repository on 1999-06-25-15:31:50-BST
jlarmour
parents:
6
diff
changeset
|
36 // Date: 1999-02-04 |
|
7253dcc42a09
Merge from eCos master repository on 1999-06-25-15:31:50-BST
jlarmour
parents:
6
diff
changeset
|
37 // Purpose: PID Serial I/O module (interrupt driven version) |
| 2 | 38 // Description: |
| 39 // | |
| 40 //####DESCRIPTIONEND#### | |
| 41 // | |
| 42 //========================================================================== | |
| 43 | |
| 44 #include <pkgconf/system.h> | |
| 45 #include <pkgconf/io_serial.h> | |
| 46 #include <pkgconf/io.h> | |
| 47 #include <cyg/io/io.h> | |
| 48 #include <cyg/hal/hal_intr.h> | |
| 49 #include <cyg/io/devtab.h> | |
| 50 #include <cyg/io/serial.h> | |
|
18
7253dcc42a09
Merge from eCos master repository on 1999-06-25-15:31:50-BST
jlarmour
parents:
6
diff
changeset
|
51 #include <cyg/infra/diag.h> |
| 2 | 52 |
| 53 #ifdef CYGPKG_IO_SERIAL_ARM_PID | |
| 54 #include "pid_serial.h" | |
| 55 | |
| 56 typedef struct pid_serial_info { | |
| 57 CYG_ADDRWORD base; | |
| 58 CYG_WORD int_num; | |
| 59 cyg_interrupt serial_interrupt; | |
| 60 cyg_handle_t serial_interrupt_handle; | |
| 61 } pid_serial_info; | |
| 62 | |
| 63 static bool pid_serial_init(struct cyg_devtab_entry *tab); | |
| 64 static bool pid_serial_putc(serial_channel *chan, unsigned char c); | |
| 65 static Cyg_ErrNo pid_serial_lookup(struct cyg_devtab_entry **tab, | |
| 66 struct cyg_devtab_entry *sub_tab, | |
| 67 const char *name); | |
| 68 static unsigned char pid_serial_getc(serial_channel *chan); | |
| 69 static bool pid_serial_set_config(serial_channel *chan, cyg_serial_info_t *config); | |
| 70 static void pid_serial_start_xmit(serial_channel *chan); | |
| 71 static void pid_serial_stop_xmit(serial_channel *chan); | |
| 72 | |
| 73 static cyg_uint32 pid_serial_ISR(cyg_vector_t vector, cyg_addrword_t data); | |
| 74 static void pid_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); | |
| 75 | |
| 76 static SERIAL_FUNS(pid_serial_funs, | |
| 77 pid_serial_putc, | |
| 78 pid_serial_getc, | |
| 79 pid_serial_set_config, | |
| 80 pid_serial_start_xmit, | |
| 81 pid_serial_stop_xmit | |
| 82 ); | |
| 83 | |
| 84 #ifdef CYGPKG_IO_SERIAL_ARM_PID_SERIAL0 | |
| 85 static pid_serial_info pid_serial_info0 = {0x0D800000, CYGNUM_HAL_INTERRUPT_SERIALA}; | |
| 86 #if CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BUFSIZE > 0 | |
| 87 static unsigned char pid_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BUFSIZE]; | |
| 88 static unsigned char pid_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BUFSIZE]; | |
| 89 | |
| 90 static SERIAL_CHANNEL_USING_INTERRUPTS(pid_serial_channel0, | |
| 91 pid_serial_funs, | |
| 92 pid_serial_info0, | |
| 93 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BAUD), | |
| 94 CYG_SERIAL_STOP_DEFAULT, | |
| 95 CYG_SERIAL_PARITY_DEFAULT, | |
| 96 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 97 CYG_SERIAL_FLAGS_DEFAULT, | |
| 98 &pid_serial_out_buf0[0], sizeof(pid_serial_out_buf0), | |
| 99 &pid_serial_in_buf0[0], sizeof(pid_serial_in_buf0) | |
| 100 ); | |
| 101 #else | |
| 102 static SERIAL_CHANNEL(pid_serial_channel0, | |
| 103 pid_serial_funs, | |
| 104 pid_serial_info0, | |
| 105 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_PID_SERIAL0_BAUD), | |
| 106 CYG_SERIAL_STOP_DEFAULT, | |
| 107 CYG_SERIAL_PARITY_DEFAULT, | |
| 108 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 109 CYG_SERIAL_FLAGS_DEFAULT | |
| 110 ); | |
| 111 #endif | |
| 112 | |
| 113 DEVTAB_ENTRY(pid_serial_io0, | |
| 114 CYGDAT_IO_SERIAL_ARM_PID_SERIAL0_NAME, | |
| 115 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:
58
diff
changeset
|
116 &cyg_io_serial_devio, |
| 2 | 117 pid_serial_init, |
| 118 pid_serial_lookup, // Serial driver may need initializing | |
| 119 &pid_serial_channel0 | |
| 120 ); | |
| 121 #endif // CYGPKG_IO_SERIAL_ARM_PID_SERIAL0 | |
| 122 | |
| 123 #ifdef CYGPKG_IO_SERIAL_ARM_PID_SERIAL1 | |
| 124 static pid_serial_info pid_serial_info1 = {0x0D800020, CYGNUM_HAL_INTERRUPT_SERIALB}; | |
| 125 #if CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BUFSIZE > 0 | |
| 126 static unsigned char pid_serial_out_buf1[CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BUFSIZE]; | |
| 127 static unsigned char pid_serial_in_buf1[CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BUFSIZE]; | |
| 128 | |
| 129 static SERIAL_CHANNEL_USING_INTERRUPTS(pid_serial_channel1, | |
| 130 pid_serial_funs, | |
| 131 pid_serial_info1, | |
| 132 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BAUD), | |
| 133 CYG_SERIAL_STOP_DEFAULT, | |
| 134 CYG_SERIAL_PARITY_DEFAULT, | |
| 135 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 136 CYG_SERIAL_FLAGS_DEFAULT, | |
| 137 &pid_serial_out_buf1[0], sizeof(pid_serial_out_buf1), | |
| 138 &pid_serial_in_buf1[0], sizeof(pid_serial_in_buf1) | |
| 139 ); | |
| 140 #else | |
| 141 static SERIAL_CHANNEL(pid_serial_channel1, | |
| 142 pid_serial_funs, | |
| 143 pid_serial_info1, | |
| 144 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_PID_SERIAL1_BAUD), | |
| 145 CYG_SERIAL_STOP_DEFAULT, | |
| 146 CYG_SERIAL_PARITY_DEFAULT, | |
| 147 CYG_SERIAL_WORD_LENGTH_DEFAULT, | |
| 148 CYG_SERIAL_FLAGS_DEFAULT | |
| 149 ); | |
| 150 #endif | |
| 151 | |
| 152 DEVTAB_ENTRY(pid_serial_io1, | |
| 153 CYGDAT_IO_SERIAL_ARM_PID_SERIAL1_NAME, | |
| 154 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:
58
diff
changeset
|
155 &cyg_io_serial_devio, |
| 2 | 156 pid_serial_init, |
| 157 pid_serial_lookup, // Serial driver may need initializing | |
| 158 &pid_serial_channel1 | |
| 159 ); | |
| 160 #endif // CYGPKG_IO_SERIAL_ARM_PID_SERIAL1 | |
| 161 | |
| 162 // Internal function to actually configure the hardware to desired baud rate, etc. | |
| 163 static bool | |
| 164 pid_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init) | |
| 165 { | |
| 166 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 167 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 168 unsigned short baud_divisor = select_baud[new_config->baud]; | |
| 169 unsigned char _lcr, _ier; | |
| 170 if (baud_divisor == 0) return false; // Invalid configuration | |
| 171 _ier = port->ier; | |
| 172 port->ier = 0; // Disable port interrupts while changing hardware | |
| 173 _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] | | |
| 174 select_stop_bits[new_config->stop] | | |
| 175 select_parity[new_config->parity]; | |
| 176 port->lcr = _lcr; | |
| 177 port->lcr |= LCR_DL; | |
| 178 port->mdl = baud_divisor >> 8; | |
| 179 port->ldl = baud_divisor & 0xFF; | |
| 180 port->lcr &= ~LCR_DL; | |
| 181 if (init) { | |
| 182 port->fcr = 0x07; // Enable and clear FIFO | |
| 183 if (chan->out_cbuf.len != 0) { | |
| 184 port->ier = IER_RCV; | |
| 185 } else { | |
| 186 port->ier = 0; | |
| 187 } | |
| 188 port->mcr = MCR_INT|MCR_DTR|MCR_RTS; // Master interrupt enable | |
| 189 } else { | |
| 190 port->ier = _ier; | |
| 191 } | |
| 192 if (new_config != &chan->config) { | |
| 193 chan->config = *new_config; | |
| 194 } | |
| 195 return true; | |
| 196 } | |
| 197 | |
| 198 // Function to initialize the device. Called at bootstrap time. | |
| 199 static bool | |
| 200 pid_serial_init(struct cyg_devtab_entry *tab) | |
| 201 { | |
| 202 serial_channel *chan = (serial_channel *)tab->priv; | |
| 203 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 204 #ifdef CYGDBG_IO_INIT | |
| 205 diag_printf("PID SERIAL init - dev: %x.%d\n", pid_chan->base, pid_chan->int_num); | |
| 206 #endif | |
| 207 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices | |
| 208 if (chan->out_cbuf.len != 0) { | |
| 209 cyg_drv_interrupt_create(pid_chan->int_num, | |
| 210 99, // Priority - what goes here? | |
| 211 (cyg_addrword_t)chan, // Data item passed to interrupt handler | |
| 212 pid_serial_ISR, | |
| 213 pid_serial_DSR, | |
| 214 &pid_chan->serial_interrupt_handle, | |
| 215 &pid_chan->serial_interrupt); | |
| 216 cyg_drv_interrupt_attach(pid_chan->serial_interrupt_handle); | |
| 217 cyg_drv_interrupt_unmask(pid_chan->int_num); | |
| 218 } | |
| 219 pid_serial_config_port(chan, &chan->config, true); | |
| 220 return true; | |
| 221 } | |
| 222 | |
| 223 // This routine is called when the device is "looked" up (i.e. attached) | |
| 224 static Cyg_ErrNo | |
| 225 pid_serial_lookup(struct cyg_devtab_entry **tab, | |
| 226 struct cyg_devtab_entry *sub_tab, | |
| 227 const char *name) | |
| 228 { | |
| 229 serial_channel *chan = (serial_channel *)(*tab)->priv; | |
| 230 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices | |
| 231 return ENOERR; | |
| 232 } | |
| 233 | |
| 234 // Send a character to the device output buffer. | |
| 235 // Return 'true' if character is sent to device | |
| 236 static bool | |
| 237 pid_serial_putc(serial_channel *chan, unsigned char c) | |
| 238 { | |
| 239 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 240 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 241 if (port->lsr & LSR_THE) { | |
| 242 // Transmit buffer is empty | |
| 243 port->thr = c; | |
| 244 return true; | |
| 245 } else { | |
| 246 // No space | |
| 247 return false; | |
| 248 } | |
| 249 } | |
| 250 | |
| 251 // Fetch a character from the device input buffer, waiting if necessary | |
| 252 static unsigned char | |
| 253 pid_serial_getc(serial_channel *chan) | |
| 254 { | |
| 255 unsigned char c; | |
| 256 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 257 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 258 while ((port->lsr & LSR_RSR) == 0) ; // Wait for char | |
| 259 c = port->rhr; | |
| 260 return c; | |
| 261 } | |
| 262 | |
| 263 // Set up the device characteristics; baud rate, etc. | |
| 264 static bool | |
| 265 pid_serial_set_config(serial_channel *chan, cyg_serial_info_t *config) | |
| 266 { | |
| 267 return pid_serial_config_port(chan, config, false); | |
| 268 } | |
| 269 | |
| 270 // Enable the transmitter on the device | |
| 271 static void | |
| 272 pid_serial_start_xmit(serial_channel *chan) | |
| 273 { | |
| 274 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 275 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 276 port->ier |= IER_XMT; // Enable xmit interrupt | |
| 277 } | |
| 278 | |
| 279 // Disable the transmitter on the device | |
| 280 static void | |
| 281 pid_serial_stop_xmit(serial_channel *chan) | |
| 282 { | |
| 283 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 284 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 285 port->ier &= ~IER_XMT; // Disable xmit interrupt | |
| 286 } | |
| 287 | |
| 288 // Serial I/O - low level interrupt handler (ISR) | |
| 289 static cyg_uint32 | |
| 290 pid_serial_ISR(cyg_vector_t vector, cyg_addrword_t data) | |
| 291 { | |
| 292 serial_channel *chan = (serial_channel *)data; | |
| 293 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 294 cyg_drv_interrupt_mask(pid_chan->int_num); | |
| 295 cyg_drv_interrupt_acknowledge(pid_chan->int_num); | |
| 296 return CYG_ISR_CALL_DSR; // Cause DSR to be run | |
| 297 } | |
| 298 | |
| 299 // Serial I/O - high level interrupt handler (DSR) | |
| 300 static void | |
| 301 pid_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) | |
| 302 { | |
| 303 serial_channel *chan = (serial_channel *)data; | |
| 304 pid_serial_info *pid_chan = (pid_serial_info *)chan->dev_priv; | |
| 305 volatile struct serial_port *port = (volatile struct serial_port *)pid_chan->base; | |
| 306 unsigned char isr; | |
|
58
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
307 while ((isr = port->isr & 0x0E) != 0) { |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
308 if (isr == ISR_Tx) { |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
309 (chan->callbacks->xmt_char)(chan); |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
310 } else if (isr == ISR_RxTO) { |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
311 (chan->callbacks->rcv_char)(chan, port->rhr); |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
312 } else if (isr == ISR_Rx) { |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
313 (chan->callbacks->rcv_char)(chan, port->rhr); |
|
6e51d764f8f1
Merge from eCos master repository on 1999-12-10-07:47:04-GMT
jlarmour
parents:
48
diff
changeset
|
314 } |
| 2 | 315 } |
| 316 cyg_drv_interrupt_unmask(pid_chan->int_num); | |
| 317 } | |
| 318 #endif |
