linux ---------驱动开发遇到的问题及解决方法

来源:互联网 发布:淘宝女装软文 编辑:程序博客网 时间:2024/06/18 17:24

      (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 fucntion\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内核不一样哇,所以源码有些小不一样也是很正常。

原创粉丝点击