一、虚拟字符驱动的程序的源码
/***********************************
*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 变量