source: rtems/c/src/lib/libbsp/m68k/efi68k/console/console.c @ 8f35817

4.104.114.84.95
Last change on this file since 8f35817 was 8f35817, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 15, 1997 at 6:52:26 PM

eliminated potential for overfilling buffer on read

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 *  This file contains the efi68k console IO package.
3 *
4 *  COPYRIGHT (c) 1989-1997.
5 *  On-Line Applications Research Corporation (OAR).
6 *  Copyright assigned to U.S. Government, 1994.
7 *
8 *  The license and distribution terms for this file may in
9 *  the file LICENSE in this distribution or at
10 *  http://www.OARcorp.com/rtems/license.html.
11 *
12 *  $Id$
13 */
14
15#include <stdlib.h>
16#include <bsp.h>
17#include <rtems/libio.h>
18
19
20#define BAUD 38400
21#define CLK_FREQ 8000000.0
22
23/* BUFFER_LENGTH must be 2^n for n=1, 2, 3, .... */
24#define BUFFER_LENGTH 256
25#define RTS_STOP_SIZE BUFFER_LENGTH-64
26#define RTS_START_SIZE 16
27
28char xmt_buf[BUFFER_LENGTH];
29char rcv_buf[BUFFER_LENGTH];
30/* in: last entry into the buffer; always on a valid character */
31/* out: points to the next character to be pull from the buffer */
32/*    in+1=out => buffer empty */
33/*    in+2=out => buffer full */
34struct UART_buf {
35  char *offset; 
36  char *in; 
37  char *out;
38};
39static volatile struct UART_buf  xmt = { xmt_buf, (char *)0, (char *)1};
40static volatile struct UART_buf  rcv = { rcv_buf, (char *)0, (char *)1};
41static volatile char _debug_flag = 0;
42static volatile char _tx_stop = 0;
43
44/* _catchUARTint is the interrupt front-end */
45extern void _catchUARTint();
46asm("   .text
47        .align 2
48        .globl _catchUARTint
49_catchUARTint:
50        lea    %sp@(4),%sp                /* pop return address */
51        moveml %d0-%d7/%a0-%a6,%sp@-       /* save registers */
52        jbsr    uart_interrupt
53        moveml  %sp@+,%d0-%d7/%a0-%a6                           
54        rte
55    ");
56
57/* _fake_trap_1 will continue the UART interrupt (%sr *still*
58   UART_ISR_LEVEL) as a trap #1 to enter the debugger */
59asm("   .text
60        .align 2
61_fake_trap_1:
62        unlk %a6                /* clear interrupt frame */
63        lea %sp@(4),%sp         /* remove jbsr instruction */
64        moveml %sp@+,%d0-%d7/%a0-%a6 /* pop registers */
65        jmp (33*6-12+_VBR)      /* jump exception 1 */
66        ");
67
68/* dispatch UART interrupt */
69void xmit_interrupt(void);
70void rcvr_interrupt(void);
71void modem_status(void);
72void _fake_trap_1(void);
73void uart_interrupt(void) {
74  register char a;
75
76  a=*IIR & (NIP | IID_MASK); /* read interrupt id register */
77  switch (a) {
78  case 0x04: case 0x0c:
79    rcvr_interrupt();
80    break;
81  case 0x02:
82    xmit_interrupt();
83    break;
84  case 0x00:
85    modem_status();
86    break;
87  default:
88    break;
89  }
90  if (_debug_flag) {
91    _debug_flag = 0;            /* reset the flag */
92    _fake_trap_1();             /* fake a trap #1 */
93  }
94}
95
96/* transfer received character to the buffer */
97void rcvr_interrupt(void) {
98  register char *a, c;
99  register int length;
100
101  while ( (*LSR & DR) != 0) {
102    if ((c=*RBR) == 0x1a)       /* use ctl-z to reboot */
103      reboot();
104    else if (c == 0x03) {       /* use ctl-c to enter debugger */
105      _debug_flag = 1;
106      continue;
107    }
108    *(char *)((int)rcv.offset +(int)
109              (a=(char *)(((int)rcv.in+1) & ((int)BUFFER_LENGTH-1)))) = c;
110    if ((char *)(((int)rcv.in+2) & ((int)BUFFER_LENGTH-1)) != rcv.out)
111      rcv.in=a;
112  }
113  length = (BUFFER_LENGTH -1) & ( 
114    ( ((int)rcv.out <= (int)rcv.in) ? 0 : BUFFER_LENGTH) - (int)rcv.out
115    + (int)rcv.in + 1);
116  if (length >= RTS_STOP_SIZE)
117    *MCR &= (char) (~RTS);
118}
119
120/* tranfer buffered characters to the UART */
121void xmit_interrupt(void) {
122  register short int i, oldsr;
123
124  _CPU_ISR_Disable( oldsr ); /* for when outbyte calls */
125  if ( (*LSR & THRE) != 0 && _tx_stop == 0 )
126    for (i=0;i<16;i++) {
127      if ((char *)(((int)xmt.in+1) & ((int)BUFFER_LENGTH-1))== xmt.out)
128        break;
129      *THR=*(char *)((int)xmt.offset+(int)xmt.out);
130      xmt.out= (char *)(((int)xmt.out+1) & ((int)BUFFER_LENGTH-1));
131    }
132  _CPU_ISR_Enable( oldsr );
133}
134
135void modem_status(void) {
136  register char a;
137 
138  if ( ((a=*MDSR) & DCTS) != 0 )
139    if ( (a & CTS) == 0)
140      _tx_stop = 1;
141    else {
142      _tx_stop = 0;
143      xmit_interrupt();
144    }
145}
146
147/* transfer character from the buffer */
148char inbyte(void) {
149  register char a;
150  register int length;
151
152  while ((char *)(((int)rcv.in+1) & ((int)BUFFER_LENGTH-1))== rcv.out);
153  a=*(char *)((int)rcv.offset+(int)rcv.out);
154  rcv.out= (char *)(((int)rcv.out+1) & ((int)BUFFER_LENGTH-1));
155  length = (BUFFER_LENGTH -1) & ( 
156    ( ((int)rcv.out <= (int)rcv.in) ? 0 : BUFFER_LENGTH) - (int)rcv.out
157    + (int)rcv.in + 1);
158  if (length < RTS_START_SIZE)
159    *MCR |= (char) RTS;
160  return (a);
161}
162
163/* once room is avaliable in the buffer, transfer
164   the character into the buffer and enable
165   the xmtr interrupt */
166void outbyte(char c) {
167  register char *a;
168 
169  while ((char *)(((int)xmt.in+2) & ((int)BUFFER_LENGTH-1)) == xmt.out);
170  *(char *)((int)xmt.offset+(int)
171            (a=(char *)(((int)xmt.in+1) & ((int)BUFFER_LENGTH-1))))=c;
172  xmt.in=a;
173
174  if ( (*LSR & THRE) != 0 )     /* if THRE, uart has already interrupted */
175    xmit_interrupt();           /*   and was ignored. Need to restart. */
176}
177
178void _UART_flush(void) {
179  /* loop till xmt buffer empty. Works with interrupts disabled */
180  while ((char *)(((int)xmt.in+1) & ((int)BUFFER_LENGTH-1)) != xmt.out)
181    xmit_interrupt();
182  /* loop till UART buffer empty */
183  while ( (*LSR & TEMT) == 0 );
184}
185
186/*  console_initialize
187 *
188 *  This routine initializes the console IO driver.
189 *
190 *  Input parameters: NONE
191 *
192 *  Output parameters:  NONE
193 *
194 *  Return values:
195 */
196 
197void console_init()
198{
199  /* set clock divisor */
200  *LCR = (char)(DLAB);
201  *DLL = (char)((int)(CLK_FREQ/BAUD/16.0+0.5) & 0xFF);
202  *DLM = (char)(((int)(CLK_FREQ/BAUD/16.0+0.5) & 0xFF00) >> 8);
203
204  /* Line control setup */
205  *LCR = (char)(WL_8 | NSB);
206
207  /* Interrupt setup */
208  *IER = (char) 0x0b;           /* enable transmit, receive, modem stat int */
209 
210  /* FIFO setup */
211  *FCR = (char)(FIFO_E | 0xc0);
212
213  /* Modem control setup */
214  *MCR = (char) RTS;
215
216  /* init tx_stop with CTS */
217  _tx_stop = ( (*MDSR & CTS) ? 0 : 1);
218
219  set_vector(_catchUARTint, UART_ISR_LEVEL+24, 0);
220}
221
222rtems_device_driver console_initialize(
223  rtems_device_major_number  major,
224  rtems_device_minor_number  minor,
225  void                      *arg
226)
227{
228  rtems_status_code status;
229
230  status = rtems_io_register_name(
231    "/dev/console",
232    major,
233    (rtems_device_minor_number) 0
234  );
235 
236  if (status != RTEMS_SUCCESSFUL)
237    rtems_fatal_error_occurred(status);
238 
239  return RTEMS_SUCCESSFUL;
240
241}
242
243
244/*  is_character_ready
245 *
246 *  This routine returns TRUE if a character is available.
247 *
248 *  Input parameters: NONE
249 *
250 *  Output parameters:  NONE
251 *
252 *  Return values:
253 */
254
255rtems_boolean is_character_ready(
256  char *ch
257)
258{
259  if ((char *)(((int)rcv.in+1) & ((int)BUFFER_LENGTH-1))== rcv.out)
260    return(FALSE);
261  else
262    return(TRUE);
263}
264
265/*
266 *  Open entry point
267 */
268 
269rtems_device_driver console_open(
270  rtems_device_major_number major,
271  rtems_device_minor_number minor,
272  void                    * arg
273)
274{
275  return RTEMS_SUCCESSFUL;
276}
277 
278/*
279 *  Close entry point
280 */
281 
282rtems_device_driver console_close(
283  rtems_device_major_number major,
284  rtems_device_minor_number minor,
285  void                    * arg
286)
287{
288  return RTEMS_SUCCESSFUL;
289}
290 
291/*
292 * read bytes from the serial port. We only have stdin.
293 */
294 
295rtems_device_driver console_read(
296  rtems_device_major_number major,
297  rtems_device_minor_number minor,
298  void                    * arg
299)
300{
301  rtems_libio_rw_args_t *rw_args;
302  char *buffer;
303  int maximum;
304  int count = 0;
305 
306  rw_args = (rtems_libio_rw_args_t *) arg;
307 
308  buffer = rw_args->buffer;
309  maximum = rw_args->count;
310 
311  for (count = 0; count < maximum; count++) {
312    buffer[ count ] = inbyte();
313    if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
314      buffer[ count++ ]  = '\n';
315      break;
316    }
317  }
318 
319  rw_args->bytes_moved = count;
320  return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
321}
322 
323/*
324 * write bytes to the serial port. Stdout and stderr are the same.
325 */
326 
327rtems_device_driver console_write(
328  rtems_device_major_number major,
329  rtems_device_minor_number minor,
330  void                    * arg
331)
332{
333  int count;
334  int maximum;
335  rtems_libio_rw_args_t *rw_args;
336  char *buffer;
337 
338  rw_args = (rtems_libio_rw_args_t *) arg;
339 
340  buffer = rw_args->buffer;
341  maximum = rw_args->count;
342 
343  for (count = 0; count < maximum; count++) {
344    if ( buffer[ count ] == '\n') {
345      outbyte('\r');
346    }
347    outbyte( buffer[ count ] );
348  }
349 
350  rw_args->bytes_moved = maximum;
351  return 0;
352}
353 
354/*
355 *  IO Control entry point
356 */
357 
358rtems_device_driver console_control(
359  rtems_device_major_number major,
360  rtems_device_minor_number minor,
361  void                    * arg
362)
363{
364  return RTEMS_SUCCESSFUL;
365}
Note: See TracBrowser for help on using the repository browser.