您的位置:首页 > 其它

s3c6410的UART设备驱动(3)

2015-01-13 13:48 295 查看
上一篇说到了第二部分,但没说完,这一篇接着说第二部分,如下这部分:

在模块初始化是调用uart_register_driver和uart_add_one_port注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver和uart_remove_one_port以注销UART驱动并移除端口。

1、先来看uart_add_one_port函数,源码如下:

/**
 * uart_add_one_port - attach a driver-defined port structure

 * @drv: pointer to the uart low level driver structure for this port

 * @port: 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 s3c24xx_serial_probe(struct platform_device *dev,struct s3c24xx_uart_info *info)函数中被调用,

和平台设备有关的函数。

调用如下:

samsung.c

int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)

{
struct s3c24xx_uart_port *ourport;
int ret;

。。。
ourport = &s3c24xx_serial_ports[probe_index];
probe_index++;

ret = s3c24xx_serial_init_port(ourport, info, dev);
。。。
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);//ourport->port=struct uart_port
platform_set_drvdata(dev, &ourport->port);
。。。。
ret = device_create_file(&dev->dev, &dev_attr_clock_source);
if (ret < 0)
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
。。。

return 0;

}

s3c2410.c

static int s3c2410_serial_probe(struct platform_device *dev)

{
return s3c24xx_serial_probe(dev, &s3c2410_uart_inf);

}

static struct platform_driver s3c2410_serial_driver = {
.probe
= s3c2410_serial_probe,
.remove
= __devexit_p(s3c24xx_serial_remove),
.driver
= {
.name = "s3c2410-uart",
.owner
= THIS_MODULE,
},

};

static int __init s3c2410_serial_init(void)

{
return s3c24xx_serial_init(&s3c2410_serial_driver, &s3c2410_uart_inf);

}

static void __exit s3c2410_serial_exit(void)

{
platform_driver_unregister(&s3c2410_serial_driver);

}

module_init(s3c2410_serial_init);

module_exit(s3c2410_serial_exit);

int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)

{
struct uart_state *state;
int ret = 0;
struct device *tty_dev;

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

state = drv->state + port->line;//可能有多个port,这里获取对应的port口的state

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

state->port = port;

/*

对state结构体中的成员port赋值,部分源码如下:

struct uart_state {

........
struct uart_info*info;
struct uart_port*port;
struct mutex mutex;

};

*/

state->pm_state = -1;
port->cons = drv->cons;
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, port);
看函数名就知道了干什么的。源码如下:先说下 struct uart_port *port结构体有什么用?在我看来,一个此种结构体的实例,就表示有一个串口可供我们使用。在列出在第一篇中列出的这个结构体的实例(其中的一部分),如下所示:

static struct s3c24xx_uart_ports s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.port = { //struct uart_port
.lock= __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype  = UPIO_MEM,
.irq= IRQ_S3CUART_RX0,
.uartclk  = 0,
.fifosize  = 16,
.ops= &s3c24xx_serial_ops,
.flags
  = UPF_BOOT_AUTOCONF,
.line= 0,
}
}看这些都是什么?是不是和一个具体的串口很相关,如中断等等。

在看一下uart_configure_port函数

static void

uart_configure_port(struct uart_driver *drv, struct uart_state *state,struct uart_port *port)

{
unsigned int flags;
/*
* If there isn't a port here, don't do anything further.
*/
if (!port->iobase && !port->mapbase && !port->membase)
return;

/*
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/

flags = 0;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {//UPF_BOOT_AUTOCONF
if (!(port->flags & UPF_FIXED_TYPE)) {
port->type = PORT_UNKNOWN;
flags |= UART_CONFIG_TYPE;
}
port->ops->config_port(port, flags);//s3c24xx_serial_config_port=request mem region
}

有关的一些标志位,通过port->ops->config_port(port, flags)这个函数进行。是在下面这个结构中的函数,和具体硬件有关。这个结构体在第一篇中,也有说明。
/*
 * 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);
......
void(*set_ldisc)(struct uart_port *);
void(*pm)(struct uart_port *, unsigned int state,
     unsigned int oldstate);
int(*set_wake)(struct uart_port *, unsigned int state);
.....
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
int(*request_port)(struct uart_port *);
void(*config_port)(struct uart_port *, int);
int(*verify_port)(struct uart_port *, struct serial_struct *);
........
};
static struct uart_ops s3c24xx_serial_ops = {
.pm = s3c24xx_serial_pm,
.tx_empty
= s3c24xx_serial_tx_empty,
。。。
.config_port
= s3c24xx_serial_config_port,
。。

};
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.port = {
。。。
.fifosize
= 16,
.ops =
&s3c24xx_serial_ops,
。。。
}
},

};
static void s3c24xx_serial_config_port(struct uart_port *port, int flags)

{
struct s3c24xx_uart_info *info = s3c24xx_port_to_info(port);//s3c2400_uart_inf
if (flags & UART_CONFIG_TYPE &&s3c24xx_serial_request_port(port) == 0)
port->type = info->type;
//s3c24xx_serial_request_port=request memory

}
static int s3c24xx_serial_request_port(struct uart_port *port)

{
const char *name = s3c24xx_serial_portname(port);
return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;

}

if (port->type != PORT_UNKNOWN) {
unsigned long flags;
/*Power up port for set_mctrl() */
uart_change_pm(state, 0);和电源管理有关
/*
*Ensure that the modem control lines are de-activated.
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/流控制有关
spin_lock_irqsave(&port->lock, flags);
port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
spin_unlock_irqrestore(&port->lock, flags);
/*
* 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, port->line, port->dev);这个函数以前也说过,主要和sysfs文件系统有关-添加注册port->dev 
 //device_create 创建一个设备并注册到内核驱动架构

return ret;
}

对应的uart_remove_one_port函数就不讲了。源码如下:

/**

 * uart_remove_one_port - detach a driver defined port structure

 * @drv: pointer to the uart low level driver structure for this port

 * @port: uart port structure for this port

 *

 

int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)

{

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

info = state->info;
if (info && info->port.tty)
tty_vhangup(info->port.tty);

/*
* All users of this port should now be disconnected from
* this driver, and the port shut down.  We should be the
* only thread fiddling with this port from now on.
*/
state->info = NULL;

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

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

/*
* Kill the tasklet, and free resources.
*/

}

看这些注释,就可以明白个大概。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: