UART设备驱动设计

/driver/serial/serial-core.c 中实现了UART设备的通用tty驱动层,称为串口核心层。

UART驱动的主要任务是 实现serial-core.c中定义的一组uart_xxx接口。
serial-core.c串口核心层完全可以当做一个tty设备驱动的实例,它是实现了UART设备的tty驱动。

串口核心层为串口设备驱动提供了3个结构体。
1. uart_driver
包含了串口设备的驱动名,设备名,设备号等信息。
它封装了tty_driver,使得底层UART驱动无需关心tty_driver.

struct uart_driver {
    struct module        *owner;
    const char        *driver_name;   //驱动名  /sys, /proc 下名称
    const char        *dev_name;      //设备名, /dev 下名称
    int             major;
    int             minor;
    int             nr;
    struct console        *cons;

    /*
     * these are private; the low level driver should not
     * touch these; they should be initialised to NULL
     */
    struct uart_state    *state;
    struct tty_driver    *tty_driver;
};

int uart_register_driver(struct uart_driver *drv)
void uart_unregister_driver(struct uart_driver*drv
)

一个tty驱动必须注册/注销tty_driver,而一个UART驱动则必须注册/注销uart_driver:

/**
 *    uart_register_driver - register a driver with the uart core layer
 *    @drv: low level driver structure
 *
 *    Register a uart driver with the core driver. We in turn register
 *    with the tty layer, and initialise the core driver per-port state.
 *
 *    We have a proc file in /proc/tty/driver which is named after the
 *    normal driver.
 *
 *    drv->port should be NULL, and the per-port structures should be
 *    registered using uart_add_one_port after this call has succeeded.
 */
int uart_register_driver(struct uart_driver *drv)
{
    struct tty_driver *normal;
    int i, retval;

    BUG_ON(drv->state);

    /*
     * Maybe we should be using a slab cache for this, especially if
     * we have a large number of ports to handle.
     */
    drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
    if (!drv->state)
        goto out;

    normal = alloc_tty_driver(drv->nr);   //分配tty_driver.
    if (!normal)
        goto out_kfree;

    drv->tty_driver = normal;          
    //初始化tty_driver
    normal->owner        = drv->owner;
    normal->driver_name    = drv->driver_name;
    normal->name        = drv->dev_name;
    normal->major        = drv->major;
    normal->minor_start    = drv->minor;
    normal->type        = TTY_DRIVER_TYPE_SERIAL;
    normal->subtype        = SERIAL_TYPE_NORMAL;
    normal->init_termios    = tty_std_termios;
    normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
    normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
    normal->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
    normal->driver_state = drv;
    tty_set_operations(normal, &uart_ops);

    /*
     * Initialise the UART state(s).
     */
    for (i = 0; i < drv->nr; i++) {
        struct uart_state *state = drv->state + i;
        struct tty_port *port = &state->port;

        tty_port_init(port);
        port->ops = &uart_port_ops;
        port->close_delay = 500;    /* .5 seconds */
        port->closing_wait = 30000;    /* 30 seconds */
        tasklet_init(&state->tlet, uart_tasklet_action,   //初始化一个tasklet延时执行机制
             (unsigned long)state);
    }

    retval = tty_register_driver(normal);     //注册tty驱动
    if (retval >= 0)
        return retval;

    put_tty_driver(normal);
out_kfree:
    kfree(drv->state);
out:
    return -ENOMEM;
}

/**
 *    uart_unregister_driver - remove a driver from the uart core layer
 *    @drv: low level driver structure
 *
 *    Remove all references to a driver from the core driver. The low
 *    level driver must have removed all its ports via the
 *    uart_remove_one_port() if it registered them with uart_add_one_port().
 *    (ie, drv->port == NULL)
 */
void uart_unregister_driver(struct uart_driver *drv)
{
    struct tty_driver *p = drv->tty_driver;
    tty_unregister_driver(p);             //注销tty驱动
    put_tty_driver(p);
    kfree(drv->state);
    drv->tty_driver = NULL;
}

2  uart_port
用于描述一个UART端口的I/O端口或I/O内存地址,FIFO大小,端口类型等。

typedef unsigned int __bitwise__ upf_t;

struct uart_port {
    spinlock_t        lock;            /* port lock */ //端口锁
    unsigned long        iobase;            /* in/out[bwl] */  //I/O端口基地址
    unsigned char __iomem    *membase;        /* read/write[bwl] */  //I/O内存及地址
    unsigned int        (*serial_in)(struct uart_port *, int);       
    void            (*serial_out)(struct uart_port *, int, int);
    void            (*set_termios)(struct uart_port *,
                 struct ktermios *new,
                 struct ktermios *old);
    void            (*pm)(struct uart_port *, unsigned int state,
                 unsigned int old);
    unsigned int        irq;            /* irq number */   //中断号
    unsigned long        irqflags;        /* irq flags */   
    unsigned int        uartclk;        /* base uart clock */  //UART时钟
    unsigned int        fifosize;        /* tx fifo size */    //传输的FIFO大小
    unsigned char        x_char;            /* xon/xoff char */  //xon/xoff字节
    unsigned char        regshift;        /* reg offset shift */ //寄存器移位
    unsigned char        iotype;            /* io access style */  //I/O存取类型
    unsigned char        unused1;

#define UPIO_PORT        (0)    //I/O 端口
#define UPIO_HUB6        (1)
#define UPIO_MEM        (2)     //I/O内存
#define UPIO_MEM32        (3)
#define UPIO_AU            (4)            /* Au1x00 type IO */
#define UPIO_TSI        (5)            /* Tsi108/109 type IO */
#define UPIO_DWAPB        (6)            /* DesignWare APB UART */
#define UPIO_RM9000        (7)            /* RM9000 type IO */

