Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1300254
  • 博文数量: 548
  • 博客积分: 7597
  • 博客等级: 少将
  • 技术积分: 4224
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-15 13:21
个人简介

嵌入式软件工程师&&太极拳

文章分类

全部博文(548)

文章存档

2014年(10)

2013年(76)

2012年(175)

2011年(287)

分类:

2012-02-25 16:43:13

使用文件私有数据的字符设备驱动设计
 
 
  1. 编写源代码
  /* mem_dev.h */
  #ifndef _MEMDEV_H_ 
  #define _MEMDEV_H_ 
  
  #ifndef MEMDEV_MAJOR 
  #define MEMDEV_MAJOR  260     
  //memdev采用静态分配设备号,不要和其它设备重复 
  #endif 
  
  #ifndef MEMDEV_NR_DEVS 
  #define MEMDEV_NR_DEVS  2 
  #endif 
  
  #ifndef MEMDEV_SIZE 
  #define MEMDEV_SIZE  4096 
  #endif  
  
  //mem设备描述结构体
  struct mem_dev 
  { 
  char *data; 
  unsigned long size; 
  };  
  #endif 
 
 
  /* mem_dev.c */
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include  
  #include
  
  #include "mem_dev.h"  
  
   
  static int mem_major = MEMDEV_MAJOR; 
   
  module_param(mem_major,int,S_IRUGO); 
   
  struct mem_dev *mem_devp; 
   
  struct cdev cdev; 
   
  int mem_open(struct inode *inode,struct file *filp) 
  { 
      struct mem_dev *dev; 
       
      int num = MINOR(inode->i_rdev); 
       
      if(num >=MEMDEV_NR_DEVS) 
          return -ENODEV; 
      dev = &mem_devp[num]; 
   
      filp->private_data = dev; 
   
      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 *poss) 
  { 
      unsigned long p = *poss; 
      unsigned int count = size; 
      int ret = 0; 
      struct mem_dev *dev = filp->private_data; 
   
      if(p >= MEMDEV_SIZE) 
          return 0; 
      if(count > MEMDEV_SIZE-p) 
          count = MEMDEV_SIZE-p; 
   
      if(copy_to_user(buf,(void*)(dev->data+p),count)) 
      { 
          ret = -EFAULT; 
      } 
      else 
      { 
          *poss +=count; 
          ret = count; 
          printk(KERN_INFO "read %d bytes from %lu/n",count,p); 
      } 
   
      return ret; 
  } 
   
  static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *poss) 
  { 
      unsigned long p = *poss; 
      unsigned int count = size; 
      int ret=0; 
      struct mem_dev *dev = filp->private_data; 
   
      if(p>=MEMDEV_SIZE) 
          return 0; 
      if(count>MEMDEV_SIZE-p) 
          count = MEMDEV_SIZE-p; 
   
      if(copy_from_user(dev->data+p,buf,count)) 
      { 
          ret = -EFAULT; 
      } 
      else 
      { 
          *poss += count; 
          ret = count; 
          printk(KERN_INFO "write %d bytes from %lu/n",count,p); 
      } 
       
      return ret; 
  } 
   
  static loff_t mem_llseek(struct file *filp,loff_t offset,int whence) 
  { 
      loff_t newpos; 
       
      switch(whence) 
      { 
          case 0: 
              newpos = offset; 
              break; 
          case 1: 
              newpos = filp->f_pos + offset; 
              break; 
          case 2: 
              newpos = MEMDEV_SIZE - 1 + offset; 
              break; 
          default: 
              return -EINVAL; 
      } 
      if((newpos<0) || (newpos>MEMDEV_SIZE)) 
          return -EINVAL; 
   
      filp->f_pos = newpos; 
      return newpos; 
  } 
   
  static const struct file_operations mem_fops = 
  { 
      .owner = THIS_MODULE, 
      .llseek = mem_llseek, 
      .read = mem_read, 
      .write = mem_write, 
      .open = mem_open, 
      .release = mem_release, 
  }; 
   
  static int memdev_init(void) 
  { 
      int result; 
      int i; 
      dev_t devno = MKDEV(mem_major,0); 
   
      if(mem_major) 
          result = register_chrdev_region(devno,2,"memdev"); 
      else 
      { 
          result = alloc_chrdev_region(&devno,0,2,"memdev"); 
          mem_major = MAJOR(devno); 
      } 
   
      if(result < 0) 
          return result; 
       
      cdev_init(&cdev,&mem_fops); 
      cdev.owner = THIS_MODULE; 
      cdev.ops = &mem_fops; 
   
      cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS); 
   
      mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev),GFP_KERNEL); 
      if(!mem_devp) 
      { 
          result = -ENOMEM; 
          goto fail_malloc; 
      } 
       
      memset(mem_devp,0,MEMDEV_NR_DEVS * sizeof(struct mem_dev)); 
   
      for(i=0;i      { 
          mem_devp[i].size = MEMDEV_SIZE; 
          mem_devp[i].data = kmalloc(MEMDEV_SIZE,GFP_KERNEL); 
          memset(mem_devp[i].data,0,MEMDEV_SIZE); 
      } 
   
      return 0; 
   
  fail_malloc: 
      unregister_chrdev_region(devno,2); 
      return result; 
  } 
   
  static void memdev_exit(void) 
  { 
      cdev_del(&cdev); 
      kfree(mem_devp); 
      unregister_chrdev_region(MKDEV(mem_major,0),2); 
  } 
   
  MODULE_AUTHOR("Zechin Liao"); 
  MODULE_LICENSE("GPL"); 
   
  module_init(memdev_init); 
  module_exit(memdev_exit);
 
 
  /* Makefile */
  KVERS = $(shell uname -r)
  
  # Kernel modules
  obj-m += mem_dev.o
  
  #Specify flags for the module compilation.
  #EXTRA_CFLAGS=-g -o0
  
  build: kernel_modules
  
  kernel_modules:
     make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
  
  clean:
     make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
 
 
  /* memdev_app.c */
  #include    
  #include    
  #include    
  #include      
  #include
     
  int main()    
  {    
      int fd;    
      char buf[4096];    
    
      printf("\n");
      strcpy(buf,"This is a example of charactar devices driver");    
      printf("buf:%s\n",buf);    
          
      fd=open("/dev/memdev",O_RDWR);       
      if(fd == -1)    
      {    
          printf("open mem_dev failed!\n");    
          return -1;              
      }    
          
      write(fd,buf,sizeof(buf));    
      lseek(fd,0,SEEK_SET);    
      strcpy(buf,"nothing");    
      read(fd,buf,sizeof(buf));    
      printf("buf:%s\n",buf);    
     
      return 0;    
  }
 
  2. 编译
      输入“make”命令编译,得到mem_dev.ko文件。
  3. 加载模块
      输入“sudo insmod mem_dev.ko”,通过“lsmod”命令,发现mem_dev模块已加载。再通过“cat /proc/devices”命令查看,发现多出了主设备号为260的“mem_dev”字符设备驱动。
  4. 创建设备节点
      输入“sudo mknod /dev/memdev c 260 0”创建设备节点。
  5. 验证
      通过“sudo echo "hello world" > /dev/memdev”命令和“sudo cat /dev/memdev”命令分别验证设备的写和读,结果证明字符串正确的写入了mem_dev字符设备。
  6. 应用程序验证
     (1)编译memdev_app.c
          gcc -o memdev_app memdev_app.c
      (2)运行memdev_app
          ./memdev_app
  7. 删除设备节点
      sudo rm /dev/memdev
  8. 卸载模块
      rmmod mem_dev
 
  至此,虚拟字符设备驱动完满完成。
 
阅读(476) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~