source: rtems/c/src/libchip/serial/ns16550.c @ c8bd3cd

4.115
Last change on this file since c8bd3cd was c8bd3cd, checked in by Sebastian Huber <sebastian.huber@…>, on 02/08/13 at 12:39:59

libchip/serial: Add const qualifier

  • Property mode set to 100644
File size: 20.0 KB
Line 
1/**
2 *  @file
3 * 
4 *  This file contains the TTY driver for the National Semiconductor NS16550.
5 *
6 *  This part is widely cloned and second sourced.  It is found in a number
7 *  of "Super IO" controllers.
8 *
9 *  This driver uses the termios pseudo driver.
10 */
11
12/*
13 *  COPYRIGHT (c) 1998 by Radstone Technology
14 *
15 *  THIS FILE IS PROVIDED TO YOU, THE USER, "AS IS", WITHOUT WARRANTY OF ANY
16 *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
17 *  IMPLIED WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
18 *  AS TO THE QUALITY AND PERFORMANCE OF ALL CODE IN THIS FILE IS WITH YOU.
19 *
20 *  You are hereby granted permission to use, copy, modify, and distribute
21 *  this file, provided that this notice, plus the above copyright notice
22 *  and disclaimer, appears in all copies. Radstone Technology will provide
23 *  no support for this code.
24 *
25 *  COPYRIGHT (c) 1989-2012.
26 *  On-Line Applications Research Corporation (OAR).
27 *
28 *  The license and distribution terms for this file may be
29 *  found in the file LICENSE in this distribution or at
30 *  http://www.rtems.com/license/LICENSE.
31 */
32
33#include <stdlib.h>
34
35#include <rtems.h>
36#include <rtems/libio.h>
37#include <rtems/ringbuf.h>
38#include <rtems/bspIo.h>
39#include <rtems/termiostypes.h>
40
41#include <libchip/serial.h>
42#include <libchip/sersupp.h>
43
44#include <bsp.h>
45
46#include "ns16550_p.h"
47#include "ns16550.h"
48
49#if defined(BSP_FEATURE_IRQ_EXTENSION)
50  #include <bsp/irq.h>
51#elif defined(BSP_FEATURE_IRQ_LEGACY)
52  #include <bsp/irq.h>
53#elif defined(__PPC__) || defined(__i386__)
54  #include <bsp/irq.h>
55  #define BSP_FEATURE_IRQ_LEGACY
56  #ifdef BSP_SHARED_HANDLER_SUPPORT
57    #define BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
58  #endif
59#endif
60
61/*
62 * Flow control is only supported when using interrupts
63 */
64
65const console_flow ns16550_flow_RTSCTS = {
66  ns16550_negate_RTS,             /* deviceStopRemoteTx */
67  ns16550_assert_RTS              /* deviceStartRemoteTx */
68};
69
70const console_flow ns16550_flow_DTRCTS = {
71  ns16550_negate_DTR,             /* deviceStopRemoteTx */
72  ns16550_assert_DTR              /* deviceStartRemoteTx */
73};
74
75const console_fns ns16550_fns = {
76  libchip_serial_default_probe,   /* deviceProbe */
77  ns16550_open,                   /* deviceFirstOpen */
78  ns16550_close,                  /* deviceLastClose */
79  NULL,                           /* deviceRead */
80  ns16550_write_support_int,      /* deviceWrite */
81  ns16550_init,                   /* deviceInitialize */
82  ns16550_write_polled,           /* deviceWritePolled */
83  ns16550_set_attributes,         /* deviceSetAttributes */
84  true                            /* deviceOutputUsesInterrupts */
85};
86
87const console_fns ns16550_fns_polled = {
88  libchip_serial_default_probe,        /* deviceProbe */
89  ns16550_open,                        /* deviceFirstOpen */
90  ns16550_close,                       /* deviceLastClose */
91  ns16550_inbyte_nonblocking_polled,   /* deviceRead */
92  ns16550_write_support_polled,        /* deviceWrite */
93  ns16550_init,                        /* deviceInitialize */
94  ns16550_write_polled,                /* deviceWritePolled */
95  ns16550_set_attributes,              /* deviceSetAttributes */
96  false                                /* deviceOutputUsesInterrupts */
97};
98
99static uint32_t NS16550_GetBaudDivisor(const console_tbl *c, uint32_t baud)
100{
101  uint32_t clock = c->ulClock;
102  uint32_t baudDivisor = (clock != 0 ? clock : 115200) / (baud * 16);
103
104  if (c->deviceType == SERIAL_NS16550_WITH_FDR) {
105    uint32_t fractionalDivider = 0x10;
106    uint32_t err = baud;
107    uint32_t mulVal;
108    uint32_t divAddVal;
109
110    clock /= 16 * baudDivisor;
111    for (mulVal = 1; mulVal < 16; ++mulVal) {
112      for (divAddVal = 0; divAddVal < mulVal; ++divAddVal) {
113        uint32_t actual = (mulVal * clock) / (mulVal + divAddVal);
114        uint32_t newErr = actual > baud ? actual - baud : baud - actual;
115
116        if (newErr < err) {
117          err = newErr;
118          fractionalDivider = (mulVal << 4) | divAddVal;
119        }
120      }
121    }
122
123    (*c->setRegister)(
124      c->ulCtrlPort1,
125      NS16550_FRACTIONAL_DIVIDER,
126      fractionalDivider
127    );
128  }
129
130  return baudDivisor;
131}
132
133/*
134 *  ns16550_init
135 */
136
137NS16550_STATIC void ns16550_init(int minor)
138{
139  uintptr_t               pNS16550;
140  uint8_t                 ucDataByte;
141  uint32_t                ulBaudDivisor;
142  ns16550_context        *pns16550Context;
143  setRegister_f           setReg;
144  getRegister_f           getReg;
145  console_tbl             *c = Console_Port_Tbl [minor];
146
147  pns16550Context=(ns16550_context *)malloc(sizeof(ns16550_context));
148
149  if (pns16550Context == NULL) {
150    printk( "%s: Error: Not enough memory\n", __func__);
151    rtems_fatal_error_occurred( 0xdeadbeef);
152  }
153
154  Console_Port_Data[minor].pDeviceContext=(void *)pns16550Context;
155  pns16550Context->ucModemCtrl=SP_MODEM_IRQ;
156
157  pNS16550 = c->ulCtrlPort1;   
158  setReg   = c->setRegister;
159  getReg   = c->getRegister;
160
161  /* Clear the divisor latch, clear all interrupt enables,
162   * and reset and
163   * disable the FIFO's.
164   */
165
166  (*setReg)(pNS16550, NS16550_LINE_CONTROL, 0x0);
167  ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR );
168
169  /* Set the divisor latch and set the baud rate. */
170
171  ulBaudDivisor = NS16550_GetBaudDivisor(c, (uintptr_t) c->pDeviceParams);
172  ucDataByte = SP_LINE_DLAB;
173  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
174
175  /* XXX */
176  (*setReg)(pNS16550,NS16550_TRANSMIT_BUFFER,(uint8_t)(ulBaudDivisor & 0xffU));
177  (*setReg)(
178    pNS16550,NS16550_INTERRUPT_ENABLE,
179    (uint8_t)(( ulBaudDivisor >> 8 ) & 0xffU )
180  );
181
182  /* Clear the divisor latch and set the character size to eight bits */
183  /* with one stop bit and no parity checking. */
184  ucDataByte = EIGHT_BITS;
185  (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucDataByte);
186
187  /* Enable and reset transmit and receive FIFOs. TJA     */
188  ucDataByte = SP_FIFO_ENABLE;
189  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
190
191  ucDataByte = SP_FIFO_ENABLE | SP_FIFO_RXRST | SP_FIFO_TXRST;
192  (*setReg)(pNS16550, NS16550_FIFO_CONTROL, ucDataByte);
193
194  ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
195
196  /* Set data terminal ready. */
197  /* And open interrupt tristate line */
198  (*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
199
200  (*getReg)(pNS16550, NS16550_LINE_STATUS );
201  (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER );
202}
203
204/*
205 *  ns16550_open
206 */
207
208NS16550_STATIC int ns16550_open(
209  int major,
210  int minor,
211  void *arg
212)
213{
214  rtems_libio_open_close_args_t *oc = (rtems_libio_open_close_args_t *) arg;
215  struct rtems_termios_tty *tty = (struct rtems_termios_tty *) oc->iop->data1;
216  console_tbl *c = Console_Port_Tbl [minor];
217  console_data *d = &Console_Port_Data [minor];
218
219  d->termios_data = tty;
220
221  /* Assert DTR */
222  if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
223    ns16550_assert_DTR( minor);
224  }
225
226  /* Set initial baud */
227  rtems_termios_set_initial_baud( tty, (intptr_t) c->pDeviceParams);
228
229  if (c->pDeviceFns->deviceOutputUsesInterrupts) {
230    ns16550_initialize_interrupts( minor);
231    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
232  }
233
234  return RTEMS_SUCCESSFUL;
235}
236
237/*
238 *  ns16550_close
239 */
240
241NS16550_STATIC int ns16550_close(
242  int      major,
243  int      minor,
244  void    * arg
245)
246{
247  console_tbl *c = Console_Port_Tbl [minor];
248
249  /*
250   * Negate DTR
251   */
252  if (c->pDeviceFlow != &ns16550_flow_DTRCTS) {
253    ns16550_negate_DTR(minor);
254  }
255
256  ns16550_enable_interrupts(c, NS16550_DISABLE_ALL_INTR);
257
258  if (c->pDeviceFns->deviceOutputUsesInterrupts) {
259    ns16550_cleanup_interrupts(minor);
260  }
261
262  return(RTEMS_SUCCESSFUL);
263}
264
265/**
266 * @brief Polled write for NS16550.
267 */
268void ns16550_outch_polled(console_tbl *c, char out)
269{
270  uintptr_t port = c->ulCtrlPort1;
271  getRegister_f get = c->getRegister;
272  setRegister_f set = c->setRegister;
273  uint32_t status = 0;
274  rtems_interrupt_level level;
275
276  /* Save port interrupt mask */
277  uint32_t interrupt_mask = get( port, NS16550_INTERRUPT_ENABLE);
278
279  /* Disable port interrupts */
280  ns16550_enable_interrupts( c, NS16550_DISABLE_ALL_INTR);
281
282  while (true) {
283    /* Try to transmit the character in a critical section */
284    rtems_interrupt_disable( level);
285
286    /* Read the transmitter holding register and check it */
287    status = get( port, NS16550_LINE_STATUS);
288    if ((status & SP_LSR_THOLD) != 0) {
289      /* Transmit character */
290      set( port, NS16550_TRANSMIT_BUFFER, out);
291
292      /* Finished */
293      rtems_interrupt_enable( level);
294      break;
295    } else {
296      rtems_interrupt_enable( level);
297    }
298
299    /* Wait for transmitter holding register to be empty */
300    do {
301      status = get( port, NS16550_LINE_STATUS);
302    } while ((status & SP_LSR_THOLD) == 0);
303  }
304
305  /* Restore port interrupt mask */
306  set( port, NS16550_INTERRUPT_ENABLE, interrupt_mask);
307}
308
309NS16550_STATIC void ns16550_write_polled(int minor, char out)
310{
311  console_tbl *c = Console_Port_Tbl [minor];
312 
313  ns16550_outch_polled( c, out );
314}
315
316/*
317 * These routines provide control of the RTS and DTR lines
318 */
319
320/*
321 *  ns16550_assert_RTS
322 */
323
324NS16550_STATIC int ns16550_assert_RTS(int minor)
325{
326  uint32_t                pNS16550;
327  uint32_t                Irql;
328  ns16550_context        *pns16550Context;
329  setRegister_f           setReg;
330
331  pns16550Context=(ns16550_context *) Console_Port_Data[minor].pDeviceContext;
332
333  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
334  setReg   = Console_Port_Tbl[minor]->setRegister;
335
336  /*
337   * Assert RTS
338   */
339  rtems_interrupt_disable(Irql);
340  pns16550Context->ucModemCtrl|=SP_MODEM_RTS;
341  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
342  rtems_interrupt_enable(Irql);
343  return 0;
344}
345
346/*
347 *  ns16550_negate_RTS
348 */
349
350NS16550_STATIC int ns16550_negate_RTS(int minor)
351{
352  uint32_t                pNS16550;
353  uint32_t                Irql;
354  ns16550_context        *pns16550Context;
355  setRegister_f           setReg;
356
357  pns16550Context=(ns16550_context *) Console_Port_Data[minor].pDeviceContext;
358
359  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
360  setReg   = Console_Port_Tbl[minor]->setRegister;
361
362  /*
363   * Negate RTS
364   */
365  rtems_interrupt_disable(Irql);
366  pns16550Context->ucModemCtrl&=~SP_MODEM_RTS;
367  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
368  rtems_interrupt_enable(Irql);
369  return 0;
370}
371
372/*
373 * These flow control routines utilise a connection from the local DTR
374 * line to the remote CTS line
375 */
376
377/*
378 *  ns16550_assert_DTR
379 */
380
381NS16550_STATIC int ns16550_assert_DTR(int minor)
382{
383  uint32_t                pNS16550;
384  uint32_t                Irql;
385  ns16550_context        *pns16550Context;
386  setRegister_f           setReg;
387
388  pns16550Context=(ns16550_context *) Console_Port_Data[minor].pDeviceContext;
389
390  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
391  setReg   = Console_Port_Tbl[minor]->setRegister;
392
393  /*
394   * Assert DTR
395   */
396  rtems_interrupt_disable(Irql);
397  pns16550Context->ucModemCtrl|=SP_MODEM_DTR;
398  (*setReg)(pNS16550, NS16550_MODEM_CONTROL, pns16550Context->ucModemCtrl);
399  rtems_interrupt_enable(Irql);
400  return 0;
401}
402
403/*
404 *  ns16550_negate_DTR
405 */
406
407NS16550_STATIC int ns16550_negate_DTR(int minor)
408{
409  uint32_t                pNS16550;
410  uint32_t                Irql;
411  ns16550_context        *pns16550Context;
412  setRegister_f           setReg;
413
414  pns16550Context=(ns16550_context *) Console_Port_Data[minor].pDeviceContext;
415
416  pNS16550 = Console_Port_Tbl[minor]->ulCtrlPort1;
417  setReg   = Console_Port_Tbl[minor]->setRegister;
418
419  /*
420   * Negate DTR
421   */
422  rtems_interrupt_disable(Irql);
423  pns16550Context->ucModemCtrl&=~SP_MODEM_DTR;
424  (*setReg)(pNS16550, NS16550_MODEM_CONTROL,pns16550Context->ucModemCtrl);
425  rtems_interrupt_enable(Irql);
426  return 0;
427}
428
429/*
430 *  ns16550_set_attributes
431 *
432 *  This function sets the channel to reflect the requested termios
433 *  port settings.
434 */
435
436NS16550_STATIC int ns16550_set_attributes(
437  int                   minor,
438  const struct termios *t
439)
440{
441  uint32_t                pNS16550;
442  uint32_t                ulBaudDivisor;
443  uint8_t                 ucLineControl;
444  uint32_t                baud_requested;
445  setRegister_f           setReg;
446  uint32_t                Irql;
447  const console_tbl      *c = Console_Port_Tbl [minor];
448
449  pNS16550 = c->ulCtrlPort1;
450  setReg   = c->setRegister;
451
452  /*
453   *  Calculate the baud rate divisor
454   */
455
456  baud_requested = rtems_termios_baud_to_number(t->c_cflag);
457  ulBaudDivisor = NS16550_GetBaudDivisor(c, baud_requested);
458
459  ucLineControl = 0;
460
461  /*
462   *  Parity
463   */
464
465  if (t->c_cflag & PARENB) {
466    ucLineControl |= SP_LINE_PAR;
467    if (!(t->c_cflag & PARODD))
468      ucLineControl |= SP_LINE_ODD;
469  }
470
471  /*
472   *  Character Size
473   */
474
475  if (t->c_cflag & CSIZE) {
476    switch (t->c_cflag & CSIZE) {
477      case CS5:  ucLineControl |= FIVE_BITS;  break;
478      case CS6:  ucLineControl |= SIX_BITS;   break;
479      case CS7:  ucLineControl |= SEVEN_BITS; break;
480      case CS8:  ucLineControl |= EIGHT_BITS; break;
481    }
482  } else {
483    ucLineControl |= EIGHT_BITS;               /* default to 9600,8,N,1 */
484  }
485
486  /*
487   *  Stop Bits
488   */
489
490  if (t->c_cflag & CSTOPB) {
491    ucLineControl |= SP_LINE_STOP;              /* 2 stop bits */
492  } else {
493    ;                                           /* 1 stop bit */
494  }
495
496  /*
497   *  Now actually set the chip
498   */
499
500  rtems_interrupt_disable(Irql);
501
502    /*
503     *  Set the baud rate
504     */
505
506    (*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
507    /* XXX are these registers right? */
508    (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
509    (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
510
511    /*
512     *  Now write the line control
513     */
514    (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
515
516  rtems_interrupt_enable(Irql);
517
518  return 0;
519}
520
521#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
522
523/**
524 * @brief Process interrupt.
525 */
526NS16550_STATIC void ns16550_process( int minor)
527{
528  console_tbl *c = Console_Port_Tbl [minor];
529  console_data *d = &Console_Port_Data [minor];
530  ns16550_context *ctx = d->pDeviceContext;
531  uint32_t port = c->ulCtrlPort1;
532  getRegister_f get = c->getRegister;
533  int i = 0;
534  char buf [SP_FIFO_SIZE];
535
536  /* Iterate until no more interrupts are pending */
537  do {
538    /* Fetch received characters */
539    for (i = 0; i < SP_FIFO_SIZE; ++i) {
540      if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
541        buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
542      } else {
543        break;
544      }
545    }
546
547    /* Enqueue fetched characters */
548    rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
549
550    /* Check if we can dequeue transmitted characters */
551    if (ctx->transmitFifoChars > 0
552        && (get( port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
553      unsigned chars = ctx->transmitFifoChars;
554
555      /*
556       * We finished the transmission, so clear the number of characters in the
557       * transmit FIFO.
558       */
559      ctx->transmitFifoChars = 0;
560
561      /* Dequeue transmitted characters */
562      if (rtems_termios_dequeue_characters( d->termios_data, chars) == 0) {
563        /* Nothing to do */
564        d->bActive = false;
565        ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
566      }
567    }
568  } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
569}
570#endif
571
572/**
573 * @brief Transmits up to @a len characters from @a buf.
574 *
575 * This routine is invoked either from task context with disabled interrupts to
576 * start a new transmission process with exactly one character in case of an
577 * idle output state or from the interrupt handler to refill the transmitter.
578 *
579 * Returns always zero.
580 */
581NS16550_STATIC ssize_t ns16550_write_support_int(
582  int minor,
583  const char *buf,
584  size_t len
585)
586{
587  console_tbl *c = Console_Port_Tbl [minor];
588  console_data *d = &Console_Port_Data [minor];
589  ns16550_context *ctx = d->pDeviceContext;
590  uint32_t port = c->ulCtrlPort1;
591  setRegister_f set = c->setRegister;
592  int i = 0;
593  int out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
594
595  for (i = 0; i < out; ++i) {
596    set( port, NS16550_TRANSMIT_BUFFER, buf [i]);
597  }
598
599  if (len > 0) {
600    ctx->transmitFifoChars = out;
601    d->bActive = true;
602    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR);
603  }
604
605  return 0;
606}
607
608/*
609 *  ns16550_enable_interrupts
610 *
611 *  This routine initializes the port to have the specified interrupts masked.
612 */
613NS16550_STATIC void ns16550_enable_interrupts(
614  console_tbl *c,
615  int         mask
616)
617{
618  uint32_t       pNS16550;
619  setRegister_f  setReg;
620
621  pNS16550 = c->ulCtrlPort1;
622  setReg   = c->setRegister;
623
624  (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
625}
626
627#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
628  NS16550_STATIC rtems_isr ns16550_isr(void *arg)
629  {
630    int minor = (int) arg;
631
632    ns16550_process( minor);
633  }
634#endif
635
636/*
637 *  ns16550_initialize_interrupts
638 *
639 *  This routine initializes the port to operate in interrupt driver mode.
640 */
641NS16550_STATIC void ns16550_initialize_interrupts( int minor)
642{
643#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
644  console_tbl *c = Console_Port_Tbl [minor];
645#endif
646  console_data *d = &Console_Port_Data [minor];
647
648  d->bActive = false;
649
650  #ifdef BSP_FEATURE_IRQ_EXTENSION
651    {
652      rtems_status_code sc = RTEMS_SUCCESSFUL;
653      sc = rtems_interrupt_handler_install(
654        c->ulIntVector,
655        "NS16550",
656        RTEMS_INTERRUPT_SHARED,
657        ns16550_isr,
658        (void *) minor
659      );
660      if (sc != RTEMS_SUCCESSFUL) {
661        /* FIXME */
662        printk( "%s: Error: Install interrupt handler\n", __func__);
663        rtems_fatal_error_occurred( 0xdeadbeef);
664      }
665    }
666  #elif defined(BSP_FEATURE_IRQ_LEGACY)
667    {
668      int rv = 0;
669      #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
670        rtems_irq_connect_data cd = {
671          c->ulIntVector,
672          ns16550_isr,
673          (void *) minor,
674          NULL,
675          NULL,
676          NULL,
677          NULL
678        };
679        rv = BSP_install_rtems_shared_irq_handler( &cd);
680      #else
681        rtems_irq_connect_data cd = {
682          c->ulIntVector,
683          ns16550_isr,
684          (void *) minor,
685          NULL,
686          NULL,
687          NULL
688        };
689        rv = BSP_install_rtems_irq_handler( &cd);
690      #endif
691      if (rv == 0) {
692        /* FIXME */
693        printk( "%s: Error: Install interrupt handler\n", __func__);
694        rtems_fatal_error_occurred( 0xdeadbeef);
695      }
696    }
697  #endif
698}
699
700NS16550_STATIC void ns16550_cleanup_interrupts(int minor)
701{
702  #if defined(BSP_FEATURE_IRQ_EXTENSION)
703    rtems_status_code sc = RTEMS_SUCCESSFUL;
704    console_tbl *c = Console_Port_Tbl [minor];
705    sc = rtems_interrupt_handler_remove(
706      c->ulIntVector,
707      ns16550_isr,
708      (void *) minor
709    );
710    if (sc != RTEMS_SUCCESSFUL) {
711      /* FIXME */
712      printk("%s: Error: Remove interrupt handler\n", __func__);
713      rtems_fatal_error_occurred(0xdeadbeef);
714    }
715  #elif defined(BSP_FEATURE_IRQ_LEGACY)
716    int rv = 0;
717    console_tbl *c = Console_Port_Tbl [minor];
718    rtems_irq_connect_data cd = {
719      .name = c->ulIntVector,
720      .hdl = ns16550_isr,
721      .handle = (void *) minor
722    };
723    rv = BSP_remove_rtems_irq_handler(&cd);
724    if (rv == 0) {
725      /* FIXME */
726      printk("%s: Error: Remove interrupt handler\n", __func__);
727      rtems_fatal_error_occurred(0xdeadbeef);
728    }
729  #endif
730}
731
732/*
733 *  ns16550_write_support_polled
734 *
735 *  Console Termios output entry point.
736 *
737 */
738
739NS16550_STATIC ssize_t ns16550_write_support_polled(
740  int         minor,
741  const char *buf,
742  size_t      len
743)
744{
745  int nwrite = 0;
746
747  /*
748   * poll each byte in the string out of the port.
749   */
750  while (nwrite < len) {
751    /*
752     * transmit character
753     */
754    ns16550_write_polled(minor, *buf++);
755    nwrite++;
756  }
757
758  /*
759   * return the number of bytes written.
760   */
761  return nwrite;
762}
763
764/*
765 *  Debug gets() support
766 */
767int ns16550_inch_polled(
768  console_tbl *c
769)
770{
771  uint32_t             pNS16550;
772  unsigned char        ucLineStatus;
773  uint8_t              cChar;
774  getRegister_f        getReg;
775
776  pNS16550 = c->ulCtrlPort1;
777  getReg   = c->getRegister;
778
779  ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
780  if (ucLineStatus & SP_LSR_RDY) {
781    cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
782    return (int)cChar;
783  }
784  return -1;
785}
786
787/*
788 *  ns16550_inbyte_nonblocking_polled
789 *
790 *  Console Termios polling input entry point.
791 */
792NS16550_STATIC int ns16550_inbyte_nonblocking_polled(int minor)
793{
794  console_tbl *c = Console_Port_Tbl [minor];
795 
796  return ns16550_inch_polled( c );
797}
Note: See TracBrowser for help on using the repository browser.