开干:
1、闲言碎语
这个驱动,越写觉的越简单,入门难,入门之后感觉还好。Linux开发还是比较友好的。
2、编写MPU6050带字符驱动的i2c从设备驱动
要实现的功能就是,将MPU6050作为字符驱动,在应用层,对其进行读数据。实现简单的功能。在前面的分析和实践中,可以看到实现字符驱动主要是实现file_operation中的方法,注册初始化cdev,让cdev和file_opration产生联系,字符驱动的初始化通过module_init来声明。实现i2c从设备驱动,主要是i2c_client和i2c_driver通过名字匹配,然后调用probe函数对设备进行初始化。那么,实现字符驱动的i2c从设备驱动,其实就是在i2c从设备驱动中添加字符驱动操作方法,从而在/dev中产生设备节点,让用户可以通过Linux
application的API对其进行操作。
本文实现了带字符驱动的i2c从设备驱动,然后编写了用户层测试程序,测试结果正确。下面对部分代码进行分析。
定义i2c_driver,file_operations,
static struct i2c_driver mpu6xxx_driver = {
.driver = {
.name = "mpu6xxx",
.owner = THIS_MODULE,
},
.class = I2C_CLASS_HWMON,
.id_table = mpu6xxx_ids,
.probe = mpu6xxx_probe,
.remove = mpu6xxx_remove,
};
主要实现其中的probe函数。
struct file_operations mpu6xxx_fops = {
owner : THIS_MODULE,
unlocked_ioctl : mpu6xxx_ioctl,
open : mpu6xxx_open,
release : mpu6xxx_release,
};
主要实现其中的ioctl函数。
probe函数实现:
static int mpu6xxx_probe(struct i2c_client *client, const struct i2c_device_id *id){
u16 version;
int result,retval = -1;
struct mpu6xxx_data *mpu6xxx;
dev_t dev;
printk(KERN_DEBUG "mpu6xxx driver probe... \n");
if(!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)){
retval = -EINVAL;
goto failed;
} //核查i2c驱动
mpu6xxx = kzalloc(sizeof(struct mpu6xxx_data),GFP_KERNEL);
//分配用户数据
if(!mpu6xxx)
{
retval = -ENOMEM;
goto failed;
}
memset(&mpu6xxx->gyro,0,sizeof(struct sub_sensor));
memset(&mpu6xxx->accel,0,sizeof(struct sub_sensor));
mutex_init(&mpu6xxx->lock);
mpu6xxx->client = client;
i2c_set_clientdata(client,mpu6xxx); //用来在驱动中获取数据
this_client = client;
version = i2c_smbus_read_byte_data(client,MPU6050_REG_WHO_AM_I);
if(version != 0x70)
{
printk("error retval %d , version %.2x \n",retval , version);
retval = -2;
goto failed;
}
//检查version
result = alloc_chrdev_region(&dev,this_major,1,"mpu6xxx");
if(result < 0)
{
retval = result;
goto failed;
}
this_major = MAJOR(dev);
cdev_init(&mpu6xxx->cdev,&mpu6xxx_fops);
mpu6xxx->cdev.owner = THIS_MODULE;
result = cdev_add(&mpu6xxx->cdev,dev,1);
if(result)
{
retval = result;
goto failed;
}
mpu_cls = class_create(THIS_MODULE,"mpu6xxx");
if(IS_ERR(mpu_cls))
{
retval = -3;
goto failed;
}
mpu_device = device_create(mpu_cls,NULL,dev,NULL,"mpu6xxx");
if(IS_ERR(mpu_device))
{
class_destroy(mpu_cls);
}
//注册cdev,以及在/dev中产生节点
mpu6xxx_reset(mpu6xxx);
mpu6xxx_disable(mpu6xxx);
retval = 0;
printk(KERN_DEBUG "mpuxxx probe succeed...\n");
return retval;
failed:
return retval;
};
ioctl实现:
static int mpu6xxx_ioctl(struct file *file, unsigned int cmd,unsigned long arg)
{
int re = -1;
void __user *argp = (void __user *)arg;
struct mpu6xxx_data *mpu6xxx = i2c_get_clientdata(this_client);
printk("ioctl ... cmd %d mpucmd %d BUFFERSIZE %d\n",cmd,MPU_IOCTL_GETGYRO,BUFFERSIZE);
switch(cmd)
{
case MPU_IOCTL_GETGYRO:
// ioctl这个cmd码,可以参考博客http://blog.csdn.net/shanshanpt/article/details/19897897
mutex_lock(&(mpu6xxx->lock) ); //通过互斥操作来避免频繁读写
re = mpu6xxx_read_data(mpu6xxx,0);
if(re != 0) return re;
printk("x : %d \n", mpu6xxx->gyro.x.value);
if(copy_to_user(argp,&mpu6xxx->gyro,sizeof(struct sub_sensor))) //将数据拷贝到用户空间
{
printk("failed copy data .. \n");
mutex_unlock(&mpu6xxx->lock);
return -EFAULT;
}
printk("ioctl succed...\n");
mutex_unlock(&mpu6xxx->lock);
break ;
case MPU_IOCTL_GETACCEL:
mutex_lock(&(mpu6xxx->lock) );
re = mpu6xxx_read_data(mpu6xxx,1);
if(re != 0) return re;
if(copy_to_user(argp,&mpu6xxx->accel,sizeof(struct sub_sensor)))
{
mutex_unlock(&(mpu6xxx->lock) );
printk("failed copy data .. \n");
return -EFAULT;
}
mutex_unlock(&(mpu6xxx->lock) );
break;
default: break;
}
return 0;
}
驱动加载结果:
应用层代码结果:
在动6050时,数据会变动。并且数据大小正常。

最新文章

  1. JAVA Socket 实现HTTP与HTTPS客户端发送POST与GET方式请求
  2. CSS 元素垂直居中的 6种方法
  3. HTTP Error 500.21解决方案
  4. DEEPIN 2014 正式版 试用体验
  5. 【转】(DT系列一)DTS结构及其编译方法----不错
  6. js转码和解码兼容低版本火狐
  7. http 代理 测试
  8. java虚拟机内存溢出各种场景总结
  9. 为什么在Python3.4.1里输入print 10000L或10000L失败
  10. lucene 从2.4.0—3.6.0—4.3.1版本升级
  11. 关于oracle数据库(4)数据类型
  12. C# 多线程复习笔记
  13. Linux系统调用列表(转)
  14. Actifio最新软件下载更新
  15. WordCount编码实现及单元测试(第二次作业)
  16. js中的Call()和apply()
  17. db_recovery_file_dest_size
  18. Linux 文件查找命令详解
  19. Maven hive-jdbc教程
  20. Socket使用大全

热门文章

  1. BZOJ.4540.[HNOI2016]序列(莫队/前缀和/线段树 单调栈 RMQ)
  2. Django 自定义模板语法
  3. windows提交代码到git仓库
  4. sklearn LDA降维算法
  5. c# 后台绑定treeview 多个tab
  6. day2_抓包_python基础
  7. python 3.5 连接mysql数据库
  8. 如何实现CSS限制字数,超出部份显示点点点...
  9. Deepin 15.4 编译安装 LNMP(PHP 5.6.31 + Nginx 1.12.1 + MySQL 5.6.36)
  10. Unity设置播放模式下始终先执行指定的场景