linux内核串口初始化,linux 串口驱动(二)初始化

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.串口结构体,他们之间的关系如图所示:

bbe42b9750643a53155822934e4c0dc6.png

//(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->

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值