Created
May 8, 2014 07:10
-
-
Save jannson/69ea5ede1f80f49cdfc6 to your computer and use it in GitHub Desktop.
字符设备驱动示例
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* http://blog.chinaunix.net/uid-28732854-id-3858242.html */ | |
/*******************************memdev.h********************************/ | |
#ifndef _MEMDEV_H_ | |
#define _MEMDEV_H_ | |
#ifndef MEMDEV_MAJOR | |
#define MEMDEV_MAJOR 251 /*预设的mem的主设备号*/ | |
#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 /* _MEMDEV_H_ */ | |
/*********************memdev.c******************************/ | |
#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 <linux/slab.h> | |
#include <asm/io.h> | |
#include <asm/system.h> | |
#include <asm/uaccess.h> | |
#include "memdev.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 *ppos) | |
{ | |
unsigned long p = *ppos; | |
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 { | |
*ppos += count; | |
ret = count; | |
printk(KERN_INFO "read %d bytes(s) from %ld\n", count, p); | |
} | |
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; | |
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 { | |
*ppos += count; | |
ret = count; | |
printk(KERN_INFO "written %d bytes(s) from %ld\n", count, p); | |
} | |
return ret; | |
} | |
/* | |
* seek文件定位函数 | |
* */ | |
static loff_t mem_llseek(struct file *filp, loff_t offset, int whence) | |
{ | |
loff_t newpos; | |
switch(whence) { | |
case 0: /* SEEK_SET */ | |
newpos = offset; | |
break; | |
case 1: /* SEEK_CUR */ | |
newpos = filp->f_pos + offset; | |
break; | |
case 2: /* SEEK_END */ | |
newpos = MEMDEV_SIZE -1 + offset; | |
break; | |
default: /* can't happen */ | |
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结构*/ | |
cdev_init(&cdev, &mem_fops); | |
cdev.owner = THIS_MODULE; | |
/* 注册字符设备 */ | |
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, sizeof(struct mem_dev)); | |
/*为设备分配内存*/ | |
for (i=0; i < MEMDEV_NR_DEVS; 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, 1); | |
return result; | |
} | |
/*模块卸载函数*/ | |
static void memdev_exit(void) | |
{ | |
cdev_del(&cdev); /*注销设备*/ | |
kfree(mem_devp); /*释放设备结构体内存*/ | |
unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/ | |
} | |
MODULE_AUTHOR("www.enjoylinux.cn"); | |
MODULE_LICENSE("GPL"); | |
module_init(memdev_init); | |
module_exit(memdev_exit); | |
/******************app_mem.c************************/ | |
#include <stdio.h> | |
#include <string.h> | |
int main() | |
{ | |
FILE *fp0 = NULL; | |
char Buf[4096]; | |
/*初始化Buf*/ | |
strcpy(Buf, "Mem is char dev!"); | |
printf("BUF: %s\n",Buf); | |
/*打开设备文件*/ | |
fp0 = fopen("/dev/memdev0","r+"); | |
if (fp0 == NULL) { | |
printf("Open Memdev0 Error!\n"); | |
return -1; | |
} | |
/*写入设备*/ | |
fwrite(Buf, sizeof(Buf), 1, fp0); | |
/*重新定位文件位置(思考没有该指令,会有何后果)*/ | |
fseek(fp0, 0, SEEK_SET); | |
/*清除Buf*/ | |
strcpy(Buf, "Buf is NULL!"); | |
printf("BUF: %s\n",Buf); | |
/*读出设备*/ | |
fread(Buf, sizeof(Buf), 1, fp0); | |
/*检测结果*/ | |
printf("BUF: %s\n",Buf); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment