module_init(s3c2440_serial_init);
static int __init s3c2440_serial_init(void)
{
return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
}
int s3c24xx_serial_init(struct platform_driver *drv,
struct s3c24xx_uart_info *info)
{
dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
#ifdef CONFIG_PM
drv->suspend = s3c24xx_serial_suspend;
drv->resume = s3c24xx_serial_resume;
#endif
return platform_driver_register(drv);
}
static struct platform_driver s3c2440_serial_driver = {
.probe = s3c2440_serial_probe,
.remove = __devexit_p(s3c24xx_serial_remove),
.driver = {
.name = "s3c2440-uart",
.owner = THIS_MODULE,
},
};
当注册驱动程序的时候,会调用 probe 函数,即 s3c2440_serial_probe 函数。
static int s3c2440_serial_probe(struct platform_device *dev)
{
dbg("s3c2440_serial_probe: dev=%p\n", dev);
return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
}
参数 dev 是前面我们注册的设备,以uart0为例,它的结构如下:
static struct platform_device s3c24xx_uart_device0 = {
.id = 0,
.name = "s3c2440-uart",
.resource = s3c2410_uart0_resource,
.num_resources = ARRAY_SIZE(s3c2410_uart0_resource),
.dev = {
.platform_data = uart_cfgs,
}
};
static struct resource s3c2410_uart0_resource[] = {
[0] = {
.start = S3C2410_PA_UART0,
.end = S3C2410_PA_UART0 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX0,
.end = IRQ_S3CUART_ERR0,
.flags = IORESOURCE_IRQ,
}
};
static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.hwport = 0,
.flags = 0,
.ucon = UCON,
.ulcon = ULCON,
.ufcon = UFCON,
},
[1] = {
.hwport = 1,
.flags = 0,
.ucon = UCON,
.ulcon = ULCON,
.ufcon = UFCON,
},
[2] = {
.hwport = 2,
.flags = 0,
.ucon = UCON,
.ulcon = ULCON,
.ufcon = UFCON,
},
};
参数 s3c2440_uart_inf 是一个全局变量,下面是它的定义:
static struct s3c24xx_uart_info s3c2440_uart_inf = {
.name = "Samsung S3C2440 UART",
.type = PORT_S3C2440,
.fifosize = 64,
.rx_fifomask = S3C2440_UFSTAT_RXMASK,
.rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
.rx_fifofull = S3C2440_UFSTAT_RXFULL,
.tx_fifofull = S3C2440_UFSTAT_TXFULL,
.tx_fifomask = S3C2440_UFSTAT_TXMASK,
.tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
.get_clksrc = s3c2440_serial_getsource,
.set_clksrc = s3c2440_serial_setsource,
.reset_port = s3c2440_serial_resetport,
};
int s3c24xx_serial_probe(struct platform_device *dev,
struct s3c24xx_uart_info *info)
{
struct s3c24xx_uart_port *ourport;
int ret;
dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
//描述A
ourport = &s3c24xx_serial_ports[probe_index];
probe_index++;
dbg("%s: initialising port %p...\n", __func__, ourport);
//描述B
ret = s3c24xx_serial_init_port(ourport, info, dev);
if (ret < 0)
goto probe_err;
dbg("%s: adding port\n", __func__);
//描述C
uart_add_one_port(&s3c24xx_uart_drv, &ourport->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__);
ret = s3c24xx_serial_cpufreq_register(ourport);
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");
return 0;
probe_err:
return ret;
}
描述A:
变量 s3c24xx_serial_ports 是一个全局变量,以uart0为例, 变量 probe_index 也是一个全局变量,从0开始
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.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,
}
}
}
所以局部变量 ourport 的值为:
{
.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,
}
}
static struct uart_ops s3c24xx_serial_ops = {
.pm = s3c24xx_serial_pm,
.tx_empty = s3c24xx_serial_tx_empty,
.get_mctrl = s3c24xx_serial_get_mctrl,
.set_mctrl = s3c24xx_serial_set_mctrl,
.stop_tx = s3c24xx_serial_stop_tx,
.start_tx = s3c24xx_serial_start_tx,
.stop_rx = s3c24xx_serial_stop_rx,
.enable_ms = s3c24xx_serial_enable_ms,
.break_ctl = s3c24xx_serial_break_ctl,
.startup = s3c24xx_serial_startup,
.shutdown = s3c24xx_serial_shutdown,
.set_termios = s3c24xx_serial_set_termios,
.type = s3c24xx_serial_type,
.release_port = s3c24xx_serial_release_port,
.request_port = s3c24xx_serial_request_port,
.config_port = s3c24xx_serial_config_port,
.verify_port = s3c24xx_serial_verify_port,
};
描述B:
static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
struct s3c24xx_uart_info *info,
struct platform_device *platdev)
{
struct uart_port *port = &ourport->port;
/*
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,
}
*/
struct s3c2410_uartcfg *cfg;
struct resource *res;
int ret;
dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
if (platdev == NULL)
return -ENODEV;
cfg = s3c24xx_dev_to_cfg(&platdev->dev);
if (port->mapbase != 0)
return 0;
if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
return -ERANGE;
}
/* setup info for port */
port->dev = &platdev->dev;
ourport->info = info;
/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;
dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);
port->uartclk = 1;
if (cfg->uart_flags & UPF_CONS_FLOW) {
dbg("s3c24xx_serial_init_port: enabling flow control\n");
port->flags |= UPF_CONS_FLOW;
}
/* sort our the physical and virtual addresses for each UART */
res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
if (res == NULL) {
printk(KERN_ERR "failed to find memory resource for uart\n");
return -EINVAL;
}
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
port->mapbase = res->start;
port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
ret = platform_get_irq(platdev, 0);
if (ret < 0)
port->irq = 0;
else {
port->irq = ret;
ourport->rx_irq = ret;
ourport->tx_irq = ret + 1;
}
ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;
ourport->clk = clk_get(&platdev->dev, "uart");
dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
port->mapbase, port->membase, port->irq,
ourport->rx_irq, ourport->tx_irq, port->uartclk);
/* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport(port, cfg);
return 0;
}
可以看出,这个函数的主要目的就是:
用之前注册的设备platdev【struct platform_device】的值初始化struct uart_port结构的port的其它成员变量,如:
uartclk /* base uart clock */
membase /* read/write[bwl] */
irq /* irq number */
mapbase /* for ioremap */
其实这里的uart_port就相当于我们实际上的一个uart接口,当读写uart接口的时候,就是在调用uart_port中的成员。
简单梳理一下,当我们自己写uart驱动的时候:
1> 先定义一个设备,比如这里的 s3c24xx_uart_device0
static struct platform_device s3c24xx_uart_device0 = {
.id = 0,
.name = "s3c2440-uart",
.resource = s3c2410_uart0_resource,
.num_resources = ARRAY_SIZE(s3c2410_uart0_resource),
.dev = {
.platform_data = uart_cfgs,
}
};
static struct resource s3c2410_uart0_resource[] = {
[0] = {
.start = S3C2410_PA_UART0,
.end = S3C2410_PA_UART0 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX0,
.end = IRQ_S3CUART_ERR0,
.flags = IORESOURCE_IRQ,
}
};
在这里定义了两种资源类型,MEM和IRQ。上面的函数就是通过获取该资源从而配置port变量。
该变量需要通过 platform_add_devices 函数添加该设备。
2> 再定义一个struct uart_port类型的变量,这里定义的是struct s3c24xx_uart_port型的变量,
其实是对struct uart_port的封装,因为struct s3c24xx_uart_port结构是包含了struct uart_port的
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
//这里的port即 struct uart_port 类型
.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,
}
}
}
在probe函数中用第1步中定义的设备结构体初始化该uart_port结构体。在probe函数下一步操作中,会将
该uart_port加入到 uart_driver 中。
描述C:
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
{
struct uart_state *state;
struct tty_port *port;
int ret = 0;
struct device *tty_dev;
BUG_ON(in_interrupt());
if (uport->line >= drv->nr)
return -EINVAL;
state = drv->state + uport->line;
port = &state->port;
mutex_lock(&port_mutex);
mutex_lock(&port->mutex);
if (state->uart_port) {
ret = -EINVAL;
goto out;
}
//描述1
state->uart_port = uport;
state->pm_state = -1;
uport->cons = drv->cons;
uport->state = state;
/*
* If this port is a console, then the spinlock is already
* initialised.
*/
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, uport);
/*
* 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, uport->line, uport->dev);
if (likely(!IS_ERR(tty_dev))) {
device_init_wakeup(tty_dev, 1);
device_set_wakeup_enable(tty_dev, 0);
} else
printk(KERN_ERR "Cannot register tty device on line %d\n",
uport->line);
/*
* Ensure UPF_DEAD is not set.
*/
uport->flags &= ~UPF_DEAD;
out:
mutex_unlock(&port->mutex);
mutex_unlock(&port_mutex);
return ret;
}
说明:
参数 s3c24xx_uart_drv 是一个全局变量,它的定义如下:
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
.dev_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
.driver_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
s3c24xx_uart_drv 变量中的另外两个重要的成员
struct uart_state *state;
struct tty_driver *tty_driver;
在 uart_register_driver 函数中初始化,前面已经分析过。
描述1:
将前面初始化后的 uart_port 挂载到 uart_driver 中
接着前面的描述,当我们自己写uart驱动的时候:
3> 需要定义一个 struct uart_driver 结构的变量,如这里的:
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
.dev_name = "s3c2410_serial",
.nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
.driver_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
该变量中的最后两个成员必须初始化为空,并通过 uart_register_driver 函数配置该变量。
最后用一张图来说明它们之间的关系