用户空间访问I2C设备驱动

2012-01-11 15:33:43
标签:Linux I2C 字符设备 设备驱动 用户空间
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ticktick.blog.51cto.com/823160/761830

    关于Linux下如何编写芯片的I2C驱动,本系列第一篇文章《手把手教你写Linux I2C设备驱动》对编写I2C Client 设备驱动的关键代码给出了初步的讲述和示例,第二篇文章《Linux下读写芯片的I2C寄存器》对于具体如何在驱动层封装读写芯片I2C寄存器也进行了详细的描述,这两篇文章的代码整合到一起,就构成了I2C设备驱动的主要部分,本文则致力于将该驱动进一步封装,为用户空间提供访问的接口。

    如果希望在用户空间访问我们写的I2C设备驱动,最常用的做法就是为该I2C驱动编写一套字符设备驱动,这样,用户空间则可以通过对字符设备驱动的访问,间接地实现对I2C芯片寄存器的读写控制。下面,我们在前两篇文章的代码的基础上,封装一层字符设备驱动,并给出在用户空间的使用示例。

1.  编写字符设备驱动

    关于字符设备驱动的编写,我依然从实例应用的角度来展开描述,关于原理性的东西,网上有许多文章,可以搜索参考。

    (1)首先,创建一个包含有cdev对象的结构体及对象,代表着本实例的字符设备对象。

  1. struct tvp5158_dev{        
  2.     struct cdev cdev;  
  3. int major;      
  4.     struct semaphore semLock;          
  5. };  
  6. // global dev object  
  7. struct tvp5158_dev g_tvp5158_dev; 

    cdev即字符设备对象,major为分配的字符设备主设备号,semaphore用于互斥,保护i2c读写过程。

    (2)第二步,创建文件操作结构体对象

  1. struct file_operations tvp5158_dev_FileOps = {  
  2.         .owner   = THIS_MODULE,  
  3.         .open    = tvp5158_devOpen,  
  4.         .release = tvp5158_devRelease,  
  5.         .ioctl   = tvp5158_devIoctl,  
  6. }; 

    我们把对I2C寄存器的读写操作放到 ioctl 命令中执行,不需要实现 read 和 write 函数,故这里只实现文件的打开、释放、以及 ioctl 操作。

    (3) 实现设备打开和关闭函数

  1. static int tvp5158_devOpen(struct inode *inode, struct file *filp)  
  2. {  
  3. printk(KERN_INFO "I2C: tvp5158_devOpen, %4d, %2d \n", major, minor);  
  4.  
  5.     filp->private_data = NULL;  
  6.  
  7.     return 0;  
  8. }  
  9.  
  10. static int tvp5158_devRelease(struct inode *inode, struct file *filp)  
  11. {  
  12.     printk(KERN_INFO "I2C: tvp5158_devRelease");  
  13.  
  14.     return 0;  

    (4)实现 IOCTL 函数

    这里的ioctl 函数的实现很关键,是驱动层与用户层交互的核心部分,这里将会定义相关的I2C读写命令枚举,并且调用前面文章中封装好的I2C读写代码。

  1. #define I2C_CMD_READ       (0x01)  
  2. #define I2C_CMD_WRITE      (0x02)  
  3.  
  4. struct I2C_Param{  
  5.     uint8_t *reg;  
  6.     uint8_t *value;  
  7. };  
  8.  
  9. static int tvp5158_devIoctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)  
  10. {  
  11. uint8_t reg,data;
  12.     struct  I2C_Param param;  
  13.       
  14.     down_interruptible(&g_tvp5158_dev.semLock);  
  15.       
  16.     // get i2c param from userspace  
  17.     copy_from_user(&param, (void *)arg, sizeof(param));  
  18.       
  19.     switch(cmd){  
  20.     case I2C_CMD_WRITE:  
  21.         {  
  22. copy_from_user(&reg, param.reg,sizeof(uint8_t));
  23. copy_from_user(&data,param.value,sizeof(uint8_t));
  24.             tvp5158_i2c_write(&g_tvp5158_obj->client, reg, data);  
  25.             break;  
  26.         }  
  27.     case I2C_CMD_READ:  
  28.         {  
  29. copy_from_user(&reg, param.reg,sizeof(uint8_t));
  30.             tvp5158_i2c_read(&g_tvp5158_obj->client, reg, &data);  
  31.             copy_to_user(param.value,&data,sizeof(uint8_t));  
  32.             break;  
  33.         }  
  34.     default:  
  35.         break;  
  36.     }  
  37.     up(&g_tvp5158_dev.semLock);  
  38.       
  39.     return 0;  

    其中,I2C_Param是与用户空间交互用的参数结构体,用户空间必须定义相同的结构体以保证交互的正确性。g_tvp5158_obj 和 tvp5158_i2c_read/write 均为前面文章中定义的变量和函数。

    (5)在__init 代码中注册本字符设备驱动

  1. static int __init tvp5158_i2c_init(void)  
  2. {  
  3.     int result;  
  4.     dev_t dev = 0;  
  5.     result = alloc_chrdev_region(&dev, 0, 1, “tvp5158_dev”);  
  6.     if (result < 0) {  
  7.         printk(KERN_WARNING "I2C: can't get device major num \n");  
  8.         return result;  
  9.     }  
  10. g_tvp5158_dev.major = MAJOR(dev);      
  11.  
  12.     sema_init(&g_tvp5158_dev.semLock, 1);  
  13.     cdev_init(&g_tvp5158_dev.cdev, &tvp5158_dev_FileOps);  
  14.       
  15.     g_tvp5158_dev.cdev.owner = THIS_MODULE;  
  16.     g_tvp5158_dev.cdev.ops   = &tvp5158_dev_FileOps;  
  17.  
  18.     cdev_add(&g_tvp5158_dev.cdev, dev, 1);     
  19.       
  20.     return i2c_add_driver(&tvp5158_i2c_driver);;  
  21. }  
 

   (6)在 __exit 代码中注销本字符设备驱动

  1. static void __exit tvp5158_i2c_exit(void)  
  2. {  
  3.     dev_t devno = MKDEV(g_tvp5158_dev.major, 0);  
  4.  
  5.     i2c_del_driver(&tvp5158_i2c_driver);  
  6.  
  7.     cdev_del(&g_tvp5158_dev.cdev);  
  8.  
  9.     unregister_chrdev_region(devno, 1);  

        注意,本初始化代码和逆初始化在第一篇文章中已经出现过,这里补充完整了,将字符设备驱动的代码添加进来了。

2.  用户空间的使用方法

    首先,编写Makefile将驱动编译成模块,然后在用户空间对生成的模块(*.ko)进行加载(insmod),然后再 /dev 目录下创建设备节点 /dev/tvp5158_dev ,最后,在用户空间即可编写测试代码,打开该设备文件,通过 ioctl 命令进行访问。

    上面这个过程示例如下:

  1. // 假设生成的模块.ko名称为 tvp5158.ko 
  2. 第一步:insmod tvp5158.ko 
  3.  
  4. // 假设上面tvp5158_i2c_init函数中 g_tvp5158_dev.major 的值为 74 
  5. 第二步:mknod /dev/tvp5158_dev c 74 0 

    下面给出最后在用户空间的测试代码示例。

  1. #include <stdio.h>  
  2.  
  3. int main()  
  4. {  
  5.     int status;  
  6.     struct I2C_Param param;  
  7.  
  8. unit8_t reg = 0x08;
  9. unit8_t value = 0;
  10.  
  11.     int fd = open("/dev/tvp5158_dev", O_RDWR);  
  12.     if( fd < 0)  
  13.     {  
  14.         return -1;  
  15.     }  
  16.       
  17.     param.reg    = &reg;  
  18.     param.value  = &value;  
  19.     status = ioctl(fd,I2C_CMD_READ,&param);  
  20.     if( status < 0)  
  21.     {  
  22.         printf("read fail!\n");  
  23.         return -1;  
  24.     }  
  25.     printf("the 0x80 reg 's value = %d\n",value);  
  26.       
  27.     close(fd);  
  28.       
  29.     return 0;  

 3.   总结

    到此为止,Linux下的I2C设备驱动基本编写过程已经讲述完毕,以后凡是拿到新的芯片,需要在Linux下读写I2C寄存器,均可参考本系列的代码进行编写。当然,这里只是讲述了I2C设备驱动编写的一些最基本的方法,关于I2C设备驱动的原理部分并没有涉及,希望自己以后更加深入地了解了Linux设备驱动原理后再进一步阐述。本文希望对初学者有所帮助,文中有什么讲述不正确的地方,欢迎留言或者来信lujun.hust@gmail.com交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/253588.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

097实战 关于ETL的几种运行方式

一&#xff1a;代码部分 1.新建maven项目 2.添加需要的java代码   3.书写mapper类 4.书写runner类 二&#xff1a;运行方式 1.本地运行 2.集群运行 3.本地提交集群运行 三&#xff1a;本地运行方式 1.解压hadoop到本地 2.修改配置文件HADOOP_HOME 3.解压common的压缩包 4.将压…

模拟ssh, hashlib模块, struct模块, subprocess模块

一. 模拟ssh # 服务器端 import socket import subprocess # 系统操作server socket.socket()server.bind((127.0.0.1,8008))server.listen(5)while True:print("server is working.....")conn,addr server.accept()# 字节类型while True:# 针对window系统try:…

使用pssh进行并行批量操作

假如同时给上千台服务器执行一个命令,拷贝一个文件,杀一个进程等,有什么简化运维管理的工具呢?在小型使用中我都是使用for循 环,数量巨大,一方面不确定操作是否成功,一方面for循环语句性能不好估计且是不是同步并行执行.&#xff0c;这类工具比如 pdsh&#xff0c;mussh&#…

图像清晰度评价函数

概述 图像清晰度是用来指导调焦机构找到正焦位置的评价函数。理想的清晰度评价曲线如下图所示,其中P 是评价函数最大值的位置,其对应正焦位置,P1 和P2 为正焦位置焦前和焦后采集到图像的清晰度评价结果。 为了指导调焦机构找到正焦位置,清晰度曲线须具有以下特点: 单…

Linux下读写芯片的I2C寄存器

Linux下读写芯片的I2C寄存器 2012-01-10 11:40:18 标签&#xff1a;Linux 寄存器 驱动 读写 I2C 原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ticktick.blog.51cto.com/823160/76096…

列表和表格---学习笔记02

第7章 列表和表格 7.1 有序列表<ol type"A"><li>这里是第1个li</li><li>这里是第2个li</li><li>这里是第3个li</li></ol> ol属性&#xff1a;type : 数字(1),大小写字母(A,a),大小写罗马数字(I,i)start: "起始…

(下)挖掘传统行业日志大数据的无限价值

&#xfffc;8 月 27 日晚上八点&#xff0c;七牛云高级解决方案架构师程雪松在 IT 大咖说进行了题为《挖掘传统行业日志大数据的无限价值》的直播&#xff0c;对传统行业运维常见困境和统一日志管理的必要性进行了深入解析&#xff0c;并通过 Pandora 的一些真实用户案例和大家…

CMOS图像传感器 —— ISOCELL

最近,外媒曝光了三星最新的CIS传感器路线图,路线图显示,三星在2亿像素之外已经规划2025年推出576MP像素的传感器,也就是5亿7千6百万像素。 若5.76亿像素的传感器推出,意味着手机传感器可媲美中高端单反水平了。三星没有提及这个5.76亿像素的传感器是怎样实现的。因…

LeetCode 153. Find Minimum in Rotated Sorted Array (在旋转有序数组中找到最小值)

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). Find the minimum element. You may assume no duplicate exists in the array. 题目标签&#xff1a;Array, Binary Se…

YUV图像

YUV420P&#xff0c;Y&#xff0c;U&#xff0c;V三个分量都是平面格式&#xff0c;分为 I420 和 YV12 。 I420 格式和 YV12 格式的不同处在U平面和V平面的位置不同。在I420格式中&#xff0c;U平面紧跟在Y平面之后&#xff0c;然后才是V平面&#xff08;即&#xff1a;YUV&…

色调映射(Tone Mapping)

一、概述 虽然HDR 图像有较大的动态范围,能更细致地反映真实场景,但他的缺点也很明显。一是同尺寸的数据比低动态范围图像大,需要更大的存储空间与传输带宽。二是难以输出,目前大多数显示器、打印机等图形输出设备的动态范围要比普通的高动态范围图像小得多。。因此,色调映…

实用软件工具

1.突破百度网盘下载速度现在&#xff0c;使用 Aria2下载 Aria2-不限速全平台下载利器但是百度网盘账号会被限速 &#xff0c;冲会员解除正常限制网速2.Safari 预览&#xff0c;将网页转化为自定义尺寸 PDF 3.清除Xcode 缓存 删除模拟器运行缓存&#xff0c;找到Developer->…

[原创]Toolbar setNavigationIcon无效

最近在做一个Toolbar&#xff0c;setNavigationIcon()这个方法一直无效&#xff0c;说什么的都有&#xff0c;什么getSupportActionBar().setNavigationIcon()的&#xff0c;说设置style的&#xff0c;说放到setSupportActionBar()之后的。 其实没有说全&#xff0c;还应该放到…

YUV格式详解

分类&#xff1a; H.264 MPEG TV 2008-05-14 09:24 16181人阅读 评论(21) 收藏 举报 YUV是指亮度参量和色度参量分开表示的像素格式&#xff0c;而这样分开的好处就是不但可以避免相互干扰&#xff0c;还可以降低色度的采样率而不会对图像质量影响太大。YUV是一个比较笼统地说…

KVM安装、镜像创建(一)

环境准备 VMware Workstation Pro启动虚拟化 查看启动的系统是否支持vmx或svm grep -E (vmx|svm) /proc/cpuinfo 备注&#xff1a;操作系统centos 7 KVM安装 1、yum查看kvm安装包 yum list |grep kvm 2、安装 yum install -y qemu-kvm qemu-kvm-tools libvirt3、启动libvirtd s…

Sensor 结构——前照、背照、堆栈

优异的工艺和技术可以使得即便不使用更新结构的CMOS,同样拥有更好的量子效率、固有热噪声、增益、满阱电荷、宽容度、灵敏度等关键型指标。在相同技术和工艺下,底大一级的确压死人(全画幅和aps-c)。人类的进步就是在不断发现问题,解决问题。背照式以及堆栈式CMOS的出现,也…

少犯非智力错误

工作节省时间最重要的方法之一就是少犯非智力错误。 同事反馈说不能预览&#xff0c;排查半天找不到问题&#xff0c;最后发现是IP地址配错了。 现场问题同事搞半天找不出原因&#xff0c;结果一看是网域配错了。 还有些问题开始排查定位不到原因&#xff0c;回头看时才发现端口…

搭建分布式hadoop2.x集群

前期准备&#xff1a; 1.我这里用了三台虚拟机&#xff0c;.默认已经配置好静态IP和IP域名映射&#xff0c;它们相互之间可以ping通 第一台&#xff1a;192.168.174.131 hadoopNumber01.medal.com 第二台&#xff1a;192.168.174.132 hadoopNumber02.meda.com 第三台…

ortp库使用入门

原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ticktick.blog.51cto.com/823160/345642 我们知道&#xff0c; RTP&#xff08;Real-timeTransportProtocol&#xff09;是用于Internet上…

可测性设计技术

传统的设计过程和测试过程是分开的&#xff0c;而且测试往往只在设计阶段的后期才被考虑。近年来&#xff0c;测试越来越早地被考虑并出现在设计过程中&#xff0c;被称为“可测性设计”。可测性设计的主要思路就是在设计之初就考虑关于测试方面的设计&#xff0c;并在设计阶段…