    unsigned int        read_status_mask;    /* driver specific */  //驱动特定的读状态掩码
    unsigned int        ignore_status_mask;    /* driver specific */ //驱动特定的忽略状态掩码
    struct uart_state    *state;            /* pointer to parent state */ //指向parent状态信息
    struct uart_icount    icount;            /* statistics */  //计数

    struct console        *cons;            /* struct console, if any */ //console结构体
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
    unsigned long        sysrq;            /* sysrq timeout */  //sysrq超时
#endif

    upf_t            flags;

#define UPF_FOURPORT        ((__force upf_t) (1 << 1))
#define UPF_SAK            ((__force upf_t) (1 << 2))
#define UPF_SPD_MASK        ((__force upf_t) (0x1030))
#define UPF_SPD_HI        ((__force upf_t) (0x0010))
#define UPF_SPD_VHI        ((__force upf_t) (0x0020))
#define UPF_SPD_CUST        ((__force upf_t) (0x0030))
#define UPF_SPD_SHI        ((__force upf_t) (0x1000))
#define UPF_SPD_WARP        ((__force upf_t) (0x1010))
#define UPF_SKIP_TEST        ((__force upf_t) (1 << 6))
#define UPF_AUTO_IRQ        ((__force upf_t) (1 << 7))
#define UPF_HARDPPS_CD        ((__force upf_t) (1 << 11))
#define UPF_LOW_LATENCY        ((__force upf_t) (1 << 13))
#define UPF_BUGGY_UART        ((__force upf_t) (1 << 14))
#define UPF_NO_TXEN_TEST    ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER    ((__force upf_t) (1 << 16))
#define UPF_CONS_FLOW        ((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ        ((__force upf_t) (1 << 24))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE        ((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF    ((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT        ((__force upf_t) (1 << 29))
#define UPF_DEAD        ((__force upf_t) (1 << 30))
#define UPF_IOREMAP        ((__force upf_t) (1 << 31))

#define UPF_CHANGE_MASK        ((__force upf_t) (0x17fff))
#define UPF_USR_MASK        ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))

    unsigned int        mctrl;            /* current modem ctrl settings */ //目前modem控制设置
    unsigned int        timeout;        /* character-based timeout */ //基于字符的超时
    unsigned int        type;            /* port type */  //端口类型
    const struct uart_ops    *ops;     //UART 操作符
    unsigned int        custom_divisor;
    unsigned int        line;            /* port index */  //端口索引
    resource_size_t        mapbase;        /* for ioremap */  //ioremap后基地址
    struct device        *dev;            /* parent device */  //parent设备
    unsigned char        hub6;            /* this should be in the 8250 driver */
    unsigned char        suspended;
    unsigned char        unused[2];
    void            *private_data;        /* generic platform data pointer */
};


串口核心层提供如下函数用来添加/删除一个端口:
int uart_add_one_port(struct uart_driver*drv,struct uart_port*uport);
int uart_remove_one_port(struct uart_driver*drv,struct uart_port *uport
);

/**
 *    uart_add_one_port - attach a driver-defined port structure
 *    @drv: pointer to the uart low level driver structure for this port
 *    @uport: uart port structure to use for this port.
 *
 *    This allows the driver to register its own uart_port structure
 *    with the core driver. The main purpose is to allow the low
 *    level uart drivers to expand uart_port, rather than having yet
 *    more levels of structures.
 */
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
    struct uart_state *state;
    struct tty_port *port;
    int ret = 0;
    struct device *tty_dev;

    BUG_ON(in_interrupt());

    if (uport->line >= drv->nr)
        return -EINVAL;

    state = drv->state + uport->line;
    port = &state->port;

    mutex_lock(&port_mutex);
    mutex_lock(&port->mutex);
    if (state->uart_port) {
        ret = -EINVAL;
        goto out;
    }

    state->uart_port = uport;
    state->pm_state = -1;

    uport->cons = drv->cons;
    uport->state = state;

    /*
     * If this port is a console, then the spinlock is already
     * initialised.
     */
    if (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {
        spin_lock_init(&uport->lock);
        lockdep_set_class(&uport->lock, &port_lock_key);
    }

    uart_configure_port(drv, state, uport);

    /*
     * Register the port whether it's detected or not. This allows
     * setserial to be used to alter this ports parameters.
     */
    tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
    if (likely(!IS_ERR(tty_dev))) {
        device_init_wakeup(tty_dev, 1);
        device_set_wakeup_enable(tty_dev, 0);
    } else
        printk(KERN_ERR "Cannot register tty device on line %d\n",
         uport->line);

    /*
     * Ensure UPF_DEAD is not set.
     */
    uport->flags &= ~UPF_DEAD;

 out:
    mutex_unlock(&port->mutex);
    mutex_unlock(&port_mutex);

    return ret;
}

