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

4.115
Last change on this file since 5155069 was 5155069, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 5, 2015 at 9:05:49 AM

libchip/serial: Fix warning

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