source: rtems/c/src/libchip/serial/mc68681.c @ 9eef52b

4.104.114.84.95
Last change on this file since 9eef52b was 7deeb16, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 22, 1998 at 11:49:38 AM

Added initial part of iniitialization.

  • Property mode set to 100644
File size: 15.2 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 "mc68681_p.h"
27#include "mc68681.h"
28
29/*
30 * Flow control is only supported when using interrupts
31 */
32
33console_flow mc68681_flow_RTSCTS =
34{
35  mc68681_negate_RTS,             /* deviceStopRemoteTx */
36  mc68681_assert_RTS              /* deviceStartRemoteTx */
37};
38
39console_flow mc68681_flow_DTRCTS =
40{
41  mc68681_negate_DTR,             /* deviceStopRemoteTx */
42  mc68681_assert_DTR              /* deviceStartRemoteTx */
43};
44
45console_fns mc68681_fns =
46{
47  mc68681_probe,                  /* deviceProbe */
48  mc68681_open,                   /* deviceFirstOpen */
49  mc68681_flush,                  /* deviceLastClose */
50  NULL,                           /* deviceRead */
51  mc68681_write_support_int,      /* deviceWrite */
52  mc68681_initialize_interrupts,  /* deviceInitialize */
53  mc68681_write_polled,           /* deviceWritePolled */
54  FALSE,                          /* deviceOutputUsesInterrupts */
55};
56
57console_fns mc68681_fns_polled =
58{
59  mc68681_probe,                       /* deviceProbe */
60  mc68681_open,                        /* deviceFirstOpen */
61  mc68681_close,                       /* deviceLastClose */
62  mc68681_inbyte_nonblocking_polled,   /* deviceRead */
63  mc68681_write_support_polled,        /* deviceWrite */
64  mc68681_init,                        /* deviceInitialize */
65  mc68681_write_polled,                /* deviceWritePolled */
66  FALSE,                               /* deviceOutputUsesInterrupts */
67};
68
69extern void set_vector( rtems_isr_entry, rtems_vector_number, int );
70
71/*
72 *  Console Device Driver Entry Points
73 */
74
75static boolean mc68681_probe(int minor)
76{
77  /*
78   * If the configuration dependent probe has located the device then
79   * assume it is there
80   */
81  return(TRUE);
82}
83
84static void mc68681_init(int minor)
85{
86/* XXX */
87  unsigned32              pMC68681_port;
88  unsigned32              pMC68681;
89  unsigned8               ucTrash;
90  unsigned8               ucDataByte;
91  unsigned32              ulBaudDivisor;
92  mc68681_context        *pmc68681Context;
93  setRegister_f           setReg;
94  getRegister_f           getReg;
95
96#if 1
97ulBaudDivisor = ucDataByte = ucTrash =  0;
98#endif
99  pmc68681Context = (mc68681_context *) malloc(sizeof(mc68681_context));
100
101  Console_Port_Data[minor].pDeviceContext = (void *)pmc68681Context;
102#if 0
103  pmc68681Context->ucModemCtrl = SP_MODEM_IRQ;
104#endif
105
106  pMC68681_port = Console_Port_Tbl[minor].ulCtrlPort1;
107  pMC68681      = Console_Port_Tbl[minor].ulCtrlPort2;
108  setReg        = Console_Port_Tbl[minor].setRegister;
109  getReg        = Console_Port_Tbl[minor].getRegister;
110
111
112  /*
113   *  Reset Receiver
114   */
115
116  (*setReg)( pMC68681, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
117  (*setReg)( pMC68681, MC68681_COMMAND, MC68681_MODE_REG_RESET_RX );
118
119  /*
120   *  Reset Transmitter
121   */
122
123  (*setReg)( pMC68681, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
124  (*setReg)( pMC68681, MC68681_COMMAND, MC68681_MODE_REG_RESET_TX );
125
126  (*setReg)( pMC68681, MC68681_MODE_REG_1A, 0x00 );
127  (*setReg)( pMC68681, MC68681_MODE_REG_2A, 0x02 );
128
129 
130#if 0
131  /* FOM NS16550 */
132  /* Clear the divisor latch, clear all interrupt enables,
133   * and reset and
134   * disable the FIFO's.
135   */
136
137  (*setReg)(pMC68681, MC68681_LINE_CONTROL, 0x0);
138  (*setReg)(pMC68681, MC68681_INTERRUPT_ENABLE, 0x0);
139
140  /* Set the divisor latch and set the baud rate. */
141
142  ulBaudDivisor=MC68681_Baud((unsigned32)Console_Port_Tbl[minor].pDeviceParams);
143  ucDataByte = SP_LINE_DLAB;
144  (*setReg)(pMC68681, MC68681_LINE_CONTROL, ucDataByte);
145  (*setReg)(pMC68681, MC68681_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
146  (*setReg)(pMC68681, MC68681_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
147
148  /* Clear the divisor latch and set the character size to eight bits */
149  /* with one stop bit and no parity checking. */
150  ucDataByte = EIGHT_BITS;
151  (*setReg)(pMC68681, MC68681_LINE_CONTROL, ucDataByte);
152
153  /* Enable and reset transmit and receive FIFOs. TJA     */
154  ucDataByte = SP_FIFO_ENABLE;
155  (*setReg)(pMC68681, MC68681_FIFO_CONTROL, ucDataByte);
156
157  ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
158  (*setReg)(pMC68681, MC68681_FIFO_CONTROL, ucDataByte);
159
160  /*
161   * Disable interrupts
162   */
163  ucDataByte = 0;
164  (*setReg)(pMC68681, MC68681_INTERRUPT_ENABLE, ucDataByte);
165
166  /* Set data terminal ready. */
167  /* And open interrupt tristate line */
168  (*setReg)(pMC68681, MC68681_MODEM_CONTROL,pmc68681Context->ucModemCtrl);
169
170  ucTrash = (*getReg)(pMC68681, MC68681_LINE_STATUS );
171  ucTrash = (*getReg)(pMC68681, MC68681_RECEIVE_BUFFER );
172#endif
173}
174
175static int mc68681_open(
176  int      major,
177  int      minor,
178  void    * arg
179)
180{
181/* XXX */
182  /*
183   * Assert DTR
184   */
185
186  if(Console_Port_Tbl[minor].pDeviceFlow != &mc68681_flow_DTRCTS) {
187    mc68681_assert_DTR(minor);
188  }
189
190  return(RTEMS_SUCCESSFUL);
191}
192
193static int mc68681_close(
194  int      major,
195  int      minor,
196  void    * arg
197)
198{
199/* XXX */
200  /*
201   * Negate DTR
202   */
203  if(Console_Port_Tbl[minor].pDeviceFlow != &mc68681_flow_DTRCTS) {
204    mc68681_negate_DTR(minor);
205  }
206
207  return(RTEMS_SUCCESSFUL);
208}
209
210/*
211 *  mc68681_write_polled
212 */
213
214static void mc68681_write_polled(
215  int   minor, 
216  char  cChar
217)
218{
219  unsigned32              pMC68681;
220  unsigned char           ucLineStatus;
221  int                     iTimeout;
222  getRegister_f           getReg;
223  setData_f               setData;
224
225  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
226  getReg   = Console_Port_Tbl[minor].getRegister;
227  setData  = Console_Port_Tbl[minor].setData;
228
229  /*
230   * wait for transmitter holding register to be empty
231   */
232  iTimeout = 1000;
233  ucLineStatus = (*getReg)(pMC68681, MC68681_STATUS);
234  while ((ucLineStatus & MC68681_TX_READY) == 0) {
235
236    /*
237     * Yield while we wait
238     */
239
240     if(_System_state_Is_up(_System_state_Get())) {
241       rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
242     }
243     ucLineStatus = (*getReg)(pMC68681, MC68681_STATUS);
244     if(!--iTimeout) {
245       break;
246     }
247  }
248
249  /*
250   * transmit character
251   */
252
253  (*setData)(pMC68681, cChar);
254}
255
256/*
257 * These routines provide control of the RTS and DTR lines
258 */
259
260/*
261 *  mc68681_assert_RTS
262 */
263
264static int mc68681_assert_RTS(int minor)
265{
266/* XXX */
267
268  unsigned32              pMC68681;
269  unsigned32              Irql;
270  mc68681_context        *pmc68681Context;
271  setRegister_f           setReg;
272
273
274  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
275
276  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
277  setReg   = Console_Port_Tbl[minor].setRegister;
278
279  /*
280   * Assert RTS
281   */
282  rtems_interrupt_disable(Irql);
283#if 0
284  pmc68681Context->ucModemCtrl |= SP_MODEM_RTS;
285  (*setReg)(pMC68681, MC68681_MODEM_CONTROL, pmc68681Context->ucModemCtrl);
286#endif
287  rtems_interrupt_enable(Irql);
288  return 0;
289}
290
291/*
292 *  mc68681_negate_RTS
293 */
294static int mc68681_negate_RTS(int minor)
295{
296/* XXX */
297  unsigned32              pMC68681;
298  unsigned32              Irql;
299  mc68681_context        *pmc68681Context;
300  setRegister_f           setReg;
301
302  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
303
304  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
305  setReg   = Console_Port_Tbl[minor].setRegister;
306
307  /*
308   * Negate RTS
309   */
310  rtems_interrupt_disable(Irql);
311#if 0
312  pmc68681Context->ucModemCtrl &= ~SP_MODEM_RTS;
313  (*setReg)(pMC68681, MC68681_MODEM_CONTROL, pmc68681Context->ucModemCtrl);
314#endif
315  rtems_interrupt_enable(Irql);
316  return 0;
317}
318
319/*
320 * These flow control routines utilise a connection from the local DTR
321 * line to the remote CTS line
322 */
323
324/*
325 *  mc68681_assert_DTR
326 */
327
328static int mc68681_assert_DTR(int minor)
329{
330/* XXX */
331  unsigned32              pMC68681;
332  unsigned32              Irql;
333  mc68681_context        *pmc68681Context;
334  setRegister_f           setReg;
335
336  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
337
338  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
339  setReg   = Console_Port_Tbl[minor].setRegister;
340
341  /*
342   * Assert DTR
343   */
344  rtems_interrupt_disable(Irql);
345#if 0
346  pmc68681Context->ucModemCtrl |= SP_MODEM_DTR;
347  (*setReg)(pMC68681, MC68681_MODEM_CONTROL, pmc68681Context->ucModemCtrl);
348#endif
349  rtems_interrupt_enable(Irql);
350  return 0;
351}
352
353/*
354 *  mc68681_negate_DTR
355 */
356
357static int mc68681_negate_DTR(int minor)
358{
359/* XXX */
360  unsigned32              pMC68681;
361  unsigned32              Irql;
362  mc68681_context        *pmc68681Context;
363  setRegister_f           setReg;
364
365  pmc68681Context = (mc68681_context *) Console_Port_Data[minor].pDeviceContext;
366
367  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
368  setReg   = Console_Port_Tbl[minor].setRegister;
369
370  /*
371   * Negate DTR
372   */
373  rtems_interrupt_disable(Irql);
374#if 0
375  pmc68681Context->ucModemCtrl &= ~SP_MODEM_DTR;
376  (*setReg)(pMC68681, MC68681_MODEM_CONTROL,pmc68681Context->ucModemCtrl);
377#endif
378  rtems_interrupt_enable(Irql);
379  return 0;
380}
381
382/*
383 *  mc68681_isr
384 *
385 *  This routine is the console interrupt handler.
386 *
387 *  Input parameters:
388 *    vector - vector number
389 *
390 *  Output parameters: NONE
391 *
392 *  Return values:     NONE
393 */
394
395static void mc68681_process(
396        int             minor
397)
398{
399/* XXX */
400  unsigned32              pMC68681;
401  volatile unsigned8      ucLineStatus; 
402  volatile unsigned8      ucInterruptId;
403  char                    cChar;
404  getRegister_f           getReg;
405  setRegister_f           setReg;
406
407#if 1
408cChar = ucInterruptId = ucLineStatus = 0;
409#endif
410  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
411  getReg   = Console_Port_Tbl[minor].getRegister;
412  setReg   = Console_Port_Tbl[minor].setRegister;
413
414#if 0
415  do {
416    /*
417     * Deal with any received characters
418     */
419    while(TRUE) {
420      ucLineStatus = (*getReg)(pMC68681, MC68681_LINE_STATUS);
421      if(~ucLineStatus & SP_LSR_RDY) {
422        break;
423      }
424      cChar = (*getReg)(pMC68681, MC68681_RECEIVE_BUFFER);
425      rtems_termios_enqueue_raw_characters(
426        Console_Port_Data[minor].termios_data,
427        &cChar,
428        1
429      );
430    }
431
432    while(TRUE) {
433      if(Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
434        Console_Port_Data[minor].bActive = FALSE;
435        if(Console_Port_Tbl[minor].pDeviceFlow != &mc68681_flow_RTSCTS) {
436          mc68681_negate_RTS(minor);
437        }
438
439        /*
440         * There is no data to transmit
441         */
442        break;
443      }
444
445      ucLineStatus = (*getReg)(pMC68681, MC68681_LINE_STATUS);
446      if(~ucLineStatus & SP_LSR_THOLD) {
447        /*
448         * We'll get another interrupt when
449         * the transmitter holding reg. becomes
450         * free again
451         */
452        break;
453      }
454
455      Ring_buffer_Remove_character( &Console_Port_Data[minor].TxBuffer, cChar);
456      /*
457       * transmit character
458       */
459      (*setReg)(pMC68681, MC68681_TRANSMIT_BUFFER, cChar);
460    }
461
462    ucInterruptId = (*getReg)(pMC68681, MC68681_INTERRUPT_ID);
463  }
464  while((ucInterruptId&0xf) != 0x1);
465#endif
466}
467
468static rtems_isr mc68681_isr(
469  rtems_vector_number vector
470)
471{
472  int     minor;
473
474  for(minor=0 ; minor<Console_Port_Count ; minor++) {
475    if(vector == Console_Port_Tbl[minor].ulIntVector) {
476      mc68681_process(minor);
477    }
478  }
479}
480
481/*
482 *  mc68681_flush
483 */
484
485static int mc68681_flush(int major, int minor, void *arg)
486{
487  while(!Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer)) {
488    /*
489     * Yield while we wait
490     */
491    if(_System_state_Is_up(_System_state_Get())) {
492      rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
493    }
494  }
495
496  mc68681_close(major, minor, arg);
497
498  return(RTEMS_SUCCESSFUL);
499}
500
501/*
502 *  mc68681_initialize_interrupts
503 *
504 *  This routine initializes the console's receive and transmit
505 *  ring buffers and loads the appropriate vectors to handle the interrupts.
506 *
507 *  Input parameters:  NONE
508 *
509 *  Output parameters: NONE
510 *
511 *  Return values:     NONE
512 */
513
514static void mc68681_enable_interrupts(
515  int minor
516)
517{
518/* XXX */
519  unsigned32            pMC68681;
520  unsigned8             ucDataByte;
521  setRegister_f         setReg;
522
523#if 1
524ucDataByte = 0;
525#endif
526  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
527  setReg   = Console_Port_Tbl[minor].setRegister;
528
529#if 0
530  /*
531   * Enable interrupts
532   */
533  ucDataByte = SP_INT_RX_ENABLE | SP_INT_TX_ENABLE;
534  (*setReg)(pMC68681, MC68681_INTERRUPT_ENABLE, ucDataByte);
535#endif
536}
537
538static void mc68681_initialize_interrupts(int minor)
539{
540  mc68681_init(minor);
541
542  Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer);
543
544  Console_Port_Data[minor].bActive = FALSE;
545
546  set_vector(mc68681_isr, Console_Port_Tbl[minor].ulIntVector, 1);
547
548  mc68681_enable_interrupts(minor);
549}
550
551/*
552 *  mc68681_write_support_int
553 *
554 *  Console Termios output entry point.
555 */
556
557static int mc68681_write_support_int(
558  int   minor, 
559  const char *buf, 
560  int   len
561)
562{
563  int i;
564  unsigned32 Irql;
565
566  for(i=0 ; i<len ;) {
567    if(Ring_buffer_Is_full(&Console_Port_Data[minor].TxBuffer)) {
568      if(!Console_Port_Data[minor].bActive) {
569        /*
570         * Wake up the device
571         */
572        rtems_interrupt_disable(Irql);
573        Console_Port_Data[minor].bActive = TRUE;
574        if(Console_Port_Tbl[minor].pDeviceFlow != &mc68681_flow_RTSCTS) {
575          mc68681_assert_RTS(minor);
576        }
577        mc68681_process(minor);
578        rtems_interrupt_enable(Irql);
579      } else {
580        /*
581         * Yield
582         */
583        rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
584      }
585
586      /*
587       * Wait for ring buffer to empty
588       */
589      continue;
590    }
591    else {
592      Ring_buffer_Add_character( &Console_Port_Data[minor].TxBuffer, buf[i]);
593      i++;
594    }
595  }
596
597  /*
598   * Ensure that characters are on the way
599   */
600
601  if(!Console_Port_Data[minor].bActive) {
602    /*
603     * Wake up the device
604     */
605    rtems_interrupt_disable(Irql);
606    Console_Port_Data[minor].bActive = TRUE;
607    if(Console_Port_Tbl[minor].pDeviceFlow != &mc68681_flow_RTSCTS) {
608      mc68681_assert_RTS(minor);
609    }
610    mc68681_process(minor);
611    rtems_interrupt_enable(Irql);
612  }
613
614  return (len);
615}
616
617/*
618 *  mc68681_write_support_polled
619 *
620 *  Console Termios output entry point.
621 *
622 */
623
624static int mc68681_write_support_polled(
625  int         minor, 
626  const char *buf, 
627  int         len
628)
629{
630  int nwrite = 0;
631
632  /*
633   * poll each byte in the string out of the port.
634   */
635  while (nwrite < len) {
636    /*
637     * transmit character
638     */
639    mc68681_write_polled(minor, *buf++);
640    nwrite++;
641  }
642
643  /*
644   * return the number of bytes written.
645   */
646  return nwrite;
647}
648
649/*
650 *  mc68681_inbyte_nonblocking_polled
651 *
652 *  Console Termios polling input entry point.
653 */
654
655static int mc68681_inbyte_nonblocking_polled( 
656  int minor
657)
658{
659  unsigned32           pMC68681;
660  unsigned char        ucLineStatus;
661  char                 cChar;
662  getRegister_f        getReg;
663  getData_f            getData;
664
665  pMC68681 = Console_Port_Tbl[minor].ulCtrlPort1;
666  getReg   = Console_Port_Tbl[minor].getRegister;
667  getData  = Console_Port_Tbl[minor].getData;
668
669  ucLineStatus = (*getReg)(pMC68681, MC68681_STATUS);
670  if(ucLineStatus & MC68681_RX_READY) {
671    cChar = (*getData)(pMC68681);
672    return (int)cChar;
673  } else {
674    return(-1);
675  }
676}
Note: See TracBrowser for help on using the repository browser.