您的位置:首页 > 运维架构 > Linux

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  啊




 
 
#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 驱动编程
相关文章推荐