/**
 *    uart_remove_one_port - detach a driver defined port structure
 *    @drv: pointer to the uart low level driver structure for this port
 *    @uport: uart port structure for this port
 *
 *    This unhooks (and hangs up) the specified port structure from the
 *    core driver. No further calls will be made to the low-level code
 *    for this port.
 */
int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport)
{
    struct uart_state *state = drv->state + uport->line;
    struct tty_port *port = &state->port;

    BUG_ON(in_interrupt());

    if (state->uart_port != uport)
        printk(KERN_ALERT "Removing wrong port: %p != %p\n",
            state->uart_port, uport);

    mutex_lock(&port_mutex);

    /*
     * Mark the port "dead" - this prevents any opens from
     * succeeding while we shut down the port.
     */
    mutex_lock(&port->mutex);
    uport->flags |= UPF_DEAD;
    mutex_unlock(&port->mutex);

    /*
     * Remove the devices from the tty layer
     */
    tty_unregister_device(drv->tty_driver, uport->line);

    if (port->tty)
        tty_vhangup(port->tty);

    /*
     * Free the port IO and memory resources, if any.
     */
    if (uport->type != PORT_UNKNOWN)
        uport->ops->release_port(uport);

    /*
     * Indicate that there isn't a port here anymore.
     */
    uport->type = PORT_UNKNOWN;

    /*
     * Kill the tasklet, and free resources.
     */
    tasklet_kill(&state->tlet);

    state->uart_port = NULL;
    mutex_unlock(&port_mutex);

    return 0;
}

3.  uart_ops:
定义了对UART的一系列操作,包括发送,接收和线路设置等。
uart_ops直接面向串口的UART,类似于面向对象中的基类、派生类的关系。
派生类针对特定的事物会更加具体,而基类则处于更高的抽象层次。

/*
 * This structure describes all the operations that can be
 * done on the physical hardware.
 */
struct uart_ops {
    unsigned int    (*tx_empty)(struct uart_port *);
    void        (*set_mctrl)(struct uart_port *, unsigned int mctrl);
    unsigned int    (*get_mctrl)(struct uart_port *);
    void        (*stop_tx)(struct uart_port *);   //停止发送
    void        (*start_tx)(struct uart_port *);  //开始发送
    void        (*send_xchar)(struct uart_port *, char ch);   //发送xchar
    void        (*stop_rx)(struct uart_port *);               //停止接收
    void        (*enable_ms)(struct uart_port *);
    void        (*break_ctl)(struct uart_port *, int ctl);
    int        (*startup)(struct uart_port *);
    void        (*shutdown)(struct uart_port *);
    void        (*flush_buffer)(struct uart_port *);
    void        (*set_termios)(struct uart_port *, struct ktermios *new,
                 struct ktermios *old);                       //设置termios
    void        (*set_ldisc)(struct uart_port *, int new);
    void        (*pm)(struct uart_port *, unsigned int state,
             unsigned int oldstate);
    int        (*set_wake)(struct uart_port *, unsigned int state);

    /*
     * Return a string describing the type of the port
     */
    const char *(*type)(struct uart_port *);   //返回一个描述端口类型的字符串

    /*
     * Release IO and memory resources used by the port.
     * This includes iounmap if necessary.
     */
    void        (*release_port)(struct uart_port *);  //释放端口使用的I/O和内存资源,必要的情况下,应该进行iounmap操作。

    /*
     * Request IO and memory resources used by the port.
     * This includes iomapping the port if necessary.
     */
    int        (*request_port)(struct uart_port *);  //申请端口使用的I/O和内存资源。
    void        (*config_port)(struct uart_port *, int);
    int        (*verify_port)(struct uart_port *, struct serial_struct *);
    int        (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
    void    (*poll_put_char)(struct uart_port *, unsigned char);
    int        (*poll_get_char)(struct uart_port *);
#endif
};

一个串口驱动要完成主要工作如下:
a. 定义 uart_driver, uart_ops, uart_port 等结构体的实例,并在适当的地方根据硬件和驱动的情况初始化它们,具体设备xxx的驱动可以将这些结构套接在新定义的xxx_uart_driver, xxx_uart_ops, xxx_uart_port内。
b. 在模块初始化时调用uart_register_driver()和uart_add_one_port()来注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver()和uart_remove_one_port()来注销UART驱动并移除端口。
c. 根据具体的硬件Datasheet来实现uart_ops中的成员函数,这些函数的实现是UART驱动的主体工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值