虚拟字符驱动的心得

一、虚拟字符驱动的程序的源码

/***********************************
*function: 虚拟字符设备驱动程序的测试程序
*AURHOR: DREAM
*data:2013/7/7/12:42
************************************/
#include<stdio.h>
#include<string.h>
#define MEM_SIZE 4096
#define MEM_NAME global_mem_dev
#define MAGIC 'k'
#define MEM_CLEAR _IOW (MAGIC,1,int)
int main()
{
 char buf[MEM_SIZE];
 FILE *fp;
 int ret;
 /*初始化buf*/
 strcpy(buf,"MEM_DEV is a vitual device file");
 printf("buf:%s\n",buf);
 /*打开设备文件*/
 fp=fopen("/dev/global_mem_dev","r+");                          //犯的严重错误
 if(fp==NULL)
 {
  printf("fopen global_mem file fail\n"); 
  return -1;
 }
 printf("fopen global_mem_dev successed\n");
 /*写设备文件*/
 ret=fwrite(buf,sizeof(char),50,fp);   //设定写50个字符
 if(ret<0)
  {
   printf("fwrite global_mem fail\n");
   return -1;
  }
 else
  {
   printf("%d char is written\n",ret);
   
  }
 /*重新定位llseek*/
 fseek(fp,0,SEEK_SET);              //错误1
 /*清除buf*/
// memset(buf,0,sizeof(char));
 strcpy(buf,"Buf is NULL!");
 printf("buf: %s\n",buf);
 sleep(5);
 
 /*读取设备字符*/
 ret=fread(buf,sizeof(char),50,fp);
 if(ret<0)
  {
   printf("fread global_mem fail\n");
   return -1;
  }
 else
  {
   printf("%d char is readed\n",ret);
   
  }
 /*输出buf*/
 printf("buf:%s\n",buf);
 fclose(fp);
 return 0;
}

/*********************************
*function:global_mem_dev 虚拟字符驱动
*AUTHOR:DREAM
*date:2013/7/7 21:04
**********************************/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/slab.h>

//#define major_dev 0                                           //错误1
static int major_dev=0;  

static char DEV_NAME[]="global_mem_dev";

