⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 16550a.c

📁 xenomai 很好的linux实时补丁
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 2005, 2006 Jan Kiszka <jan.kiszka@web.de>. * * Xenomai is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Xenomai is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Xenomai; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <linux/module.h>#include <linux/ioport.h>#include <asm/io.h>#include <rtdm/rtserial.h>#include <rtdm/rtdm_driver.h>#define MAX_DEVICES         8#define IN_BUFFER_SIZE      4096#define OUT_BUFFER_SIZE     4096#define DEFAULT_BAUD_BASE   115200#define DEFAULT_TX_FIFO     16#define PARITY_MASK         0x03#define DATA_BITS_MASK      0x03#define STOP_BITS_MASK      0x01#define FIFO_MASK           0xC0#define EVENT_MASK          0x0F#define LCR_DLAB            0x80#define FCR_FIFO            0x01#define FCR_RESET           0x06#define IER_RX              0x01#define IER_TX              0x02#define IER_STAT            0x04#define IER_MODEM           0x08#define IIR_MODEM           0x00#define IIR_PIRQ            0x01#define IIR_TX              0x02#define IIR_RX              0x04#define IIR_STAT            0x06#define IIR_TMO             0x0C#define IIR_MASK            0x0F#define RHR(dev) (ioaddr[dev] + 0)  /* Receive Holding Buffer */#define THR(dev) (ioaddr[dev] + 0)  /* Transmit Holding Buffer */#define DLL(dev) (ioaddr[dev] + 0)  /* Divisor Latch LSB */#define IER(dev) (ioaddr[dev] + 1)  /* Interrupt Enable Register */#define DLM(dev) (ioaddr[dev] + 1)  /* Divisor Latch MSB */#define IIR(dev) (ioaddr[dev] + 2)  /* Interrupt Id Register */#define FCR(dev) (ioaddr[dev] + 2)  /* Fifo Control Register */#define LCR(dev) (ioaddr[dev] + 3)  /* Line Control Register */#define MCR(dev) (ioaddr[dev] + 4)  /* Modem Control Register */#define LSR(dev) (ioaddr[dev] + 5)  /* Line Status Register */#define MSR(dev) (ioaddr[dev] + 6)  /* Modem Status Register */struct rt_16550_context {    struct rtser_config     config;    rtdm_irq_t              irq_handle;    rtdm_lock_t             lock;    int                     dev_id;    int                     in_head;    int                     in_tail;    volatile size_t         in_npend;    int                     in_nwait;    rtdm_event_t            in_event;    char                    in_buf[IN_BUFFER_SIZE];    volatile unsigned long  in_lock;    uint64_t                *in_history;    int                     out_head;    int                     out_tail;    size_t                  out_npend;    rtdm_event_t            out_event;    char                    out_buf[OUT_BUFFER_SIZE];    rtdm_mutex_t            out_lock;    uint64_t                last_timestamp;    volatile int            ioc_events;    rtdm_event_t            ioc_event;    volatile unsigned long  ioc_event_lock;    int                     ier_status;    int                     mcr_status;    int                     status;};static const struct rtser_config default_config = {    0xFFFF, RTSER_DEF_BAUD, RTSER_DEF_PARITY, RTSER_DEF_BITS,    RTSER_DEF_STOPB, RTSER_DEF_HAND, RTSER_DEF_FIFO_DEPTH, RTSER_DEF_TIMEOUT,    RTSER_DEF_TIMEOUT, RTSER_DEF_TIMEOUT, RTSER_DEF_TIMESTAMP_HISTORY,    RTSER_DEF_EVENT_MASK};static struct rtdm_device   *device[MAX_DEVICES];static unsigned long        ioaddr[MAX_DEVICES];static unsigned int         irq[MAX_DEVICES];static unsigned int         baud_base[MAX_DEVICES];static int                  tx_fifo[MAX_DEVICES];static unsigned int         start_index;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)static int                  ioaddr_c;static int                  irq_c;static int                  baud_base_c;static int                  tx_fifo_c;module_param_array(ioaddr, ulong, &ioaddr_c, 0400);module_param_array(irq, uint, &irq_c, 0400);module_param_array(baud_base, uint, &baud_base_c, 0400);module_param_array(tx_fifo, int, &tx_fifo_c, 0400);#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) */MODULE_PARM(ioaddr, "1-" __MODULE_STRING(MAX_DEVICES) "i");MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_DEVICES) "i");MODULE_PARM(baud_base, "1-" __MODULE_STRING(MAX_DEVICES) "i");MODULE_PARM(tx_fifo, "1-" __MODULE_STRING(MAX_DEVICES) "i");#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) */MODULE_PARM_DESC(ioaddr, "I/O addresses of the serial devices");MODULE_PARM_DESC(irq, "IRQ numbers of the serial devices");MODULE_PARM_DESC(baud_base,    "Maximum baud rate of the serial device (internal clock rate / 16)");MODULE_PARM_DESC(tx_fifo, "Transmitter FIFO size");module_param(start_index, uint, 0400);MODULE_PARM_DESC(start_index, "First device instance number to be used");MODULE_LICENSE("GPL");MODULE_AUTHOR("jan.kiszka@web.de");static inline int rt_16550_rx_interrupt(struct rt_16550_context *ctx,                                        uint64_t *timestamp){    int dev_id = ctx->dev_id;    int rbytes = 0;    int lsr    = 0;    int c;    do {        c = inb(RHR(dev_id));   /* read input character */        ctx->in_buf[ctx->in_tail] = c;        if (ctx->in_history)            ctx->in_history[ctx->in_tail] = *timestamp;        ctx->in_tail = (ctx->in_tail + 1) & (IN_BUFFER_SIZE - 1);        if (++ctx->in_npend > IN_BUFFER_SIZE) {            /*DBGIF(                if (!testbits(ctx->status, RTSER_SOFT_OVERRUN_ERR))                    rtdm_printk("%s: software buffer overrun!\n",                                device[dev_id]->device_name);                );*/            lsr |= RTSER_SOFT_OVERRUN_ERR;            ctx->in_npend--;        }        rbytes++;        lsr &= ~RTSER_LSR_DATA;        lsr |= (inb(LSR(dev_id)) &                (RTSER_LSR_DATA | RTSER_LSR_OVERRUN_ERR |                 RTSER_LSR_PARITY_ERR | RTSER_LSR_FRAMING_ERR |                 RTSER_LSR_BREAK_IND));    } while (testbits(lsr, RTSER_LSR_DATA));    /* save new errors */    ctx->status |= lsr;    /* If we are enforcing the RTSCTS control flow and the input       buffer is busy above the specified high watermark, clear       RTS. *//*    if (uart->i_count >= uart->config.rts_hiwm &&        (uart->config.handshake & RT_UART_RTSCTS) != 0 &&        (uart->modem & MCR_RTS) != 0) {        uart->modem &= ~MCR_RTS;        outb(uart->modem,MCR(uart));    }*/    return rbytes;}static inline void rt_16550_tx_interrupt(struct rt_16550_context *ctx){    int c;    int count;    int dev_id = ctx->dev_id;/*    if (uart->modem & MSR_CTS)*/    {        for (count = tx_fifo[dev_id];             (count > 0) && (ctx->out_npend > 0);             count--, ctx->out_npend--) {            c = ctx->out_buf[ctx->out_head++];            outb(c, THR(dev_id));            ctx->out_head &= (OUT_BUFFER_SIZE - 1);        }    }}static inline void rt_16550_stat_interrupt(struct rt_16550_context *ctx){    ctx->status |= (inb(LSR(ctx->dev_id)) &                    (RTSER_LSR_OVERRUN_ERR | RTSER_LSR_PARITY_ERR |                     RTSER_LSR_FRAMING_ERR |RTSER_LSR_BREAK_IND));}static int rt_16550_interrupt(rtdm_irq_t *irq_context){    struct rt_16550_context *ctx;    int                     dev_id;    int                     iir;    uint64_t                timestamp = rtdm_clock_read();    int                     rbytes = 0;    int                     events = 0;    int                     modem;    int                     ret = RTDM_IRQ_NONE;    ctx = rtdm_irq_get_arg(irq_context, struct rt_16550_context);    dev_id    = ctx->dev_id;    rtdm_lock_get(&ctx->lock);    while (((iir = inb(IIR(dev_id))) & IIR_PIRQ) == 0) {        if (testbits(iir, IIR_RX | IIR_TMO)) {            rbytes += rt_16550_rx_interrupt(ctx, &timestamp);            events |= RTSER_EVENT_RXPEND;        }        if (testbits(iir, IIR_STAT))            rt_16550_stat_interrupt(ctx);        if (testbits(iir, IIR_TX))            rt_16550_tx_interrupt(ctx);        if (testbits(iir, IIR_MODEM)) {            modem = inb(MSR(dev_id));            if (modem & (modem << 4))                events |= RTSER_EVENT_MODEMHI;            if ((modem ^ 0xF0) & (modem << 4))                events |= RTSER_EVENT_MODEMLO;        }        ret = RTDM_IRQ_HANDLED;    }    if (ctx->in_nwait > 0) {        if ((ctx->in_nwait <= rbytes) || ctx->status) {            ctx->in_nwait = 0;            rtdm_event_signal(&ctx->in_event);        }        else            ctx->in_nwait -= rbytes;    }    if (ctx->status) {        events |= RTSER_EVENT_ERRPEND;        ctx->ier_status &= ~IER_STAT;    }    if (testbits(events, ctx->config.event_mask)) {        int old_events = ctx->ioc_events;        ctx->last_timestamp = timestamp;        ctx->ioc_events     = events;        if (!old_events)            rtdm_event_signal(&ctx->ioc_event);    }    if (testbits(ctx->ier_status, IER_TX) &&        (ctx->out_npend == 0)) {        /* mask transmitter empty interrupt */        ctx->ier_status &= ~IER_TX;        rtdm_event_signal(&ctx->out_event);    }    /* update interrupt mask */    outb(ctx->ier_status, IER(dev_id));    rtdm_lock_put(&ctx->lock);    return ret;}static int rt_16550_set_config(struct rt_16550_context *ctx,                               const struct rtser_config *config,                               uint64_t **in_history_ptr){    rtdm_lockctx_t  lock_ctx;    int             dev_id;    int             ret = 0;    int             baud_div = 0;    dev_id = ctx->dev_id;    /* make line configuration atomic and IRQ-safe */    rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);    if (testbits(config->config_mask, RTSER_SET_BAUD)) {        ctx->config.baud_rate = config->baud_rate;        baud_div = (baud_base[dev_id] + (ctx->config.baud_rate >> 1)) /                   ctx->config.baud_rate;        outb(LCR_DLAB,        LCR(dev_id));        outb(baud_div & 0xff, DLL(dev_id));        outb(baud_div >> 8,   DLM(dev_id));    }    if (testbits(config->config_mask, RTSER_SET_PARITY))        ctx->config.parity    = config->parity & PARITY_MASK;    if (testbits(config->config_mask, RTSER_SET_DATA_BITS))        ctx->config.data_bits = config->data_bits & DATA_BITS_MASK;    if (testbits(config->config_mask, RTSER_SET_STOP_BITS))        ctx->config.stop_bits = config->stop_bits & STOP_BITS_MASK;    if (testbits(config->config_mask, RTSER_SET_PARITY | RTSER_SET_DATA_BITS |                                      RTSER_SET_STOP_BITS | RTSER_SET_BAUD)) {        outb((ctx->config.parity << 3) | (ctx->config.stop_bits << 2) |             ctx->config.data_bits, LCR(dev_id));        ctx->status = 0;        ctx->ioc_events &= ~RTSER_EVENT_ERRPEND;    }    if (testbits(config->config_mask, RTSER_SET_FIFO_DEPTH)) {        ctx->config.fifo_depth = config->fifo_depth & FIFO_MASK;        outb(FCR_FIFO | FCR_RESET, FCR(dev_id));        outb(FCR_FIFO | ctx->config.fifo_depth, FCR(dev_id));    }    rtdm_lock_put_irqrestore(&ctx->lock, lock_ctx);    /* Timeout manipulation is not atomic. The user is supposed to take care     * not to use and change timeouts at the same time. */    if (testbits(config->config_mask, RTSER_SET_TIMEOUT_RX))        ctx->config.rx_timeout = config->rx_timeout;    if (testbits(config->config_mask, RTSER_SET_TIMEOUT_TX))        ctx->config.tx_timeout = config->tx_timeout;    if (testbits(config->config_mask, RTSER_SET_TIMEOUT_EVENT))        ctx->config.event_timeout = config->event_timeout;    if (testbits(config->config_mask, RTSER_SET_TIMESTAMP_HISTORY)) {        /* change timestamp history atomically */        rtdm_lock_get_irqsave(&ctx->lock, lock_ctx);        if (testbits(config->timestamp_history, RTSER_RX_TIMESTAMP_HISTORY)) {            if (!ctx->in_history) {                ctx->in_history = *in_history_ptr;                *in_history_ptr = NULL;                if (!ctx->in_history)                    ret = -ENOMEM;            }        } else {            *in_history_ptr = ctx->in_history;            ctx->in_history = NULL;        }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -