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

4.115
Last change on this file since 18564f5 was 18564f5, checked in by Daniel Hellstrom <daniel@…>, on 06/19/12 at 12:49:40

APBUART: fix GRMON -u support for older UARTs

  • Property mode set to 100644
File size: 17.6 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         * With old APBUARTs debug is enabled by setting LB and FL, since LB is
202         * not reset we can not trust is, however since FL is reset we guess
203         * that we are debugging old UART if both FL and LB is already set.
204         */
205#ifdef LEON3
206        if (priv->regs == dbg_uart) {
207                db = priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
208                                        LEON_REG_UART_CTRL_RE |
209                                        LEON_REG_UART_CTRL_TE |
210                                        LEON_REG_UART_CTRL_FL |
211                                        LEON_REG_UART_CTRL_LB |
212                                        LEON_REG_UART_CTRL_PE |
213                                        LEON_REG_UART_CTRL_PS);
214        } else
215#endif
216        {
217                if (priv->regs->ctrl & (LEON_REG_UART_CTRL_FL |
218                                        LEON_REG_UART_CTRL_LB))
219                        db = priv->regs->ctrl & (LEON_REG_UART_CTRL_FL |
220                                        LEON_REG_UART_CTRL_LB);
221                else                                   
222                        db = priv->regs->ctrl & LEON_REG_UART_CTRL_DB;
223        }
224
225        priv->regs->ctrl = db;
226
227        /* The system console and Debug console may depend on this device, so
228         * initialize it straight away.
229         *
230         * We default to have System Console on first APBUART, user may override
231         * this behaviour by setting the syscon option to 0.
232         */
233        if (drvmgr_on_rootbus(dev) && first_uart) {
234                priv->condev.flags = CONSOLE_FLAG_SYSCON;
235                first_uart = 0;
236        } else {
237                priv->condev.flags = 0;
238        }
239
240        value = drvmgr_dev_key_get(priv->dev, "syscon", KEY_TYPE_INT);
241        if (value) {
242                if (value->i)
243                        priv->condev.flags |= CONSOLE_FLAG_SYSCON;
244                else
245                        priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
246        }
247
248        priv->condev.fsname = NULL;
249        priv->condev.ops.get_uart_attrs = apbuart_get_attributes;
250
251        /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
252        value = drvmgr_dev_key_get(priv->dev, "mode", KEY_TYPE_INT);
253        if (value)
254                priv->mode = value->i;
255        else
256                priv->mode = TERMIOS_POLLED;
257        if (priv->mode == TERMIOS_IRQ_DRIVEN) {
258                priv->condev.callbacks = &Callbacks_intr;
259        } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
260                priv->condev.callbacks = &Callbacks_task;
261        } else {
262                priv->condev.callbacks = &Callbacks_poll;
263        }
264
265        /* Get Filesystem name prefix */
266        prefix[0] = '\0';
267        if (drvmgr_get_dev_prefix(dev, prefix)) {
268                /* Got special prefix, this means we have a bus prefix
269                 * And we should use our "bus minor"
270                 */
271                sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
272                priv->condev.fsname = priv->devName;
273        }
274
275        /* Register it as a console device, the console driver will register
276         * a termios device as well
277         */
278        console_dev_register(&priv->condev);
279
280        return DRVMGR_OK;
281}
282
283#ifdef APBUART_INFO_AVAIL
284static int apbuart_info(
285        struct drvmgr_dev *dev,
286        void (*print_line)(void *p, char *str),
287        void *p, int argc, char *argv[])
288{
289        struct apbuart_priv *priv = dev->priv;
290        char *str1;
291        char buf[64];
292
293        if (dev->priv == NULL)
294                return -DRVMGR_EINVAL;
295
296        if (priv->mode == TERMIOS_POLLED)
297                str1 = "TERMIOS_POLLED";
298        else if (priv->mode == TERMIOS_TASK_DRIVEN)
299                str1 = "TERMIOS_TASK_DRIVEN";
300        else if (priv->mode == TERMIOS_TASK_DRIVEN)
301                str1 = "TERMIOS_TASK_DRIVEN";
302        else
303                str1 = "BAD MODE";
304
305        sprintf(buf, "UART Mode:   %s", str1);
306        print_line(p, buf);
307        if (priv->condev.fsname) {
308                sprintf(buf, "FS Name:     %s", priv->condev.fsname);
309                print_line(p, buf);
310        }
311        sprintf(buf, "STATUS REG:  0x%x", priv->regs->status);
312        print_line(p, buf);
313        sprintf(buf, "CTRL REG:    0x%x", priv->regs->ctrl);
314        print_line(p, buf);
315        sprintf(buf, "SCALER REG:  0x%x  baud rate %d",
316                                priv->regs->scaler, apbuart_get_baud(priv));
317        print_line(p, buf);
318
319        return DRVMGR_OK;
320}
321#endif
322
323#ifndef LEON3
324/* This routine transmits a character, it will busy-wait until on character
325 * fits in the APBUART Transmit FIFO
326 */
327void apbuart_outbyte_polled(
328  struct apbuart_regs *regs,
329  unsigned char ch,
330  int do_cr_on_newline,
331  int wait_sent)
332{
333send:
334        while ((regs->status & LEON_REG_UART_STATUS_THE) == 0) {
335                /* Lower bus utilization while waiting for UART */
336                asm volatile ("nop"::); asm volatile ("nop"::);
337                asm volatile ("nop"::); asm volatile ("nop"::);
338                asm volatile ("nop"::); asm volatile ("nop"::);
339                asm volatile ("nop"::); asm volatile ("nop"::);
340        }
341        regs->data = (unsigned int) ch;
342
343        if ((ch == '\n') && do_cr_on_newline) {
344                ch = '\r';
345                goto send;
346        }
347
348        /* Wait until the character has been sent? */
349        if (wait_sent) {
350                while ((regs->status & LEON_REG_UART_STATUS_THE) == 0)
351                        ;
352        }
353}
354
355/* This routine polls for one character, return EOF if no character is available */
356int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
357{
358        if (regs->status & LEON_REG_UART_STATUS_ERR) {
359                regs->status = ~LEON_REG_UART_STATUS_ERR;
360        }
361
362        if ((regs->status & LEON_REG_UART_STATUS_DR) == 0)
363                return EOF;
364
365        return (int)regs->data;
366}
367#endif
368
369int apbuart_firstOpen(int major, int minor, void *arg)
370{
371        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
372        rtems_libio_open_close_args_t *ioarg = arg;
373
374        if ( ioarg && ioarg->iop )
375                uart->cookie = ioarg->iop->data1;
376        else
377                uart->cookie = NULL;
378
379        /* Enable TX/RX */
380        uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
381
382        if (uart->mode != TERMIOS_POLLED) {
383                /* Register interrupt and enable it */
384                drvmgr_interrupt_register(uart->dev, 0, "apbuart",
385                                                apbuart_isr, uart);
386
387                uart->sending = 0;
388                /* Turn on RX interrupts */
389                uart->regs->ctrl |= LEON_REG_UART_CTRL_RI;
390        }
391
392        return 0;
393}
394
395int apbuart_lastClose(int major, int minor, void *arg)
396{
397        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
398
399        if (uart->mode != TERMIOS_POLLED) {
400                /* Turn off RX interrupts */
401                uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
402
403                /**** Flush device ****/
404                while (uart->sending) {
405                        /* Wait until all data has been sent */
406                }
407
408                /* Disable and unregister interrupt handler */
409                drvmgr_interrupt_unregister(uart->dev, 0, apbuart_isr, uart);
410        }
411
412#ifdef LEON3
413        /* Disable TX/RX if not used for DEBUG */
414        if (uart->regs != dbg_uart)
415                uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE);
416#endif
417
418        return 0;
419}
420
421int apbuart_pollRead(int minor)
422{
423        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
424
425        return apbuart_inbyte_nonblocking(uart->regs);
426}
427
428int apbuart_pollRead_task(int minor)
429{
430        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
431        int c, tot;
432        char buf[32];
433
434        tot = 0;
435        while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
436                buf[tot] = c;
437                tot++;
438                if (tot > 31) {
439                        rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
440                        tot = 0;
441                }
442        }
443        if (tot > 0)
444                rtems_termios_enqueue_raw_characters(uart->cookie, buf, tot);
445
446        return EOF;
447}
448
449struct apbuart_baud {
450        unsigned int num;
451        unsigned int baud;
452};
453struct apbuart_baud apbuart_baud_table[] = {
454        {B50, 50},
455        {B75, 75},
456        {B110, 110},
457        {B134, 134},
458        {B150, 150},
459        {B200, 200},
460        {B300, 300},
461        {B600, 600},
462        {B1200, 1200},
463        {B1800, 1800},
464        {B2400, 2400},
465        {B4800, 4800},
466        {B9600, 9600},
467        {B19200, 19200},
468        {B38400, 38400},
469        {B57600, 57600},
470        {B115200, 115200},
471        {B230400, 230400},
472        {B460800, 460800},
473};
474#define BAUD_NUM (sizeof(apbuart_baud_table)/sizeof(struct apbuart_baud))
475
476int apbuart_baud_num2baud(unsigned int num)
477{
478        int i;
479
480        for(i=0; i<BAUD_NUM; i++)
481                if (apbuart_baud_table[i].num == num)
482                        return apbuart_baud_table[i].baud;
483        return -1;
484}
485
486struct apbuart_baud *apbuart_baud_find_closest(unsigned int baud)
487{
488        int i, diff;
489
490        for(i=0; i<BAUD_NUM-1; i++) {
491                diff = apbuart_baud_table[i+1].baud -
492                        apbuart_baud_table[i].baud;
493                if (baud < (apbuart_baud_table[i].baud + diff/2))
494                        return &apbuart_baud_table[i];
495        }
496        return &apbuart_baud_table[BAUD_NUM-1];
497}
498
499int apbuart_get_baud(struct apbuart_priv *uart)
500{
501        unsigned int core_clk_hz;
502        unsigned int scaler;
503
504        /* Get current scaler setting */
505        scaler = uart->regs->scaler;
506
507        /* Get APBUART core frequency */
508        drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
509
510        /* Calculate baud rate from generator "scaler" number */
511        return core_clk_hz / ((scaler + 1) * 8);
512}
513
514struct apbuart_baud *apbuart_get_baud_closest(struct apbuart_priv *uart)
515{
516        return apbuart_baud_find_closest(apbuart_get_baud(uart));
517}
518
519int apbuart_set_attributes(int minor, const struct termios *t)
520{
521        unsigned int core_clk_hz;
522        unsigned int scaler;
523        unsigned int ctrl;
524        int baud;
525        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
526
527        switch(t->c_cflag & CSIZE) {
528                default:
529                case CS5:
530                case CS6:
531                case CS7:
532                        /* Hardware doesn't support other than CS8 */
533                        return -1;
534                case CS8:
535                        break;
536        }
537
538        /* Read out current value */
539        ctrl = uart->regs->ctrl;
540
541        switch(t->c_cflag & (PARENB|PARODD)){
542                case (PARENB|PARODD):
543                        /* Odd parity */
544                        ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
545                        break;
546
547                case PARENB:
548                        /* Even parity */
549                        ctrl &= ~LEON_REG_UART_CTRL_PS;
550                        ctrl |= LEON_REG_UART_CTRL_PE;
551                        break;
552
553                default:
554                case 0:
555                case PARODD:
556                        /* No Parity */
557                        ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
558        }
559
560        if (!(t->c_cflag & CLOCAL))
561                ctrl |= LEON_REG_UART_CTRL_FL;
562        else
563                ctrl &= ~LEON_REG_UART_CTRL_FL;
564
565        /* Update new settings */
566        uart->regs->ctrl = ctrl;
567
568        /* Baud rate */
569        baud = apbuart_baud_num2baud(t->c_cflag & CBAUD);
570        if (baud > 0){
571                /* Get APBUART core frequency */
572                drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
573
574                /* Calculate Baud rate generator "scaler" number */
575                scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
576
577                /* Set new baud rate by setting scaler */
578                uart->regs->scaler = scaler;
579        }
580
581        return 0;
582}
583
584void apbuart_get_attributes(struct console_dev *condev, struct termios *t)
585{
586        struct apbuart_priv *uart = (struct apbuart_priv *)condev;
587        unsigned int ctrl;
588        struct apbuart_baud *baud;
589
590        t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL|CBAUD);
591
592        /* Hardware support only CS8 */
593        t->c_cflag |= CS8;
594
595        /* Read out current parity */
596        ctrl = uart->regs->ctrl;
597        if (ctrl & LEON_REG_UART_CTRL_PE) {
598                if (ctrl & LEON_REG_UART_CTRL_PS)
599                        t->c_cflag |= PARENB|PARODD; /* Odd parity */
600                else
601                        t->c_cflag |= PARENB; /* Even parity */
602        }
603
604        if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
605                t->c_cflag |= CLOCAL;
606
607        baud = apbuart_get_baud_closest(uart);
608        t->c_cflag |= baud->num;
609}
610
611ssize_t apbuart_write_polled(int minor, const char *buf, size_t len)
612{
613        int nwrite = 0;
614        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
615
616        while (nwrite < len) {
617                apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
618                nwrite++;
619        }
620        return nwrite;
621}
622
623ssize_t apbuart_write_intr(int minor, const char *buf, size_t len)
624{
625        struct apbuart_priv *uart = (struct apbuart_priv *)minor;
626        unsigned int oldLevel;
627        unsigned int ctrl;
628
629        rtems_interrupt_disable(oldLevel);
630
631        /* Enable TX interrupt */
632        ctrl = uart->regs->ctrl;
633        uart->regs->ctrl = ctrl | LEON_REG_UART_CTRL_TI;
634
635        if (ctrl & LEON_REG_UART_CTRL_FA) {
636                /* APBUART with FIFO.. Fill as many as FIFO allows */
637                uart->sending = 0;
638                while (((uart->regs->status & LEON_REG_UART_STATUS_TF) == 0) &&
639                       (uart->sending < len)) {
640                        uart->regs->data = *buf;
641                        buf++;
642                        uart->sending++;
643                }
644        } else {
645                /* start UART TX, this will result in an interrupt when done */
646                uart->regs->data = *buf;
647
648                uart->sending = 1;
649        }
650
651        rtems_interrupt_enable(oldLevel);
652
653        return 0;
654}
655
656/* Handle UART interrupts */
657void apbuart_isr(void *arg)
658{
659        struct apbuart_priv *uart = arg;
660        unsigned int status;
661        char data;
662        int cnt;
663
664        /* Get all received characters */
665        if (uart->mode == TERMIOS_TASK_DRIVEN) {
666                if ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR)
667                        rtems_termios_rxirq_occured(uart->cookie);
668        } else {
669                while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
670                        /* Data has arrived, get new data */
671                        data = uart->regs->data;
672
673                        /* Tell termios layer about new character */
674                        rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
675                }
676        }
677
678        if (uart->sending && (status & LEON_REG_UART_STATUS_THE)) {
679                /* Sent the one char, we disable TX interrupts */
680                uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
681
682                /* Tell close that we sent everything */
683                cnt = uart->sending;
684                uart->sending = 0;
685
686                /* apbuart_write_intr() will get called from this function */
687                rtems_termios_dequeue_characters(uart->cookie, cnt);
688        }
689}
Note: See TracBrowser for help on using the repository browser.