module_init(s3c24xx_serial_modinit);
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;
}
我们先看一下 uart_register_driver 函数的原型
int uart_register_driver(struct uart_driver *drv);
该函数只有一个参数 struct uart_driver *drv
struct uart_driver 结构在uart驱动开发中是一个非常重要的结构,先看一下这个结构体的定义:
struct uart_driver {
struct module *owner;
const char *driver_name;
const char *dev_name;
int major;
int minor;
int nr;
struct console *cons;
/*
* these are private; the low level driver should not
* touch these; they should be initialised to NULL
*/
struct uart_state *state;
struct tty_driver *tty_driver;
};
前面几个成员都比较简单,规定了驱动的名称和设备的名称,还有主、次设备号和uart设备的个数;
最后两个结构体成员比较重要,看上面的注释说这是私有的数据,驱动开发者不应该去操作这两个成
员,它们应该被初始化为空。
事实上,uart_register_driver 函数主要就是在操作这两个结构体成员,下面的代码将会分析。作为
驱动开发者,我们应该像下面这样定义一个 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,
};
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal = NULL;
int i, retval;
BUG_ON(drv->state);
/*
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
//说明1
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;
//说明2
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;
drv->tty_driver = normal;
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
/*
* Initialise the UART state(s).
*/
//说明3
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
tty_port_init(port);
port->close_delay = 500; /* .5 seconds */
port->closing_wait = 30000; /* 30 seconds */
tasklet_init(&state->tlet, uart_tasklet_action,
(unsigned long)state);
}
//说明4
retval = tty_register_driver(normal);
out:
if (retval < 0) {
put_tty_driver(normal);
kfree(drv->state);
}
return retval;
}
说明1:
分配drv->nr个struct uart_state结构体大小的内存,把地址赋给drv->state,
struct uart_state也是一个很重要的结构体,其中的struct uart_port *uart_port成员
将在我们自己写的驱动probe函数中进行初始化,后面会分析。
说明2:
这里主要为成员变量 drv->tty_driver 分配内存,并且初始化 tty_driver。
可以看出前面几个成员的值都是通过drv传递进来的;最后将成员driver_state指向drv;
tty_set_operations(normal, &uart_ops)这个函数很简单,主要是为成员ops赋值。
变量 uart_ops 是一个全局变量。
struct tty_driver *alloc_tty_driver(int lines)
{
struct tty_driver *driver;
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) {
kref_init(&driver->kref);
driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines;
/* later we'll move allocation of tables here */
}
return driver;
}
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
driver->ops = op;
};
说明3:
这里主要初始化struct tty_driver结构体中的struct tty_port成员
说明4:
调用 tty_register_driver 函数注册一个字符设备
int tty_register_driver(struct tty_driver *driver)
{
int error;
int i;
dev_t dev;
void **p = NULL;
TTY_DRIVER_DEVPTS_MEM:使用devpts进行动态内存映射
//driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
//说明1
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
}
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);
}
if (error < 0) {
kfree(p);
return error;
}
//说明2
if (p) {
driver->ttys = (struct tty_struct **)p;
driver->termios = (struct ktermios **)(p + driver->num);
} else {
driver->ttys = NULL;
driver->termios = NULL;
}
cdev_init(&driver->cdev, &tty_fops);
driver->cdev.owner = driver->owner;
error = cdev_add(&driver->cdev, dev, driver->num);
if (error) {
unregister_chrdev_region(dev, driver->num);
driver->ttys = NULL;
driver->termios = NULL;
kfree(p);
return error;
}
mutex_lock(&tty_mutex);
//说明3:
list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex);
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
for (i = 0; i < driver->num; i++)
tty_register_device(driver, i, NULL);
}
proc_tty_register_driver(driver);
driver->flags |= TTY_DRIVER_INSTALLED;
return 0;
}
说明:
在这个函数里我们可以看见这几个很熟悉的函数:
1,register_chrdev_region
2,cdev_init
3,cdev_add
以上这些都表明这是在向内核注册一个字符设备。
说明1和说明2:
先看一下 struct tty_driver 结构体中的两个成员:
struct tty_driver {
...
/*
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
struct ktermios **termios;
...
};
这两个成员都是二级指针,注释说明它们是指向tty数据结构的指针,这里首先为它们
分配地址,其中的ttys变量将会在调用tty_open的时候用到。
说明3:
将该驱动挂载到全局变量tty_drivers中,将来我们调用tty_open的时候会从这个全局变量
中查找该驱动。
附记:
A:
cdev_init函数中用到的变量 tty_fops 是一个全局变量,定义如下:
static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
.unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
};
B:
uart_register_driver -> tty_set_operations(normal, &uart_ops)中
的 uart_ops 也是一个全局变量,定义如下:
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
};
C:
struct uart_state 结构的声明如下:
struct uart_state {
struct tty_port port;
int pm_state;
struct circ_buf xmit;
struct tasklet_struct tlet;
struct uart_port *uart_port;
};
D:
struct tty_driver 结构的声明如下:
struct tty_driver {
int magic; /* magic number for this structure */
struct kref kref; /* Reference management */
struct cdev cdev;
struct module *owner;
const char *driver_name;
const char *name;
int name_base; /* offset of printed name */
int major; /* major device number */
int minor_start; /* start of minor device number */
int minor_num; /* number of *possible* devices */
int num; /* number of devices allocated */
short type; /* type of tty driver */
short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */
/*
* Pointer to the tty data structures
*/
struct tty_struct **ttys;
struct ktermios **termios;
struct ktermios **termios_locked;
void *driver_state;
/*
* Driver methods
*/
const struct tty_operations *ops;
struct list_head tty_drivers;
};
总结:
uart_register_driver函数主要围绕着结构体 struct uart_driver 展开,
其中该结构中的前几个成员需要我们自己定义,最后两个成员由该函数分配内存
并初始化。
uart_register_driver函数最后调用tty_register_driver函数向内核中注册
一个字符设备。
struct uart_driver结构起着非常重要的作用,在后面其它的操作中,基本上
都是围绕着该结构进行的