source: rtems/c/src/lib/libbsp/powerpc/ppcn_60x/console/ns16550.c @ 0c04c377

4.104.114.84.95
Last change on this file since 0c04c377 was 0c04c377, checked in by Joel Sherrill <joel.sherrill@…>, on 02/18/99 at 16:48:14

./clock/Makefile.in,v
./clock/clock.c,v
./console/Makefile.in,v
./console/config.c,v
./console/console.c,v
./console/console.h,v
./console/debugio.c,v
./console/i8042.c,v
./console/i8042_p.h,v
./console/i8042vga.c,v
./console/i8042vga.h,v
./console/ns16550.c,v
./console/ns16550.h,v
./console/ns16550_p.h,v
./console/ns16550cfg.c,v
./console/ns16550cfg.h,v
./console/vga.c,v
./console/vga_p.h,v
./console/z85c30.c,v
./console/z85c30.h,v
./console/z85c30_p.h,v
./console/z85c30cfg.c,v
./console/z85c30cfg.h,v
./include/Makefile.in,v
./include/bsp.h,v
./include/chain.h,v
./include/coverhd.h,v
./include/extisrdrv.h,v
./include/nvram.h,v
./include/pci.h,v
./include/tod.h,v
./network/Makefile.in,v
./network/amd79c970.c,v
./network/amd79c970.h,v
./nvram/Makefile.in,v
./nvram/ds1385.h,v
./nvram/mk48t18.h,v
./nvram/nvram.c,v
./nvram/prepnvr.h,v
./nvram/stk11c68.h,v
./pci/Makefile.in,v
./pci/pci.c,v
./start/Makefile.in,v
./start/start.s,v
./startup/Makefile.in,v
./startup/bspclean.c,v
./startup/bspstart.c,v
./startup/bsptrap.s,v
./startup/device-tree,v
./startup/genpvec.c,v
./startup/linkcmds,v
./startup/rtems-ctor.cc,v
./startup/sbrk.c,v
./startup/setvec.c,v
./startup/spurious.c,v
./startup/swap.c,v
./timer/Makefile.in,v
./timer/timer.c,v
./tod/Makefile.in,v
./tod/cmos.h,v
./tod/tod.c,v
./universe/Makefile.in,v
./universe/universe.c,v
./vectors/Makefile.in,v
./vectors/README,v
./vectors/align_h.s,v
./vectors/vectors.s,v
./wrapup/Makefile.in,v
./Makefile.in,v
./README,v
./STATUS,v
./bsp_specs,v

  • Property mode set to 100644
File size: 13.1 KB
Line 
1/*
2 *  This file contains the TTY driver for the NS16550
3 *
4 *  COPYRIGHT (c) 1998 by Radstone Technology
5 *
6 *
7 * THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
8 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
9 * IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
10 * AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
11 *
12 * You are hereby granted permission to use, copy, modify, and distribute
13 * this file, provided that this notice, plus the above copyright notice
14 * and disclaimer, appears in all copies. Radstone Technology will provide
15 * no support for this code.
16 *
17 *  This driver uses the termios pseudo driver.
18 */
19
20#include <rtems.h>
21#include <bsp.h>
22#include <rtems/libio.h>
23#include <stdlib.h>
24
25#include "console.h"
26#include "ns16550_p.h"
27
28/*
29 * Flow control is only supported when using interrupts
30 */
31console_flow ns16550_flow_RTSCTS =
32{
33        ns16550_negate_RTS,             /* deviceStopRemoteTx */
34        ns16550_assert_RTS              /* deviceStartRemoteTx */
35};
36
37console_flow ns16550_flow_DTRCTS =
38{
39        ns16550_negate_DTR,             /* deviceStopRemoteTx */
40        ns16550_assert_DTR              /* deviceStartRemoteTx */
41};
42
43console_fns ns16550_fns =
44{
45        ns16550_probe,                  /* deviceProbe */
46        ns16550_open,                   /* deviceFirstOpen */
47        ns16550_flush,                  /* deviceLastClose */
48        NULL,                           /* deviceRead */
49        ns16550_write_support_int,      /* deviceWrite */
50        ns16550_initialize_interrupts,  /* deviceInitialize */
51        ns16550_write_polled,           /* deviceWritePolled */
52        FALSE,                          /* deviceOutputUsesInterrupts */
53};
54
55console_fns ns16550_fns_polled =
56{
57        ns16550_probe,                  /* deviceProbe */
58        ns16550_open,                   /* deviceFirstOpen */
59        ns16550_close,                  /* deviceLastClose */
60        ns16550_inbyte_nonblocking_polled,      /* deviceRead */
61        ns16550_write_support_polled,   /* deviceWrite */
62        ns16550_init,                   /* deviceInitialize */
63        ns16550_write_polled,           /* deviceWritePolled */
64        FALSE,                          /* deviceOutputUsesInterrupts */
65};
66
67/*
68 *  Console Device Driver Entry Points
69 */
70static boolean ns16550_probe(int minor)
71{
72        /*
73         * If the configuration dependant probe has located the device then
74         * assume it is there
75         */
76        return(TRUE);
77}
78
79static void ns16550_init(int minor)
80{
81        PSP_READ_REGISTERS      pNS16550Read;
82        PSP_WRITE_REGISTERS     pNS16550Write;
83        unsigned8               ucTrash;
84        unsigned8               ucDataByte;
85        unsigned32              ulBaudDivisor;
86        ns16550_context         *pns16550Context;
87
88        pns16550Context=(ns16550_context *)malloc(sizeof(ns16550_context));
89
90        Console_Port_Data[minor].pDeviceContext=(void *)pns16550Context;
91        pns16550Context->ucModemCtrl=SP_MODEM_IRQ;
92
93        pNS16550Read=(PSP_READ_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
94        pNS16550Write=(PSP_WRITE_REGISTERS)pNS16550Read;
95
96        /* Clear the divisor latch, clear all interrupt enables,
97         * and reset and
98         * disable the FIFO's.
99         */
100
101        outport_byte(&pNS16550Write->LineControl, 0x0);
102        outport_byte(&pNS16550Write->InterruptEnable, 0x0);
103
104        /* Set the divisor latch and set the baud rate. */
105
106        ulBaudDivisor=NS16550_Baud(
107                (unsigned32)Console_Port_Tbl[minor].pDeviceParams);
108        ucDataByte = SP_LINE_DLAB;
109        outport_byte(&pNS16550Write->LineControl, ucDataByte);
110        outport_byte(&pNS16550Write->TransmitBuffer, ulBaudDivisor&0xff);
111        outport_byte(&pNS16550Write->InterruptEnable, (ulBaudDivisor>>8)&0xff);
112
113        /* Clear the divisor latch and set the character size to eight bits */
114        /* with one stop bit and no parity checking. */
115
116        ucDataByte = EIGHT_BITS;
117        outport_byte(&pNS16550Write->LineControl, ucDataByte);
118
119        /* Enable and reset transmit and receive FIFOs. TJA     */
120        ucDataByte = SP_FIFO_ENABLE;
121        outport_byte(&pNS16550Write->FifoControl, ucDataByte);
122
123        ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
124        outport_byte(&pNS16550Write->FifoControl, ucDataByte);
125
126        /*
127         * Disable interrupts
128         */
129        ucDataByte = 0;
130        outport_byte(&pNS16550Write->InterruptEnable, ucDataByte);
131
132        /* Set data terminal ready. */
133        /* And open interrupt tristate line */
134
135        outport_byte(&pNS16550Write->ModemControl,
136                     pns16550Context->ucModemCtrl);
137
138        inport_byte(&pNS16550Read->LineStatus, ucTrash);
139        inport_byte(&pNS16550Read->ReceiveBuffer, ucTrash);
140}
141
142static int ns16550_open(
143        int      major,
144        int      minor,
145        void    * arg
146)
147{
148        PSP_WRITE_REGISTERS     pNS16550Write;
149
150        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
151
152        /*
153         * Assert DTR
154         */
155        if(Console_Port_Tbl[minor].pDeviceFlow
156           !=&ns16550_flow_DTRCTS)
157        {
158                ns16550_assert_DTR(minor);
159        }
160
161        return(RTEMS_SUCCESSFUL);
162}
163
164static int ns16550_close(
165        int      major,
166        int      minor,
167        void    * arg
168)
169{
170        PSP_WRITE_REGISTERS     pNS16550Write;
171
172        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
173
174        /*
175         * Negate DTR
176         */
177        if(Console_Port_Tbl[minor].pDeviceFlow
178           !=&ns16550_flow_DTRCTS)
179        {
180                ns16550_negate_DTR(minor);
181        }
182
183        return(RTEMS_SUCCESSFUL);
184}
185
186/*
187 *  ns16550_write_polled
188 */
189static void ns16550_write_polled(
190        int   minor,
191        char  cChar
192)
193{
194        PSP_READ_REGISTERS      pNS16550Read;
195        PSP_WRITE_REGISTERS     pNS16550Write;
196        unsigned char   ucLineStatus;
197        int iTimeout;
198
199        pNS16550Read=(PSP_READ_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
200        pNS16550Write=(PSP_WRITE_REGISTERS)pNS16550Read;
201
202        /*
203         * wait for transmitter holding register to be empty
204         */
205        iTimeout=1000;
206        inport_byte(&pNS16550Read->LineStatus, ucLineStatus);
207        while ((ucLineStatus & SP_LSR_THOLD) == 0)
208        {
209                /*
210                 * Yield while we wait
211                 */
212                if(_System_state_Is_up(_System_state_Get()))
213                {
214                        rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
215                }
216                inport_byte(&pNS16550Read->LineStatus, ucLineStatus);
217                if(!--iTimeout)
218                {
219                        break;
220                }
221        }
222
223        /*
224         * transmit character
225         */
226        outport_byte(&pNS16550Write->TransmitBuffer, cChar);
227}
228
229/*
230 * These routines provide control of the RTS and DTR lines
231 */
232/*
233 *  ns16550_assert_RTS
234 */
235static void ns16550_assert_RTS(int minor)
236{
237        PSP_WRITE_REGISTERS     pNS16550Write;
238        unsigned32 Irql;
239        ns16550_context *pns16550Context;
240
241        pns16550Context=(ns16550_context *)
242                       Console_Port_Data[minor].pDeviceContext;
243
244        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
245
246        /*
247         * Assert RTS
248         */
249        rtems_interrupt_disable(Irql);
250        pns16550Context->ucModemCtrl|=SP_MODEM_RTS;
251        outport_byte(&pNS16550Write->ModemControl,
252                     pns16550Context->ucModemCtrl);
253        rtems_interrupt_enable(Irql);
254}
255
256/*
257 *  ns16550_negate_RTS
258 */
259static void ns16550_negate_RTS(int minor)
260{
261        PSP_WRITE_REGISTERS     pNS16550Write;
262        unsigned32 Irql;
263        ns16550_context *pns16550Context;
264
265        pns16550Context=(ns16550_context *)
266                       Console_Port_Data[minor].pDeviceContext;
267
268        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
269
270        /*
271         * Negate RTS
272         */
273        rtems_interrupt_disable(Irql);
274        pns16550Context->ucModemCtrl&=~SP_MODEM_RTS;
275        outport_byte(&pNS16550Write->ModemControl,
276                     pns16550Context->ucModemCtrl);
277        rtems_interrupt_enable(Irql);
278}
279
280/*
281 * These flow control routines utilise a connection from the local DTR
282 * line to the remote CTS line
283 */
284/*
285 *  ns16550_assert_DTR
286 */
287static void ns16550_assert_DTR(int minor)
288{
289        PSP_WRITE_REGISTERS     pNS16550Write;
290        unsigned32 Irql;
291        ns16550_context *pns16550Context;
292
293        pns16550Context=(ns16550_context *)
294                       Console_Port_Data[minor].pDeviceContext;
295
296        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
297
298        /*
299         * Assert DTR
300         */
301        rtems_interrupt_disable(Irql);
302        pns16550Context->ucModemCtrl|=SP_MODEM_DTR;
303        outport_byte(&pNS16550Write->ModemControl,
304                     pns16550Context->ucModemCtrl);
305        rtems_interrupt_enable(Irql);
306}
307
308/*
309 *  ns16550_negate_DTR
310 */
311static void ns16550_negate_DTR(int minor)
312{
313        PSP_WRITE_REGISTERS     pNS16550Write;
314        unsigned32 Irql;
315        ns16550_context *pns16550Context;
316
317        pns16550Context=(ns16550_context *)
318                       Console_Port_Data[minor].pDeviceContext;
319
320        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
321
322        /*
323         * Negate DTR
324         */
325        rtems_interrupt_disable(Irql);
326        pns16550Context->ucModemCtrl&=~SP_MODEM_DTR;
327        outport_byte(&pNS16550Write->ModemControl,
328                     pns16550Context->ucModemCtrl);
329        rtems_interrupt_enable(Irql);
330}
331
332/*
333 *  ns16550_isr
334 *
335 *  This routine is the console interrupt handler for COM1 and COM2
336 *
337 *  Input parameters:
338 *    vector - vector number
339 *
340 *  Output parameters: NONE
341 *
342 *  Return values:     NONE
343 */
344
345static void ns16550_process(
346        int             minor
347)
348{
349        PSP_READ_REGISTERS      pNS16550Read;
350        PSP_WRITE_REGISTERS     pNS16550Write;
351        volatile unsigned8 ucLineStatus, ucInterruptId;
352        char    cChar;
353
354        pNS16550Read=(PSP_READ_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
355        pNS16550Write=(PSP_WRITE_REGISTERS)pNS16550Read;
356
357        do
358        {
359                /*
360                 * Deal with any received characters
361                 */
362                while(TRUE)
363                {
364                        inport_byte(&pNS16550Read->LineStatus, ucLineStatus);
365                        if(~ucLineStatus & SP_LSR_RDY)
366                        {
367                                break;
368                        }
369                        inport_byte(&pNS16550Read->ReceiveBuffer, cChar);
370                        rtems_termios_enqueue_raw_characters(
371                                Console_Port_Data[minor].termios_data,
372                                &cChar, 1 );
373                }
374
375                while(TRUE)
376                {
377                        if(Ring_buffer_Is_empty(
378                                &Console_Port_Data[minor].TxBuffer))
379                        {
380                                Console_Port_Data[minor].bActive=FALSE;
381                                if(Console_Port_Tbl[minor].pDeviceFlow
382                                   !=&ns16550_flow_RTSCTS)
383                                {
384                                        ns16550_negate_RTS(minor);
385                                }
386                                /*
387                                 * There is no data to transmit
388                                 */
389                                break;
390                        }
391
392                        inport_byte(&pNS16550Read->LineStatus, ucLineStatus);
393                        if(~ucLineStatus & SP_LSR_THOLD)
394                        {
395                                /*
396                                 * We'll get another interrupt when
397                                 * the transmitter holding reg. becomes
398                                 * free again
399                                 */
400                                break;
401                        }
402
403                        Ring_buffer_Remove_character(
404                                &Console_Port_Data[minor].TxBuffer,
405                                cChar);
406                        /*
407                         * transmit character
408                         */
409                        outport_byte(&pNS16550Write->TransmitBuffer, cChar);
410                }
411
412                inport_byte(&pNS16550Read->InterruptId, ucInterruptId);
413        }
414        while((ucInterruptId&0xf)!=0x1);
415}
416
417static rtems_isr ns16550_isr(
418  rtems_vector_number vector
419)
420{
421        int     minor;
422
423        for(minor=0;minor<Console_Port_Count;minor++)
424        {
425                if(vector==Console_Port_Tbl[minor].ulIntVector)
426                {
427                        ns16550_process(minor);
428                }
429        }
430}
431
432/*
433 *  ns16550_flush
434 */
435static int ns16550_flush(int major, int minor, void *arg)
436{
437        while(!Ring_buffer_Is_empty(&Console_Port_Data[minor].TxBuffer))
438        {
439                /*
440                 * Yield while we wait
441                 */
442                if(_System_state_Is_up(_System_state_Get()))
443                {
444                        rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
445                }
446        }
447
448        ns16550_close(major, minor, arg);
449
450        return(RTEMS_SUCCESSFUL);
451}
452
453/*
454 *  ns16550_initialize_interrupts
455 *
456 *  This routine initializes the console's receive and transmit
457 *  ring buffers and loads the appropriate vectors to handle the interrupts.
458 *
459 *  Input parameters:  NONE
460 *
461 *  Output parameters: NONE
462 *
463 *  Return values:     NONE
464 */
465
466static void ns16550_enable_interrupts(
467        int minor
468)
469{
470        PSP_WRITE_REGISTERS     pNS16550Write;
471        unsigned8       ucDataByte;
472
473        pNS16550Write=(PSP_WRITE_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
474
475        /*
476         * Enable interrupts
477         */
478        ucDataByte = SP_INT_RX_ENABLE | SP_INT_TX_ENABLE;
479        outport_byte(&pNS16550Write->InterruptEnable, ucDataByte);
480
481}
482
483static void ns16550_initialize_interrupts(int minor)
484{
485        ns16550_init(minor);
486
487        Ring_buffer_Initialize(&Console_Port_Data[minor].TxBuffer);
488
489        Console_Port_Data[minor].bActive = FALSE;
490
491        set_vector(ns16550_isr,
492                   Console_Port_Tbl[minor].ulIntVector,
493                   1);
494
495        ns16550_enable_interrupts(minor);
496}
497
498/*
499 *  ns16550_write_support_int
500 *
501 *  Console Termios output entry point.
502 *
503 */
504static int ns16550_write_support_int(
505  int   minor,
506  const char *buf,
507  int   len)
508{
509        int i;
510        unsigned32 Irql;
511
512        for(i=0; i<len;)
513        {
514                if(Ring_buffer_Is_full(&Console_Port_Data[minor].TxBuffer))
515                {
516                        if(!Console_Port_Data[minor].bActive)
517                        {
518                                /*
519                                 * Wake up the device
520                                 */
521                                rtems_interrupt_disable(Irql);
522                                Console_Port_Data[minor].bActive = TRUE;
523                                if(Console_Port_Tbl[minor].pDeviceFlow
524                                   !=&ns16550_flow_RTSCTS)
525                                {
526                                        ns16550_assert_RTS(minor);
527                                }
528                                ns16550_process(minor);
529                                rtems_interrupt_enable(Irql);
530                        }
531                        else
532                        {
533                                /*
534                                 * Yield
535                                 */
536                                rtems_task_wake_after(RTEMS_YIELD_PROCESSOR);
537                        }
538
539                        /*
540                         * Wait for ring buffer to empty
541                         */
542                        continue;
543                }
544                else
545                {
546                        Ring_buffer_Add_character(
547                                &Console_Port_Data[minor].TxBuffer,
548                                buf[i]);
549                        i++;
550                }
551        }
552
553        /*
554         * Ensure that characters are on the way
555         */
556        if(!Console_Port_Data[minor].bActive)
557        {
558                /*
559                 * Wake up the device
560                 */
561                rtems_interrupt_disable(Irql);
562                Console_Port_Data[minor].bActive = TRUE;
563                if(Console_Port_Tbl[minor].pDeviceFlow
564                   !=&ns16550_flow_RTSCTS)
565                {
566                        ns16550_assert_RTS(minor);
567                }
568                ns16550_process(minor);
569                rtems_interrupt_enable(Irql);
570        }
571
572        return (len);
573}
574
575/*
576 *  ns16550_write_support_polled
577 *
578 *  Console Termios output entry point.
579 *
580 */
581static int ns16550_write_support_polled(
582  int   minor,
583  const char *buf,
584  int   len)
585{
586        int nwrite = 0;
587
588        /*
589         * poll each byte in the string out of the port.
590         */
591        while (nwrite < len)
592        {
593                /*
594                 * transmit character
595                 */
596                ns16550_write_polled(minor, *buf++);
597                nwrite++;
598        }
599
600        /*
601         * return the number of bytes written.
602         */
603        return nwrite;
604}
605
606/*
607 *  ns16550_inbyte_nonblocking_polled
608 *
609 *  Console Termios polling input entry point.
610 */
611
612static int ns16550_inbyte_nonblocking_polled(
613        int minor
614)
615{
616        PSP_READ_REGISTERS      pNS16550Read;
617        unsigned char   ucLineStatus;
618        char    cChar;
619
620        pNS16550Read=(PSP_READ_REGISTERS)Console_Port_Tbl[minor].ulCtrlPort1;
621
622        inport_byte(&pNS16550Read->LineStatus, ucLineStatus);
623        if(ucLineStatus & SP_LSR_RDY)
624        {
625                inport_byte(&pNS16550Read->ReceiveBuffer, cChar);
626                return((int)cChar);
627        }
628        else
629        {
630        return(-1);
631        }
632}
Note: See TracBrowser for help on using the repository browser.