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

4.11
Last change on this file since c1764100 was c1764100, checked in by Daniel Hellstrom <daniel@…>, on Dec 16, 2011 at 10:39:23 AM

LEON3: new Console driver, APBUART driver using Driver Manager

This patch reimplements the console driver of the LEON3 BSP, it
has split up the console driver in two parts: Console driver and
UART driver. Before the only UART supported was APBUART and only
on-chip APBUARTs found during startup. However splitting the
driver in two allows any UART interface to reuse the termios
attach code of the console driver, pratically this has always
been a problem when discovering APBUARTs after startup for
example the PCI board GR-RASTA-IO has APBUARTs and must wait
until after PCI has been setup.

Since the only current driver that supports the new console
driver uses the Driver Manager, the new console driver is
only enabled when Driver Manager is initialized during startup.

The new APBUART driver supports:

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