source: rtems/c/src/libchip/serial/mc68681.c @ 198d851

4.104.114.84.9
Last change on this file since 198d851 was 198d851, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 15, 1998 at 11:20:33 PM

Switched from driver's own buffering to using termios. This eliminated
the need for the ringbuffer manipulation in this driver. It should
also allow the removal of mc68681_flush. This greatly simplified the
interrupt processing.

Reworked Interrupt Mask Register handling. Added imr field to the device
context. This handling makes sure that the IMR accurately reflects the
state of the port in use and its mate. This required the reworking of
the mc68681_enable_interrupts() routine to allow for the specification
of which interrupt sources were being enabled/disabled.

Reworked initialization to reset using port address rather than chip
base address. Basically we were always resetting port 0.

Added deviceType field which allows for multiple chips of the same
class to have the same vector number.

  • Property mode set to 100644
File size: 22.6 KB
Line 
1/*
2 *  This file contains the termios TTY driver for the Motorola MC68681.
3 *
4 *  This part is available from a number of secondary sources.
5 *  In particular, we know about the following:
6 *
7 *     + Exar 88c681 and 68c681
8 *
9 *  COPYRIGHT (c) 1989-1998.
10 *  On-Line Applications Research Corporation (OAR).
11 *  Copyright assigned to U.S. Government, 1994.
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.OARcorp.com/rtems/license.html.
16 *
17 *  $Id$
18 */
19
20#include <rtems.h>
21#include <rtems/libio.h>
22#include <stdlib.h>
23#include <ringbuf.h>
24
25#include <libchip/serial.h>
26#include "sersupp.h"
27#include "mc68681_p.h"
28#include "mc68681.h"
29
30/*
31 * Flow control is only supported when using interrupts
32 */
33
34console_fns mc68681_fns =
35{
36  libchip_serial_default_probe,   /* deviceProbe */
37  mc68681_open,                   /* deviceFirstOpen */
38  NULL,                           /* deviceLastClose */
39  NULL,                           /* deviceRead */
40  mc68681_write_support_int,      /* deviceWrite */
41  mc68681_initialize_interrupts,  /* deviceInitialize */
42  mc68681_write_polled,           /* deviceWritePolled */
43  mc68681_set_attributes,         /* deviceSetAttributes */
44  TRUE                            /* deviceOutputUsesInterrupts */
45};
46
47console_fns mc68681_fns_polled =
48{
49  libchip_serial_default_probe,        /* deviceProbe */
50  mc68681_open,                        /* deviceFirstOpen */
51  mc68681_close,                       /* deviceLastClose */
52  mc68681_inbyte_nonblocking_polled,   /* deviceRead */
53  mc68681_write_support_polled,        /* deviceWrite */
54  mc68681_init,                        /* deviceInitialize */
55  mc68681_write_polled,                /* deviceWritePolled */
56  mc68681_set_attributes,              /* deviceSetAttributes */
57  FALSE,                               /* deviceOutputUsesInterrupts */
58};
59
60extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
61
62/*
63 *  Console Device Driver Entry Points
64 */
65
66/*
67 *  mc68681_baud_rate
68 *
69 *  This routine returns the proper ACR bit and baud rate field values
70 *  based on the requested baud rate.  The baud rate set to be used
71 *  must be configured by the user.
72 */
73
74/* major index of 0 : ACR[7] = 0, X = 0 -- 68c681 only has these */
75/* major index of 1 : ACR[7] = 1, X = 0 -- 68c681 only has these */
76/* major index of 2 : ACR[7] = 0, X = 1 */
77/* major index of 3 : ACR[7] = 1, X = 1 */
78
79/* mc68681_baud_table_t mc68681_baud_rate_table[4] = { */
80mc68681_baud_t mc68681_baud_rate_table[4][RTEMS_TERMIOS_NUMBER_BAUD_RATES] = {
81  { /* ACR[7] = 0, X = 0 */
82    MC68681_BAUD_NOT_VALID,    /* B0 */
83    0x00,                      /* B50 */
84    MC68681_BAUD_NOT_VALID,    /* B75 */
85    0x01,                      /* B110 */
86    0x02,                      /* B134 */
87    MC68681_BAUD_NOT_VALID,    /* B150 */
88    0x03,                      /* B200 */
89    0x04,                      /* B300 */
90    0x05,                      /* B600 */
91    0x06,                      /* B1200 */
92    MC68681_BAUD_NOT_VALID,    /* B1800 */
93    0x08,                      /* B2400 */
94    0x09,                      /* B4800 */
95    0x0B,                      /* B9600 */
96    MC68681_BAUD_NOT_VALID,    /* B19200 */
97    0x0C,                      /* B38400 */
98    MC68681_BAUD_NOT_VALID,    /* B57600 */
99    MC68681_BAUD_NOT_VALID,    /* B115200 */
100    MC68681_BAUD_NOT_VALID,    /* B230400 */
101    MC68681_BAUD_NOT_VALID     /* B460800 */
102  },
103  { /* ACR[7] = 1, X = 0 */
104    MC68681_BAUD_NOT_VALID,    /* B0 */
105    MC68681_BAUD_NOT_VALID,    /* B50 */
106    0x00,                      /* B75 */
107    0x01,                      /* B110 */
108    0x02,                      /* B134 */
109    0x03,                      /* B150 */
110    MC68681_BAUD_NOT_VALID,    /* B200 */
111    0x04,                      /* B300 */
112    0x05,                      /* B600 */
113    0x06,                      /* B1200 */
114    0x0A,                      /* B1800 */
115    0x08,                      /* B2400 */
116    0x09,                      /* B4800 */
117    0x0B,                      /* B9600 */
118    0x0C,                      /* B19200 */
119    MC68681_BAUD_NOT_VALID,    /* B38400 */
120    MC68681_BAUD_NOT_VALID,    /* B57600 */
121    MC68681_BAUD_NOT_VALID,    /* B115200 */
122    MC68681_BAUD_NOT_VALID,    /* B230400 */
123    MC68681_BAUD_NOT_VALID     /* B460800 */
124  },
125  { /* ACR[7] = 0, X = 1 */
126    MC68681_BAUD_NOT_VALID,    /* B0 */
127    MC68681_BAUD_NOT_VALID,    /* B50 */
128    0x00,                      /* B75 */
129    0x01,                      /* B110 */
130    0x02,                      /* B134 */
131    0x03,                      /* B150 */
132    MC68681_BAUD_NOT_VALID,    /* B200 */
133    MC68681_BAUD_NOT_VALID,    /* B300 */
134    MC68681_BAUD_NOT_VALID,    /* B600 */
135    MC68681_BAUD_NOT_VALID,    /* B1200 */
136    0x0A,                      /* B1800 */
137    MC68681_BAUD_NOT_VALID,    /* B2400 */
138    0x08,                      /* B4800 */
139    0x0B,                      /* B9600 */
140    0x0C,                      /* B19200 */
141    MC68681_BAUD_NOT_VALID,    /* B38400 */
142    0x07,                      /* B57600 */
143    0x08,                      /* B115200 */
144    MC68681_BAUD_NOT_VALID,    /* B230400 */
145    MC68681_BAUD_NOT_VALID     /* B460800 */
146  },
147  { /* ACR[7] = 1, X = 1 */
148    MC68681_BAUD_NOT_VALID,    /* B0 */
149    0x00,                      /* B50 */
150    MC68681_BAUD_NOT_VALID,    /* B75 */
151    0x01,                      /* B110 */
152    0x02,                      /* B134 */
153    MC68681_BAUD_NOT_VALID,    /* B150 */
154    0x03,                      /* B200 */
155    MC68681_BAUD_NOT_VALID,    /* B300 */
156    MC68681_BAUD_NOT_VALID,    /* B600 */
157    MC68681_BAUD_NOT_VALID,    /* B1200 */
158    MC68681_BAUD_NOT_VALID,    /* B1800 */
159    MC68681_BAUD_NOT_VALID,    /* B2400 */
160    0x09,                      /* B4800 */
161    0x0B,                      /* B9600 */
162    MC68681_BAUD_NOT_VALID,    /* B19200 */
163    0x0C,                      /* B38400 */
164    0x07,                      /* B57600 */
165    0x08,                      /* B115200 */
166    MC68681_BAUD_NOT_VALID,    /* B230400 */
167    MC68681_BAUD_NOT_VALID     /* B460800 */
168  },
169};
170
171MC68681_STATIC int mc68681_baud_rate(
172  int           minor,
173  int           baud,
174  unsigned int *baud_mask_p,
175  unsigned int *acr_bit_p,
176  unsigned int *command
177);
178
179/*
180 *  mc68681_set_attributes
181 *
182 *  This function sets the DUART channel to reflect the requested termios
183 *  port settings.
184 */
185
186MC68681_STATIC int mc68681_set_attributes( 
187  int minor,
188  const struct termios *t
189)
190{
191  unsigned32             pMC68681_port;
192  unsigned32             pMC68681;
193  unsigned int           mode1;
194  unsigned int           mode2;
195  unsigned int           baud_mask;
196  unsigned int           acr_bit;
197  unsigned int           cmd;
198  setRegister_f          setReg;
199  rtems_interrupt_level  Irql;
200
201  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
202  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
203  setReg        = Console_Port_Tbl[minor].setRegister;
204
205  /*
206   *  Set the baud rate
207   */
208
209  if (mc68681_baud_rate( minor, t->c_cflag, &baud_mask, &acr_bit, &cmd ) == -1)
210    return -1;
211
212  baud_mask |=  baud_mask << 4;
213  acr_bit   <<= 7;
214
215  /*
216   *  Parity
217   */
218
219  mode1 = 0;
220  mode2 = 0;
221
222  if (t->c_cflag & PARENB) {
223    if (t->c_cflag & PARODD)
224      mode1 |= 0x04;
225    else
226      mode1 |= 0x04;
227  } else {
228   mode1 |= 0x10;
229  }
230
231  /*
232   *  Character Size
233   */
234
235  if (t->c_cflag & CSIZE) {
236    switch (t->c_cflag & CSIZE) {
237      case CS5:  break;
238      case CS6:  mode1 |= 0x01;  break;
239      case CS7:  mode1 |= 0x02;  break;
240      case CS8:  mode1 |= 0x03;  break;
241    }
242  } else {
243    mode1 |= 0x03;       /* default to 9600,8,N,1 */
244  }
245
246  /*
247   *  Stop Bits
248   */
249 
250  if (t->c_cflag & CSTOPB) {
251    mode2 |= 0x07;                      /* 2 stop bits */
252  } else {
253    if ((t->c_cflag & CSIZE) == CS5)    /* CS5 and 2 stop bits not supported */
254      return -1;
255    mode2 |= 0x0F;                      /* 1 stop bit */
256  }
257
258  rtems_interrupt_disable(Irql);
259    (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr_bit );
260    (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud_mask );
261    if ( cmd ) {
262      (*setReg)( pMC68681_port, MC68681_COMMAND, cmd );         /* RX */
263      (*setReg)( pMC68681_port, MC68681_COMMAND, cmd | 0x20 );  /* TX */
264    }
265    (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
266    (*setReg)( pMC68681_port, MC68681_MODE, mode1 );
267    (*setReg)( pMC68681_port, MC68681_MODE, mode2 );
268  rtems_interrupt_enable(Irql);
269  return 0;
270}
271
272/*
273 *  mc68681_initialize_context
274 *
275 *  This function sets the default values of the per port context structure.
276 */
277
278MC68681_STATIC void mc68681_initialize_context(
279  int               minor,
280  mc68681_context  *pmc68681Context
281)
282{
283  int          port;
284  unsigned int pMC68681;
285  unsigned int pMC68681_port;
286 
287  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
288  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
289
290  pmc68681Context->mate = -1;
291
292  for (port=0 ; port<Console_Port_Count ; port++ ) {
293    if ( Console_Port_Tbl[port].ulCtrlPort1 == pMC68681 && 
294         Console_Port_Tbl[port].ulCtrlPort2 != pMC68681_port ) {
295      pmc68681Context->mate = port;
296      pmc68681Context->imr  = 0;
297      break;
298    }
299  }
300
301}
302
303/*
304 *  mc68681_init
305 *
306 *  This function initializes the DUART to a quiecsent state.
307 */
308
309MC68681_STATIC void mc68681_init(int minor)
310{
311  unsigned32              pMC68681_port;
312  unsigned32              pMC68681;
313  mc68681_context        *pmc68681Context;
314  setRegister_f           setReg;
315  getRegister_f           getReg;
316
317  pmc68681Context = (mc68681_context *) malloc(sizeof(mc68681_context));
318
319  Console_Port_Data[minor].pDeviceContext = (void *)pmc68681Context;
320
321  mc68681_initialize_context( minor, pmc68681Context );
322
323  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
324  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
325  setReg        = Console_Port_Tbl[minor].setRegister;
326  getReg        = Console_Port_Tbl[minor].getRegister;
327
328  /*
329   *  Reset everything and leave this port disabled.
330   */
331
332  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
333  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
334  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
335  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_BREAK );
336  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_STOP_BREAK );
337  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
338  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
339
340
341  (*setReg)( pMC68681_port, MC68681_MODE_REG_1A, 0x00 );
342  (*setReg)( pMC68681_port, MC68681_MODE_REG_2A, 0x02 );
343
344  /*
345   *  Disable interrupts on RX and TX for this port
346   */
347
348  mc68681_enable_interrupts( minor, MC68681_IMR_DISABLE_ALL );
349}
350
351/*
352 *  mc68681_open
353 *
354 *  This function opens a port for communication.
355 *
356 *  Default state is 9600 baud, 8 bits, No parity, and 1 stop bit.
357 */
358
359MC68681_STATIC int mc68681_open(
360  int      major,
361  int      minor,
362  void    *arg
363)
364{
365  unsigned32             pMC68681;
366  unsigned32             pMC68681_port;
367  unsigned int           baud;
368  unsigned int           acr;
369  unsigned int           vector;
370  unsigned int           command;
371  rtems_interrupt_level  Irql;
372  setRegister_f          setReg;
373
374  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
375  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
376  setReg        = Console_Port_Tbl[minor].setRegister;
377  vector        = Console_Port_Tbl[minor].ulIntVector;
378
379  /* XXX default baud rate should be from configuration table */
380
381  (void) mc68681_baud_rate( minor, B9600, &baud, &acr, &command );
382
383  /*
384   *  Set the DUART channel to a default useable state
385   */
386
387  rtems_interrupt_disable(Irql);
388    (*setReg)( pMC68681, MC68681_AUX_CTRL_REG, acr );
389    (*setReg)( pMC68681_port, MC68681_CLOCK_SELECT, baud );
390    if ( command ) {
391      (*setReg)( pMC68681_port, MC68681_COMMAND, command );         /* RX */
392      (*setReg)( pMC68681_port, MC68681_COMMAND, command | 0x20 );  /* TX */
393    }
394    (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_MR_PTR );
395    (*setReg)( pMC68681_port, MC68681_MODE, 0x13 );
396    (*setReg)( pMC68681_port, MC68681_MODE, 0x07 );
397  rtems_interrupt_enable(Irql);
398
399  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_TX );
400  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_ENABLE_RX );
401
402  (*setReg)( pMC68681, MC68681_INTERRUPT_VECTOR_REG, vector );
403
404  return RTEMS_SUCCESSFUL;
405}
406
407/*
408 *  mc68681_close
409 *
410 *  This function shuts down the requested port.
411 */
412
413MC68681_STATIC int mc68681_close(
414  int      major,
415  int      minor,
416  void    *arg
417)
418{
419  unsigned32      pMC68681;
420  unsigned32      pMC68681_port;
421  setRegister_f   setReg;
422
423  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
424  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
425  setReg        = Console_Port_Tbl[minor].setRegister;
426
427  /*
428   *  Disable interrupts from this channel and then disable it totally.
429   */
430
431  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_TX );
432  (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_DISABLE_RX );
433
434  return(RTEMS_SUCCESSFUL);
435}
436
437/*
438 *  mc68681_write_polled
439 *
440 *  This routine polls out the requested character.
441 */
442
443MC68681_STATIC void mc68681_write_polled(
444  int   minor, 
445  char  cChar
446)
447{
448  unsigned32              pMC68681_port;
449  unsigned char           ucLineStatus;
450  int                     iTimeout;
451  getRegister_f           getReg;
452  setRegister_f           setReg;
453
454  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
455  getReg        = Console_Port_Tbl[minor].getRegister;
456  setReg        = Console_Port_Tbl[minor].setRegister;
457
458  /*
459   * wait for transmitter holding register to be empty
460   */
461  iTimeout = 1000;
462  ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
463  while ((ucLineStatus & (MC68681_TX_READY|MC68681_TX_EMPTY)) == 0) {
464
465    if ((ucLineStatus & 0xF0))
466      (*setReg)( pMC68681_port, MC68681_COMMAND, MC68681_MODE_REG_RESET_ERROR );
467
468    /*
469     * Yield while we wait
470     */
471
472     if(_System_state_Is_up(_System_state_Get())) {
473       rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
474     }
475     ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
476     if(!--iTimeout) {
477       break;
478     }
479  }
480
481  /*
482   * transmit character
483   */
484
485  (*setReg)(pMC68681_port, MC68681_TX_BUFFER, cChar);
486}
487
488/*
489 *  mc68681_isr
490 *
491 *  This is the single interrupt entry point which parcels interrupts
492 *  out to the various ports.
493 */
494
495MC68681_STATIC rtems_isr mc68681_isr(
496  rtems_vector_number vector
497)
498{
499  int     minor;
500
501  for(minor=0 ; minor<Console_Port_Count ; minor++) {
502    if(Console_Port_Tbl[minor].ulIntVector == vector && 
503       Console_Port_Tbl[minor].deviceType == SERIAL_MC68681 ) {
504      mc68681_process(minor);
505    }
506  }
507}
508
509/*
510 *  mc68681_flush
511 *
512 *  This routine waits before all output is completed before closing
513 *  the requested port.
514 *
515 *  NOTE:  This is the "interrupt mode" close entry point.
516 */
517
518/* XXX remove me */
519MC68681_STATIC int mc68681_flush(int major, int minor, void *arg)
520{
521#if 0
522  while(!Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
523    /*
524     * Yield while we wait
525     */
526    if(_System_state_Is_up(_System_state_Get())) {
527      rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
528    }
529  }
530
531  mc68681_close(major, minor, arg);
532
533#endif
534  return(RTEMS_SUCCESSFUL);
535}
536
537/*
538 *  mc68681_initialize_interrupts
539 *
540 *  This routine initializes the console's receive and transmit
541 *  ring buffers and loads the appropriate vectors to handle the interrupts.
542 */
543
544MC68681_STATIC void mc68681_initialize_interrupts(int minor)
545{
546  mc68681_init(minor);
547
548  Console_Port_Data[minor].bActive = FALSE;
549
550  set_vector(mc68681_isr, Console_Port_Tbl[minor].ulIntVector, 1);
551
552  mc68681_enable_interrupts(minor,MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
553}
554
555/*
556 *  mc68681_write_support_int
557 *
558 *  Console Termios output entry point when using interrupt driven output.
559 */
560
561MC68681_STATIC int mc68681_write_support_int(
562  int         minor, 
563  const char *buf, 
564  int         len
565)
566{
567  unsigned32      Irql;
568  unsigned32      pMC68681_port;
569  setRegister_f   setReg;
570
571  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
572  setReg        = Console_Port_Tbl[minor].setRegister;
573
574  /*
575   *  We are using interrupt driven output and termios only sends us one character
576   *  at a time.
577   */
578
579  if ( !len )
580    return 0;
581
582  /*
583   * Wake up the device
584   */
585  rtems_interrupt_disable(Irql);
586    Console_Port_Data[minor].bActive = TRUE;
587    (*setReg)(pMC68681_port, MC68681_TX_BUFFER, *buf);
588    mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL);
589  rtems_interrupt_enable(Irql);
590  return 1;
591}
592
593/*
594 *  mc68681_write_support_polled
595 *
596 *  Console Termios output entry point when using polled output.
597 *
598 */
599
600MC68681_STATIC int mc68681_write_support_polled(
601  int         minor, 
602  const char *buf, 
603  int         len
604)
605{
606  int nwrite = 0;
607
608  /*
609   * poll each byte in the string out of the port.
610   */
611  while (nwrite < len) {
612    /*
613     * transmit character
614     */
615    mc68681_write_polled(minor, *buf++);
616    nwrite++;
617  }
618
619  /*
620   * return the number of bytes written.
621   */
622  return nwrite;
623}
624
625/*
626 *  mc68681_inbyte_nonblocking_polled
627 *
628 *  Console Termios polling input entry point.
629 */
630
631MC68681_STATIC int mc68681_inbyte_nonblocking_polled( 
632  int minor
633)
634{
635  unsigned32           pMC68681_port;
636  unsigned char        ucLineStatus;
637  unsigned char        cChar;
638  getRegister_f        getReg;
639
640  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
641  getReg        = Console_Port_Tbl[minor].getRegister;
642
643  ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
644  if(ucLineStatus & MC68681_RX_READY) {
645    cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
646    return (int)cChar;
647  } else {
648    return -1;
649  }
650}
651
652MC68681_STATIC int mc68681_baud_rate(
653  int           minor,
654  int           baud,
655  unsigned int *baud_mask_p,
656  unsigned int *acr_bit_p,
657  unsigned int *command
658)
659{
660  unsigned int     baud_mask;
661  unsigned int     acr_bit;
662  int              status;
663  int              is_extended;
664  int              baud_requested;
665  mc68681_baud_table_t  *baud_tbl;
666
667  baud_mask = 0;
668  acr_bit = 0;
669  status = 0;
670
671  if ( !(Console_Port_Tbl[minor].ulDataPort & MC68681_DATA_BAUD_RATE_SET_1) )
672    acr_bit = 1;
673
674  is_extended = 0;
675
676  switch (Console_Port_Tbl[minor].ulDataPort & MC68681_XBRG_MASK) {
677    case MC68681_XBRG_IGNORED:
678      *command = 0x00;
679      break;
680    case MC68681_XBRG_ENABLED:
681      *command = 0x80;
682      is_extended = 1;
683      break;
684    case MC68681_XBRG_DISABLED:
685      *command = 0x90;
686      break;
687  }
688
689  baud_requested = baud & CBAUD;
690  if (!baud_requested)
691    baud_requested = B9600;              /* default to 9600 baud */
692 
693  baud_requested = termios_baud_to_index( baud_requested );
694
695  baud_tbl = (mc68681_baud_table_t *) Console_Port_Tbl[minor].ulClock;
696  if (!baud_tbl)
697    baud_tbl = (mc68681_baud_table_t *)mc68681_baud_rate_table;
698
699  if ( is_extended )
700    baud_mask = (unsigned int)baud_tbl[ acr_bit + 2 ][ baud_requested ];
701  else
702    baud_mask = baud_tbl[ acr_bit ][ baud_requested ];
703
704  if ( baud_mask == MC68681_BAUD_NOT_VALID )
705    status = -1;
706
707  /*
708   *  upper nibble is receiver and lower nibble is transmitter
709   */
710
711  *baud_mask_p = (baud_mask << 4) | baud_mask;
712  *acr_bit_p   = acr_bit;
713  return status;
714}
715
716/*
717 *  mc68681_process
718 *
719 *  This routine is the per port console interrupt handler.
720 */
721
722MC68681_STATIC void mc68681_process(
723  int  minor
724)
725{
726  unsigned32              pMC68681;
727  unsigned32              pMC68681_port;
728  volatile unsigned8      ucLineStatus; 
729  char                    cChar;
730  getRegister_f           getReg;
731  setRegister_f           setReg;
732
733  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort1;
734  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort2;
735  getReg        = Console_Port_Tbl[minor].getRegister;
736  setReg        = Console_Port_Tbl[minor].setRegister;
737
738  /*
739   * Deal with any received characters
740   */
741  while(TRUE) {
742    ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
743    if(!(ucLineStatus & MC68681_RX_READY)) {
744      break;
745    }
746    /*
747     *  If there is a RX error, then dump all the data.
748     */
749    if ( ucLineStatus & MC68681_RX_ERRORS ) {
750      do {
751        cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
752        ucLineStatus = (*getReg)(pMC68681_port, MC68681_STATUS);
753      } while ( ucLineStatus & MC68681_RX_READY );
754      continue;
755    }
756    cChar = (*getReg)(pMC68681_port, MC68681_RX_BUFFER);
757    rtems_termios_enqueue_raw_characters( 
758      Console_Port_Data[minor].termios_data,
759      &cChar, 
760      1 
761    );
762  }
763
764  /*
765   *  Deal with the transmitter
766   */
767
768  ucLineStatus = (*getReg)(pMC68681, MC68681_INTERRUPT_STATUS_REG);
769  if (pMC68681 != pMC68681_port)
770    ucLineStatus >>= 4;
771
772  if(ucLineStatus & MC68681_IR_TX_READY) {
773    mc68681_enable_interrupts(minor, MC68681_IMR_ENABLE_ALL_EXCEPT_TX);
774    rtems_termios_dequeue_characters(Console_Port_Data[minor].termios_data, 1);
775  }
776
777}
778
779/*
780 *  mc68681_build_imr
781 *
782 *  This function returns the value for the interrupt mask register for this
783 *  DUART.  Since this is a shared register, we must look at the other port
784 *  on this chip to determine whether or not it is using interrupts.
785 */
786
787MC68681_STATIC unsigned int mc68681_build_imr(
788  int  minor,
789  int  enable_flag
790)
791{
792  int              mate;
793  int              is_a;
794  unsigned int     mask;
795  unsigned int     mate_mask;
796  unsigned int     pMC68681;
797  unsigned int     pMC68681_port;
798  mc68681_context *pmc68681Context;
799  mc68681_context *mateContext;
800 
801  pMC68681        = Console_Port_Tbl[minor].ulCtrlPort1;
802  pMC68681_port   = Console_Port_Tbl[minor].ulCtrlPort2;
803  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
804  mate            = pmc68681Context->mate;
805
806  mask = 0;
807  mate_mask = 0;
808
809  is_a = (pMC68681 == pMC68681_port);
810 
811  /*
812   *  If there is a mate for this port, get its IMR mask.
813   */
814
815  if ( mate != -1 ) {
816    mateContext = Console_Port_Data[mate].pDeviceContext;
817   
818    if (mateContext)
819      mate_mask = mateContext->imr;
820  }
821
822  /*
823   *  Calculate this port's IMR mask and save it in the context area.
824   */
825
826  if ( Console_Port_Tbl[minor].pDeviceFns->deviceOutputUsesInterrupts )
827    mask = enable_flag;
828
829  pmc68681Context->imr = mask;
830
831  /*
832   *  Now return the full IMR value
833   */
834
835  if (is_a)
836    return (mate_mask << 4) | mask;
837
838  return (mask << 4) | mate_mask;
839}
840
841/*
842 *  mc68681_enable_interrupts
843 *
844 *  This function initializes the hardware for this port to use interrupts.
845 */
846
847MC68681_STATIC void mc68681_enable_interrupts(
848  int minor,
849  int imr_mask
850)
851{
852  unsigned32            pMC68681;
853  setRegister_f         setReg;
854
855  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
856  setReg   = Console_Port_Tbl[minor].setRegister;
857
858  /*
859   *  Enable interrupts on RX and TX -- not break
860   */
861
862  (*setReg)(
863     pMC68681,
864     MC68681_INTERRUPT_MASK_REG,
865     mc68681_build_imr(minor, imr_mask)
866  );
867}
868
Note: See TracBrowser for help on using the repository browser.