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.
*/
}
看这些注释,就可以明白个大概。
在模块初始化是调用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.
*/
}
看这些注释,就可以明白个大概。
相关文章推荐
- s3c6410的UART设备驱动(2)
- s3c6410的UART设备驱动(1)
- s3c6410的UART设备驱动(2)
- s3c6410的UART设备驱动(4)
- s3c6410的UART设备驱动(5)
- s3c6410的UART设备驱动(3)
- s3c6410的UART设备驱动(5)
- s3c6410的UART设备驱动(5)
- s3c6410的UART设备驱动(4)
- s3c6410的UART设备驱动(1)
- s3c6410的UART设备驱动(5)
- UART设备驱动分析
- UART设备驱动
- linux设备模型之uart驱动架构分析
- S3C6410裸机UART驱动(将printf重定义到串口)
- UART设备驱动探究1
- S3C6410 按键驱动(五) --- 驱动源代码(我采用自动分配设备号的方法,注册设备)
- linux终端设备uart驱动分析
- Linux终端设备驱动 ----UART的驱动
- linux设备模型之uart驱动架构分析