linux 3 串口初始化失败,Linux串口驱动程序(2)-串口驱动程序初始化分析

1、串口驱动程序结构分析

对用户来讲,能够正常使用串口肯定是需要实现如下函数的:

1、串口设备文件的打开

2、串口设备文件的初始化

3、串口设备文件的读写

4、串口设备文件的控制

2、串口驱动中重要的数据结构

首先分析一下串口读写的流程

6a925af019b8d0b765430edf0f00b743.png

当用户读写串口设备文件的时候,就会调用到usart_write函数(图中没有),在usart_write函数中会读取uart_state数组里的数据,数组中的元素包含2个信息,info和port分别对应不同串口的uart_port和uart_info,在uart_port里面包含uart_ops,这里面的函数就是用来实现硬件操作的。uart_state数组的获取又依赖于uart_driver结构,在执行uart_open时,他的指针会指向uart_state。

• UART驱动程序结构:struct uart_driver,对应一个串口驱动

• UART端口结构: struct uart_port,对应一个串口设备

• UART相关操作函数结构: struct uart_ops,对应串口的硬件操作函数

• UART状态结构: struct uart_state

• UART信息结构: struct uart_info

3、初始化分析

打开Samsung.c文件,里面有这个函数:

/* module initialisation code */

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这个函数注册了一个串口驱动。跳到这个串口驱动的定义中:

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,

};

再打开s3c2440.c文件,找到模块初始化函数:

static int __init s3c2440_serial_init(void)

{

return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);

}

static void __exit s3c2440_serial_exit(void)

{

platform_driver_unregister(&s3c2440_serial_driver);

}

module_init(s3c2440_serial_init);

module_exit(s3c2440_serial_exit);

模块初始化函数优势调用s3c24xx_serial_init实现的,找到它的定义

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);

}

这里面又是调用平台驱动初始化来完成的。在平台设备注册的时候回将驱动和设备匹配,如果匹配成功,将调用驱动的prob函数,我们看看s3c2440_serial_driver 的prob函数是什么样的:

static struct platform_driver s3c2440_serial_driver = {

.probe= s3c2440_serial_probe,

.remove= __devexit_p(s3c24xx_serial_remove),

.driver= {

.name= "s3c2440-uart",

.owner= THIS_MODULE,

},

};

找到s3c2440_serial_probe最终实现的地方:

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);

ourport = &s3c24xx_serial_ports[probe_index];

probe_index++;

dbg("%s: initialising port %p...\n", __func__, ourport);

ret = s3c24xx_serial_init_port(ourport, info, dev);

if (ret < 0)

goto probe_err;

dbg("%s: adding port\n", __func__);

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;

}

我们来分析这段代码:

这段代码首先从s3c24xx_serial_ports数组中寻找一个元素,这个数组里保存的是各个串口的信息。

假如说找到了串口0,拿到串口0后调用s3c24xx_serial_init_port完成串口的初始化,看看初始化函数:

/* s3c24xx_serial_init_port

*

* initialise a single serial port from the platform device given

*/

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;

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;

}

这里面主要完成3项工作:

1、取串口的基地址

2、取串口的中断号

3、复位FIFO

在回到s3c24xx_serial_probe函数,在初始化串口后,接下来完成下面的操作:

2、添加端口uart_add_one_port

3、添加属性文件,这样在sys下面就可以看到串口的信息了

4、初始化动态频率调节s3c24xx_serial_cpufreq_register。

最后总结如下图:

d3c53be21c8a5f73a27e9ee3f8a01202.png

8951d05108042c663ab9ac5c21cf7dfd.png

更多Linux资料及视频教程点击这里

a691a6a2e149c1a7c61bf06562448211.png

2c2fdb3a5908b69aa7ef9057afee1fdb.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
系统根据B/S,即所谓的电脑浏览器/网络服务器方式,运用Java技术性,挑选MySQL作为后台系统。系统主要包含对客服聊天管理、字典表管理、公告信息管理、金融工具管理、金融工具收藏管理、金融工具银行卡管理、借款管理、理财产品管理、理财产品收藏管理、理财产品银行卡管理、理财银行卡信息管理、银行卡管理、存款管理、银行卡记录管理、取款管理、转账管理、用户管理、员工管理等功能模块。 文中重点介绍了银行管理的专业技术发展背景和发展状况,随后遵照软件传统式研发流程,最先挑选适用思维和语言软件开发平台,依据需求分析报告模块和设计数据库结构,再根据系统功能模块的设计制作系统功能模块图、流程表和E-R图。随后设计架构以及编写代码,并实现系统能模块。最终基本完成系统检测和功能测试。结果显示,该系统能够实现所需要的作用,工作状态没有明显缺陷。 系统登录功能是程序必不可少的功能,在登录页面必填的数据有两项,一项就是账号,另一项数据就是密码,当管理员正确填写并提交这二者数据之后,管理员就可以进入系统后台功能操作区。进入银行卡列表,管理员可以进行查看列表、模糊搜索以及相关维护等操作。用户进入系统可以查看公告和模糊搜索公告信息、也可以进行公告维护操作。理财产品管理页面,管理员可以进行查看列表、模糊搜索以及相关维护等操作。产品类型管理页面,此页面提供给管理员的功能有:新增产品类型,修改产品类型,删除产品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值