source: rtems/bsps/sparc/shared/uart/apbuart_cons.c @ aea3134e

5
Last change on this file since aea3134e was aea3134e, checked in by Daniel Hellstrom <daniel@…>, on 06/15/18 at 06:49:31

leon,apbuart: replace termios c_cflag & CBAUD with c_{i,o}speed

ince some time RTEMS started to use the termios c_ispeed and
c_ospeed variables in the termios struct to hold the UART baudrate.
However the APBUART driver still uses the old c_cflag sometimes
causing other UART parameters to get overwritten, for example the
partiy setting no mapped to the same bits as the old CBAUD mask.

At the same time the RTEMS primitievs for setting/reading
c_{i,o}speed is now used.

  • Property mode set to 100644
File size: 18.8 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 <stdlib.h>
22#include <assert.h>
23#include <rtems/bspIo.h>
24#include <string.h>
25#include <stdio.h>
26
27#include <drvmgr/drvmgr.h>
28#include <drvmgr/ambapp_bus.h>
29#include <bsp/apbuart.h>
30#include <ambapp.h>
31#include <grlib.h>
32#include <bsp/cons.h>
33#include <rtems/termiostypes.h>
34#include <bsp/apbuart_cons.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 */
45#ifdef LEON3
46extern struct apbuart_regs *leon3_debug_uart; /* The debug UART */
47#endif
48
49/* Probed hardware capabilities */
50enum {
51        CAP_FIFO = 0x01, /* FIFO available */
52        CAP_DI   = 0x02, /* RX delayed interrupt available */
53};
54struct apbuart_priv {
55        struct console_dev condev;
56        struct drvmgr_dev *dev;
57        struct apbuart_regs *regs;
58        struct rtems_termios_tty *tty;
59        char devName[32];
60        volatile int sending;
61        int mode;
62        int cap;
63};
64
65/* Getters for different interfaces. It happens to be just casting which we do
66 * in one place to avoid getting cast away. */
67static struct console_dev *base_get_condev(rtems_termios_device_context *base)
68{
69        return (struct console_dev *) base;
70}
71
72static struct apbuart_priv *condev_get_priv(struct console_dev *condev)
73{
74        return (struct apbuart_priv *) condev;
75}
76
77static struct apbuart_priv *base_get_priv(rtems_termios_device_context *base)
78{
79        return condev_get_priv(base_get_condev(base));
80}
81
82/* TERMIOS Layer Callback functions */
83static bool first_open(
84  rtems_termios_tty *tty,
85  rtems_termios_device_context *base,
86  struct termios *term,
87  rtems_libio_open_close_args_t *args
88);
89static void last_close(
90  rtems_termios_tty *tty,
91  rtems_termios_device_context *base,
92  rtems_libio_open_close_args_t *args
93);
94static void write_interrupt(
95  rtems_termios_device_context *base,
96  const char *buf,
97  size_t len
98);
99static bool set_attributes(
100        rtems_termios_device_context *base,
101        const struct termios *t
102);
103static void get_attributes(
104        rtems_termios_device_context *base,
105        struct termios *t
106);
107static int read_polled(rtems_termios_device_context *base);
108static int read_task(rtems_termios_device_context *base);
109static void write_polled(
110  rtems_termios_device_context *base,
111  const char *buf,
112  size_t len
113);
114
115static void apbuart_cons_isr(void *arg);
116int apbuart_get_baud(struct apbuart_priv *uart);
117
118int apbuart_init1(struct drvmgr_dev *dev);
119#ifdef APBUART_INFO_AVAIL
120static int apbuart_info(
121        struct drvmgr_dev *dev,
122        void (*print_line)(void *p, char *str),
123        void *p, int, char *argv[]);
124#define APBUART_INFO_FUNC apbuart_info
125#else
126#define APBUART_INFO_FUNC NULL
127#endif
128
129struct drvmgr_drv_ops apbuart_ops =
130{
131        .init = {apbuart_init1, NULL, NULL, NULL},
132        .remove = NULL,
133        .info = APBUART_INFO_FUNC
134};
135
136static struct amba_dev_id apbuart_ids[] =
137{
138        {VENDOR_GAISLER, GAISLER_APBUART},
139        {0, 0}          /* Mark end of table */
140};
141
142static struct amba_drv_info apbuart_drv_info =
143{
144        {
145                DRVMGR_OBJ_DRV,                         /* Driver */
146                NULL,                                   /* Next driver */
147                NULL,                                   /* Device list */
148                DRIVER_AMBAPP_GAISLER_APBUART_ID,       /* Driver ID */
149                "APBUART_DRV",                          /* Driver Name */
150                DRVMGR_BUS_TYPE_AMBAPP,                 /* Bus Type */
151                &apbuart_ops,
152                NULL,                                   /* Funcs */
153                0,                                      /* No devices yet */
154                sizeof(struct apbuart_priv),            /*DrvMgr alloc private*/
155        },
156        &apbuart_ids[0]
157};
158
159void apbuart_cons_register_drv (void)
160{
161        DBG("Registering APBUART Console driver\n");
162        drvmgr_drv_register(&apbuart_drv_info.general);
163}
164
165static const rtems_termios_device_handler handler_interrupt = {
166        .first_open     = first_open,
167        .last_close     = last_close,
168        .write          = write_interrupt,
169        .set_attributes = set_attributes,
170        .mode           = TERMIOS_IRQ_DRIVEN
171};
172
173static const rtems_termios_device_handler handler_task = {
174        .first_open     = first_open,
175        .last_close     = last_close,
176        .poll_read      = read_task,
177        .write          = write_interrupt,
178        .set_attributes = set_attributes,
179        .mode           = TERMIOS_TASK_DRIVEN
180};
181
182static const rtems_termios_device_handler handler_polled = {
183        .first_open     = first_open,
184        .last_close     = last_close,
185        .poll_read      = read_polled,
186        .write          = write_polled,
187        .set_attributes = set_attributes,
188        .mode           = TERMIOS_POLLED
189};
190
191/*
192 * APBUART hardware instantiation is flexible. Probe features here and driver
193 * can select appropriate routines for the hardware. probecap() return value
194 * is a CAP_ bitmask.
195 */
196static int probecap(struct apbuart_regs *regs)
197{
198        int cap = 0;
199
200        /* Probe FIFO */
201        if (regs->ctrl & APBUART_CTRL_FA) {
202                cap |= CAP_FIFO;
203
204                /* Probe RX delayed interrupt */
205                regs->ctrl |= APBUART_CTRL_DI;
206                if (regs->ctrl & APBUART_CTRL_DI) {
207                        regs->ctrl &= ~APBUART_CTRL_DI;
208                        cap |= CAP_DI;
209                }
210        }
211
212        return cap;
213}
214
215int apbuart_init1(struct drvmgr_dev *dev)
216{
217        struct apbuart_priv *priv;
218        struct amba_dev_info *ambadev;
219        struct ambapp_core *pnpinfo;
220        union drvmgr_key_value *value;
221        char prefix[32];
222        unsigned int db;
223        static int first_uart = 1;
224
225        /* The default operation in AMP is to use APBUART[0] for CPU[0],
226         * APBUART[1] for CPU[1] and so on. The remaining UARTs is not used
227         * since we don't know how many CPU-cores there are. Note this only
228         * affects the on-chip amba bus (the root bus). The user can override
229         * the default resource sharing by defining driver resources for the
230         * APBUART devices on each AMP OS instance.
231         */
232#if defined(RTEMS_MULTIPROCESSING) && defined(LEON3)
233        if (drvmgr_on_rootbus(dev) && dev->minor_drv != LEON3_Cpu_Index &&
234            drvmgr_keys_get(dev, NULL) != 0) {
235                /* User hasn't configured on-chip APBUART, leave it untouched */
236                return DRVMGR_EBUSY;
237        }
238#endif
239
240        DBG("APBUART[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
241        /* Private data was allocated and zeroed by driver manager */
242        priv = dev->priv;
243        if (!priv)
244                return DRVMGR_NOMEM;
245        priv->dev = dev;
246
247        /* Get device information from AMBA PnP information */
248        ambadev = (struct amba_dev_info *)priv->dev->businfo;
249        if (ambadev == NULL)
250                return -1;
251        pnpinfo = &ambadev->info;
252        priv->regs = (struct apbuart_regs *)pnpinfo->apb_slv->start;
253
254        /* Clear HW regs, leave baudrate register as it is */
255        priv->regs->status = 0;
256
257        /* leave Transmitter/receiver if this is the RTEMS debug UART (assume
258         * it has been setup by boot loader).
259         */
260        db = 0;
261#ifdef LEON3
262        if (priv->regs == leon3_debug_uart) {
263                db = priv->regs->ctrl & (LEON_REG_UART_CTRL_RE |
264                                        LEON_REG_UART_CTRL_TE |
265                                        LEON_REG_UART_CTRL_PE |
266                                        LEON_REG_UART_CTRL_PS);
267        }
268#endif
269        /* Let UART debug tunnelling be untouched if Flow-control is set.
270         *
271         * With old APBUARTs debug is enabled by setting LB and FL, since LB or
272         * DB are not reset we can not trust them. However since FL is reset we
273         * guess that we are debugging if FL is already set, the debugger set
274         * either LB or DB depending on UART capabilities.
275         */
276        if (priv->regs->ctrl & LEON_REG_UART_CTRL_FL) {
277                db |= priv->regs->ctrl & (LEON_REG_UART_CTRL_DB |
278                      LEON_REG_UART_CTRL_LB | LEON_REG_UART_CTRL_FL);
279        }
280
281        priv->regs->ctrl = db;
282
283        priv->cap = probecap(priv->regs);
284
285        /* The system console and Debug console may depend on this device, so
286         * initialize it straight away.
287         *
288         * We default to have System Console on first APBUART, user may override
289         * this behaviour by setting the syscon option to 0.
290         */
291        if (drvmgr_on_rootbus(dev) && first_uart) {
292                priv->condev.flags = CONSOLE_FLAG_SYSCON;
293                first_uart = 0;
294        } else {
295                priv->condev.flags = 0;
296        }
297
298        value = drvmgr_dev_key_get(priv->dev, "syscon", DRVMGR_KT_INT);
299        if (value) {
300                if (value->i)
301                        priv->condev.flags |= CONSOLE_FLAG_SYSCON;
302                else
303                        priv->condev.flags &= ~CONSOLE_FLAG_SYSCON;
304        }
305
306        /* Select 0=Polled, 1=IRQ, 2=Task-Driven UART Mode */
307        value = drvmgr_dev_key_get(priv->dev, "mode", DRVMGR_KT_INT);
308        if (value)
309                priv->mode = value->i;
310        else
311                priv->mode = TERMIOS_POLLED;
312        /* TERMIOS device handlers */
313        if (priv->mode == TERMIOS_IRQ_DRIVEN) {
314                priv->condev.handler = &handler_interrupt;
315        } else if (priv->mode == TERMIOS_TASK_DRIVEN) {
316                priv->condev.handler = &handler_task;
317        } else {
318                priv->condev.handler = &handler_polled;
319        }
320
321        priv->condev.fsname = NULL;
322        /* Get Filesystem name prefix */
323        prefix[0] = '\0';
324        if (drvmgr_get_dev_prefix(dev, prefix)) {
325                /* Got special prefix, this means we have a bus prefix
326                 * And we should use our "bus minor"
327                 */
328                sprintf(priv->devName, "/dev/%sapbuart%d", prefix, dev->minor_bus);
329                priv->condev.fsname = priv->devName;
330        } else {
331                sprintf(priv->devName, "/dev/apbuart%d", dev->minor_drv);
332        }
333
334        /* Register it as a console device, the console driver will register
335         * a termios device as well
336         */
337        console_dev_register(&priv->condev);
338
339        return DRVMGR_OK;
340}
341
342#ifdef APBUART_INFO_AVAIL
343static int apbuart_info(
344        struct drvmgr_dev *dev,
345        void (*print_line)(void *p, char *str),
346        void *p, int argc, char *argv[])
347{
348        struct apbuart_priv *priv = dev->priv;
349        char *str1;
350        char buf[64];
351
352        if (dev->priv == NULL)
353                return -DRVMGR_EINVAL;
354
355        if (priv->mode == TERMIOS_POLLED)
356                str1 = "TERMIOS_POLLED";
357        else if (priv->mode == TERMIOS_IRQ_DRIVEN)
358                str1 = "TERMIOS_IRQ_DRIVEN";
359        else if (priv->mode == TERMIOS_TASK_DRIVEN)
360                str1 = "TERMIOS_TASK_DRIVEN";
361        else
362                str1 = "BAD MODE";
363
364        sprintf(buf, "UART Mode:   %s", str1);
365        print_line(p, buf);
366        if (priv->condev.fsname) {
367                sprintf(buf, "FS Name:     %s", priv->condev.fsname);
368                print_line(p, buf);
369        }
370        sprintf(buf, "STATUS REG:  0x%x", priv->regs->status);
371        print_line(p, buf);
372        sprintf(buf, "CTRL REG:    0x%x", priv->regs->ctrl);
373        print_line(p, buf);
374        sprintf(buf, "SCALER REG:  0x%x  baud rate %d",
375                                priv->regs->scaler, apbuart_get_baud(priv));
376        print_line(p, buf);
377
378        return DRVMGR_OK;
379}
380#endif
381
382static bool first_open(
383        rtems_termios_tty *tty,
384        rtems_termios_device_context *base,
385        struct termios *term,
386        rtems_libio_open_close_args_t *args
387)
388{
389        struct apbuart_priv *uart = base_get_priv(base);
390
391        uart->tty = tty;
392
393        /* Inherit UART hardware parameters from bootloader on system console */
394        if (uart->condev.flags & CONSOLE_FLAG_SYSCON_GRANT) {
395                get_attributes(base, term);
396                term->c_oflag |= ONLCR;
397                set_attributes(base, term);
398        }
399
400        /* Enable TX/RX */
401        uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
402
403        if (uart->mode != TERMIOS_POLLED) {
404                int ret;
405                uint32_t ctrl;
406
407                /* Register interrupt and enable it */
408                ret = drvmgr_interrupt_register(
409                        uart->dev, 0, uart->devName, apbuart_cons_isr, tty
410                );
411                if (ret) {
412                        return false;
413                }
414
415                uart->sending = 0;
416
417                /* Turn on RX interrupts */
418                ctrl = uart->regs->ctrl;
419                ctrl |= APBUART_CTRL_RI;
420                if (uart->cap & CAP_DI) {
421                        /* Use RX FIFO interrupt only if delayed interrupt available. */
422                        ctrl |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
423                }
424                uart->regs->ctrl = ctrl;
425        }
426
427        return true;
428}
429
430static void last_close(
431        rtems_termios_tty *tty,
432        rtems_termios_device_context *base,
433        rtems_libio_open_close_args_t *args
434)
435{
436        struct apbuart_priv *uart = base_get_priv(base);
437        rtems_interrupt_lock_context lock_context;
438
439        if (uart->mode != TERMIOS_POLLED) {
440                /* Turn off RX interrupts */
441                rtems_termios_device_lock_acquire(base, &lock_context);
442                uart->regs->ctrl &=
443                        ~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
444                rtems_termios_device_lock_release(base, &lock_context);
445
446                /**** Flush device ****/
447                while (uart->sending) {
448                        /* Wait until all data has been sent */
449                }
450                while (
451                        (uart->regs->ctrl & APBUART_CTRL_TE) &&
452                        !(uart->regs->status & APBUART_STATUS_TS)
453                ) {
454                        /* Wait until all data has left shift register */
455                }
456
457                /* Disable and unregister interrupt handler */
458                drvmgr_interrupt_unregister(uart->dev, 0, apbuart_cons_isr, tty);
459        }
460
461#ifdef LEON3
462        /* Disable TX/RX if not used for DEBUG */
463        if (uart->regs != leon3_debug_uart)
464                uart->regs->ctrl &= ~(APBUART_CTRL_RE | APBUART_CTRL_TE);
465#endif
466}
467
468static int read_polled(rtems_termios_device_context *base)
469{
470        struct apbuart_priv *uart = base_get_priv(base);
471
472        return apbuart_inbyte_nonblocking(uart->regs);
473}
474
475/* This function is called from TERMIOS rxdaemon task without device lock. */
476static int read_task(rtems_termios_device_context *base)
477{
478        rtems_interrupt_lock_context lock_context;
479        struct apbuart_priv *uart = base_get_priv(base);
480        struct apbuart_regs *regs = uart->regs;
481        int cnt;
482        char buf[33];
483        struct rtems_termios_tty *tty;
484        uint32_t ctrl_add;
485
486        ctrl_add = APBUART_CTRL_RI;
487        if (uart->cap & CAP_DI) {
488                ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
489        }
490        tty = uart->tty;
491        do {
492                cnt = 0;
493                while (
494                        (regs->status & APBUART_STATUS_DR) &&
495                        (cnt < sizeof(buf))
496                ) {
497                        buf[cnt] = regs->data;
498                        cnt++;
499                }
500                if (0 < cnt) {
501                        /* Tell termios layer about new characters */
502                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
503                }
504
505                /*
506                 * Turn on RX interrupts. A new character in FIFO now may not
507                 * cause interrupt so we must check data ready again
508                 * afterwards.
509                 */
510                rtems_termios_device_lock_acquire(base, &lock_context);
511                regs->ctrl |= ctrl_add;
512                rtems_termios_device_lock_release(base, &lock_context);
513        } while (regs->status & APBUART_STATUS_DR);
514
515        return EOF;
516}
517
518int apbuart_get_baud(struct apbuart_priv *uart)
519{
520        unsigned int core_clk_hz;
521        unsigned int scaler;
522
523        /* Get current scaler setting */
524        scaler = uart->regs->scaler;
525
526        /* Get APBUART core frequency */
527        drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
528
529        /* Calculate baud rate from generator "scaler" number */
530        return core_clk_hz / ((scaler + 1) * 8);
531}
532
533static bool set_attributes(
534        rtems_termios_device_context *base,
535        const struct termios *t
536)
537{
538        unsigned int core_clk_hz;
539        unsigned int scaler;
540        unsigned int ctrl;
541        int baud;
542        struct apbuart_priv *uart = base_get_priv(base);
543        rtems_interrupt_lock_context lock_context;
544
545        switch(t->c_cflag & CSIZE) {
546                default:
547                case CS5:
548                case CS6:
549                case CS7:
550                        /* Hardware doesn't support other than CS8 */
551                        return false;
552                case CS8:
553                        break;
554        }
555
556        rtems_termios_device_lock_acquire(base, &lock_context);
557
558        /* Read out current value */
559        ctrl = uart->regs->ctrl;
560
561        switch(t->c_cflag & (PARENB|PARODD)){
562                case (PARENB|PARODD):
563                        /* Odd parity */
564                        ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
565                        break;
566
567                case PARENB:
568                        /* Even parity */
569                        ctrl &= ~LEON_REG_UART_CTRL_PS;
570                        ctrl |= LEON_REG_UART_CTRL_PE;
571                        break;
572
573                default:
574                case 0:
575                case PARODD:
576                        /* No Parity */
577                        ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
578        }
579
580        if (!(t->c_cflag & CLOCAL))
581                ctrl |= LEON_REG_UART_CTRL_FL;
582        else
583                ctrl &= ~LEON_REG_UART_CTRL_FL;
584
585        /* Update new settings */
586        uart->regs->ctrl = ctrl;
587
588        rtems_termios_device_lock_release(base, &lock_context);
589
590        /* Baud rate */
591        baud = rtems_termios_baud_to_number(t->c_ospeed);
592        if (baud > 0){
593                /* Get APBUART core frequency */
594                drvmgr_freq_get(uart->dev, DEV_APB_SLV, &core_clk_hz);
595
596                /* Calculate Baud rate generator "scaler" number */
597                scaler = (((core_clk_hz*10)/(baud*8))-5)/10;
598
599                /* Set new baud rate by setting scaler */
600                uart->regs->scaler = scaler;
601        }
602
603        return true;
604}
605
606static void get_attributes(
607        rtems_termios_device_context *base,
608        struct termios *t
609)
610{
611        struct apbuart_priv *uart = base_get_priv(base);
612        unsigned int ctrl;
613
614        t->c_cflag = t->c_cflag & ~(CSIZE|PARENB|PARODD|CLOCAL);
615
616        /* Hardware support only CS8 */
617        t->c_cflag |= CS8;
618
619        /* Read out current parity */
620        ctrl = uart->regs->ctrl;
621        if (ctrl & LEON_REG_UART_CTRL_PE) {
622                if (ctrl & LEON_REG_UART_CTRL_PS)
623                        t->c_cflag |= PARENB|PARODD; /* Odd parity */
624                else
625                        t->c_cflag |= PARENB; /* Even parity */
626        }
627
628        if ((ctrl & LEON_REG_UART_CTRL_FL) == 0)
629                t->c_cflag |= CLOCAL;
630
631        rtems_termios_set_best_baud(t, apbuart_get_baud(uart));
632}
633
634static void write_polled(
635        rtems_termios_device_context *base,
636        const char *buf,
637        size_t len
638)
639{
640        struct apbuart_priv *uart = base_get_priv(base);
641        int nwrite = 0;
642
643        while (nwrite < len) {
644                apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
645                nwrite++;
646        }
647}
648
649static void write_interrupt(
650        rtems_termios_device_context *base,
651        const char *buf,
652        size_t len
653)
654{
655        struct apbuart_priv *uart = base_get_priv(base);
656        struct apbuart_regs *regs = uart->regs;
657        int sending;
658        unsigned int ctrl;
659
660        ctrl = regs->ctrl;
661
662        if (len > 0) {
663                /*
664                 * sending is used to remember how much we have outstanding so
665                 * we can tell termios later.
666                 */
667                /* Enable TX interrupt (interrupt is edge-triggered) */
668                regs->ctrl = ctrl | APBUART_CTRL_TI;
669
670                if (ctrl & APBUART_CTRL_FA) {
671                        /* APBUART with FIFO.. Fill as many as FIFO allows */
672                        sending = 0;
673                        while (
674                                ((regs->status & APBUART_STATUS_TF) == 0) &&
675                                (sending < len)
676                        ) {
677                                regs->data = *buf;
678                                buf++;
679                                sending++;
680                        }
681                } else {
682                        /* start UART TX, this will result in an interrupt when done */
683                        regs->data = *buf;
684
685                        sending = 1;
686                }
687        } else {
688                /* No more to send, disable TX interrupts */
689                regs->ctrl = ctrl & ~APBUART_CTRL_TI;
690
691                /* Tell close that we sent everything */
692                sending = 0;
693        }
694
695        uart->sending = sending;
696}
697
698/* Handle UART interrupts */
699static void apbuart_cons_isr(void *arg)
700{
701        rtems_termios_tty *tty = arg;
702        rtems_termios_device_context *base;
703        struct console_dev *condev = rtems_termios_get_device_context(tty);
704        struct apbuart_priv *uart = condev_get_priv(condev);
705        struct apbuart_regs *regs = uart->regs;
706        unsigned int status;
707        char buf[33];
708        int cnt;
709
710        if (uart->mode == TERMIOS_TASK_DRIVEN) {
711                if ((status = regs->status) & APBUART_STATUS_DR) {
712                        rtems_interrupt_lock_context lock_context;
713
714                        /* Turn off RX interrupts */
715                        base = rtems_termios_get_device_context(tty);
716                        rtems_termios_device_lock_acquire(base, &lock_context);
717                        regs->ctrl &=
718                            ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
719                              APBUART_CTRL_RF);
720                        rtems_termios_device_lock_release(base, &lock_context);
721                        /* Activate termios RX daemon task */
722                        rtems_termios_rxirq_occured(tty);
723                }
724        } else {
725                /*
726                 * Get all new characters from APBUART RX (FIFO) and store them
727                 * on the stack. Then tell termios about the new characters.
728                 * Maximum APBUART RX FIFO size is 32 characters.
729                 */
730                cnt = 0;
731                while (
732                        ((status=regs->status) & APBUART_STATUS_DR) &&
733                        (cnt < sizeof(buf))
734                ) {
735                        buf[cnt] = regs->data;
736                        cnt++;
737                }
738                if (0 < cnt) {
739                        /* Tell termios layer about new characters */
740                        rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
741                }
742        }
743
744        if (uart->sending && (status & APBUART_STATUS_TE)) {
745                /* Tell close that we sent everything */
746                cnt = uart->sending;
747
748                /*
749                 * Tell termios how much we have sent. dequeue() may call
750                 * write_interrupt() to refill the transmitter.
751                 * write_interrupt() will eventually be called with 0 len to
752                 * disable TX interrupts.
753                 */
754                rtems_termios_dequeue_characters(tty, cnt);
755        }
756}
757
Note: See TracBrowser for help on using the repository browser.