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

4.11
Last change on this file since bef5e23e was 4d3e70f4, checked in by Daniel Hellstrom <daniel@…>, on Apr 13, 2015 at 9:26:52 AM

DRVMGR: KEY_TYPE now a enum drvmgr_kt

  • 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_cflag & CBAUD);
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|CBAUD);
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.