source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c @ 1c6926c1

Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on Mar 21, 2017 at 7:39:48 PM

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 17.7 KB
Line 
1/*  This file contains the driver for the GRLIB APBUART serial port. The driver
2 *  is implemented by using the cons.c console layer. Interrupt/Polling/Task
3 *  driven mode can be configured using driver resources:
4 *
5 *  - mode   (0=Polling, 1=Interrupt, 2=Task-Driven-Interrupt Mode)
6 *  - syscon (0=Force not Ssystem Console, 1=Suggest System Console)
7 *
8 *  The BSP define APBUART_INFO_AVAIL in order to add the info routine
9 *  used for debugging.
10 *
11 *  COPYRIGHT (c) 2010.
12 *  Cobham Gaisler AB.
13 *
14 *  The license and distribution terms for this file may be
15 *  found in the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 */
18
19/******************* Driver manager interface ***********************/
20#include <bsp.h>
21#include <rtems/libio.h>
22#include <stdlib.h>
23#include <assert.h>
24#include <rtems/bspIo.h>
25#include <string.h>
26#include <stdio.h>
27
28#include <drvmgr/drvmgr.h>
29#include <drvmgr/ambapp_bus.h>
30#include <bsp/apbuart.h>
31#include <ambapp.h>
32#include <grlib.h>
33#include <bsp/cons.h>
34#include <rtems/termiostypes.h>
35#include <bsp/apbuart_cons.h>
36
37/*#define DEBUG 1  */
38
39#ifdef DEBUG
40#define DBG(x...) printk(x)
41#else
42#define DBG(x...)
43#endif
44
45/* LEON3 Low level transmit/receive functions provided by debug-uart code */
46extern void apbuart_outbyte_polled(
47  struct apbuart_regs *regs,
48  unsigned char ch,
49  int do_cr_on_newline,
50  int wait_sent);
51extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
52extern struct apbuart_regs *dbg_uart; /* The debug UART */
53
54struct apbuart_priv {
55        struct console_dev condev;
56        struct drvmgr_dev *dev;
57        struct apbuart_regs *regs;
58        char devName[32];
59        void *cookie;
60        int sending;
61        int mode;
62};
63
64/* TERMIOS Layer Callback functions */
65void apbuart_get_attributes(struct console_dev *condev, struct termios *t);
66int apbuart_set_attributes(int minor, const struct termios *t);
67ssize_t apbuart_write_polled(int minor, const char *buf, size_t len);
68int apbuart_pollRead(int minor);
69ssize_t apbuart_write_intr(int minor, const char *buf, size_t len);
70int apbuart_pollRead_task(int minor);
71int apbuart_firstOpen(int major, int minor, void *arg);
72int apbuart_lastClose(int major, int minor, void *arg);
73
74void apbuart_isr(void *arg);
75int apbuart_get_baud(struct apbuart_priv *uart);
76
77int apbuart_init1(struct drvmgr_dev *dev);
78#ifdef APBUART_INFO_AVAIL
79static int apbuart_info(
80        struct drvmgr_dev *dev,
81        void (*print_line)(void *p, char *str),
82        void *p, int, char *argv[]);
83#define APBUART_INFO_FUNC apbuart_info
84#else
85#define APBUART_INFO_FUNC NULL
86#endif
87
88struct drvmgr_drv_ops apbuart_ops =
89{
90        .init = {apbuart_init1, NULL, NULL, NULL},
91        .remove = NULL,
92        .info = APBUART_INFO_FUNC
93};
94
95static struct amba_dev_id apbuart_ids[] =
96{
97        {VENDOR_GAISLER, GAISLER_APBUART},
98        {0, 0}          /* Mark end of table */
99};
100
101static struct amba_drv_info apbuart_drv_info =
102{
103        {
104                DRVMGR_OBJ_DRV,                         /* Driver */
105                NULL,                                   /* Next driver */
106                NULL,                                   /* Device list */
107                DRIVER_AMBAPP_GAISLER_APBUART_ID,       /* Driver ID */
108                "APBUART_DRV",                          /* Driver Name */
109                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
110                &apbuart_ops,
111                NULL,                                   /* Funcs */
112                0,                                      /* No devices yet */
113                sizeof(struct apbuart_priv),            /*DrvMgr alloc private*/
114        },
115        &apbuart_ids[0]
116};
117
118void apbuart_cons_register_drv (void)
119{
120        DBG("Registering APBUART Console driver\n");
121        drvmgr_drv_register(&apbuart_drv_info.general);
122}
123
124/* Interrupt mode routines */
125static const rtems_termios_callbacks Callbacks_intr = {
126    apbuart_firstOpen,           /* firstOpen */
127    apbuart_lastClose,           /* lastClose */
128    NULL,                        /* pollRead */
129    apbuart_write_intr,          /* write */
130    apbuart_set_attributes,      /* setAttributes */
131    NULL,                        /* stopRemoteTx */
132    NULL,                        /* startRemoteTx */
133    TERMIOS_IRQ_DRIVEN           /* outputUsesInterrupts */
134};
135
136/* Polling mode routines */
137static const rtems_termios_callbacks Callbacks_task = {
138    apbuart_firstOpen,           /* firstOpen */
139    apbuart_lastClose,           /* lastClose */
140    apbuart_pollRead_task,       /* pollRead */
141    apbuart_write_intr,          /* write */
142    apbuart_set_attributes,      /* setAttributes */
143    NULL,                        /* stopRemoteTx */
144    NULL,                        /* startRemoteTx */
145    TERMIOS_TASK_DRIVEN          /* outputUsesInterrupts */
146};
147
148/* Polling mode routines */
149static const rtems_termios_callbacks Callbacks_poll = {
150    apbuart_firstOpen,           /* firstOpen */
151    apbuart_lastClose,           /* lastClose */
152    apbuart_pollRead,            /* pollRead */
153    apbuart_write_polled,        /* write */
154    apbuart_set_attributes,      /* setAttributes */
155    NULL,                        /* stopRemoteTx */
156    NULL,                        /* startRemoteTx */
157    TERMIOS_POLLED               /* outputUsesInterrupts */
158};
159
160int apbuart_init1(struct drvmgr_dev *dev)
161{
162        struct apbuart_priv *priv;
163        struct amba_dev_info *ambadev;
164        struct ambapp_core *pnpinfo;
165        union drvmgr_key_value *value;
166        char prefix[32];
167        unsigned int db;
168        static int first_uart = 1;
169
170        /* The default operation in AMP is to use APBUART[0] for CPU[0],
171         * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
172         * since we don't know how many CPU-cores there are. Note this only
173         * affects the on-chip amba bus (the root bus). The user can override
174         * the default resource sharing by defining driver resources for the
175         * APBUART devices on each AMP OS instance.
176         */
177#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
178        if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
179            drvmgr_keys_get(dev, NULL) != 0) {
180                /* User hasn't configured on-chip APBUART, leave it untouched */
181                return DRVMGR_EBUSY;
182        }
183#endif
184
185        DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
186        /* Private data was allocated and zeroed by driver manager */
187        priv = dev->priv;
188        if (!priv)
189                return DRVMGR_NOMEM;
190        priv->dev = dev;
191
192        /* Get device information from AMBA PnP information */
193        ambadev = (struct amba_dev_info *)priv->dev->businfo;
194        if (ambadev == NULL)
195                return -1;
196        pnpinfo = &ambadev->info;
197        priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
198
199        /* Clear HW regs, leave baudrate register as it is */
200        priv->regs->status = 0;
201
202        /* leave Transmitter/receiver if this is the RTEMS debug UART (assume
203         * it has been setup by boot loader).
204         */
205        db = 0;
206#ifdef LEON3
207        if (priv->regs == dbg_uart) {
208                db = priv->regs->ctrl & (LEON_REG_UART_CTRL_RE |
209                                        LEON_REG_UART_CTRL_TE |
210                                        LEON_REG_UART_CTRL_PE |
211                                        LEON_REG_UART_CTRL_PS);
212        }
213#endif
214        /* Let UART debug tunnelling be untouched if Flow-control is set.
215         *
216         * With old APBUARTs debug is enabled by setting LB and FL, since LB or
217         * DB are not reset we can not trust them. However since FL is reset we
218         * guess that we are debugging if FL is already set, the debugger set
219         * either LB or DB depending on UART capabilities.
220         */
221        if (priv->regs->ctrl & LEON_REG_UART_CTRL_FL) {
222                db |= priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
223                      LEON_REG_UART_CTRL_LB | LEON_REG_UART_CTRL_FL);
224        }
225
226        priv->regs->ctrl = db;
227
228        /* The system console and Debug console may depend on this device, so
229         * initialize it straight away.
230         *
231         * We default to have System Console on first APBUART, user may override
232         * this behaviour by setting the syscon option to 0.
233         */
234        if (drvmgr_on_rootbus(dev) && first_uart) {
235                priv->condev.flags = CONSOLE_FLAG_SYSCON;
236                first_uart = 0;
237        } else {
238                priv->condev.flags = 0;
239        }
240
241        value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT);
242        if (value) {
243                if (value->i)
244                        priv->condev.flags |= CONSOLE_FLAG_SYSCON;
245                else
246                        priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
247        }
248
249        priv->condev.fsname = NULL;
250        priv->condev.ops.get_uart_attrs = apbuart_get_attributes;
251
252        /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
253        value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
254        if (value)
255                priv->mode = value->i;
256        else
257                priv->mode = TERMIOS_POLLED;
258        if (priv->mode == TERMIOS_IRQ_DRIVEN) {
259                priv->condev.callbacks = &Callbacks_intr;
260        } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
261                priv->condev.callbacks = &Callbacks_task;
262        } else {
263                priv->condev.callbacks = &Callbacks_poll;
264        }
265
266        /* Get Filesystem name prefix */
267        prefix[0] = '\0';
268        if (drvmgr_get_dev_prefix(dev, prefix)) {
269                /* Got special prefix, this means we have a bus prefix
270                 * And we should use our "bus minor"
271                 */
272                sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
273                priv->condev.fsname = priv->devName;
274        }
275
276        /* Register it as a console device, the console driver will register
277         * a termios device as well
278         */
279        console_dev_register(&priv->condev);
280
281        return DRVMGR_OK;
282}
283
284#ifdef APBUART_INFO_AVAIL
285static int apbuart_info(
286        struct drvmgr_dev *dev,
287        void (*print_line)(void *p, char *str),
288        void *p, int argc, char *argv[])
289{
290        struct apbuart_priv *priv = dev->priv;
291        char *str1;
292        char buf[64];
293
294        if (dev->priv == NULL)
295                return -DRVMGR_EINVAL;
296
297        if (priv->mode == TERMIOS_POLLED)
298                str1 = "TERMIOS_POLLED";
299        else if (priv->mode == TERMIOS_TASK_DRIVEN)
300                str1 = "TERMIOS_TASK_DRIVEN";
301        else if (priv->mode == TERMIOS_TASK_DRIVEN)
302                str1 = "TERMIOS_TASK_DRIVEN";
303        else
304                str1 = "BAD MODE";
305
306        sprintf(buf, "UART Mode:   %s", str1);
307        print_line(p, buf);
308        if (priv->condev.fsname) {
309                sprintf(buf, "FS Name:     %s", priv->condev.fsname);
310                print_line(p, buf);
311        }
312        sprintf(buf, "STATUS REG:  0x%x", priv->regs->status);
313        print_line(p, buf);
314        sprintf(buf, "CTRL REG:    0x%x", priv->regs->ctrl);
315        print_line(p, buf);
316        sprintf(buf, "SCALER REG:  0x%x  baud rate %d",
317                                priv->regs->scaler, apbuart_get_baud(priv));
318        print_line(p, buf);
319
320        return DRVMGR_OK;
321}
322#endif
323
324#ifndef LEON3
325/* This routine transmits a character, it will busy-wait until on character
326 * fits in the APBUART Transmit FIFO
327 */
328void apbuart_outbyte_polled(
329  struct apbuart_regs *regs,
330  unsigned char ch,
331  int do_cr_on_newline,
332  int wait_sent)
333{
334send:
335        while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) {
336                /* Lower bus utilization while waiting for UART */
337                asm volatile ("nop"::); asm volatile ("nop"::);
338                asm volatile ("nop"::); asm volatile ("nop"::);
339                asm volatile ("nop"::); asm volatile ("nop"::);
340                asm volatile ("nop"::); asm volatile ("nop"::);
341        }
342        regs->data = (unsigned int) ch;
343
344        if ((ch == '\n') && do_cr_on_newline) {
345                ch = '\r';
346                goto send;
347        }
348
349        /* Wait until the character has been sent? */
350        if (wait_sent) {
351                while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
352                        ;
353        }
354}
355
356/* This routine polls for one character, return EOF if no character is available */
357int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
358{
359        if (regs->status & LEON_REG_UART_STATUS_ERR) {
360                regs->status = ~LEON_REG_UART_STATUS_ERR;
361        }
362
363        if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
364                return EOF;
365
366        return (int)regs->data;
367}
368#endif
369
370int apbuart_firstOpen(int major, int minor, void *arg)
371{
372        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
373        rtems_libio_open_close_args_t *ioarg = arg;
374
375        if ( ioarg && ioarg->iop )
376                uart->cookie = ioarg->iop->data1;
377        else
378                uart->cookie = NULL;
379
380        /* Enable TX/RX */
381        uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
382
383        if (uart->mode != TERMIOS_POLLED) {
384                /* Register interrupt and enable it */
385                drvmgr_interrupt_register(uart->dev, 0, "apbuart",
386                                                apbuart_isr, uart);
387
388                uart->sending = 0;
389                /* Turn on RX interrupts */
390                uart->regs->ctrl |= LEON_REG_UART_CTRL_RI;
391        }
392
393        return 0;
394}
395
396int apbuart_lastClose(int major, int minor, void *arg)
397{
398        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
399
400        if (uart->mode != TERMIOS_POLLED) {
401                /* Turn off RX interrupts */
402                uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
403
404                /**** Flush device ****/
405                while (uart->sending) {
406                        /* Wait until all data has been sent */
407                }
408
409                /* Disable and unregister interrupt handler */
410                drvmgr_interrupt_unregister(uart->dev, 0, apbuart_isr, uart);
411        }
412
413#ifdef LEON3
414        /* Disable TX/RX if not used for DEBUG */
415        if (uart->regs != dbg_uart)
416                uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE);
417#endif
418
419        return 0;
420}
421
422int apbuart_pollRead(int minor)
423{
424        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
425
426        return apbuart_inbyte_nonblocking(uart->regs);
427}
428
429int apbuart_pollRead_task(int minor)
430{
431        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
432        int c, tot;
433        char buf[32];
434
435        tot = 0;
436        while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
437                buf[tot] = c;
438                tot++;
439                if (tot > 31) {
440                        rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
441                        tot = 0;
442                }
443        }
444        if (tot > 0)
445                rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
446
447        return EOF;
448}
449
450struct apbuart_baud {
451        unsigned int num;
452        unsigned int baud;
453};
454static struct apbuart_baud apbuart_baud_table[] = {
455        {B50, 50},
456        {B75, 75},
457        {B110, 110},
458        {B134, 134},
459        {B150, 150},
460        {B200, 200},
461        {B300, 300},
462        {B600, 600},
463        {B1200, 1200},
464        {B1800, 1800},
465        {B2400, 2400},
466        {B4800, 4800},
467        {B9600, 9600},
468        {B19200, 19200},
469        {B38400, 38400},
470        {B57600, 57600},
471        {B115200, 115200},
472        {B230400, 230400},
473        {B460800, 460800},
474};
475#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
476
477static int apbuart_baud_num2baud(unsigned int num)
478{
479        int i;
480
481        for(i=0; i<BAUD_NUM; i++)
482                if (apbuart_baud_table[i].num == num)
483                        return apbuart_baud_table[i].baud;
484        return -1;
485}
486
487static struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
488{
489        int i, diff;
490
491        for(i=0; i<BAUD_NUM-1; i++) {
492                diff = apbuart_baud_table[i+1].baud -
493                        apbuart_baud_table[i].baud;
494                if (baud < (apbuart_baud_table[i].baud + diff/2))
495                        return &apbuart_baud_table[i];
496        }
497        return &apbuart_baud_table[BAUD_NUM-1];
498}
499
500int apbuart_get_baud(struct apbuart_priv *uart)
501{
502        unsigned int core_clk_hz;
503        unsigned int scaler;
504
505        /* Get current scaler setting */
506        scaler = uart->regs->scaler;
507
508        /* Get APBUART core frequency */
509        drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
510
511        /* Calculate baud rate from generator "scaler" number */
512        return core_clk_hz / ((scaler + 1) * 8);
513}
514
515static struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
516{
517        return apbuart_baud_find_closest(apbuart_get_baud(uart));
518}
519
520int apbuart_set_attributes(int minor, const struct termios *t)
521{
522        unsigned int core_clk_hz;
523        unsigned int scaler;
524        unsigned int ctrl;
525        int baud;
526        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
527
528        switch(t->c_cflag & CSIZE) {
529                default:
530                case CS5:
531                case CS6:
532                case CS7:
533                        /* Hardware doesn't support other than CS8 */
534                        return -1;
535                case CS8:
536                        break;
537        }
538
539        /* Read out current value */
540        ctrl = uart->regs->ctrl;
541
542        switch(t->c_cflag & (PARENB|PARODD)){
543                case (PARENB|PARODD):
544                        /* Odd parity */
545                        ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
546                        break;
547
548                case PARENB:
549                        /* Even parity */
550                        ctrl &= ~LEON_REG_UART_CTRL_PS;
551                        ctrl |= LEON_REG_UART_CTRL_PE;
552                        break;
553
554                default:
555                case 0:
556                case PARODD:
557                        /* No Parity */
558                        ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
559        }
560
561        if (!(t->c_cflag & CLOCAL))
562                ctrl |= LEON_REG_UART_CTRL_FL;
563        else
564                ctrl &= ~LEON_REG_UART_CTRL_FL;
565
566        /* Update new settings */
567        uart->regs->ctrl = ctrl;
568
569        /* Baud rate */
570  baud = apbuart_baud_num2baud(t->c_ospeed);
571        if (baud > 0){
572                /* Get APBUART core frequency */
573                drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
574
575                /* Calculate Baud rate generator "scaler" number */
576                scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
577
578                /* Set new baud rate by setting scaler */
579                uart->regs->scaler = scaler;
580        }
581
582        return 0;
583}
584
585void apbuart_get_attributes(struct console_dev *condev, struct termios *t)
586{
587        struct apbuart_priv *uart = (struct apbuart_priv *)condev;
588        unsigned int ctrl;
589        struct apbuart_baud *baud;
590
591  t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
592
593        /* Hardware support only CS8 */
594        t->c_cflag |= CS8;
595
596        /* Read out current parity */
597        ctrl = uart->regs->ctrl;
598        if (ctrl & LEON_REG_UART_CTRL_PE) {
599                if (ctrl & LEON_REG_UART_CTRL_PS)
600                        t->c_cflag |= PARENB|PARODD; /* Odd parity */
601                else
602                        t->c_cflag |= PARENB; /* Even parity */
603        }
604
605        if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
606                t->c_cflag |= CLOCAL;
607
608        baud = apbuart_get_baud_closest(uart);
609        t->c_cflag |= baud->num;
610}
611
612ssize_t apbuart_write_polled(int minor, const char *buf, size_t len)
613{
614        int nwrite = 0;
615        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
616
617        while (nwrite < len) {
618                apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
619                nwrite++;
620        }
621        return nwrite;
622}
623
624ssize_t apbuart_write_intr(int minor, const char *buf, size_t len)
625{
626        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
627        unsigned int oldLevel;
628        unsigned int ctrl;
629
630        rtems_interrupt_disable(oldLevel);
631
632        /* Enable TX interrupt */
633        ctrl = uart->regs->ctrl;
634        uart->regs->ctrl = ctrl | LEON_REG_UART_CTRL_TI;
635
636        if (ctrl & LEON_REG_UART_CTRL_FA) {
637                /* APBUART with FIFO.. Fill as many as FIFO allows */
638                uart->sending = 0;
639                while (((uart->regs->status & LEON_REG_UART_STATUS_TF) == 0) &&
640                       (uart->sending < len)) {
641                        uart->regs->data = *buf;
642                        buf++;
643                        uart->sending++;
644                }
645        } else {
646                /* start UART TX, this will result in an interrupt when done */
647                uart->regs->data = *buf;
648
649                uart->sending = 1;
650        }
651
652        rtems_interrupt_enable(oldLevel);
653
654        return 0;
655}
656
657/* Handle UART interrupts */
658void apbuart_isr(void *arg)
659{
660        struct apbuart_priv *uart = arg;
661        unsigned int status;
662        char data;
663        int cnt;
664
665        /* Get all received characters */
666        if (uart->mode == TERMIOS_TASK_DRIVEN) {
667                if ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR)
668                        rtems_termios_rxirq_occured(uart->cookie);
669        } else {
670                while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
671                        /* Data has arrived, get new data */
672                        data = uart->regs->data;
673
674                        /* Tell termios layer about new character */
675                        rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
676                }
677        }
678
679        if (uart->sending && (status & LEON_REG_UART_STATUS_THE)) {
680                /* Sent the one char, we disable TX interrupts */
681                uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
682
683                /* Tell close that we sent everything */
684                cnt = uart->sending;
685                uart->sending = 0;
686
687                /* apbuart_write_intr() will get called from this function */
688                rtems_termios_dequeue_characters(uart->cookie, cnt);
689        }
690}
Note: See TracBrowser for help on using the repository browser.