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

4.11
Last change on this file since 2698728 was 4f1173bc, checked in by Jennifer Averett <jennifer.averett@…>, on Feb 23, 2012 at 4:40:33 PM

Avoid NULL dereference in printk() before libchip console initialized

With the addition of dynamically registered libchip serial devices,
there is the need to be able to use printk() before the console driver
has initialized the indirect pointer table. This lets printk() support
routines call pass a control structure directly without a lookup through
the uninitialized indirect one.

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