Linux串口分析open

来源:互联网 发布:在线客服聊天软件 编辑:程序博客网 时间:2024/06/05 16:46
/* * uart 打开分析 * * 问题: 当应用程序调用open系统调用函数,那么是如何open串口的? *  * *//*Samsung.c 函数的模块入口函数 *它是一个公用的借口,不管2440/6410都会调用该函数 * */static int __init s3c24xx_serial_modinit(void){int ret;ret = uart_register_driver(&s3c24xx_uart_drv);if (ret < 0) {printk(KERN_ERR "failed to register UART driver\n");return -1;}return 0;}int uart_register_driver(struct uart_driver *drv){/*无关的代码忽略**/struct tty_driver *normal;normal = alloc_tty_driver(drv->nr);if (!normal)goto out_kfree;/*把normal 赋值给 uart驱动的tty_driver*/drv->tty_driver = normal;/*设置normal的operations*/tty_set_operations(normal, &uart_ops);/*注册tty驱动*/tty_register_driver(normal);}int tty_register_driver(struct tty_driver *driver){/*分配主设备号*/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);/*初始化字符设备,注册字符设备*/cdev_init(&driver->cdev, &tty_fops);driver->cdev.owner = driver->owner;error = cdev_add(&driver->cdev, dev, driver->num);}/* * 当应用程序调用open系统调用后,sys_open就会调用字符驱动的file_operations中的open函数 * 也就是tty_fops中的open函数 * */static int tty_open(struct inode *inode, struct file *filp){/*首先判断打开的设备是否是: *MAJOR = 5, MINOR = 0  *MAJOR = 5, MINOR = 1  *MAJOR = 4, MINOR = 0 * 其实打开的是2440_Serial0设备 * * MAJOR = 204 MINOR = 64 * */if (device == MKDEV(TTYAUX_MAJOR, 0)) {tty = get_current_tty();if (!tty) {tty_unlock();mutex_unlock(&tty_mutex);return -ENXIO;}driver = tty_driver_kref_get(tty->driver);index = tty->index;filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block *//* noctty = 1; *//* FIXME: Should we take a driver reference ? */tty_kref_put(tty);goto got_driver;}#ifdef CONFIG_VTif (device == MKDEV(TTY_MAJOR, 0)) {extern struct tty_driver *console_driver;driver = tty_driver_kref_get(console_driver);index = fg_console;noctty = 1;goto got_driver;}#endifif (device == MKDEV(TTYAUX_MAJOR, 1)) {struct tty_driver *console_driver = console_device(&index);if (console_driver) {driver = tty_driver_kref_get(console_driver);if (driver) {/* Don't let /dev/console block */filp->f_flags |= O_NONBLOCK;noctty = 1;goto got_driver;}}tty_unlock();mutex_unlock(&tty_mutex);return -ENODEV;}/*当上面的判断不正确时,就执行这句*/driver = get_tty_driver(device, &index);if (!driver) {tty_unlock();mutex_unlock(&tty_mutex);return -ENODEV;}/*如果tty存在,不存在则重新初始化一个tty_struct的结构*/if (tty) {retval = tty_reopen(tty);if (retval)tty = ERR_PTR(retval);} else/*该函数主要是分配tty,然后初始化tty.  * 接着将tty_struct存放到tty_driver的tty_struct[]数组中 * 根据tty_struct->index*/tty = tty_init_dev(driver, index, 0);/*它接着会调用tty->ops->open。 其实这个open函数就是 * uart_opsz中的uart_open函数 * * */if (tty->ops->open)retval = tty->ops->open(tty, filp);}/* 通过device设备号来找到设备对应的tty_driver.并且将索引保存到index中 * * **/static struct tty_driver *get_tty_driver(dev_t device, int *index){struct tty_driver *p;list_for_each_entry(p, &tty_drivers, tty_drivers) {dev_t base = MKDEV(p->major, p->minor_start);if (device < base || device >= base + p->num)continue;*index = device - base;return tty_driver_kref_get(p);}return NULL;}/*初始化tty中的重要的几条语句 * * 1. 将tty和线路规程联系在一起.其中通过索引号N_TTY。将来 *    tty_struct中的ldisc成员将为tty_ldisc_N_TTY * 2. 将tty_struct中的ops设置为tty_driver中的ops。而tty_driver中的ops *    是通过tty_set_operations(normal, &uart_ops);设置进去的。 也就是uart_ops * */void initialize_tty_struct(struct tty_struct *tty,struct tty_driver *driver, int idx){tty_ldisc_init(tty);tty->driver = driver;tty->ops = driver->ops;tty->index = idx;}/* *  找到保存在tty_driver中的uart_state. *  其实uart_state就是在初始化保存进uart_driver中 *  *  然后调用uart_start初始化serial port *  * */static int uart_open(struct tty_struct *tty, struct file *filp){/* * We take the semaphore inside uart_get to guarantee that we won't * be re-entered while allocating the state structure, or while we * request any IRQs that the driver may need.  This also has the nice * side-effect that it delays the action of uart_hangup, so we can * guarantee that state->port.tty will always contain something * reasonable. */state = uart_get(drv, line);if (IS_ERR(state)) {retval = PTR_ERR(state);goto fail;}port = &state->port;/* * Once we set tty->driver_data here, we are guaranteed that * uart_close() will decrement the driver module use count. * Any failures from here onwards should not touch the count. */tty->driver_data = state;state->uart_port->state = state;tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;tty->alt_speed = 0;tty_port_tty_set(port, tty);/* * Start up the serial port. */retval = uart_startup(tty, state, 0);}static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw){/*其中最重要的一句就是调用ops->startup. 也就是初始化uart_port中的ops. 也就是s3c24xx_serial_ops*/uport->ops->startup(uport);}/** 此函数就是去打开rx和tx的中断,然后使能中断* 然后就是一直等待中断的到来。然后跳到中断处理程序去处理中断*/static int s3c24xx_serial_startup(struct uart_port *port){struct s3c24xx_uart_port *ourport = to_ourport(port);int ret;dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",    port->mapbase, port->membase);rx_enabled(port) = 1;ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,  s3c24xx_serial_portname(port), ourport);if (ret != 0) {printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);return ret;}ourport->rx_claimed = 1;dbg("requesting tx irq...\n");tx_enabled(port) = 1;ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,  s3c24xx_serial_portname(port), ourport);if (ret) {printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);goto err;}ourport->tx_claimed = 1;dbg("s3c24xx_serial_startup ok\n");/* the port reset code should have done the correct * register setup for the port controls */return ret;}总结:open的主要作用是 在内核通过创建并初始化一个tty_struct来描述具体对应的一个硬件设备,比如这里就是用一个tty_struct来描述s3c24xx上的uart0的,然后找到uart_port中ops的startup方法初始化uart的硬件。具体的tty_struct初始化过程中最重要的几步如下1.初始化tty-struct的ops,就是将tty_driver中的ops赋值给tty_struct2.初始化tty线路规程操作集3.初始化tty_struct中的uart_state,uart_state中包含uart_port信息,这一步通过步骤1中ops中的open方法来完成。4.根据步骤3中找到的uart_state,找到里面的uart_port的ops中的startup方法来初始化uart硬件


0 0
原创粉丝点击