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

4.115
Last change on this file since f68401e was 48a22ed, checked in by Joel Sherrill <joel.sherrill@…>, on 07/09/13 at 16:15:57

libchip ns16550.c: Improve comment

  • Property mode set to 100644
File size: 19.7 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
137void 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
208int 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
241int 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
309void 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
436int 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     *  NOTE: When the Divisor Latch Access Bit (DLAB) is set to 1,
506     *        the transmit buffer and interrupt enable registers
507     *        turn into the LSB and MSB divisor latch registers.
508     */
509
510    (*setReg)(pNS16550, NS16550_LINE_CONTROL, SP_LINE_DLAB);
511    (*setReg)(pNS16550, NS16550_TRANSMIT_BUFFER, ulBaudDivisor&0xff);
512    (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, (ulBaudDivisor>>8)&0xff);
513
514    /*
515     *  Now write the line control
516     */
517    (*setReg)(pNS16550, NS16550_LINE_CONTROL, ucLineControl );
518
519  rtems_interrupt_enable(Irql);
520
521  return 0;
522}
523
524#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
525
526/**
527 * @brief Process interrupt.
528 */
529NS16550_STATIC void ns16550_process( int minor)
530{
531  console_tbl *c = Console_Port_Tbl [minor];
532  console_data *d = &Console_Port_Data [minor];
533  ns16550_context *ctx = d->pDeviceContext;
534  uint32_t port = c->ulCtrlPort1;
535  getRegister_f get = c->getRegister;
536  int i = 0;
537  char buf [SP_FIFO_SIZE];
538
539  /* Iterate until no more interrupts are pending */
540  do {
541    /* Fetch received characters */
542    for (i = 0; i < SP_FIFO_SIZE; ++i) {
543      if ((get( port, NS16550_LINE_STATUS) & SP_LSR_RDY) != 0) {
544        buf [i] = (char) get(port, NS16550_RECEIVE_BUFFER);
545      } else {
546        break;
547      }
548    }
549
550    /* Enqueue fetched characters */
551    rtems_termios_enqueue_raw_characters( d->termios_data, buf, i);
552
553    /* Check if we can dequeue transmitted characters */
554    if (ctx->transmitFifoChars > 0
555        && (get( port, NS16550_LINE_STATUS) & SP_LSR_THOLD) != 0) {
556
557      /* Dequeue transmitted characters */
558      rtems_termios_dequeue_characters(
559        d->termios_data,
560        ctx->transmitFifoChars
561      );
562    }
563  } while ((get( port, NS16550_INTERRUPT_ID) & SP_IID_0) == 0);
564}
565#endif
566
567/**
568 * @brief Transmits up to @a len characters from @a buf.
569 *
570 * This routine is invoked either from task context with disabled interrupts to
571 * start a new transmission process with exactly one character in case of an
572 * idle output state or from the interrupt handler to refill the transmitter.
573 *
574 * Returns always zero.
575 */
576ssize_t ns16550_write_support_int(
577  int minor,
578  const char *buf,
579  size_t len
580)
581{
582  console_tbl *c = Console_Port_Tbl [minor];
583  console_data *d = &Console_Port_Data [minor];
584  ns16550_context *ctx = d->pDeviceContext;
585  uint32_t port = c->ulCtrlPort1;
586  setRegister_f set = c->setRegister;
587  int i = 0;
588  int out = len > SP_FIFO_SIZE ? SP_FIFO_SIZE : len;
589
590  for (i = 0; i < out; ++i) {
591    set( port, NS16550_TRANSMIT_BUFFER, buf [i]);
592  }
593
594  ctx->transmitFifoChars = out;
595
596  if (out > 0) {
597    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR);
598  } else {
599    ns16550_enable_interrupts( c, NS16550_ENABLE_ALL_INTR_EXCEPT_TX);
600  }
601
602  return 0;
603}
604
605/*
606 *  ns16550_enable_interrupts
607 *
608 *  This routine initializes the port to have the specified interrupts masked.
609 */
610NS16550_STATIC void ns16550_enable_interrupts(
611  console_tbl *c,
612  int         mask
613)
614{
615  uint32_t       pNS16550;
616  setRegister_f  setReg;
617
618  pNS16550 = c->ulCtrlPort1;
619  setReg   = c->setRegister;
620
621  (*setReg)(pNS16550, NS16550_INTERRUPT_ENABLE, mask);
622}
623
624#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
625  void ns16550_isr(void *arg)
626  {
627    int minor = (int) arg;
628
629    ns16550_process( minor);
630  }
631#endif
632
633/*
634 *  ns16550_initialize_interrupts
635 *
636 *  This routine initializes the port to operate in interrupt driver mode.
637 */
638NS16550_STATIC void ns16550_initialize_interrupts( int minor)
639{
640#if defined(BSP_FEATURE_IRQ_EXTENSION) || defined(BSP_FEATURE_IRQ_LEGACY)
641  console_tbl *c = Console_Port_Tbl [minor];
642#endif
643
644  #ifdef BSP_FEATURE_IRQ_EXTENSION
645    {
646      rtems_status_code sc = RTEMS_SUCCESSFUL;
647      sc = rtems_interrupt_handler_install(
648        c->ulIntVector,
649        "NS16550",
650        RTEMS_INTERRUPT_SHARED,
651        ns16550_isr,
652        (void *) minor
653      );
654      if (sc != RTEMS_SUCCESSFUL) {
655        /* FIXME */
656        printk( "%s: Error: Install interrupt handler\n", __func__);
657        rtems_fatal_error_occurred( 0xdeadbeef);
658      }
659    }
660  #elif defined(BSP_FEATURE_IRQ_LEGACY)
661    {
662      int rv = 0;
663      #ifdef BSP_FEATURE_IRQ_LEGACY_SHARED_HANDLER_SUPPORT
664        rtems_irq_connect_data cd = {
665          c->ulIntVector,
666          ns16550_isr,
667          (void *) minor,
668          NULL,
669          NULL,
670          NULL,
671          NULL
672        };
673        rv = BSP_install_rtems_shared_irq_handler( &cd);
674      #else
675        rtems_irq_connect_data cd = {
676          c->ulIntVector,
677          ns16550_isr,
678          (void *) minor,
679          NULL,
680          NULL,
681          NULL
682        };
683        rv = BSP_install_rtems_irq_handler( &cd);
684      #endif
685      if (rv == 0) {
686        /* FIXME */
687        printk( "%s: Error: Install interrupt handler\n", __func__);
688        rtems_fatal_error_occurred( 0xdeadbeef);
689      }
690    }
691  #endif
692}
693
694NS16550_STATIC void ns16550_cleanup_interrupts(int minor)
695{
696  #if defined(BSP_FEATURE_IRQ_EXTENSION)
697    rtems_status_code sc = RTEMS_SUCCESSFUL;
698    console_tbl *c = Console_Port_Tbl [minor];
699    sc = rtems_interrupt_handler_remove(
700      c->ulIntVector,
701      ns16550_isr,
702      (void *) minor
703    );
704    if (sc != RTEMS_SUCCESSFUL) {
705      /* FIXME */
706      printk("%s: Error: Remove interrupt handler\n", __func__);
707      rtems_fatal_error_occurred(0xdeadbeef);
708    }
709  #elif defined(BSP_FEATURE_IRQ_LEGACY)
710    int rv = 0;
711    console_tbl *c = Console_Port_Tbl [minor];
712    rtems_irq_connect_data cd = {
713      .name = c->ulIntVector,
714      .hdl = ns16550_isr,
715      .handle = (void *) minor
716    };
717    rv = BSP_remove_rtems_irq_handler(&cd);
718    if (rv == 0) {
719      /* FIXME */
720      printk("%s: Error: Remove interrupt handler\n", __func__);
721      rtems_fatal_error_occurred(0xdeadbeef);
722    }
723  #endif
724}
725
726/*
727 *  ns16550_write_support_polled
728 *
729 *  Console Termios output entry point.
730 *
731 */
732
733ssize_t ns16550_write_support_polled(
734  int         minor,
735  const char *buf,
736  size_t      len
737)
738{
739  int nwrite = 0;
740
741  /*
742   * poll each byte in the string out of the port.
743   */
744  while (nwrite < len) {
745    /*
746     * transmit character
747     */
748    ns16550_write_polled(minor, *buf++);
749    nwrite++;
750  }
751
752  /*
753   * return the number of bytes written.
754   */
755  return nwrite;
756}
757
758/*
759 *  Debug gets() support
760 */
761int ns16550_inch_polled(
762  console_tbl *c
763)
764{
765  uint32_t             pNS16550;
766  unsigned char        ucLineStatus;
767  uint8_t              cChar;
768  getRegister_f        getReg;
769
770  pNS16550 = c->ulCtrlPort1;
771  getReg   = c->getRegister;
772
773  ucLineStatus = (*getReg)(pNS16550, NS16550_LINE_STATUS);
774  if (ucLineStatus & SP_LSR_RDY) {
775    cChar = (*getReg)(pNS16550, NS16550_RECEIVE_BUFFER);
776    return (int)cChar;
777  }
778  return -1;
779}
780
781/*
782 *  ns16550_inbyte_nonblocking_polled
783 *
784 *  Console Termios polling input entry point.
785 */
786int ns16550_inbyte_nonblocking_polled(int minor)
787{
788  console_tbl *c = Console_Port_Tbl [minor];
789 
790  return ns16550_inch_polled( c );
791}
Note: See TracBrowser for help on using the repository browser.