source: rtems/c/src/libchip/serial/mc68681.c @ aa0da6b

4.104.114.84.95
Last change on this file since aa0da6b was cd58d82, checked in by Joel Sherrill <joel.sherrill@…>, on 06/22/98 at 09:28:03

Initial version of these files.

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