#define DEV_SIZE 4096
#define MAGIC 'k'
#define MEM_CLEAR _IOW (MAGIC,1,int)
struct global_mem
{
 struct cdev dev;
 char mem[DEV_SIZE];
};
struct global_mem *global_mem_devp;
static int global_mem_dev_open(struct inode *inode,struct file *filp)
{
 //将设备结构体的指针传递给文件私有数据指针
 filp->private_data=global_mem_devp;
 return 0;
}
static int global_mem_dev_release(struct inode *inode,struct file *filp)
{
 return 0;
}
static ssize_t global_mem_dev_write(struct file *filp, const char __user *buf,  size_t size, loff_t *ppos)
{
 unsigned long p=*ppos;
 int count=size;
 int ret=0;
 struct global_mem *new_global_mem_dev;
 new_global_mem_dev=filp->private_data;

 /*越界检测*/
 if(p>=DEV_SIZE)
  return ((count>0) ? -ENXIO : 0);
 if(count>(DEV_SIZE-p))
  count=DEV_SIZE-p;
 /*user to kernel*/
 if(copy_from_user(new_global_mem_dev->mem+p,buf,count))                                        //拷贝成功返回为0
  ret=-EFAULT;
 *ppos+=count;
 ret=count;
 /*调试信息*/
 printk(KERN_INFO"%d bytes is written from %ld\n",count,p);
 return ret;
}
static ssize_t global_mem_dev_read(struct file *filp, char __user *buf,  size_t size, loff_t *ppos)            //错误12
{
 int count=size;
 int ret=0;
 
 unsigned long p=*ppos;
 struct global_mem *new_global_mem_dev;
 new_global_mem_dev=filp->private_data;

 /*越界检测*/
 if(p>=DEV_SIZE)
  return ((count>0) ? -ENXIO : 0);
 if(count>(DEV_SIZE-p))
  count=DEV_SIZE-p;

 if(copy_to_user(buf,new_global_mem_dev->mem+p,count))
  ret=-EFAULT;
 *ppos+=count;
 ret=count;
 /*调试信息*/
 printk(KERN_WARNING"%d bytes is Readed from %ld\n",count,p);
 return ret;
}
static loff_t global_mem_dev_llseek(struct file *filp, loff_t offset, int orig)
{
 int base,ret=0;
 base=orig;
// struct global_mem *new_global_mem;
// new_global_mem_dev=filp->private_data;
 /*检测越界*/
 switch(base)
  {
  case 0:
  if(offset>DEV_SIZE||offset<0)                                 //错误6
   {
    ret= -EINVAL;
    break;
   }
  filp->f_pos=(unsigned int)offset;
  ret=filp->f_pos;
  
  case 1:
  if((filp->f_pos+offset)>DEV_SIZE||(filp->f_pos+offset)<0)
   { 
    ret= -EINVAL;
    break;
   }
  filp->f_pos+=(unsigned int)offset;
  ret=filp->f_pos;
  break;
   
  case 2:
  if(offset>0)
   {
    ret= -EINVAL;
    break;
   }
  if((filp->f_pos+offset)>DEV_SIZE||(filp->f_pos+offset)<0)
   { 
    ret= -EINVAL;
    break;
   }
  filp->f_pos+=(unsigned int)offset;
  ret=filp->f_pos;
  break;
   
  default:
   ret=-EINVAL;
   break;
   }
 return ret;
 
}
static int global_mem_dev_ioctl(struct inode *inode,
    struct file *filp,
    unsigned int cmd,
    unsigned long arg)
{
 int ret;
 struct global_mem *new_global_mem_dev;
 new_global_mem_dev=filp->private_data;
 /*类型检测*/
 if(_IOC_TYPE(cmd)!=MAGIC)
  printk("MAGIC type define error\n");
 
 switch(cmd)
  {
  case MEM_CLEAR:
   memset(new_global_mem_dev->mem,0,DEV_SIZE);                   //类型转换
   printk("global_mem_dev is set zero");
   break;
  default:
   ret=-EINVAL;
   break;
  }
  return 0;
}
static  struct file_operations global_mem_dev_fops={    //static const struct file_operations global_mem_dev_fops={
  .owner=THIS_MODULE,
  .open=global_mem_dev_open,
  .release=global_mem_dev_release,
  .write=global_mem_dev_write,                         //函数与原型相符合   错误11
  .read=global_mem_dev_read,
  .llseek=global_mem_dev_llseek,
  .ioctl=global_mem_dev_ioctl,
};
static void global_mem_setup_cdev(struct global_mem *cdev,int index)
{
 int err;
 dev_t new_dev=MKDEV(major_dev,index);
 
 cdev_init(&cdev->dev,&global_mem_dev_fops);                                          //错误5   应该使用global_mem_dev_ptr
 (cdev->dev).owner=THIS_MODULE;
 (cdev->dev).ops=&global_mem_dev_fops;
 /*调试信息*/
 printk(" init device  successed\n");    //错误2
 /*添加设备*/
 printk("major_dev is %d\n",MAJOR(new_dev)); 
 err=cdev_add(&cdev->dev,MKDEV(major_dev,index),1);                                           //错误9
 /*调试信息*/ 
 if(err<0)
  {
  printk(KERN_NOTICE"Fail adding %s major_dev ID is %d err ID is %d\n",DEV_NAME,major_dev,err);
  }
 else
  {
  printk(" add device  successed\n");    //错误2
  printk("err = %d\n",err);
  }
}
static int __init global_mem_init(void)

 /*第一步:分配设备号*/
 int ret;
 dev_t dev;
 /*获取设备号*/
 dev=MKDEV(major_dev,0);
 /*申请设备号*/
 /*手动分配*/
 if(major_dev)
  ret = register_chrdev_region(dev,1,"global_mem_dev");               //返回成功为0
 else
 {
  ret=alloc_chrdev_region(&dev,0,1,"global_mem_dev");
  major_dev=MAJOR(dev);
 }
 printk("major_dev is %d\n",major_dev);
 /*调试信息*/
 if(ret<0)
  {
  printk(KERN_WARNING"failed get %s  major_dev\n",DEV_NAME);
  return -ret;
  }
 /*第二步:申请内核空间*/
 /*动态申请内核空间*/
 global_mem_devp=kmalloc(sizeof(struct global_mem),GFP_KERNEL);           //申请成功返回为指针,失败返回为NULL
 if(!global_mem_devp)
  {
  return -ENOMEM;
  goto fail_malloc;
  }
 /*清空内核空间*/
// memset(global_mem_dev_ptr,0,DEV_SIZE);                                 //错误3  
 memset(global_mem_devp,0,sizeof(struct global_mem)); 
 /*调试信息*/
 printk(" kernel space successed\n");    //错误2

 global_mem_setup_cdev(global_mem_devp,0);

 /*调试信息*/
 printk("%s drivers installed \n",DEV_NAME);    //错误2
 printk("dev_name is %s\n",DEV_NAME);
 printk("major_dev is %d\n",major_dev);
fail_malloc:
// unregister_chrdev_region(new_dev,1);                                                     //错误4 new_dev 未申请
 unregister_chrdev_region(MKDEV(major_dev,0),1);
 return ret;  
}
static void __exit global_mem_exit(void)
{
 cdev_del(&global_mem_devp->dev);//注销设备                                             //错误7
 kfree(global_mem_devp);                 //错误8  释放设备结构体的内存
 unregister_chrdev_region(MKDEV(major_dev,0),1); //释放设备号
 printk("global_mem_dev uninstalled\n");
}
module_init(global_mem_init);                                                                     //错误10
module_exit(global_mem_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DREAM");
module_param(major_dev,int,S_IRUGO);
EXPORT_SYMBOL(major_dev);

二、第一次由自己完成的程序,一个好的驱动工程师也就是一个好的测试工程师,首先明确测试应用程序,特别注意要设备文件的位置是/dev/global_mem_dev ,

1、注意写程序时,明确流程图

2、注册设备驱动的步骤

3、return 返回类型

4、遇到的最大的问题是显示注册添加设备成功,但是在cat /proc/devices  却看不到

5、怎么自己创建struct 变量

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值