source: rtems/c/src/libchip/serial/ns16550.c @ 229bcca8

4.115
Last change on this file since 229bcca8 was 229bcca8, checked in by Jennifer Averett <Jennifer.Averett@…>, on 10/18/11 at 18:40:27

2011-10-18 Jennifer Averett <Jennifer.Averett@…>

PR 1917/bsps

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