Chinaunix首页 | 论坛 | 博客
  • 博客访问: 338736
  • 博文数量: 45
  • 博客积分: 669
  • 博客等级: 上士
  • 技术积分: 675
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-27 17:59
文章分类
文章存档

2015年(5)

2014年(6)

2013年(4)

2012年(30)

分类: LINUX

2012-08-23 07:32:16

本实践实现对一段内存的的打开,关闭,读写的操作,并通过应用程序测试设备及驱动是否运行正常
 
test_drv.c


点击(此处)折叠或打开

  1. #include<linux/module.h>
  2.   #include<linux/init.h>
  3.   #include<linux/fs.h>
  4.   #include<linux/kernel.h>
  5.   #include<linux/slab.h>
  6.   #include<linux/types.h>
  7.   #include<linux/errno.h>
  8.   #include<linux/cdev.h>
  9.   #include<asm/uaccess.h>
  10.   
  11.   #define TEST_DEVICE_NAME "test_dev"
  12.   #define BUFF_SZ 1024
  13.   
  14.   static struct cdev test_dev;
  15.   static char *data = NULL;
  16.   int major =0;
  17.   
  18.   //读函数
  19.   static ssize_t test_read(struct file *file,char *buf,size_t count,loff_t *f_pos)
  20.   {
  21.    int len;
  22.    if(count<0)
  23.    {
  24.    return -EINVAL;
  25.    }
  26.    len=strlen(data);
  27.    count=(len>count)?count:len; //取len与count的小值
  28.    if(copy_to_user(buf,data,count)) //把内核缓冲数据复制到用户空间
  29.    {
  30.    return -EFAULT;
  31.    }
  32.   
  33.    return count;
  34.   
  35.   }
  36.   
  37.   static int test_write(struct file *file ,const char *buffer,unsigned int count,loff_t *f_pos)
  38.   {
  39.    if(count <0)
  40.    {
  41.    return -EINVAL;
  42.    }
  43.   
  44.    memset(data,0 ,BUFF_SZ);
  45.    count=(BUFF_SZ >count)?count:BUFF_SZ;
  46.    if(copy_from_user(data,buffer,count)) //用户空间数据复制到内核空间
  47.    {
  48.    return - EFAULT;
  49.    }
  50.    return count;
  51.   
  52.   }
  53.   
  54.   
  55.   static int test_open(struct inode *inode,struct file *file)
  56.   {
  57.    printk("This is open operation\n");
  58.    //分配并初始化缓存区
  59.    data = (char *)kmalloc(sizeof(char) *BUFF_SZ,GFP_KERNEL);
  60.    if(!data)
  61.    {
  62.    return -ENOMEM;
  63.    }
  64.    memset(data,0,BUFF_SZ);
  65.    return 0;
  66.   
  67.   }
  68.   
  69.   //关闭函数
  70.   static int test_release(struct inode *inode,struct file *file)
  71.   {
  72.    printk("this is release operation\n");
  73.    if(data)
  74.    {
  75.    kfree(data); //释放缓存区
  76.    data = NULL; //防止野指针
  77.    }
  78.    return 0;
  79.   }
  80.   
  81.   
  82.   //创建,初始化字符设备,并注册到系统
  83.   static int test_setup_cdev(struct cdev *dev,int minor,struct file_operations *fops)
  84.   {
  85.    int err,devno =MKDEV(major,minor);
  86.    cdev_init(dev,fops);;//初始化cdev结构
  87.    dev->owner =THIS_MODULE;
  88.    dev->ops = fops;
  89.    err = cdev_add(dev,devno,1);//注册字符设备
  90.    if(err)
  91.    {
  92.    printk(KERN_NOTICE " %d add test %d failed",err,minor);
  93.    }
  94.   
  95.    return 0;
  96.   }
  97.   
  98.   
  99.   //虚拟设备的file operation 结构
  100.   static struct file_operations test_fops=
  101.   {
  102.    .owner = THIS_MODULE,
  103.    .read = test_read,
  104.    .write =test_write,
  105.    .open = test_open,
  106.    .release =test_release,
  107.   
  108.   };
  109.   
  110.   //设备驱动模块加载函数
  111.   int init_module(void)
  112.   {
  113.    int result;
  114.    dev_t dev =MKDEV(major,0); //dev_t
  115.    if(major)
  116.    {//静态注册设备,设备号先前制定好,并设定设备名
  117.    result =register_chrdev_region(dev,1,TEST_DEVICE_NAME);
  118.    }
  119.    else
  120.    { //动态注册。指定设备的次设备号(即需要的设备个数)
  121.    result = alloc_chrdev_region(&dev,0,1,TEST_DEVICE_NAME);
  122.    major = MAJOR(dev); //获得主设备号
  123.    }
  124.   
  125.    if(result<0)
  126.    {
  127.    printk(KERN_WARNING"Test device:fail to get major %d\n",major);
  128.    return result;
  129.    }
  130.    test_setup_cdev(&test_dev,0,&test_fops);
  131.    printk("this major of test device is %d\n",major);
  132.    return 0;
  133.   }
  134.   
  135.   //卸载模块
  136.   void cleanup_module()
  137.   {
  138.    cdev_del(&test_dev);
  139.    unregister_chrdev_region(MKDEV(major,0),1);
  140.    printk("test device uninstalled\n");
  141.   
  142.   
  143.   }

  

  

