Linux驱动之I2C框架(3.4内核)

在上一节的文章中介绍了在linux2.6内核中的I2C驱动框架,2.6内核现在已基本上不再使用了,可能版本有点太老了,但对于我们分析内核结构来说也不算过时,看懂旧的再看新的也就没有那么大的压力了,那今天就来分析一下Linux3.4内核中的I2C框架吧
分析文件·drivers/i2c/busses/i2c-s3c2410.c
在这里插入图片描述
注册平台设备驱动,查看probe函数的内容
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我只截取部分内容,从这些内容中就可以看出套路其实和之前的差不多,也是定义一个关于i2c的结构体,然后去设置这个结构体,设置的时候有一个比较重要的成员s3c24xx_i2c_algorithm,包含了和设备相关的发送和接收数据的函数,这个成员一定要赋值,设置好了i2c结构体,最后就是注册它,使用i2c_add_numbered_adapter函数
在这里插入图片描述
再去调用i2c_register_adapter函数 ,这函数中的重要代码片段如下
在这里插入图片描述
在这里插入图片描述
遍历内核中一个链表,使用i2c_new_device创建设备,传入参数adapter和board_info,i2c_new_client函数的内容这里就不再看了,就是使用传入的i2c_adapter和board_inifo构造i2c_client结构体,然后链入内核链表,看到这里只有一个未知的变量,就是board_info结构体中是什么内容,以及board_info链表在哪里设置?
接下来就要分析这里的内容了,在架构相关的文件里,我在2410架构的文件中没有找到相关内容,就来看mach-mini2440.c吧,是一样的,搜索i2c_board_info,找到如下内容
在这里插入图片描述
在mini2440_init函数中调用如下代码段
在这里插入图片描述
在这里插入图片描述
i2c_register_board_info就是把构造好的i2c_board_inifo结构体链入__i2c_board_list链表中,这个链表不就是之前i2c_new_device的时候使用的那个链表嘛,好了,接着往下看__i2c_board_list在哪里被使用,搜索这个全局变量
在这里插入图片描述
是在i2c_scan_static_board_info函数中使用,i2c_scan_static_board_info函数又被i2c_register_adapter调用

看到这里就和前面的对应上了,下面,来对前面的过程进行总结

当单板上电内核跑起来的时候,肯定是架构相关的程序首先运行,也就是mach-xxx.c
1、mach-xxx.c文件里关于i2c是怎么处理的呢?
文件里首先会定义i2c_board_info的结构体,在mach-xxx.c的初始化函数里调用
i2c_register_board_info函数把i2c_board_inifo链接进内核的__i2c_board_list
链表当中去,mach-xxx.c中关于i2c的工作到这里就可以结束了

那么,构造的__i2c_board_list链表在什么时候被使用呢?
是在驱动i2c目录下和单板对应的驱动文件中加载,i2c-xxx.c
2、在i2c-xxx.c文件里使用,一般在文件的开始会注册平台设备驱动,除了一些必要的
i2c的硬件设置之外就是老一套,分配i2c结构体,其中包含i2c_adapter成员,
设置i2c_adapter成员中的算法(s3c24xx_i2c_algorithm)、注册(也是通过adapter)
i2c_add_numbered_adapter -> i2c_register_adapter  -> i2c_scan_static_board_info
在i2c_scan_static_board_info函数里就使用前面设置的__i2c_board_list链表
使用i2c_new_device函数,将adapter和i2c_board_info生成i2c_client,链入链表,
最终使用i2c_client

内核中i2c驱动框架的细节还有很多,我这里只是记录了我学习过程中的一点,关于更多的细节我会在后面的学习过程中遇到了再过分析。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
serial_core.c是Linux内核中的一个串口驱动核心文件,主要负责串口设备的初始化、读写和中断处理等操作。以下是该文件的代码解读: 1. 头文件包含 ``` #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> #include <linux/init.h> #include <linux/serial.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/console.h> #include <linux/console_struct.h> #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/io.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h> ``` 该文件包含了一些常用的头文件,如内核头文件、串口头文件、中断头文件等。 2. 宏定义 ``` #define serial_outp(port, value) writeb((value), (port)) #define serial_inp(port) readb(port) #define serial_outw(port, value) writew((value), (port)) #define serial_inw(port) readw(port) #define serial_outl(port, value) writel((value), (port)) #define serial_inl(port) readl(port) ``` 这些宏定义了读写串口寄存器的操作,通过调用内核提供的读写函数实现。 3. 结构体定义 ``` struct uart_port { spinlock_t lock; /* 锁 */ void __iomem *membase; /* MMIO基地址 */ unsigned char *mapbase; /* 端口映射基地址 */ unsigned char *membase_addr; /* MMIO地址 */ unsigned char *mapbase_addr; /* 端口映射地址 */ unsigned int iotype:2; /* 端口类型 */ unsigned int irq; /* 中断号 */ unsigned int uartclk; /* 时钟 */ unsigned int fifosize; /* FIFO大小 */ unsigned int flags; /* 标志 */ unsigned int regshift; /* 寄存器位移 */ unsigned int iobase; /* 端口基地址 */ unsigned int iolen; /* 端口长度 */ unsigned int regtype:2; /* 寄存器类型 */ unsigned int uartclk_high; /* 高位时钟 */ struct uart_state *state; /* 串口状态 */ struct uart_ops *ops; /* 串口操作 */ struct uart_driver *uartclk_reg; /* 时钟寄存器 */ struct console *cons; /* 控制台 */ struct device *dev; /* 设备 */ struct dma_chan *dma; /* DMA通道 */ struct dma_async_tx_descriptor *tx_dma; /* DMA传输描述符 */ struct dma_async_tx_descriptor *rx_dma; /* DMA传输描述符 */ unsigned int capabilities; /* 串口功能 */ unsigned int type; /* 串口类型 */ unsigned int line; /* 串口线路 */ unsigned int uartclk_rate; /* 时钟频率 */ struct ktermios *termios; /* 终端参数 */ struct ktermios *gpios; /* GPIO配置 */ struct delayed_work work; /* 延迟工作队列 */ }; ``` 该结构体定义了串口端口的各种信息,如锁、基地址、中断号、时钟、标志等。 4. 函数定义 该文件包含了众多函数定义,具体解读如下: (1) uart_get_baud_rate()函数 ``` unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) ``` 该函数用于获取波特率,根据终端参数计算波特率并返回。 (2) uart_update_timeout()函数 ``` void uart_update_timeout(struct uart_port *port, unsigned int cflag) ``` 该函数用于更新串口超时时间,根据终端参数计算超时时间并更新。 (3) uart_register_driver()函数 ``` int uart_register_driver(struct uart_driver *uart_drv) ``` 该函数用于注册串口驱动,将驱动加入到内核串口驱动链表中。 (4) uart_unregister_driver()函数 ``` void uart_unregister_driver(struct uart_driver *uart_drv) ``` 该函数用于注销串口驱动,从内核串口驱动链表中移除。 (5) uart_add_one_port()函数 ``` int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) ``` 该函数用于添加一个串口端口,将其加入到驱动的端口列表中。 (6) uart_remove_one_port()函数 ``` void uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) ``` 该函数用于移除一个串口端口,从驱动的端口列表中删除。 (7) uart_suspend_port()函数 ``` int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) ``` 该函数用于挂起一个串口端口,暂停其读写操作。 (8) uart_resume_port()函数 ``` int uart_resume_port(struct uart_driver *drv, struct uart_port *port) ``` 该函数用于恢复一个串口端口,重新开始读写操作。 (9) uart_change_speed()函数 ``` void uart_change_speed(struct uart_port *port, unsigned int new_speed) ``` 该函数用于改变串口的波特率,重新计算超时时间。 (10) uart_handle_sysrq_char()函数 ``` int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) ``` 该函数用于处理系统请求字符,将其发送到串口设备中。 (11) uart_insert_char()函数 ``` void uart_insert_char(struct uart_port *port, unsigned int status, unsigned int overrun, unsigned int ch, unsigned int flag) ``` 该函数用于向串口设备中插入一个字符,处理溢出和错误等情况。 (12) uart_write_wakeup()函数 ``` void uart_write_wakeup(struct uart_port *port) ``` 该函数用于唤醒串口设备的写操作,将等待的进程唤醒。 (13) uart_flush_buffer()函数 ``` void uart_flush_buffer(struct uart_port *port) ``` 该函数用于刷新串口设备的缓冲区,清空缓冲区中的数据。 (14) uart_start()函数 ``` void uart_start(struct uart_port *port) ``` 该函数用于启动串口设备的读操作,开始接收数据。 (15) uart_stop()函数 ``` void uart_stop(struct uart_port *port) ``` 该函数用于停止串口设备的读操作,停止接收数据。 (16) uart_shutdown()函数 ``` void uart_shutdown(struct uart_port *port) ``` 该函数用于关闭串口设备,释放资源。 (17) uart_handle_cts_change()函数 ``` void uart_handle_cts_change(struct uart_port *port, unsigned int status) ``` 该函数用于处理CTS(清除发送)信号的变化,控制发送操作。 (18) uart_handle_dcd_change()函数 ``` void uart_handle_dcd_change(struct uart_port *port, unsigned int status) ``` 该函数用于处理DCD(数据载波检测)信号的变化,控制读操作。 (19) uart_handle_dsr_change()函数 ``` void uart_handle_dsr_change(struct uart_port *port, unsigned int status) ``` 该函数用于处理DSR(数据终端就绪)信号的变化,控制读操作。 (20) uart_get_stats()函数 ``` void uart_get_stats(struct uart_port *port, struct uart_icount *icount) ``` 该函数用于获取串口设备的统计信息,包括接收、发送、错误等信息。 5. 总结 serial_core.c是Linux内核中的一个串口驱动核心文件,包含了众多的函数和结构体定义,实现了串口设备的初始化、读写、中断处理等操作。对于Linux内核开发人员来说,了解该文件的代码实现,对于理解串口驱动的原理和实现具有重要意义。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值