串口驱动

uart串口的整个框架如图

初始化

driver/tty/serial/omap-serial.c

static int __init serial_omap_init(void)

{

int ret;

ret = uart_register_driver(&serial_omap_reg);

if (ret != 0)

return ret;

ret = platform_driver_register(&serial_omap_driver);

if (ret != 0)

uart_unregister_driver(&serial_omap_reg);

return ret;

}

uart_register_driver函数将struct uart_driver结构体传入

 

#define OMAP_SERIAL_NAME "ttyO"

#define OMAP_MAX_HSUART_PORTS 6

#define OMAP_CONSOLE (&serial_omap_console)

#else

#define OMAP_CONSOLE NULL

 

static struct uart_driver serial_omap_reg = {

.owner = THIS_MODULE,

.driver_name = "OMAP-SERIAL",

.dev_name = OMAP_SERIAL_NAME,

.nr = OMAP_MAX_HSUART_PORTS,

.cons = OMAP_CONSOLE,

};

在这个结构体中初始化了设备的名称及设备号

 

driver/tty/serial/serial_core.c

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.

*/

/* 根据driver支持的最大设备数nr 申请nr个 uart_state空间 每个uart_state有一个uart_port */

drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);

if (!drv->state)

goto out;

/* tty层:分配一个tty_driver,并将drv->tty_driver指向它 */

normal = alloc_tty_driver(drv->nr);

if (!normal)

goto out_kfree;

drv->tty_driver = normal;

/* 将刚刚传入的结构体 struct uart_driver *drv进行一系列的初始化 */

normal->owner = drv->owner; THIS_MODULE

normal->driver_name = drv->driver_name; "OMAP-SERIAL"

normal->name = drv->dev_name; OMAP_SERIAL_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 */

}

 

retval = tty_register_driver(normal);

if (retval >= 0)

return retval;

 

put_tty_driver(normal);

out_kfree:

kfree(drv->state);

out:

return -ENOMEM;

 

}

tty核心ops

static const struct tty_operations uart_ops = {  

.open       = uart_open,  

.close      = uart_close,  

.write      = uart_write,  

.put_char   = uart_put_char,         // 单字节写函数  

.flush_chars    = uart_flush_chars,  // 刷新数据到硬件函数  

.write_room = uart_write_room,       // 指示多少缓冲空闲的函数  

.chars_in_buffer= uart_chars_in_buffer,  // 只是多少缓冲满的函数  

.flush_buffer   = uart_flush_buffer,     // 刷新数据到硬件  

.ioctl      = uart_ioctl,  

.throttle   = uart_throttle,  

.unthrottle = uart_unthrottle,  

.send_xchar = uart_send_xchar,  

.set_termios    = uart_set_termios,  // 当termios设置被改变时又tty核心调用  

.set_ldisc  = uart_set_ldisc,        // 设置线路规程函数  

.stop       = uart_stop,      

.start      = uart_start,  

.hangup     = uart_hangup,       // 挂起函数,当驱动挂起tty设备时调用  

.break_ctl  = uart_break_ctl,    // 线路中断控制函数  

.wait_until_sent= uart_wait_until_sent,  

#ifdef CONFIG_PROC_FS  

.proc_fops  = &uart_proc_fops,  

#endif  

.tiocmget   = uart_tiocmget,     // 获得当前tty的线路规程的设置  

.tiocmset   = uart_tiocmset,     // 设置当前tty线路规程的设置  

.get_icount = uart_get_icount,

#ifdef CONFIG_CONSOLE_POLL  

.poll_init  = uart_poll_init,  

.poll_get_char  = uart_poll_get_char,  

.poll_put_char  = uart_poll_put_char,  

#endif  

}; 

 

uart_register_driver注册过程:

1、根据driver支持的最大设备数,申请n个 uart_state 空间,每一个 uart_state 都有一个 uart_port 。

2、分配一个 tty_driver ,并将drv->tty_driver 指向它。

3、对 tty_driver 进行设置,其中包括默认波特率、校验方式等,还有一个重要的 Ops ,uart_ops ,它是tty核心与我们串口驱动通信的接口。

4、初始化每一个 uart_state 的 tasklet 。

5、注册 tty_driver 。

 

driver/tty/tty_io.c

int tty_register_driver(struct tty_driver *driver)

{

int error;

int i;

dev_t dev;

void **p = NULL;

struct device *d;

 

if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {

p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);

if (!p)

return -ENOMEM;

}

 

/* 如果没有设备号,则申请 */

if (!driver->major) {

error = alloc_chrdev_region(&dev, driver->minor_start,

driver->num, driver->name);

if (!error) {

driver->major = MAJOR(dev);

driver->minor_start = MINOR(dev);

}

} else {

dev = MKDEV(driver->major, driver->minor_start);

error = register_chrdev_region(dev, driver->num, driver->name); /* "ttyO" */

}

if (error < 0) {

kfree(p);

return error;

}

 

if (p) { /* 为线路规程和termios创建空间 */

driver->ttys = (struct tty_struct **)p;

driver->termios = (struct ktermios **)(p + driver->num);

} else {

driver->ttys = NULL;

driver->termios = NULL;

}

 

/* 创建字符设备,并使用cdev->tty_fops */

cdev_init(&driver->cdev, &tty_fops);

driver->cdev.owner = driver->owner;

error = cdev_add(&driver->cdev, dev, driver->num);

if (error) {

unregister_chrdev_region(dev, driver->num);

driver->ttys = NULL;

driver->termios = NULL;

kfree(p);

return error;

}

 

mutex_lock(&tty_mutex);

/* 将driver->tty_driver添加到全局链表tty_drivers */

list_add(&driver->tty_drivers, &tty_drivers);

mutex_unlock(&tty_mutex);

 

if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {

for (i = 0; i < driver->num; i++) {

d = tty_register_device(driver, i, NULL);

if (IS_ERR(d)) {

error = PTR_ERR(d);

goto err;

}

}

}

/* proc文件系统注册driver */

proc_tty_register_driver(driver);

driver->flags |= TTY_DRIVER_INSTALLED;

return 0;

 

err:

for (i--; i >= 0; i--)

tty_unregister_device(driver, i);

 

mutex_lock(&tty_mutex);

list_del(&driver->tty_drivers);

mutex_unlock(&tty_mutex);

 

unregister_chrdev_region(dev, driver->num);

driver->ttys = NULL;

driver->termios = NULL;

kfree(p);

return error;

}

tty_register_driver注册过程:

1. 为线程规程和termios分配空间,将tty_driver相应的成员指向它

2. 注册字符设备,名字是uart_driver->name,即"ttyO"。文件操作函数tty_fops

3. 将driver->tty_friver添加到全局链表tty_drivers

4. proc文件系统添加driver

 

 

节点生成

static int serial_omap_probe(struct platform_device *pdev)

/* 添加一个port,里面会生成节点 */

ret = uart_add_one_port(&serial_omap_reg, &up->port);

// driver/tty/serial/serial_core.c

/* 注册 ttyO*设备 */

tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);

// driver/tty/tty_io.c

/* 生成/dev/ttyO*节点 */

return device_create(tty_class, device, dev, NULL, name);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值