在linux2.6的基础上,编译成内核代码,Makefile如下


点击(此处)折叠或打开

  1. ifeq ($(KERNELRELEASE),)
  2. KDIR ?= /lib/modules/$(shell uname -r)/build
  3. PWD :=$(shell pwd)
  4. modules:
  5. $(MAKE) -C $(KDIR) M=$(PWD) modules
  6. modules_install:
  7. $(MAKE) -C $(KDIR) M=$(PWD) modules_install
  8. clean:
  9. rm -rf *.o *.ko *.mod.c .*.cmd *.markers *.order *.symvers .tmp_versions
  10. .PHONY: modules modules_install clean
  11. else
  12. obj-m:= test_drv.o
  13. endif


 

通过脚本文件实现驱动程序的加载与卸载

模块加载脚本

test_drv_load


点击(此处)折叠或打开

  1. #驱动模块名称
  2. module="test_drv"
  3. #设备名称
  4. device="test_dev"
  5. echo /dev/${device}
  6. mode="664"
  7. #删除已经存在的设备节点
  8. rm -f /dev/${device}
  9. #加载驱动模块
  10. echo $module.ko $*
  11. /sbin/insmod -f ./$module.ko $*
  12. #查到创建设备的的主设备号
  13. major=`cat /proc/devices | awk "\\$2==\"$device\" {print \\$1}"`
  14. echo major=$major
  15. #创建设备文件节点
  16. mknod /dev/${device} c $major 0
  17. #设备文件属性
  18. chmod $mode /dev/${device}


 

模块卸载脚本

test_drv_unload


点击(此处)折叠或打开

  1. #卸载驱动模块
  2. #删除设备文件
  3. module="test_drv"
  4. device="test_dev"
  5. # invoke rmmod with all arguments we got
  6. /sbin/rmmod $module $* || exit 1
  7. # remove nodes
  8. rm -f /dev/${device}
  9. exit 0


 

对驱动程序测试的应用程序:(通过打开设备文件,进行字符的写入和读出)

test.c


点击(此处)折叠或打开

  1. /* test.c */
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #define TEST_DEVICE_FILENAME "/dev/test_dev"
  11. #define BUFF_SZ 1024
  12.  
  13. int main()
  14. {
  15.     int fd, nwrite, nread;
  16.     char buff[BUFF_SZ];
  17.  
  18.     fd = open(TEST_DEVICE_FILENAME , O_RDWR);
  19.     if (fd < 0)
  20.     {
  21.         perror("open");
  22.         exit(1);
  23.     }
  24.        
  25.     do
  26.     {
  27.         printf("Input some words to kernel(enter 'quit' to exit):");
  28.         memset(buff, 0, BUFF_SZ);
  29.         if (fgets(buff, BUFF_SZ, stdin) == NULL)
  30.         {
  31.             perror("fgets");
  32.             break;
  33.         }
  34.         buff[strlen(buff) - 1] = '\0';
  35.        
  36.         if (write(fd, buff, strlen(buff)) < 0)
  37.         {
  38.             perror("write");
  39.             break;
  40.         }
  41.        
  42.         if (read(fd, buff, BUFF_SZ) < 0)
  43.         {
  44.             perror("read");
  45.             break;
  46.         }
  47.         else
  48.         {
  49.             printf("The read string is from kernel:%s\n", buff);
  50.         }
  51.        
  52.     } while(strncmp(buff, "quit", 4));
  53.    
  54.     close(fd);
  55.     exit(0);
  56. }

先执行make,运行加载脚本./test_drv_load. 再运行测试程序test.对驱动程序进行测试。最后卸载驱动程序 ./test_drv_unload.

 

阅读(1049) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~