comparison packages/io/serial/current/src/arm/ebsa285_serial.c @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
1 //==========================================================================
2 //
3 // io/serial/arm/ebsa285_serial.c
4 //
5 // ARM EBSA285 Serial I/O Interface Module (interrupt driven)
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): hmt
35 // Contributors: hmt
36 // Date: 1999-07-26
37 // Purpose: EBSA285 Serial I/O module (interrupt driven version)
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
48 #ifdef CYGPKG_IO_SERIAL_ARM_EBSA285
49
50 #include <cyg/io/io.h>
51 #include <cyg/hal/hal_intr.h>
52 #include <cyg/io/devtab.h>
53 #include <cyg/io/serial.h>
54 #include <cyg/infra/diag.h>
55
56 #include <cyg/hal/hal_ebsa285.h> // Hardware definitions
57
58 // ------------------------------------------------------------------------
59 // Baud rates and the like, table-driven setup
60 #define FCLK_MHZ 50
61
62 struct _baud {
63 unsigned char divisor_high, divisor_low;
64 };
65
66 // The indexing of this table must match the enum in serialio.h
67 // The arithmetic is (clock/4)/(baud * 16) - 1
68
69 #define NONE {0,0}
70 const static struct _baud bauds[] = {
71 #if (FCLK_MHZ == 50)
72 NONE, // unused
73 NONE, // 50
74 NONE, // 75
75 NONE, // 110
76 NONE, // 134.5
77 NONE, // 150
78 NONE, // 200
79 { 0xA, 0x2B }, // 300 2603 = 0x0A2B
80 { 0x5, 0x15 }, // 600 1301 = 0x0515
81 { 0x2, 0x8A }, // 1200 650 = 0x028A
82 { 0x1, 0xB1 }, // 1800 433 = 0x01B1
83 { 0x1, 0x45 }, // 2400 325 = 0x0145
84 { 0x0, 0xD8 }, // 3600 216 = 0x00D8
85 { 0x0, 0xA2 }, // 4800 162 = 0x00A2
86 { 0x0, 0x6B }, // 7200 107 = 0x006B
87 { 0x0, 0x50 }, // 9600 80 = 0x0050
88 { 0x0, 0x35 }, // 14400 53 = 0x0035
89 { 0x0, 0x28 }, // 19200 40 = 0x0028
90 { 0x0, 0x13 }, // 38400 19 = 0x0013
91 NONE, // 57600
92 NONE, // 115200
93 NONE // 230400
94 #elif (FCLK_MHZ == 60)
95 #error NOT SUPPORTED - these figures are more for documentation
96 { /* 300, */ 0xC, 0x34}, /* 2603 = 0x0A2B */
97 { /* 600, */ 0x6, 0x19}, /* 1301 = 0x0515 */
98 { /* 1200, */ 0x3, 0x0C}, /* 650 = 0x028A */
99 { /* 2400, */ 0x1, 0x86}, /* 325 = 0x0145 */
100 { /* 4800, */ 0x0, 0xC2}, /* 162 = 0x00A2 */
101 { /* 9600, */ 0x0, 0x61}, /* 80 = 0x0050 */
102 { /* 19200, */ 0x0, 0x30}, /* 40 = 0x0028 */
103 { /* 38400, */ 0x0, 0x17}, /* 19 = 0x0013 */
104 #endif
105 };
106
107 static int select_word_length[] = {
108 SA110_UART_DATA_LENGTH_5_BITS, // 5 bits
109 SA110_UART_DATA_LENGTH_6_BITS, // 6 bits
110 SA110_UART_DATA_LENGTH_7_BITS, // 7 bits
111 SA110_UART_DATA_LENGTH_8_BITS // 8 bits
112 };
113
114 static int select_stop_bits[] = {
115 -1, // unused
116 SA110_UART_STOP_BITS_ONE, // 1 stop bit
117 -1, // 1.5 stop bit
118 SA110_UART_STOP_BITS_TWO // 2 stop bits
119 };
120
121 static int select_parity[] = {
122 SA110_UART_PARITY_DISABLED, // No parity
123 SA110_UART_PARITY_ENABLED | SA110_UART_PARITY_EVEN, // Even parity
124 SA110_UART_PARITY_ENABLED | SA110_UART_PARITY_ODD, // Odd parity
125 -1, // Mark parity
126 -1 // Space parity
127 };
128
129 // ------------------------------------------------------------------------
130 // some forward references
131
132 struct ebsa285_serial_interrupt {
133 CYG_WORD int_num;
134 cyg_interrupt serial_interrupt;
135 cyg_handle_t serial_interrupt_handle;
136 };
137
138 typedef struct ebsa285_serial_info {
139 struct ebsa285_serial_interrupt rx;
140 struct ebsa285_serial_interrupt tx;
141 } ebsa285_serial_info;
142
143 static bool ebsa285_serial_init(struct cyg_devtab_entry *tab);
144 static bool ebsa285_serial_putc(serial_channel *chan, unsigned char c);
145 static Cyg_ErrNo ebsa285_serial_lookup(struct cyg_devtab_entry **tab,
146 struct cyg_devtab_entry *sub_tab,
147 const char *name);
148 static unsigned char ebsa285_serial_getc(serial_channel *chan);
149 static bool ebsa285_serial_set_config(serial_channel *chan, cyg_serial_info_t *config);
150 static void ebsa285_serial_start_xmit(serial_channel *chan);
151 static void ebsa285_serial_stop_xmit(serial_channel *chan);
152
153 static cyg_uint32 ebsa285_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
154 static void ebsa285_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
155 static cyg_uint32 ebsa285_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
156 static void ebsa285_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
157
158 static SERIAL_FUNS(ebsa285_serial_funs,
159 ebsa285_serial_putc,
160 ebsa285_serial_getc,
161 ebsa285_serial_set_config,
162 ebsa285_serial_start_xmit,
163 ebsa285_serial_stop_xmit
164 );
165
166
167 // ------------------------------------------------------------------------
168 // this is dummy in config: there is only one device on the EBSA285
169 #define CYGPKG_IO_SERIAL_ARM_EBSA285_SERIAL // so always define it
170 #ifdef CYGPKG_IO_SERIAL_ARM_EBSA285_SERIAL
171
172 static ebsa285_serial_info ebsa285_serial_info1 = {
173 { CYGNUM_HAL_INTERRUPT_SERIAL_RX },
174 { CYGNUM_HAL_INTERRUPT_SERIAL_TX }
175 };
176
177 #if CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE > 0
178 static unsigned char ebsa285_serial_out_buf[CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE];
179 static unsigned char ebsa285_serial_in_buf[CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BUFSIZE];
180
181 static SERIAL_CHANNEL_USING_INTERRUPTS(ebsa285_serial_channel,
182 ebsa285_serial_funs,
183 ebsa285_serial_info1,
184 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BAUD),
185 CYG_SERIAL_STOP_DEFAULT,
186 CYG_SERIAL_PARITY_DEFAULT,
187 CYG_SERIAL_WORD_LENGTH_DEFAULT,
188 CYG_SERIAL_FLAGS_DEFAULT,
189 &ebsa285_serial_out_buf[0], sizeof(ebsa285_serial_out_buf),
190 &ebsa285_serial_in_buf[0], sizeof(ebsa285_serial_in_buf)
191 );
192 #else
193 static SERIAL_CHANNEL(ebsa285_serial_channel,
194 ebsa285_serial_funs,
195 ebsa285_serial_info1,
196 CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_EBSA285_SERIAL_BAUD),
197 CYG_SERIAL_STOP_DEFAULT,
198 CYG_SERIAL_PARITY_DEFAULT,
199 CYG_SERIAL_WORD_LENGTH_DEFAULT,
200 CYG_SERIAL_FLAGS_DEFAULT
201 );
202 #endif
203
204 DEVTAB_ENTRY(ebsa285_serial_io,
205 CYGDAT_IO_SERIAL_ARM_EBSA285_SERIAL_NAME,
206 0, // Does not depend on a lower level interface
207 &cyg_io_serial_devio,
208 ebsa285_serial_init,
209 ebsa285_serial_lookup, // Serial driver may need initializing
210 &ebsa285_serial_channel
211 );
212 #endif // CYGPKG_IO_SERIAL_ARM_EBSA285_SERIAL
213
214 // ------------------------------------------------------------------------
215
216
217 // ------------------------------------------------------------------------
218 // Internal function to actually configure the hardware to desired baud rate, etc.
219 static bool
220 ebsa285_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
221 {
222 int dummy, h, m, l;
223
224 // Make sure everything is off
225 *SA110_UART_CONTROL_REGISTER = SA110_UART_DISABLED | SA110_SIR_DISABLED;
226
227 // Read the RXStat to drain the fifo
228 dummy = *SA110_UART_RXSTAT;
229
230 // Set the baud rate - this also turns the uart on.
231 //
232 // Note that the ordering of these writes is critical,
233 // and the writes to the H_BAUD_CONTROL and CONTROL_REGISTER
234 // are necessary to force the UART to update its register
235 // contents.
236
237 l = bauds[new_config->baud].divisor_low; // zeros in unused slots here
238 m = bauds[new_config->baud].divisor_high; // and here
239 h = SA110_UART_BREAK_DISABLED |
240 select_stop_bits[new_config->stop] | // -1s in unused slots for these
241 select_parity[new_config->parity] | // and these
242 SA110_UART_FIFO_ENABLED | // and these below
243 select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5];
244
245 if ( 0 != (l + m) && h >= 0 && h < 256 ) {
246 *SA110_UART_L_BAUD_CONTROL = l;
247 *SA110_UART_M_BAUD_CONTROL = m;
248 *SA110_UART_H_BAUD_CONTROL = h;
249 init = true; // AOK
250 }
251 else if ( init ) {
252 // put in some sensible defaults
253 *SA110_UART_L_BAUD_CONTROL = 0x13; // bp->divisor_low;
254 *SA110_UART_M_BAUD_CONTROL = 0x00; // bp->divisor_high;
255 *SA110_UART_H_BAUD_CONTROL = SA110_UART_BREAK_DISABLED |
256 SA110_UART_PARITY_DISABLED |
257 SA110_UART_STOP_BITS_ONE |
258 SA110_UART_FIFO_ENABLED |
259 SA110_UART_DATA_LENGTH_8_BITS;
260 }
261
262 // All set, re-enable the device:
263 *SA110_UART_CONTROL_REGISTER = SA110_UART_ENABLED | SA110_SIR_DISABLED;
264
265 if (init && new_config != &chan->config) {
266 // record the new setup
267 chan->config = *new_config;
268 }
269 // All done
270 return init;
271 }
272
273 // Function to initialize the device. Called at bootstrap time.
274 static bool
275 ebsa285_serial_init(struct cyg_devtab_entry *tab)
276 {
277 serial_channel *chan = (serial_channel *)tab->priv;
278 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
279 #ifdef CYGDBG_IO_INIT
280 diag_printf("EBSA285 SERIAL init - dev: %x.%d\n", ebsa285_chan->base, ebsa285_chan->int_num);
281 #endif
282 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
283 if (chan->out_cbuf.len != 0) {
284
285 // first for rx
286 cyg_drv_interrupt_create(ebsa285_chan->rx.int_num,
287 99, // Priority - unused
288 (cyg_addrword_t)chan, // Data item passed to interrupt handler
289 ebsa285_serial_rx_ISR,
290 ebsa285_serial_rx_DSR,
291 &ebsa285_chan->rx.serial_interrupt_handle,
292 &ebsa285_chan->rx.serial_interrupt);
293 cyg_drv_interrupt_attach(ebsa285_chan->rx.serial_interrupt_handle);
294 cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);
295
296 // then for tx
297 cyg_drv_interrupt_create(ebsa285_chan->tx.int_num,
298 99, // Priority - unused
299 (cyg_addrword_t)chan, // Data item passed to interrupt handler
300 ebsa285_serial_tx_ISR,
301 ebsa285_serial_tx_DSR,
302 &ebsa285_chan->tx.serial_interrupt_handle,
303 &ebsa285_chan->tx.serial_interrupt);
304 cyg_drv_interrupt_attach(ebsa285_chan->tx.serial_interrupt_handle);
305 // DO NOT cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
306 }
307 (void)ebsa285_serial_config_port(chan, &chan->config, true);
308 return true;
309 }
310
311 // This routine is called when the device is "looked" up (i.e. attached)
312 static Cyg_ErrNo
313 ebsa285_serial_lookup(struct cyg_devtab_entry **tab,
314 struct cyg_devtab_entry *sub_tab,
315 const char *name)
316 {
317 serial_channel *chan = (serial_channel *)(*tab)->priv;
318 (chan->callbacks->serial_init)(chan); // Really only required for interrupt driven devices
319 return ENOERR;
320 }
321
322 // Send a character to the device output buffer.
323 // Return 'true' if character is sent to device
324 static bool
325 ebsa285_serial_putc(serial_channel *chan, unsigned char c)
326 {
327 if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) == SA110_TX_FIFO_BUSY)
328 return false; // No space
329
330 *SA110_UART_DATA_REGISTER = c; // Transmit buffer is empty
331 return true;
332 }
333
334 // Fetch a character from the device input buffer, waiting if necessary
335 static unsigned char
336 ebsa285_serial_getc(serial_channel *chan)
337 {
338 unsigned char c;
339 while ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) == SA110_RX_FIFO_EMPTY)
340 ; // wait for char
341 c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
342 // no error checking... no way to return the info
343 return c;
344 }
345
346 // Set up the device characteristics; baud rate, etc.
347 static bool
348 ebsa285_serial_set_config(serial_channel *chan, cyg_serial_info_t *config)
349 {
350 return ebsa285_serial_config_port(chan, config, false);
351 }
352
353 // Enable the transmitter on the device (nope, already in use by hal_diag)
354 static void
355 ebsa285_serial_start_xmit(serial_channel *chan)
356 {
357 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
358 cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
359 }
360
361 // Disable the transmitter on the device (nope, remains in use by hal_diag)
362 static void
363 ebsa285_serial_stop_xmit(serial_channel *chan)
364 {
365 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
366 cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
367 }
368
369 // Serial I/O - low level interrupt handlers (ISR)
370 static cyg_uint32
371 ebsa285_serial_rx_ISR(cyg_vector_t vector, cyg_addrword_t data)
372 {
373 serial_channel *chan = (serial_channel *)data;
374 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
375 cyg_drv_interrupt_mask(ebsa285_chan->rx.int_num);
376 cyg_drv_interrupt_acknowledge(ebsa285_chan->rx.int_num);
377 return CYG_ISR_CALL_DSR; // Cause DSR to be run
378 }
379
380 static cyg_uint32
381 ebsa285_serial_tx_ISR(cyg_vector_t vector, cyg_addrword_t data)
382 {
383 serial_channel *chan = (serial_channel *)data;
384 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
385 cyg_drv_interrupt_mask(ebsa285_chan->tx.int_num);
386 cyg_drv_interrupt_acknowledge(ebsa285_chan->tx.int_num);
387 return CYG_ISR_CALL_DSR; // Cause DSR to be run
388 }
389
390 // Serial I/O - high level interrupt handlers (DSR)
391 static void
392 ebsa285_serial_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
393 {
394 serial_channel *chan = (serial_channel *)data;
395 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
396 if ((*SA110_UART_FLAG_REGISTER & SA110_RX_FIFO_STATUS_MASK) != SA110_RX_FIFO_EMPTY) {
397 char c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
398 int status;
399 c = (char)(*SA110_UART_DATA_REGISTER & 0xFF);
400 status = *SA110_UART_RXSTAT;
401 if ( 0 == (status & (SA110_UART_FRAMING_ERROR_MASK |
402 SA110_UART_PARITY_ERROR_MASK |
403 SA110_UART_OVERRUN_ERROR_MASK)) )
404 (chan->callbacks->rcv_char)(chan, c);
405 }
406 cyg_drv_interrupt_unmask(ebsa285_chan->rx.int_num);
407 }
408
409 static void
410 ebsa285_serial_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
411 {
412 serial_channel *chan = (serial_channel *)data;
413 ebsa285_serial_info *ebsa285_chan = (ebsa285_serial_info *)chan->dev_priv;
414 if ((*SA110_UART_FLAG_REGISTER & SA110_TX_FIFO_STATUS_MASK) != SA110_TX_FIFO_BUSY) {
415 (chan->callbacks->xmt_char)(chan);
416 }
417 cyg_drv_interrupt_unmask(ebsa285_chan->tx.int_num);
418 }
419 #endif // CYGPKG_IO_SERIAL_ARM_EBSA285
420
421 // ------------------------------------------------------------------------
422 // EOF ebsa285_serial.c