您的位置:首页 > 运维架构 > Linux

linux serial构架分析及驱动开发(4)

2012-03-23 18:47 405 查看
在uart_register_driver函数中有这样的一个函数:tty_set_operations(normal,&uart_ops),这个uart_ops就是tty_operations函数集,这里是串口操作的公用函数接口,本节及后面章节将结合串口操作的流程,来介绍上面的操作函数。

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,

.set_ldisc = uart_set_ldisc,

.stop = uart_stop,

.start = uart_start,

.hangup = uart_hangup,

.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,

.tiocmset = uart_tiocmset,

#ifdef CONFIG_CONSOLE_POLL

.poll_init = uart_poll_init,

.poll_get_char = uart_poll_get_char,

.poll_put_char = uart_poll_put_char,

#endif

};

当用户程序调用open函数打开串口设备首先执行tty_open(前面tty分析中已经介绍过),tty_open中tty->ops->open即是串口核心中对应的uart_open函数。

/*

* calls to uart_open are serialised by the BKL in

* fs/char_dev.c:chrdev_open()

* Note that if this fails, then uart_close() _will_ be called.

*

* In time, we want to scrap the "opening nonpresent ports"

* behaviour and implement an alternative way for setserial

* to set base addresses/ports/types. This will allow us to

* get rid of a certain amount of extra tests.

*/

static int uart_open(struct tty_struct *tty, struct file *filp)

{

//先前在uart_register_driver中已经让tty_driver->driver_state指向uart_driver;我们知道tty_driver是用tty_drivers链表来

//管理的,而uart_driver只是tty_driver的一个扩展,因此也是保存在此链表中

struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;

struct uart_state *state;

int retval, line = tty->index; //设备索引

BUG_ON(!kernel_locked());

pr_debug("uart_open(%d) called/n", line);

/*

* tty->driver->num won't change, so we won't fail here with

* tty->driver_data set to something non-NULL (and therefore

* we won't get caught by uart_close()).

*/

retval = -ENODEV;

if (line >= tty->driver->num)

goto fail;

/*

* We take the semaphore inside uart_get to guarantee that we won't

* be re-entered while allocating the info 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 info->port.tty will always contain something reasonable.

*/

//当串口打开时必然已经调用uart_add_one_port将uart_port和uart_driver绑定,因此这里我们就要分配一个uart_info并作

//相应的初始化来表示一个打开的串口设备uart_get函数就做相应的操作

state = uart_get(drv, line);

if (IS_ERR(state)) {

retval = PTR_ERR(state);

goto fail;

}

/*

* 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->port->info = &state->info;

//后面是否用工作队列操作的需要

tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;

tty->alt_speed = 0;

state->info.port.tty = tty;

/*

* If the port is in the middle of closing, bail out now.

*/

if (tty_hung_up_p(filp)) {

retval = -EAGAIN;

state->count--;

mutex_unlock(&state->mutex);

goto fail;

}

/*

* Make sure the device is in D0 state.

*/

if (state->count == 1)

uart_change_pm(state, 0); //使设备处于初始电源状态

/*

* Start up the serial port.

*/

//是串口处于工作状态,下面具体分析该函数

retval = uart_startup(state, 0);

/*

* If we succeeded, wait until the port is ready.

*/

//等待串口设备就绪,主要是针对不同进程操作同一设备情况的处理

if (retval == 0)

retval = uart_block_til_ready(filp, state);

mutex_unlock(&state->mutex);

/*

* If this is the first open to succeed, adjust things to suit.

*/

if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) {

state->info.flags |= UIF_NORMAL_ACTIVE;

uart_update_termios(state);

}

fail:

return retval;

}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

/*

* Startup the port. This will be called once per open. All calls

* will be serialised by the per-port mutex.

*/

static int uart_startup(struct uart_state *state, int init_hw)

{

struct uart_info *info = &state->info;

struct uart_port *port = state->port;

unsigned long page;

int retval = 0;

if (info->flags & UIF_INITIALIZED) //设备已经初始化完成

return 0;

/*

* Set the TTY IO error marker - we will only clear this

* once we have successfully opened the port. Also set

* up the tty->alt_speed kludge

*/

set_bit(TTY_IO_ERROR, &info->port.tty->flags); //设备未完成初始化好时设置标志,后面初始化好后清除标志

if (port->type == PORT_UNKNOWN)

return 0;

/*

* Initialise and allocate the transmit and temporary

* buffer.

*/

//为串口分配环形缓存并初始化

if (!info->xmit.buf) {

/* This is protected by the per port mutex */

page = get_zeroed_page(GFP_KERNEL);

if (!page)

return -ENOMEM;

info->xmit.buf = (unsigned char *) page;

uart_circ_clear(&info->xmit);

}

retval = port->ops->startup(port);//启动串口

if (retval == 0) {

if (init_hw) {

/*

* Initialise the hardware port settings.

*/

uart_change_speed(state, NULL);

/*

* Setup the RTS and DTR signals once the

* port is open and ready to respond.

*/

if (info->port.tty->termios->c_cflag & CBAUD)

uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);

}

if (info->flags & UIF_CTS_FLOW) {

spin_lock_irq(&port->lock);

if (!(port->ops->get_mctrl(port) & TIOCM_CTS))

info->port.tty->hw_stopped = 1;

spin_unlock_irq(&port->lock);

}

info->flags |= UIF_INITIALIZED;

clear_bit(TTY_IO_ERROR, &info->port.tty->flags);

}

if (retval && capable(CAP_SYS_ADMIN))

retval = 0;

return retval;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: