source: rtems/c/src/lib/libbsp/m68k/mvme167/console/console.c @ 08b5f55

4.104.114.84.95
Last change on this file since 08b5f55 was 5d02459, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/99 at 19:23:28

MVME167 BSP submitted by Charles Gauthier <Charles.Gauthier@…>.

  • Property mode set to 100644
File size: 41.9 KB
Line 
1/*
2 *  console.c
3 *
4 *  This file contains the MVME167 termios console package. Only asynchronous
5 *  I/O is supported. Normal I/O uses DMA for output, interrupts for input.
6 *  Very limited support is provided for polled I/O. Polled I/O is intended
7 *  only for running the RTEMS test suites, and uses the 167Bug console only.
8 *
9 *  /dev/tty0 is channel 0, Serial Port 1/Console on the MVME712M.
10 *  /dev/tty1 is channel 1, Serial Port 2/TTY01 on the MVME712M.
11 *  /dev/tty2 is channel 2, Serial Port 3 on the MVME712M.
12 *  /dev/tty3 is channel 3, Serial Port 4 on the MVME712M.
13 *
14 *  /dev/console is fixed to be /dev/tty01, Serial Port 2. 167Bug is given
15 *  Serial Port 1/Console. Do not open /dev/tty00.
16 *
17 *  Modern I/O chips often contain a number of I/O devices that can operate
18 *  almost independently of each other. Typically, in RTEMS, all devices in
19 *  an I/O chip are handled by a single device driver, but that need not be
20 *  always the case. Each device driver must supply six entry  points in the
21 *  Device Driver Table: a device initialization function, as well as an open,
22 *  close, read, write and a control function. RTEMS assigns a device major
23 *  number to each device driver. This major device number is the index of the
24 *  device driver entries in the Device Driver Table, and it used to identify
25 *  a particular device driver. To distinguish multiple I/O sub-devices within
26 *  an I/O chip, RTEMS supports device minor numbers. When a I/O device is
27 *  initialized, the major number is supplied to the initialization function.
28 *  That function must register each sub-device with a separate name and minor
29 *  number (as well as the supplied major number). When an application opens a
30 *  device by name, the corresponding major and minor numbers are returned to
31 *  the caller to be used in subsequent I/O operations (although these details
32 *  are typically hidden within the library functions).
33 *
34 *  Such a scheme recognizes that the initialization of the individual
35 *  sub-devices is generally not completely independent. For example, the
36 *  four serial ports of the CD2401 can be configured almost independently
37 *  from each other. One port could be configured to operate in asynchronous
38 *  mode with interrupt-driven I/O, while another port could be configured to
39 *  operate in HDLC mode with DMA I/O. However, a device reset command will
40 *  reset all four channels, and the width of DMA transfers and the number of
41 *  retries following bus errors selected applies to all four channels.
42 *  Consequently, when initializing one channel, one must be careful not to
43 *  destroy the configuration of other channels that are already configured.
44 *
45 *  One problem with the RTEMS I/O initialization model is that no information
46 *  other than a device major number is passed to the initialization function.
47 *  Consequently, the sub-devices must be initialized with some pre-determined
48 *  configuration. To change the configuration of a sub-device, it is
49 *  necessary to either rewrite the initialization function, or to make a
50 *  series of rtems_io_control() calls after initialization. The first
51 *  approach is not very elegant. The second approach is acceptable if an
52 *  application is simply changing baud rates, parity or other such
53 *  asynchronous parameters (as supplied by the termios package). But what if
54 *  an application requires one channel to run in HDLC or Bisync mode and
55 *  another in async mode? With a single driver per I/O chip approach, the
56 *  device driver must support multiple protocols. This is feasible, but it
57 *  often means that an application that only does asynchronous I/O now links
58 *  in code for other unused protocols, thus wasting precious ROM space.
59 *  Worse, it requires that the sub-devices be initialized in some
60 *  configuration, and that configuration then changed through a series of
61 *  device driver control calls. There is no standard API in RTEMS to switch
62 *   a serial line to some synchronous protocol.
63 *
64 *  A better approach is to treat each channel as a separate device, each with
65 *  its own device device driver. The application then supplies its own device
66 *  driver table with only the required protocols (drivers) on each line. The
67 *  problem with this approach is that the device drivers are not really
68 *  independent, given that the I/O sub-devices within a common chip are not
69 *  independent themselves. Consequently, the related device drivers must
70 *  share some information. In RTEMS, there is no standard location in which
71 *  to share information.
72 *
73 *  This driver handles all four channels, i.e. it distinguishes the
74 *  sub-devices using minor device numbers. Only asynchronous I/O is
75 *  supported. The console is currently fixed to be channel 1 on the CD2401,
76 *  which corresponds to the TTY01 port (Serial Port 2) on the MVME712M
77 *  Transition Module.
78 *
79 *  The CD2401 does either interrupt-driven or DMA I/O; it does not support
80 *  polling. In interrupt-driven or DMA I/O modes, interrupts from the CD2401
81 *  are routed to the MC68040, and the processor generates an interrupt
82 *  acknowledge cycle directly to the CD2401 to obtain an interrupt vector.
83 *  The PCCchip2 supports a pseudo-polling mode in which interrupts from the
84 *  CD2401 are not routed to the MC68040, but can be detected by the processor
85 *  by reading the appropriate CD2401 registers. In this mode, interrupt
86 *  acknowledge cycles must be generated to the CD2401 by reading the
87 *  appropriate PCCchip2 registers.
88 *
89 *  Interrupts from the four channels cannot be routed independently; either
90 *  all channels are used in the pseudo-polling mode, or all channels are used
91 *  in interrupt-driven/DMA mode. There is no advantage in using the speudo-
92 *  polling mode. Consenquently, this driver performs DMA input and output.
93 *  Output is performed directly from the termios raw output buffer, while
94 *  input is accumulated into a separate buffer.
95 *
96 *  THIS MODULE IS NOT RE-ENTRANT! Simultaneous access to a device from
97 *  multiple tasks is likely to cause significant problems! Concurrency
98 *  control is implemented in the termios package.
99*
100 *  THE INTERRUPT LEVEL IS SET TO 1 FOR ALL CHANNELS.
101 *  If the CD2401 is to be used for high speed synchronous serial I/O, the
102 *  interrupt priority might need to be increased.
103 *
104 *  ALL INTERRUPT HANDLERS ARE SHARED.
105 *  When adding extra device drivers, either rewrite the interrupt handlers
106 *  to demultiplex the interrupts, or install separate vectors. Common vectors
107 *  are currently used to catch spurious interrupts. We could already have
108 *  installed separate vectors for each channel and used the spurious
109 *  interrupt handler defined in some other BSPs, but handling spurious
110 *  interrupts from the CD2401 in this device driver allows us to record more
111 *  information on the source of the interrupts. Furthermore, we have observed
112 *  the occasional spurious interrupt from channel 0. We definitely do not
113 *  to call a debugger for those.
114 *
115 *  All page references are to the MVME166/MVME167/MVME187 Single Board
116 *  Computer Programmer's Reference Guide (MVME187PG/D2) with the April
117 *  1993 supplements/addenda (MVME187PG/D2A1).
118 *
119 *  Copyright (c) 1998, National Research Council of Canada
120 *
121 *  The license and distribution terms for this file may be
122 *  found in the file LICENSE in this distribution or at
123 *  http://www.OARcorp.com/rtems/license.html.
124 */
125
126#define M167_INIT
127
128#include <termios.h>
129#include <bsp.h>                /* Must be before libio.h */
130#include <rtems/libio.h>
131
132#define CD2401_INT_LEVEL 1      /* Interrupt level for the CD2401 */
133#define CD2401_POLLED_IO 0      /* 0 for interrupt-driven, 1 for polled I/O */
134
135
136/* Channel info */
137/* static */ struct {
138  void *tty;                    /* Really a struct rtems_termios_tty * */
139  int len;                      /* Record nb of chars being TX'ed */
140  const char *buf;              /* Record where DMA is coming from */
141  rtems_unsigned16 used_buf_A;  /* Nb of times we used output DMA channel A */
142  rtems_unsigned16 used_buf_B;  /* Nb of times we used output DMA channel B */
143  rtems_unsigned16 wait_buf_A;  /* Nb of times we waited for output DMA channel A */
144  rtems_unsigned16 wait_buf_B;  /* Nb of times we waited for output DMA channel B */
145  rtems_unsigned32 spur_cnt;    /* Nb of spurious ints so far */
146  rtems_unsigned32 spur_dev;    /* Indo on last spurious int */
147  rtems_unsigned32 buserr_addr; /* Faulting address */
148  rtems_unsigned32 buserr_type; /* Reason of bus error during DMA */
149} CD2401_Channel_Info[4];
150
151/*
152 *  The number of channels already opened. If zero, enable the interrupts. The
153 *  initial value must be 0. If initialized explicitly, the variable ends up
154 *  in the .data section. Its value is not re-initialized on system restart.
155 *  Furthermore, because the variable is changed, the .data section would not
156 *  be ROMable. We thus leave the variable uninitialized, which causes it to
157 *  be allocated in the .bss section, and rely on RTEMS to zero the .bss
158 *  section on every startup.
159 */
160rtems_unsigned8 Init_count;
161
162
163/* Record previous handlers */
164rtems_isr_entry Prev_re_isr;        /* Previous rx exception isr */
165rtems_isr_entry Prev_rx_isr;        /* Previous rx isr */
166rtems_isr_entry Prev_tx_isr;        /* Previous tx isr */
167rtems_isr_entry Prev_modem_isr;     /* Previous modem/timer isr */
168
169/* Utility functions */
170void cd2401_chan_cmd( rtems_unsigned8 channel, rtems_unsigned8 cmd, rtems_unsigned8 wait );
171rtems_unsigned16 cd2401_bitrate_divisor( rtems_unsigned32 clkrate, rtems_unsigned32* bitrate );
172void cd2401_initialize( void );
173void cd2401_interrupts_initialize( rtems_boolean enable );
174
175/* ISRs */
176rtems_isr cd2401_modem_isr( rtems_vector_number vector );
177rtems_isr cd2401_re_isr( rtems_vector_number vector );
178rtems_isr cd2401_rx_isr( rtems_vector_number vector );
179rtems_isr cd2401_tx_isr( rtems_vector_number vector );
180
181/* Termios callbacks */
182int cd2401_firstOpen( int major, int minor, void *arg );
183int cd2401_lastClose( int major, int minor, void *arg );
184int cd2401_setAttributes( int minor, const struct termios *t );
185int cd2401_startRemoteTx( int minor );
186int cd2401_stopRemoteTx( int minor );
187int cd2401_write( int minor, const char *buf, int len );
188int _167Bug_pollRead( int minor );
189int _167Bug_pollWrite( int minor, const char *buf, int len );
190
191
192/*
193 *  Utility functions.
194 */
195
196/*
197 *  cd2401_chan_cmd
198 *
199 *  Sends a CCR command to the specified channel. Waits for any unfinished
200 *  previous command to complete, then sends the specified command. Optionally
201 *  wait for the current command to finish before returning.
202 *
203 *  Input parameters:
204 *    channel - CD2401 channel number
205 *    cmd  - command byte
206 *    wait - if non-zero, wait for specified command to complete before
207 *          returning.
208 *
209 *  Output parameters: NONE
210 *
211 *  Return values: NONE
212 */
213void cd2401_chan_cmd(
214  rtems_unsigned8 channel,
215  rtems_unsigned8 cmd,
216  rtems_unsigned8 wait
217)
218{
219  if ( channel < 4 ) {
220    cd2401->car = channel;      /* Select channel */
221
222    while ( cd2401->ccr != 0 ); /* Wait for completion of any previous command */
223    cd2401->ccr = cmd;          /* Send command */
224    if ( wait )
225      while( cd2401->ccr != 0 );/* Wait for completion */
226  }
227  else {
228    /* This may not be the best error message */
229    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
230  }
231}
232
233
234/*
235 *  cd2401_bitrate_divisor
236 *
237 *  Compute the divisor and clock source to use to obtain the desired bitrate.
238 *
239 *  Input parameters:
240 *    clkrate - system clock rate (CLK input frequency)
241 *    bitrate - the desired bitrate
242 *
243 *  Output parameters:
244 *    bitrate - The actual bitrate achievable, to the nearest bps.
245 *
246 *  Return values:
247 *    Returns divisor in lower byte and clock source in upper byte for the
248 *    specified bitrate.
249 */
250rtems_unsigned16 cd2401_bitrate_divisor(
251  rtems_unsigned32 clkrate,
252  rtems_unsigned32* bitrate
253)
254{
255  rtems_unsigned32 divisor;
256  rtems_unsigned16 clksource;
257
258  divisor = *bitrate << 3;          /* temporary; multiply by 8 for CLK/8 */
259  divisor = (clkrate + (divisor>>1)) / divisor; /* divisor for clk0 (CLK/8) */
260
261  /*  Use highest speed clock source for best precision - try from clk0 to clk4:  */
262  for( clksource = 0; clksource < 0x0400 && divisor > 0x100; clksource += 0x0100 )
263      divisor >>= 2;
264  divisor--;                        /* adjustment, see specs */
265  if( divisor < 1 )
266    divisor = 1;
267  else if( divisor > 0xFF )
268    divisor = 0xFF;
269  *bitrate = clkrate / (1 << ((clksource >> 7)+3)) / (divisor+1);
270  return( clksource | divisor );
271}
272
273
274/*
275 *  cd2401_initialize
276 *
277 *  Initializes the CD2401 device. Individual channels on the chip are left in
278 *  their default reset state, and should be subsequently configured.
279 *
280 *  Input parameters: NONE
281 *
282 *  Output parameters:  NONE
283 *
284 *  Return values: NONE
285 */
286void cd2401_initialize( void )
287{
288  int i;
289
290  for ( i = 3; i >= 0; i-- ) {
291    /*
292     *  Paranoia -- Should already be blank because array should be in bss
293     *  section, which is explicitly zeroed at boot time.
294     */
295    CD2401_Channel_Info[i].tty = NULL;
296    CD2401_Channel_Info[i].len = 0;
297    CD2401_Channel_Info[i].buf = NULL;
298    CD2401_Channel_Info[i].used_buf_A = 0;
299    CD2401_Channel_Info[i].used_buf_B = 0;
300    CD2401_Channel_Info[i].wait_buf_A = 0;
301    CD2401_Channel_Info[i].wait_buf_B = 0;
302    CD2401_Channel_Info[i].spur_cnt = 0;
303    CD2401_Channel_Info[i].spur_dev = 0;
304    CD2401_Channel_Info[i].buserr_type = 0;
305    CD2401_Channel_Info[i].buserr_addr = 0;
306  }
307
308 /*
309  *  Normally, do a device reset here. If we do it, we will most likely clober
310  *  the port settings for 167Bug on channel 0. So we just shut up all the
311  *  ports by disabling their interrupts.
312  */
313#if 0
314  cd2401->gfrcr = 0;            /* So we can detect that device init is done */
315  cd2401_chan_cmd( 0x10, 0);    /* Reset all */
316  while(cd2401->gfrcr == 0);    /* Wait for reset all */
317#endif
318
319  /*
320   *  The CL-CD2400/2401 manual (part no 542400-003) states on page 87 that
321   *  the LICR "contains the number of the interrupting channel being served.
322   *  The channel number is always that of the current acknowledged interrupt."
323   *  THE USER MUST PROGRAM CHANNEL NUMBER IN LICR! It is not set automatically
324   *  by the hardware, as suggested by the manual.
325   *
326   *  The updated manual (part no 542400-007) has the story strait. The CD2401
327   *  automatically initializes the LICR to contain the channel number in bits
328   *  2 and 3. However, these bits are not preserved when the user defined bits
329   *  are written.
330   *
331   *  The same vector number is used for all four channels. Different vector
332   *  numbers could be programmed for each channel, thus avoiding the need to
333   *  demultiplex the interrupts in the ISR.
334   */
335  for ( i = 0; i < 4; i++ ) {
336    cd2401->car = i;            /* Select channel */
337    cd2401->livr = 0x5C;        /* Motorola suggested value p. 3-15 */
338    cd2401->licr = i << 2;      /* Don't rely on reset value */
339    cd2401->ier = 0;            /* Disable all interrupts */
340  }
341
342  /*
343   *  The content of the CD2401 xpilr registers must match the A7-A0 addresses
344   *  generated by the PCCchip2 during interrupt acknowledge cycles in order
345   *  for the CD2401 to recognize the IACK cycle and clear its interrupt
346   *  request.
347   */
348  cd2401->mpilr = 0x01;         /* Match pccchip2->modem_piack p. 3-27 */
349  cd2401->tpilr = 0x02;         /* Match pccchip2->tx_piack p. 3-28 */
350  cd2401->rpilr = 0x03;         /* Match pccchip2->rx_piack p. 3-29 */
351
352  /* Global CD2401 registers */
353  cd2401->dmr = 0;              /* 16-bit DMA transfers when possible */
354  cd2401->bercnt = 0;           /* Do not retry DMA upon bus errors */
355
356  /*
357   *  Setup timer prescaler period, which clocks timers 1 and 2 (or rx timeout
358   *  and tx delay). The prescaler is clocked by the system clock) / 2048. The
359   *  register must be in the range 0x0A..0xFF, ie. a rescaler period range of
360   *  about 1ms..26ms for a nominal system clock rate  of 20MHz.
361   */
362  cd2401->tpr  = 0x0A;          /* Same value as 167Bug */
363}
364
365
366/*
367 *  cd2401_interrupts_initialize
368 *
369 *  This routine enables or disables the CD2401 interrupts to the MC68040.
370 *  Interrupts cannot be enabled/disabled on a per-channel basis.
371 *
372 *  Input parameters:
373 *    enable - if true, enable the interrupts, else disable them.
374 *
375 *  Output parameters:  NONE
376 *
377 *  Return values: NONE
378 *
379 *  THE FIRST CD2401 CHANNEL OPENED SHOULD ENABLE INTERRUPTS.
380 *  THE LAST CD2401 CHANNEL CLOSED SHOULD DISABLE INTERRUPTS.
381 */
382void cd2401_interrupts_initialize(
383  rtems_boolean enable
384)
385{
386  if ( enable ) {
387   /*
388    *  Enable interrupts from the CD2401 in the PCCchip2.
389    *  During DMA transfers, the MC68040 supplies dirty data during read cycles
390    *  from the CD2401 and leaves the data dirty in its data cache if there is
391    *  a cache hit. The MC68040 updates the data cache during write cycles from
392    *  the CD2401 if there is a cache hit.
393    */
394    pccchip2->SCC_error = 0x01;
395    pccchip2->SCC_modem_int_ctl = 0x10 | CD2401_INT_LEVEL;
396    pccchip2->SCC_tx_int_ctl = 0x10 | CD2401_INT_LEVEL;
397    pccchip2->SCC_rx_int_ctl = 0x50 | CD2401_INT_LEVEL;
398
399    pccchip2->gen_control |= 0x02;      /* Enable pccchip2 interrupts */
400  }
401  else {
402    /* Disable interrupts */
403    pccchip2->SCC_modem_int_ctl &= 0xEF;
404    pccchip2->SCC_tx_int_ctl &= 0xEF;
405    pccchip2->SCC_rx_int_ctl &= 0xEF;
406  }
407}
408
409
410/* ISRs */
411
412/*
413 *  cd2401_modem_isr
414 *
415 *  Modem/timer interrupt (group 1) from CD2401. These are not used, and not
416 *  expected. Record as spurious and clear.
417 *
418 *  Input parameters:
419 *    vector - vector number
420 *
421 *  Output parameters: NONE
422 *
423 *  Return values: NONE
424 */
425rtems_isr cd2401_modem_isr(
426  rtems_vector_number vector
427)
428{
429  rtems_unsigned8 ch;
430
431  /* Get interrupting channel ID */
432  ch = cd2401->licr >> 2;
433
434  /* Record interrupt info for debugging */
435  CD2401_Channel_Info[ch].spur_dev =
436      (vector << 24) | (cd2401->stk << 16) | (cd2401->mir << 8) | cd2401->misr;
437  CD2401_Channel_Info[ch].spur_cnt++;
438
439  cd2401->meoir = 0;            /* EOI */
440}
441
442
443/*
444 *  cd2401_re_isr
445 *
446 *  RX exception interrupt (group 3, receiver exception) from CD2401. These are
447 *  not used, and not expected. Record as spurious and clear.
448 *
449 *  FIX THIS ISR TO DETECT BREAK CONDITIONS AND RAISE SIGINT
450 *
451 *  Input parameters:
452 *    vector - vector number
453 *
454 *  Output parameters: NONE
455 *
456 *  Return values: NONE
457 */
458rtems_isr cd2401_re_isr(
459  rtems_vector_number vector
460)
461{
462  rtems_unsigned8 ch;
463
464  /* Get interrupting channel ID */
465  ch = cd2401->licr >> 2;
466
467  /* Record interrupt info for debugging */
468  CD2401_Channel_Info[ch].spur_dev =
469      (vector << 24) | (cd2401->stk << 16) | (cd2401->rir << 8) | cd2401->u5.b.risrl;
470  CD2401_Channel_Info[ch].spur_cnt++;
471
472  if ( cd2401->u5.b.risrl & 0x80 )  /* Timeout interrupt? */
473    cd2401->ier &= 0xDF;            /* Disable rx timeout interrupt */
474  cd2401->reoir = 0x08;             /* EOI; exception char not read */
475}
476
477
478/*
479 *  cd2401_rx_isr
480 *
481 *  RX interrupt (group 3, receiver data) from CD2401.
482 *
483 *  Input parameters:
484 *     vector - vector number
485 *
486 *  Output parameters: NONE
487 *
488 *  Return values: NONE
489 */
490rtems_isr cd2401_rx_isr(
491  rtems_vector_number vector
492)
493{
494  char c;
495  rtems_unsigned8 ch, nchars;
496
497  ch = cd2401->licr >> 2;
498
499  /* Has this channel been initialized? */
500  if (CD2401_Channel_Info[ch].tty) {
501    /* Yes, read chars, enqueue them, and issue EOI */
502    nchars = cd2401->rfoc;      /* Number of chars to retrieve from rx FIFO */
503    while ( nchars-- > 0 ) {
504      c = (char)cd2401->dr;     /* Next char in rx FIFO */
505      rtems_termios_enqueue_raw_characters (
506        CD2401_Channel_Info[ch].tty,
507        &c,
508        1 );
509    }
510    cd2401->reoir = 0;          /* EOI */
511  } else {
512    /* No, record as spurious interrupt */
513    CD2401_Channel_Info[ch].spur_dev =
514        (vector << 24) | (cd2401->stk << 16) | (cd2401->rir << 8) | cd2401->u5.b.risrl;
515    CD2401_Channel_Info[ch].spur_cnt++;
516    cd2401->reoir = 0x04;       /* EOI - character not read */
517  }
518}
519
520
521/*
522 *  cd2401_tx_isr
523 *
524 *  TX interrupt (group 2) from CD2401.
525 *
526 *  Input parameters:
527 *    vector - vector number
528 *
529 *  Output parameters: NONE
530 *
531 *  Return values: NONE
532 */
533rtems_isr cd2401_tx_isr(
534  rtems_vector_number vector
535)
536{
537  rtems_unsigned8 ch, status, buserr;
538
539  status = cd2401->tisr;
540  ch = cd2401->licr >> 2;
541
542  /* Has this channel been initialized? */
543  if ( !CD2401_Channel_Info[ch].tty ) {
544    /* No, record as spurious interrupt */
545    CD2401_Channel_Info[ch].spur_dev =
546        (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr;
547    CD2401_Channel_Info[ch].spur_cnt++;
548    cd2401->ier &= 0xFC;        /* Shut up, whoever you are */
549    cd2401->teoir = 0x88;       /* EOI - Terminate buffer and no transfer */
550    return;
551  }
552
553  if ( status & 0x80 ) {
554    /*
555     *  Bus error occurred during DMA transfer. For now, just record.
556     *  Get reason for DMA bus error and clear the report for the next occurrence
557     */
558    buserr = pccchip2->SCC_error;
559    pccchip2->SCC_error = 0x01;
560    CD2401_Channel_Info[ch].buserr_type =
561         (vector << 24) | (buserr << 16) | (cd2401->tir << 8) | cd2401->tisr;
562    CD2401_Channel_Info[ch].buserr_addr =
563        (((rtems_unsigned32)cd2401->tcbadru) << 16) | cd2401->tcbadrl;
564
565    cd2401->teoir = 0x80;       /* EOI - terminate bad buffer */
566    return;
567  }
568
569  if ( status & 0x20 ) {
570    /* DMA done */
571    cd2401->ier &= 0xFC;        /* Shut up the interrupts */
572   
573    /* This call can result in a call to cd2401_write() */
574    rtems_termios_dequeue_characters (
575        CD2401_Channel_Info[ch].tty,
576        CD2401_Channel_Info[ch].len );
577    cd2401->teoir = 0x08;       /* EOI - no data transfered */
578  }
579  else {
580    /* Why did we get a Tx interrupt? */
581    CD2401_Channel_Info[ch].spur_dev =
582        (vector << 24) | (cd2401->stk << 16) | (cd2401->tir << 8) | cd2401->tisr;
583    CD2401_Channel_Info[ch].spur_cnt++;
584    cd2401->teoir = 0x08;       /* EOI - no data transfered */
585  }
586}
587
588
589/*
590 *  termios callbacks
591 */
592
593/*
594 *  cd2401_firstOpen
595 *
596 *  This is the first time that this minor device (channel) is opened.
597 *  Complete the asynchronous initialization.
598 *
599 *  Input parameters:
600 *    major - device major number
601 *    minor - channel number
602 *    arg - pointer to a struct rtems_libio_open_close_args_t
603 *
604 *  Output parameters: NONE
605 *
606 *  Return value: IGNORED
607 */
608int cd2401_firstOpen(
609  int major,
610  int minor,
611  void *arg
612)
613{
614  rtems_libio_open_close_args_t *args = arg;
615  rtems_libio_ioctl_args_t newarg;
616  struct termios termios;
617  rtems_status_code sc;
618
619  /*
620   * Set up the line with the specified parameters. The difficulty is that
621   * the line parameters are stored in the struct termios field of a
622   * struct rtems_termios_tty that is not defined in a public header file.
623   * Therefore, we do not have direct access to the termios passed in with
624   * arg. So we make a rtems_termios_ioctl() call to get a pointer to the
625   * termios structure.
626   *
627   * THIS KLUDGE MAY BREAK IN THE FUTURE!
628   *
629   * We could have made a tcgetattr() call if we had our fd.
630   */
631  newarg.iop = args->iop;
632  newarg.command = RTEMS_IO_GET_ATTRIBUTES;
633  newarg.buffer = &termios;
634  sc = rtems_termios_ioctl (&newarg);
635  if (sc != RTEMS_SUCCESSFUL)
636    rtems_fatal_error_occurred (sc);
637   
638  /*
639   *  Turn off hardware flow control. It is a pain with 3-wire cables.
640   *  The rtems_termios_ioctl() call below results in a call to
641   *  cd2401_setAttributes to initialize the line. The caller will "wait"
642   *  on the ttyMutex that it already owns; this is safe in RTEMS.
643   */
644  termios.c_cflag |= CLOCAL;    /* Ignore modem status lines */
645  newarg.command = RTEMS_IO_SET_ATTRIBUTES;
646  sc = rtems_termios_ioctl (&newarg);
647  if (sc != RTEMS_SUCCESSFUL)
648    rtems_fatal_error_occurred (sc);
649 
650  /* Mark that the channel as initialized */
651  CD2401_Channel_Info[minor].tty = args->iop->data1;
652
653  /* If the first of the four channels to open, set up the interrupts */
654  if ( !Init_count++ ) {
655    /* Install the interrupt handlers */
656    Prev_re_isr    = (rtems_isr_entry) set_vector( cd2401_re_isr,    0x5C, 1 );
657    Prev_modem_isr = (rtems_isr_entry) set_vector( cd2401_modem_isr, 0x5D, 1 );
658    Prev_tx_isr    = (rtems_isr_entry) set_vector( cd2401_tx_isr,    0x5E, 1 );
659    Prev_rx_isr    = (rtems_isr_entry) set_vector( cd2401_rx_isr,    0x5F, 1 );
660
661    cd2401_interrupts_initialize( TRUE );
662  }
663
664  /* Return something */
665  return RTEMS_SUCCESSFUL;
666}
667
668
669/*
670 * cd2401_lastClose
671 *
672 *  There are no more opened file descriptors to this device. Close it down.
673 *
674 *  Input parameters:
675 *    major - device major number
676 *    minor - channel number
677 *    arg - pointer to a struct rtems_libio_open_close_args_t
678 */
679int cd2401_lastClose(
680  int major,
681  int minor,
682  void *arg
683)
684{
685  /* Mark that the channel is no longer is use */
686  CD2401_Channel_Info[minor].tty = NULL;
687
688  /* If the last of the four channels to close, disable the interrupts */
689  if ( !--Init_count ) {
690    cd2401_interrupts_initialize( FALSE );
691
692    /* De-install the interrupt handlers */
693    set_vector( Prev_re_isr,    0x5C, 1 );
694    set_vector( Prev_modem_isr, 0x5D, 1 );
695    set_vector( Prev_tx_isr,    0x5E, 1 );
696    set_vector( Prev_rx_isr,    0x5F, 1 );
697  }
698
699  /* return something */
700  return RTEMS_SUCCESSFUL;
701}
702
703
704/*
705 *  cd2401_setAttributes
706 *
707 *  Set up the selected channel of the CD2401 chip for doing asynchronous
708 *  I/O with DMA.
709 *
710 *  The chip must already have been initialized by cd2401_initialize().
711 *
712 *  This code was written for clarity. The code space it occupies could be
713 *  reduced. The code could also be compiled with aggressive optimization
714 *  turned on.
715 *
716 *  Input parameters:
717 *    minor - the selected channel
718 *    t - the termios parameters
719 *
720 *  Output parameters: NONE
721 *
722 *  Return value: IGNORED
723 */
724int cd2401_setAttributes(
725  int minor,
726  const struct termios *t
727)
728{
729  rtems_unsigned8 csize, cstopb, parodd, parenb, ignpar, inpck;
730  rtems_unsigned8 hw_flow_ctl, sw_flow_ctl, extra_flow_ctl;
731  rtems_unsigned8 icrnl, igncr, inlcr, brkint, ignbrk, parmrk, istrip;
732  rtems_unsigned16 tx_period, rx_period;
733  rtems_unsigned32 out_baud, in_baud;
734
735  /* Set up the line parameters */
736
737  /* Output baud rate */
738  switch ( cfgetospeed (t) ) {
739    default:      out_baud = 9600;    break;
740    case B50:     out_baud = 50;      break;
741    case B75:     out_baud = 75;      break;
742    case B110:    out_baud = 110;     break;
743    case B134:    out_baud = 134;     break;
744    case B150:    out_baud = 150;     break;
745    case B200:    out_baud = 200;     break;
746    case B300:    out_baud = 300;     break;
747    case B600:    out_baud = 600;     break;
748    case B1200:   out_baud = 1200;    break;
749    case B1800:   out_baud = 1800;    break;
750    case B2400:   out_baud = 2400;    break;
751    case B4800:   out_baud = 4800;    break;
752    case B9600:   out_baud = 9600;    break;
753    case B19200:  out_baud = 19200;   break;
754    case B38400:  out_baud = 38400;   break;
755    case B57600:  out_baud = 57600;   break;
756    case B115200: out_baud = 115200;  break;
757    case B230400: out_baud = 230400;  break;
758    case B460800: out_baud = 460800;  break;
759 }
760
761  /* Input baud rate */
762  switch ( cfgetispeed (t) ) {
763    default:      in_baud = out_baud; break;
764    case B50:     in_baud = 50;       break;
765    case B75:     in_baud = 75;       break;
766    case B110:    in_baud = 110;      break;
767    case B134:    in_baud = 134;      break;
768    case B150:    in_baud = 150;      break;
769    case B200:    in_baud = 200;      break;
770    case B300:    in_baud = 300;      break;
771    case B600:    in_baud = 600;      break;
772    case B1200:   in_baud = 1200;     break;
773    case B1800:   in_baud = 1800;     break;
774    case B2400:   in_baud = 2400;     break;
775    case B4800:   in_baud = 4800;     break;
776    case B9600:   in_baud = 9600;     break;
777    case B19200:  in_baud = 19200;    break;
778    case B38400:  in_baud = 38400;    break;
779    case B57600:  in_baud = 57600;    break;
780    case B115200: in_baud = 115200;   break;
781    case B230400: in_baud = 230400;   break;
782    case B460800: in_baud = 460800;   break;
783  }
784
785  /* Number of bits per char */
786  switch ( t->c_cflag & CSIZE ) {
787    case CS5:     csize = 0x04;       break;
788    case CS6:     csize = 0x05;       break;
789    case CS7:     csize = 0x06;       break;
790    case CS8:     csize = 0x07;       break;
791  }
792
793  /* Parity */
794  if ( t->c_cflag & PARODD )
795    parodd = 0x80;              /* Odd parity */
796  else
797    parodd = 0;
798
799  if ( t->c_cflag & PARENB )
800    parenb = 0x40;              /* Parity enabled on Tx and Rx */
801  else
802    parenb = 0x00;              /* No parity on Tx and Rx */
803
804  /* CD2401 IGNPAR and INPCK bits are inverted wrt POSIX standard? */
805  if ( t->c_iflag & INPCK )
806    ignpar = 0;                 /* Check parity on input */
807  else
808    ignpar = 0x10;              /* Do not check parity on input */
809  if ( t->c_iflag & IGNPAR ) {
810    inpck = 0x03;               /* Discard error character */
811    parmrk = 0;
812  } else {
813    if ( t->c_iflag & PARMRK ) {
814      inpck = 0x01;             /* Translate to 0xFF 0x00 <char> */
815      parmrk = 0x04;
816    } else {
817      inpck = 0x01;             /* Translate to 0x00 */
818      parmrk = 0;
819    }
820  }
821
822  /* Stop bits */
823  if ( t->c_cflag & CSTOPB )
824    cstopb = 0x04;              /* Two stop bits */
825  else
826    cstopb = 0x02;              /* One stop bit */
827
828  /* Modem flow control */
829  if ( t->c_cflag & CLOCAL )
830    hw_flow_ctl = 0x04;         /* Always assert RTS before Tx */
831  else
832    hw_flow_ctl = 0x07;         /* Always assert RTS before Tx,
833                                   wait for CTS and DSR */
834
835  /* XON/XOFF Tx flow control */
836  if ( t->c_iflag & IXON ) {
837    sw_flow_ctl = 0x40;         /* Tx in-band flow ctl enabled, wait for XON */
838    extra_flow_ctl = 0x30;      /* Eat XON/XOFF, XON/XOFF in SCHR1, SCHR2 */
839  }
840  else {
841    sw_flow_ctl = 0;            /* Tx in-band flow ctl disabled */
842    extra_flow_ctl = 0;         /* Pass on XON/XOFF */
843  }
844
845  /* CL/LF translation */
846  if ( t->c_iflag & ICRNL )
847    icrnl = 0x40;               /* Map CR to NL on input */
848  else
849    icrnl = 0;                  /* Pass on CR */
850  if ( t->c_iflag & INLCR )
851    inlcr = 0x20;               /* Map NL to CR on input */
852  else
853    inlcr = 0;                  /* Pass on NL */
854  if ( t->c_iflag & IGNCR )
855    igncr = 0x80;               /* CR discarded on input */
856  else
857    igncr = 0;
858
859  /* Break handling */
860  if ( t->c_iflag & IGNBRK ) {
861    ignbrk = 0x10;              /* Ignore break on input */
862    brkint = 0x08;
863  } else {
864    if ( t->c_iflag & BRKINT ) {
865      ignbrk = 0;               /* Generate SIGINT (interrupt ) */
866      brkint = 0;
867    } else {
868      ignbrk = 0;               /* Convert to 0x00 */
869      brkint = 0x08;
870    }
871  }
872
873  /* Stripping */
874  if ( t->c_iflag & ISTRIP )
875    istrip = 0x80;              /* Strip to 7 bits */
876  else
877    istrip = 0;                 /* Leave as 8 bits */
878
879 
880  /* Clear channel and disable rx and tx */
881  cd2401_chan_cmd (minor, 0x40, 1);
882 
883  /* Write to the ports */
884  cd2401->car = minor;          /* Select channel */
885  cd2401->cmr = 0x42;           /* Interrupt Rx, DMA Tx, async mode */
886  cd2401->cor1 = parodd | parenb | ignpar | csize;
887  cd2401->cor2 = sw_flow_ctl | hw_flow_ctl;
888  cd2401->cor3 = extra_flow_ctl | cstopb;
889  cd2401->cor4 = 0x0A;          /* No DSR/DCD/CTS detect; FIFO threshold of 10 */
890  cd2401->cor5 = 0x0A;          /* No DSR/DCD/CTS detect; DTR threshold of 10 */
891  cd2401->cor6 = igncr | icrnl | inlcr | ignbrk | brkint | parmrk | inpck;
892  cd2401->cor7 = istrip;        /* No LNext; ignore XON/XOFF if frame error; no tx translations */
893  cd2401->u1.async.schr1 =
894      t->c_cc[VSTART];          /* Special char 1: XON character */
895  cd2401->u1.async.schr2 =
896      t->c_cc[VSTOP];           /* special char 2: XOFF character */
897  /* Special chars 3 and 4, char range, LNext, RFAR[1..4] and CRC are unused, left as is. */
898
899  /* Set baudrates for receiver and transmitter */
900  rx_period = cd2401_bitrate_divisor( 20000000Ul, &in_baud );
901  cd2401->rbpr = (unsigned char)rx_period;
902  cd2401->rcor = (unsigned char)(rx_period >> 8); /* no DPLL */
903  tx_period = cd2401_bitrate_divisor( 20000000Ul, &out_baud );
904  cd2401->tbpr = (unsigned char)tx_period;
905  cd2401->tcor = (tx_period >> 3) & 0xE0;         /* no x1 ext clk, no loopback */
906
907  /* NEED TO LOOK AT THIS LINE! */
908  /* Timeout for 4 chars at 9600, 8 bits per char, 1 stop bit */
909  cd2401->u2.w.rtpr  = 0x04;
910
911  /*  And finally:  */
912  if ( t->c_cflag & CREAD ) {
913    /* Re-initialize channel, enable rx and tx */
914    cd2401_chan_cmd (minor, 0x2A, 1);
915    /* Enable rx data ints */
916    cd2401->ier = 0x08;
917  } else {
918    /* Re-initialize channel, enable tx, disable rx */
919    cd2401_chan_cmd (minor, 0x29, 1);
920  }
921
922  /* Return something */
923  return RTEMS_SUCCESSFUL;
924}
925
926
927/*
928 *  cd2401_startRemoreTx
929 *
930 *  Defined as a callback, but it would appear that it is never called. The
931 *  POSIX standard states that when the tcflow() function is called with the
932 *  TCION action, the system wall transmit a START character. Presumably,
933 *  tcflow() is called internally when IXOFF is set in the termios c_iflag
934 *  field when the input buffer can accomodate enough characters. It should
935 *  probably be called from fillBufferQueue(). Clearly, the function is also
936 *  explicitly callable by user code. The action is clearly to send the START
937 *  character, regardless of whether START/STOP flow control is in effect.
938 *
939 *  Input parameters:
940 *    minor - selected channel
941 *
942 *  Output parameters: NONE
943 *
944 *  Return value: IGNORED
945 *
946 *  PROPER START CHARACTER MUST BE PROGRAMMED IN SCHR1.
947 */
948int cd2401_startRemoteTx(
949  int minor
950)
951{
952  cd2401->car = minor;          /* Select channel */
953  cd2401->stcr = 0x01;          /* Send SCHR1 ahead of chars in FIFO */
954
955  /* Return something */
956  return RTEMS_SUCCESSFUL;
957}
958
959
960/*
961 *  cd2401_stopRemoreTx
962 *
963 *  Defined as a callback, but it would appear that it is never called. The
964 *  POSIX standard states that when the tcflow() function is called with the
965 *  TCIOFF function, the system wall transmit a STOP character. Presumably,
966 *  tcflow() is called internally when IXOFF is set in the termios c_iflag
967 *  field as the input buffer is about to overflow. It should probably be
968 *  called from rtems_termios_enqueue_raw_characters(). Clearly, the function
969 *  is also explicitly callable by user code. The action is clearly to send
970 *  the STOP character, regardless of whether START/STOP flow control is in
971 *  effect.
972 *
973 *  Input parameters:
974 *    minor - selected channel
975 *
976 *  Output parameters: NONE
977 *
978 *  Return value: IGNORED
979 *
980 *  PROPER STOP CHARACTER MUST BE PROGRAMMED IN SCHR2.
981 */
982int cd2401_stopRemoteTx(
983  int minor
984)
985{
986  cd2401->car = minor;          /* Select channel */
987  cd2401->stcr = 0x02;          /* Send SCHR2 ahead of chars in FIFO */
988
989  /* Return something */
990  return RTEMS_SUCCESSFUL;
991}
992
993
994/*
995 * cd2401_write
996 *
997 *  Initiate DMA output. Termios guarantees that the buffer does not wrap
998 *  around, so we can do DMA strait from the supplied buffer.
999 *
1000 *  Input parameters:
1001 *    minor - selected channel
1002 *    buf - output buffer
1003 *    len - number of chars to output
1004 *
1005 *  Output parameters:  NONE
1006 *
1007 *  Return value: IGNORED
1008 *
1009 *  MUST BE EXECUTED WITH THE CD2401 INTERRUPTS DISABLED!
1010 *  The processor is placed at interrupt level CD2401_INT_LEVEL explicitly in
1011 *  console_write(). The processor is necessarily at interrupt level 1 in
1012 *  cd2401_tx_isr().
1013 */
1014int cd2401_write(
1015  int minor,
1016  const char *buf,
1017  int len
1018)
1019{
1020  cd2401->car = minor;          /* Select channel */
1021
1022  if ( (cd2401->dmabsts & 0x08) == 0 ) {
1023    /* Next buffer is A. Wait for it to be ours. */
1024    if ( cd2401->atbsts & 0x01 ) {
1025      CD2401_Channel_Info[minor].wait_buf_A++;
1026      while ( cd2401->atbsts & 0x01 );
1027    }
1028    CD2401_Channel_Info[minor].used_buf_A++;
1029    CD2401_Channel_Info[minor].len = len;
1030    CD2401_Channel_Info[minor].buf = buf;
1031    cd2401->atbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 );
1032    cd2401->atbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf );
1033    cd2401->atbcnt = len;
1034    cd2401->atbsts = 0x03;      /* CD2401 owns buffer, int when empty */
1035  }
1036  else {
1037    /* Next buffer is B. Wait for it to be ours. */
1038    if ( cd2401->btbsts & 0x01 ) {
1039      CD2401_Channel_Info[minor].wait_buf_B++;
1040      while ( cd2401->btbsts & 0x01 );
1041    }
1042    CD2401_Channel_Info[minor].used_buf_B++;
1043    CD2401_Channel_Info[minor].len = len;
1044    CD2401_Channel_Info[minor].buf = buf;
1045    cd2401->btbadru = (rtems_unsigned16)( ( (rtems_unsigned32) buf ) >> 16 );
1046    cd2401->btbadrl = (rtems_unsigned16)( (rtems_unsigned32) buf );
1047    cd2401->btbcnt = len;
1048    cd2401->btbsts = 0x03;      /* CD2401 owns buffer, int when empty */
1049  }
1050  /* Should TxD interrupts be enabled before I set up the DMA transfer? */
1051  cd2401->ier |= 0x01;          /* enable TxD ints */
1052
1053  /* Return something */
1054  return RTEMS_SUCCESSFUL;
1055}
1056
1057
1058/*
1059 * _167Bug_pollRead
1060 *
1061 *  Read a character from the 167Bug console, and return it. Return -1
1062 *  if there is no character in the input FIFO.
1063 *
1064 *  Input parameters:
1065 *    minor - selected channel
1066 *
1067 *  Output parameters:  NONE
1068 *
1069 *  Return value: char returned as positive signed int
1070 *                -1 if no character is present in the input FIFO.
1071 *
1072 *  CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
1073 *  This function is invoked when the device driver is compiled with
1074 *  CD2401_POLLED_IO set to 1 above. All I/O is then done through 167Bug.
1075 */
1076int _167Bug_pollRead(
1077  int minor
1078)
1079{
1080  int char_not_available;
1081  unsigned char c;
1082 
1083  /* Check for a char in the input FIFO */
1084  asm volatile( "trap   #15       /* Trap to 167Bug (.INSTAT) */
1085                 .short 0x01
1086                 move   %%cc, %0  /* Get condition codes */
1087                 andil  #4, %0"
1088    : "=d" (char_not_available) :: "%%cc" );
1089   
1090  if (char_not_available)
1091    return -1;
1092   
1093  /* Read the char and return it */
1094  asm volatile( "subq.l #2,%%a7   /* Space for result */
1095                 trap   #15       /* Trap to 167 Bug (.INCHR) */
1096                 .short 0x00
1097                 moveb  (%%a7)+, %0"
1098    : "=d" (c) );
1099   
1100  return (int)c;
1101}
1102
1103
1104/*
1105 * _167Bug_pollWrite
1106 *
1107 *  Output buffer through 167Bug. Returns only once every character has been
1108 *  sent (polled output).
1109 *
1110 *  Input parameters:
1111 *    minor - selected channel
1112 *    buf - output buffer
1113 *    len - number of chars to output
1114 *
1115 *  Output parameters:  NONE
1116 *
1117 *  Return value: IGNORED
1118 *
1119 *  CANNOT BE COMBINED WITH INTERRUPT DRIVEN I/O!
1120 *  This function is invoked when the device driver is compiled with
1121 *  CD2401_POLLED_IO set to 1 above. All I/O is then done through 167Bug.
1122 */
1123int _167Bug_pollWrite(
1124  int minor,
1125  const char *buf,
1126  int len
1127)
1128{
1129  const char *endbuf = buf + len;
1130 
1131  asm volatile( "pea    (%0)
1132                 pea    (%1)
1133                 trap   #15     /* trap to 167Bug (.OUTSTR) */
1134                 .short 0x21"
1135    :: "a" (endbuf), "a" (buf) );
1136   
1137  /* Return something */
1138  return RTEMS_SUCCESSFUL;
1139}
1140
1141
1142/*
1143 ***************
1144 * BOILERPLATE *
1145 ***************
1146 *
1147 *  All these functions are prototyped in rtems/c/src/lib/include/console.h,
1148 *  except console_reserve_resources(), which is prototyped in
1149 *  rtems/c/src/lib/libbsp/m68k/mvme167/include/bsp.h
1150 */
1151
1152/*
1153 * Reserve resources consumed by this driver. Allocate enough space in the
1154 * object table to hold semaphores for 4 minor devices.
1155 */
1156void console_reserve_resources(
1157  rtems_configuration_table *configuration
1158)
1159{
1160  rtems_termios_reserve_resources (configuration, 4);
1161}
1162
1163/*
1164 * Initialize and register the device
1165 */
1166rtems_device_driver console_initialize(
1167  rtems_device_major_number  major,
1168  rtems_device_minor_number  minor,
1169  void                      *arg
1170)
1171{
1172  rtems_status_code status;
1173
1174  /*
1175   * Set up TERMIOS
1176   */
1177  rtems_termios_initialize ();
1178
1179  /*
1180   * Do device-specific initialization
1181   */
1182  cd2401_initialize ();
1183
1184  /*
1185   * Register the devices
1186   */
1187  status = rtems_io_register_name ("/dev/tty0", major, 0);
1188  if (status != RTEMS_SUCCESSFUL)
1189    rtems_fatal_error_occurred (status);
1190
1191  status = rtems_io_register_name ("/dev/tty1", major, 1);
1192  if (status != RTEMS_SUCCESSFUL)
1193    rtems_fatal_error_occurred (status);
1194
1195  status = rtems_io_register_name ("/dev/console", major, 1);
1196  if (status != RTEMS_SUCCESSFUL)
1197    rtems_fatal_error_occurred (status);
1198
1199  status = rtems_io_register_name ("/dev/tty2", major, 2);
1200  if (status != RTEMS_SUCCESSFUL)
1201    rtems_fatal_error_occurred (status);
1202
1203  status = rtems_io_register_name ("/dev/tty3", major, 3);
1204  if (status != RTEMS_SUCCESSFUL)
1205    rtems_fatal_error_occurred (status);
1206
1207  return RTEMS_SUCCESSFUL;
1208}
1209
1210/*
1211 * Open the device
1212 */
1213rtems_device_driver console_open(
1214  rtems_device_major_number major,
1215  rtems_device_minor_number minor,
1216  void                    * arg
1217)
1218{
1219#if CD2401_POLLED_IO
1220
1221  /* I/O is limited to 167Bug console. minor is ignored! */
1222  static const rtems_termios_callbacks callbacks = {
1223    NULL,                       /* firstOpen */
1224    NULL,                       /* lastClose */
1225    _167Bug_pollRead,           /* pollRead */
1226    _167Bug_pollWrite,          /* write */
1227    NULL,                       /* setAttributes */
1228    NULL,                       /* stopRemoteTx */
1229    NULL,                       /* startRemoteTx */
1230    0                           /* outputUsesInterrupts */
1231  };
1232 
1233#else
1234
1235  static const rtems_termios_callbacks callbacks = {
1236    cd2401_firstOpen,           /* firstOpen */
1237    cd2401_lastClose,           /* lastClose */
1238    NULL,                       /* pollRead */
1239    cd2401_write,               /* write */
1240    cd2401_setAttributes,       /* setAttributes */
1241    cd2401_stopRemoteTx,        /* stopRemoteTx */
1242    cd2401_startRemoteTx,       /* startRemoteTx */
1243    1                           /* outputUsesInterrupts */
1244  };
1245 
1246#endif
1247
1248  return rtems_termios_open (major, minor, arg, &callbacks);
1249}
1250
1251/*
1252 * Close the device
1253 */
1254rtems_device_driver console_close(
1255  rtems_device_major_number major,
1256  rtems_device_minor_number minor,
1257  void                    * arg
1258)
1259{
1260  return rtems_termios_close (arg);
1261}
1262
1263/*
1264 * Read from the device
1265 */
1266rtems_device_driver console_read(
1267  rtems_device_major_number major,
1268  rtems_device_minor_number minor,
1269  void                    * arg
1270)
1271{
1272  return rtems_termios_read (arg);
1273}
1274
1275/*
1276 * Write to the device
1277 */
1278rtems_device_driver console_write(
1279  rtems_device_major_number major,
1280  rtems_device_minor_number minor,
1281  void                    * arg
1282)
1283{
1284  return rtems_termios_write (arg);
1285}
1286
1287/*
1288 * Handle ioctl request.
1289 */
1290rtems_device_driver console_control(
1291  rtems_device_major_number major,
1292  rtems_device_minor_number minor,
1293  void                    * arg
1294)
1295{
1296  return rtems_termios_ioctl (arg);
1297}
Note: See TracBrowser for help on using the repository browser.