linux驱动

来源:互联网 发布:林姗姗淘宝店 编辑:程序博客网 时间:2024/04/29 22:49
1.使用字符设备驱动程序
1) 编译/安装驱动
2)创建设备文件
3)访问设备

1) 在linux系统中,驱动程序通常采用内核模块的程序结构进行编码。

因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块。



   驱动名 memdev.c  #include <linux/module.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/uaccess.h>int dev1_registers[5];int dev2_registers[5];struct cdev cdev; dev_t devno;/*文件打开函数*/int mem_open(struct inode *inode, struct file *filp){        /*获取次设备号*/    int num = MINOR(inode->i_rdev);        if (num==0)        filp->private_data = dev1_registers;    else if(num == 1)        filp->private_data = dev2_registers;    else        return -ENODEV;  //无效的次设备号        return 0; }/*文件释放函数*/int mem_release(struct inode *inode, struct file *filp){  return 0;}/*读函数*/static ssize_t mem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){  unsigned long p =  *ppos;  unsigned int count = size;  int ret = 0;  int *register_addr = filp->private_data; /*获取设备的寄存器基地址*/  /*判断读位置是否有效*/  if (p >= 5*sizeof(int))    return 0;  if (count > 5*sizeof(int) - p)    count = 5*sizeof(int) - p;  /*读数据到用户空间*/  if (copy_to_user(buf, register_addr+p, count))  {    ret = -EFAULT;  }  else  {    *ppos += count;    ret = count;  }  return ret;}/*写函数*/static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){  unsigned long p =  *ppos;  unsigned int count = size;  int ret = 0;  int *register_addr = filp->private_data; /*获取设备的寄存器地址*/    /*分析和获取有效的写长度*/  if (p >= 5*sizeof(int))    return 0;  if (count > 5*sizeof(int) - p)    count = 5*sizeof(int) - p;      /*从用户空间写入数据*/  if (copy_from_user(register_addr + p, buf, count))    ret = -EFAULT;  else  {    *ppos += count;    ret = count;  }  return ret;}/* seek文件定位函数 */static loff_t mem_llseek(struct file *filp, loff_t offset, int whence){     loff_t newpos;    switch(whence) {      case SEEK_SET:         newpos = offset;        break;      case SEEK_CUR:         newpos = filp->f_pos + offset;        break;      case SEEK_END:         newpos = 5*sizeof(int)-1 + offset;        break;      default:         return -EINVAL;    }    if ((newpos<0) || (newpos>5*sizeof(int)))    return -EINVAL;        filp->f_pos = newpos;    return newpos;}/*文件操作结构体*/static const struct file_operations mem_fops ={  .llseek = mem_llseek,  .read = mem_read,  .write = mem_write,  .open = mem_open,  .release = mem_release,};/*设备驱动模块加载函数*/static int memdev_init(void){  /*初始化cdev结构*/  cdev_init(&cdev, &mem_fops);    /* 注册字符设备 */  alloc_chrdev_region(&devno, 0, 2, "memdev");  cdev_add(&cdev, devno, 2);}/*模块卸载函数*/static void memdev_exit(void){  cdev_del(&cdev);   /*注销设备*/  unregister_chrdev_region(devno, 2); /*释放设备号*/}MODULE_LICENSE("GPL");module_init(memdev_init);module_exit(memdev_exit);



Makefile文件:KDIR := /home/S5-driver/lesson7/linux-tiny6410/all:make -C $(KDIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=armclean:rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order



 应用程序: mem_write.c
 #include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main(){int fd = 0;int src = 2013;/*打开设备文件*/fd = open("/dev/memdev0",O_RDWR);/*写入数据*/write(fd, &src, sizeof(int));/*关闭设备*/close(fd);return 0;}


   arm-linux-readelf -d  mem_write.c  检查动态链接库
   一般采用静态编译
   arm-linux-gcc -static mem_write.c -o mem_write


应用程序: mem_read.c
#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>int main(){int fd = 0;int dst = 0;/*打开设备文件*/fd = open("/dev/memdev0",O_RDWR);/*写入数据*/read(fd, &dst, sizeof(int));printf("dst is %d\n",dst);/*关闭设备*/close(fd);return 0;}


 
 2.字符设备文件
 
  应用程序{文件名}  ---> 字符设备文件  --->(主设备号) ----> 设备驱动程序
 
  通过字符设备文件,应用程序可以使用相应的字符设备驱动程序来控制字符设备。创建字符设备
    文件的方法一般有两种:
       1.使用mknod命令
        mknod  /dev/文件名   c   主设备号  次设备号
       
        cat  /proc/devices   
       
        第一列               第二列
        数字(主设备号)        设备名字
       
       
       
       
        2.使用函数在驱动程序中创建

0 0
原创粉丝点击