linux ---------驱动开发遇到的问题及解决方法
2013-07-13 21:28
691 查看
(1)今天有写了下设备驱动,当然首先是自己建立一个IP核,功能很简单,就是控制8个LED灯的,所以设置了一个寄存器,添加IP核,编译,XPS下载BIT文件测试了,一切正常。
(2) 自然就是编写linux驱动了,通过生成的.ko文件,一切正常,/dev/led_ctrl_dev有了,sys/class下面也有了led_ctrl_dev。总之,insmod ,rmmod 都没问题。
(3) 上层驱动代码的编写,read()读取LED灯的状态,没问题,write()函数感觉没得效果,根本没有执行驱动代码中的 led_write()函数,因为我每次实际写入的值为上层代中传递过来的,可是每次都是FFFFFFFFFF。。。打开文件的时候用的也是O_RDWR 啊
今天又仔细研究了下,终于搞定了,看来还是得自己研究代码和原理才是关键:
问题也很简单,就是只能读设备,却不能写设备,从执行的结果页看的出来,当上层应用程序调用write()(led_ctrl_app.c 文件中)数的时候,根本没有调用驱动层的write ()在 led_ctrl.c中)。所以找为什么,首先就是那个file_operations这个结构体了,因为这两个函数是靠这个结构体里面的指针进行关联的。所以我去查了下包含file_operations的头文件linux/fs.h文件。大家可不要以为这个文件在你的PC机上的linux系统里的哦,确切的说应在Digilent-linux-3.3这个内核下面的/inlcude/linux/fs.h中的。找到它的定义如下:
truct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
};
这个write函数的参数(struct file *, const char __user *, size_t, loff_t *);,于是修改了led_ctrl.c文件中的write函数的参数。在我的文件中,我也写了iotcl函数的,可是这个函数连make的是都过不了,原因也在于此,人家结构体里面定义的是 long (*unlocked_ioctl),所以写的函数也得相应的改改,至于我之前为什么写的是iotcl,很简单,我抄的<linux设备驱动开发详解》的,它用的内核和我们这里的Digilent-linuxXXX内核不一样哇,所以源码有些小不一样也是很正常。
(2) 自然就是编写linux驱动了,通过生成的.ko文件,一切正常,/dev/led_ctrl_dev有了,sys/class下面也有了led_ctrl_dev。总之,insmod ,rmmod 都没问题。
(3) 上层驱动代码的编写,read()读取LED灯的状态,没问题,write()函数感觉没得效果,根本没有执行驱动代码中的 led_write()函数,因为我每次实际写入的值为上层代中传递过来的,可是每次都是FFFFFFFFFF。。。打开文件的时候用的也是O_RDWR 啊
#include <linux/platform_device.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/ioport.h> #include <linux/of.h> #include <linux/fs.h> #include <asm/io.h> #include <linux/slab.h> #include <linux/device.h> #include <linux/kernel.h> #define LED_PHY_ADDR 0x79c00000 #define DEVICE_NAME "led_ctrl_dev" struct led_dev{ struct cdev cdev;/*字符设备*/ unsigned char value; }; struct led_dev *led_devp; static void __iomem *LED_Regs; int led_major=0; struct class *my_class; struct device *my_device; MODULE_AUTHOR("xiao gaogao"); MODULE_LICENSE("Dual BSD/GPL"); static int led_open(struct inode *inode,struct file * filp) { return 0; }
static int led_release(struct inode *inode,struct file *filp) { return 0; }
static ssize_t led_read(struct file *filp,char *buffer,size_t length,loff_t *offset) { /* int i=0; for (i=0;i<4;i++) { *(buffer+i) = (char) ioread8(LED_Regs+i); } */ int i=0; unsigned long value=0; value= ioread32(LED_Regs); for(i=0;i<4;i++) { buffer[i]=value>>(i*8); } return value; }
static ssize_t led_write(struct file *filp,char *buffer,size_t length,loff_t *offset) { /* int i=0; for (i=0;i<4;i++) { iowrite8(*(buffer+i),LED_Regs+i); } */ int i=0; unsigned long value=0; value=(buffer[3]<<24) | (buffer[2]<<16) |( buffer[1]<<8) | (buffer[0]); iowrite32(55,LED_Regs); return value; }
static int led_ioctl(struct file *filp,unsigned int reg_num,unsigned long args) { return 0; }
static const struct file_operations led_fops = { .owner =THIS_MODULE, .open =led_open, .release =led_release, .read =led_read, .write =led_write, //.ioctl =led_ioctl, };
static void led_setup_cdev(struct led_dev *dev,int index) { int err,devno =MKDEV(led_major,index); cdev_init(&dev->cdev,&led_fops); dev->cdev.owner = THIS_MODULE; dev->cdev.ops=&led_fops; err =cdev_add(&dev->cdev,devno,1); if(err) { printk("cdev_add ERROR\n"); } //for udev my_class = class_create(THIS_MODULE,DEVICE_NAME); if(IS_ERR(my_class)) { printk("Err: failed in creating class:\n"); return ; } my_device=device_create(my_class,NULL,devno,NULL,DEVICE_NAME); if(IS_ERR(my_device)) { printk("Err:failed in device_create fucnti 4000 on\n"); } }
static int led_init(void) { dev_t dev; int result; LED_Regs = ioremap(LED_PHY_ADDR,1); printk("led_ctrl: Access addresss to device is :0x%x\n",(unsigned int)LED_Regs); if(LED_Regs ==NULL) { printk("led_ctrl Access addresss is NULL\n"); return -EIO; } dev=MKDEV(led_major,0); alloc_chrdev_region(&dev,0,1,"LED"); led_major=MAJOR(dev); led_devp = kmalloc(sizeof(struct led_dev),GFP_KERNEL); if(!led_devp) { result = -ENOMEM; return 0; } memset(led_devp,0,sizeof(struct led_dev)); led_setup_cdev(led_devp,0); iowrite32(55,LED_Regs); return 0; }
static int led_exit(void) { cdev_del(&led_devp->cdev); kfree(led_devp); device_destroy(my_class,MKDEV(led_major,0)); class_unregister(my_class); class_destroy(my_class); unregister_chrdev_region(MKDEV(led_major,0),1); printk("rm seucessfull\n"); }
module_init(led_init); module_exit(led_exit);
------------------------------------------------------------------------------------------------------------------------------ #include <stdio.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> int main() { int led_fp; int i=0,j=0; unsigned char write_buff[4]={0}; unsigned char read_buff[4]={0}; unsigned long write_value=0; led_fp=open("/dev/led_ctrl_dev",O_RDWR); if(led_fp<0) { printf("open err\n"); return 0; }else { printf("open sucess\n"); } for(i=0;i<5;i++) { read(led_fp,read_buff,sizeof(read_buff)); printf("read from led =0x"); for(j=0;j<4;j++) { printf("%x",read_buff[j]); } printf("\n"); printf("input the led_value\n"); scanf("%x",&write_buff[0]); printf("writer to led =0x"); for(j=0;j<4;j++) { printf("%x",write_buff[j]); } printf("\n"); write_value=write(led_fp,write_buff,4); printf("write_value=%x\n",write_value); } close(led_fp); return 0; }
今天又仔细研究了下,终于搞定了,看来还是得自己研究代码和原理才是关键:
问题也很简单,就是只能读设备,却不能写设备,从执行的结果页看的出来,当上层应用程序调用write()(led_ctrl_app.c 文件中)数的时候,根本没有调用驱动层的write ()在 led_ctrl.c中)。所以找为什么,首先就是那个file_operations这个结构体了,因为这两个函数是靠这个结构体里面的指针进行关联的。所以我去查了下包含file_operations的头文件linux/fs.h文件。大家可不要以为这个文件在你的PC机上的linux系统里的哦,确切的说应在Digilent-linux-3.3这个内核下面的/inlcude/linux/fs.h中的。找到它的定义如下:
truct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int (*check_flags)(int);
int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long, struct file_lock **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
};
这个write函数的参数(struct file *, const char __user *, size_t, loff_t *);,于是修改了led_ctrl.c文件中的write函数的参数。在我的文件中,我也写了iotcl函数的,可是这个函数连make的是都过不了,原因也在于此,人家结构体里面定义的是 long (*unlocked_ioctl),所以写的函数也得相应的改改,至于我之前为什么写的是iotcl,很简单,我抄的<linux设备驱动开发详解》的,它用的内核和我们这里的Digilent-linuxXXX内核不一样哇,所以源码有些小不一样也是很正常。
相关文章推荐
- 嵌入式Linux开发实验中遇到的问题及解决方法
- 嵌入式linux(内核为linux 2.6.30.4)开发中遇到的一些问题解决方法
- java开发中遇到的问题及解决方法(持续更新)
- 安卓app开发遇到的问题以及解决方法
- Android开发中遇到的问题(四)——Android中WARNING: Application does not specify an API level requirement!的解决方法
- WinCE6.0流驱动开发的两种方法及驱动加载失败问题解决
- asp.net2.0开发遇到的小问题解决方法
- 搭建WinXP+VS2008+IIS+Sql Server 2005开发环境遇到的问题及解决方法备案
- 微信小程序在开发中遇到的问题与解决方法
- Linux字符设备驱动-globalmem驱动编译加载遇到的问题及解决办法
- 学习Java Web开发中遇到的问题,及其解决方法
- Linux搭建python环境中cx_Oracle模块安装遇到的问题与解决方法
- 记录Yii2框架开发微信公众号遇到的问题及解决方法
- linux下安装Subversion遇到关于BerkeleyDB问题及解决方法
- python在linux下使用多进程遇到3770问题解决方法
- 新手安装(折腾)Linux的故事——遇到各种问题的新手解决方法
- J2EE开发工作中遇到的异常问题及解决方法总结
- linux系统用遇到Another app is currently holding the yum lock问题的解决方法
- 安装linux时遇到GPT分区表问题的解决方法
- 最近在ArcGIS Engine开发中关于调用gp工具过程出现COM 组件的调用返回了错误 HRESULT E_FAIL 错误的解决方法 和 学习oracle中遇到的一些问题总结