8250串口的初始化:
(1)定义uart_driver、uart_ops、uart_port等结构体的实例并在适当的地方更具具体的硬件驱动情况初始化他们,当然具体设备xxx的驱动可以将这些结构体套在新定义的xxx_uart_driver、xxx_uart_ops、xxx_uart_port之内。
(2)在模块初始化调用uart_register()和uart_add_one_port()以注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver()和uart_remove_one_port()以注销UART驱动以移除端口。
(3)根据具体硬件的uart_ops中的成员函数,这些函数的实现成为UART驱动的主体工作。
1.串口结构体,他们之间的关系如图所示:
//(1)串口驱动结构体
struct uart_driver {
struct module *owner; //模块所有者
const char *driver_name; //驱动名
const char *dev_name; //设备名
int major; //主设备号
int minor; //次设备号
int nr; //支持串口个数
struct console *cons;//控制台设备
struct uart_state *state; //串口状态
struct tty_driver *tty_driver; //tty设备
};
//(2)串口端口结构体
struct uart_port {
spinlock_t lock;
unsigned long iobase; //io端口基地址
unsigned char __iomem *membase; //内存端口基地址
unsigned int (*serial_in)(struct uart_port *, int); //串口读函数
void (*serial_out)(struct uart_port *, int, int); //串口写方法
void (*set_termios)(struct uart_port *,struct ktermios *new,struct ktermios *old); //串口配置方法函数
void (*pm)(struct uart_port *, unsigned int state,unsigned int old);
unsigned int irq; //中断号
unsigned long irqflags; //中断标志
unsigned int uartclk; //串口时钟
unsigned int fifosize; //fifo大小
unsigned char x_char;
unsigned char regshift; //寄存器偏移值
unsigned char iotype; //io访问类型
unsigned char unused1;
unsigned int read_status_mask;
unsigned int ignore_status_mask;
struct uart_state *state; //uart_state结构体
struct uart_icount icount; //串口使用计数
struct console *cons; //console控制台
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq;
#endif
upf_t flags;
unsigned int mctrl;
unsigned int timeout;
unsigned int type; //串口类型
const struct uart_ops *ops; //串口操作函数集
unsigned int custom_divisor;
unsigned int line; //端口号
resource_size_t mapbase; //串口寄存器基地址(物理地址)
struct device *dev; //设备文件
unsigned char hub6;
unsigned char suspended;
unsigned char irq_wake;
unsigned char unused[2];
void *private_data;
};
//(3)操作函数集
struct uart_ops {
unsigned int (*tx_empty)(struct uart_port *); //发送缓冲区为空
void (*set_mctrl)(struct uart_port *, unsigned int mctrl); //设置串口modem控制模式
unsigned int (*get_mctrl)(struct uart_port *); //获取串口modem控制模式
void (*stop_tx)(struct uart_port *); //停止发送
void (*start_tx)(struct uart_port *); //开始发送
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *); //停止接收
void (*enable_ms)(struct uart_port *); //使能modem状态信息
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *); //打开串口
void (*shutdown)(struct uart_port *); //关闭串口
void (*flush_buffer)(struct uart_port *);
void (*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old); //设置串口参数
void (*set_ldisc)(struct uart_port *, int new);
void (*pm)(struct uart_port *, unsigned int state,unsigned int oldstate);
int (*set_wake)(struct uart_port *, unsigned int state);
const char *(*type)(struct uart_port *);
void (*release_port)(struct uart_port *); //释放端口
int (*request_port)(struct uart_port *); //请求端口
void (*config_port)(struct uart_port *, int); //配置端口
int (*verify_port)(struct uart_port *, struct serial_struct *); //校验端口
int (*ioctl)(struct uart_port *, unsigned int, unsigned long); //控制
#ifdef CONFIG_CONSOLE_POLL
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
};
//(4)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;//指向对应的串口结构
};
2.串口初始化
static int __init serial8250_init(void)
{
int ret;
if (nr_uarts > UART_NR)//UART_NR =3
nr_uarts = UART_NR;//串口数量最多设为3个
printk(KERN_INFO "Serial: 8250/16550 driver, ""%d ports, IRQ sharing %sabled\n", nr_uarts,share_irqs ? "en" : "dis");
serial8250_reg.nr = UART_NR;//串口数量
/*
static struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
.major = TTY_MAJOR,//主设备号是4
.minor = 64,
.cons = SERIAL8250_CONSOLE,//终端
};
#define SERIAL8250_CONSOLE &serial8250_console
static struct console serial8250_console = {
.name = "ttyS",
.write = serial8250_console_write,
.device = uart_console_device,
.setup = serial8250_console_setup,//设置串口波特率,也就是设置串口。很重要,里面涉及到平台特性,波特率相关。
.early_setup = serial8250_console_early_setup,
.flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &serial8250_reg,
};
*/
//函数定义在serial_core.c中
//注册uart串口驱动,完善uart_driver结构serial8250_reg的uart_state成员及tty_driver成员,并注册tty驱动
ret = uart_register_driver(&serial8250_reg);
#endif
if (ret)
goto out;
//创建一个platform_device结构:serial8250_isa_devs
serial8250_isa_devs = platform_device_alloc("serial8250",PLAT8250_DEV_LEGACY);
if (!serial8250_isa_devs) {
ret = -ENOMEM;
goto unreg_uart_drv;
}
//将该结构serial8250_isa_devs注册到总线上
ret = platform_device_add(serial8250_isa_devs);
if (ret)
goto put_dev;
//对uart_8250_port结构serial8250_reg[]初始化,即对3个串口的uart_port结构初始化,并添加端口
serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
/*
static struct platform_driver serial8250_isa_driver = {
.probe = serial8250_probe,
.remove = __devexit_p(serial8250_remove),
.suspend = serial8250_suspend,
.resume = serial8250_resume,
.driver = {
.name = "serial8250",
.owner = THIS_MODULE,
},
};
*/
//注册设备,会调用serial8250_probe()。怎样调用的serial8250_probe???????
ret = platform_driver_register(&serial8250_isa_driver);
if (ret == 0)
goto out;
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_uart_drv:
#ifdef CONFIG_SPARC
sunserial_unregister_minors(&serial8250_reg, UART_NR);
#else
uart_unregister_driver(&serial8250_reg);
#endif
out:
return ret;
}
//注册串口驱动
int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal;
int i, retval;
BUG_ON(drv->state);
//为串口的uart_driver结构分配要指向的uart_state结构的空间*串口数量
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
if (!drv->state)
goto out;
//为uart_driver结构分配要指向的tty_driver结构的空间
/*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;//tty_driver的魔数
driver->num = lines;//串口数量3个
}
return driver;
}*/
normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out_kfree;
drv->tty_driver = normal;//赋值给uart_driver结构的tty_driver成员
//对tty_driver成员指向的结构初始化
normal->owner = drv->