复习day03
1.内核定时器
struct timer_list{
expires
function
data
}
jiffies
init_timer
add_timer
del_timer
mod_timer
2.系统调用
如何实现?
从用户态能够切换到内核的方法
系统调用
中断
3.字符设备驱动框架
struct cdev{
...
dev_t dev;//设备号
file_operations fops*;
...
}
设备号=主设备好+次设备号
主设备号:代表一类设备
次设备号:用于区分同类设备中不同的个体
静态分配
register_chrdev_region()
动态分配
alloc_chrdev_region()
cdev的操作
cdev_init(*cdev,*file_operations)
cdev_add(...)
cdev_del(..)
struct file_operations{
.owner =THIS_MODULE,
}
insmod cdd.ko
mknod /dev/cdd c 248 0
./test
---------------------------------------------------------------------------------------
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 1
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
printk("enter cdd_read\n");
return 0;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
return 0;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =all_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
/*初始化cdev
*cdev_int(struct cdev* dev,const struct file_operations* fops)
*/
cdev_int(&dev,&cdd_fops) ;
/*添加cdev到内核中
*cdev_add(struct cdev*p,dev_t dev ,unsigned count)
*/
ret=cdev_add(&cdev,dev,CDD_COUNT);
if(ret<0){
printk("cdev_add failed!\n");
goto failure_cdev_add;
}
return 0;
failure_cdv_add:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
/*从内核中删除cdev*/
cdev_del(&cdd_cdev);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
test.c
#include<stdio.h>
#include<fcntl.h>
#include<stdlib.h>
int fd =0;
int main(void){
char ch;
char buf[10];
fd=open("/dev/cdd",O_RDWR);
if(fd<0){
printf("open failed!\n");
return -1;
}
printf("open successed fd =%d",fd);
while(1){
printf("string to test /dev/cdd...\n");
ch=getchar();
getchar();
if(ch=='q'){
break;
}
switch(ch){
case 'r': read(fd,buf,0);break;
case 'w': write(fd,buf,0);break;
case 'o': ioctl(fd,0,0);break;
default:
break;
}
sleep(1);
}
close(fd);
return 0;
}
insmod cdd.ko
mknod /dev/cdd c 248 0
用户空间open调用到内核中的cdd_open
open
----------------
sys_open
->do_sys_open
->do_filp_open
->do_last
->nameidat_to_filp
->__dentry_open
->chrdev_open
->filp->f_op->open(cdd_open)
思考:/dev/cdd 起到的作用? 通道?
手工创建节点
mknod
自动创建设备结点
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
//动态申请的头文件
#include<linux/slab.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 10
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
struct class *dev_class=NULL;
//struct device *dev_device=NULL;
struct cdd_cdev{
struct cdev cdev;
struct device *dev_device;
u8 led;
};
struct cdd_cdev *cdd_cdevp=NULL;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
printk("enter cdd_read\n");
return 0;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
return 0;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
int i;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =alloc_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
cdd_cdevp=kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(cdd_cdevp)){
printk("kzalloc fail");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"cdd_class");
if(IS_ERR(dev_class)){
printk("class_create failed!\n");
ret=PTR_ERR(dev_class);
goto failure_dev_class;
}
for(i=0;i<CDD_COUNT;i++){
/*初始化cdev*/
cdev_init(&(cdd_cdevp[i].cdev),&cdd_fops);
/*添加cdev到内核*/
cdev_add(&(cdd_cdevp[i].cdev),dev+i,1);
/*"/dev/xxx"*/
device_create(dev_class,NULL,dev+i,NULL,"cdd%d",i);
}
return 0;
failure_dev_class:
kfree(cdd_cdevp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
int i=0;
for(i=0;i<CDD_COUNT;i++){
device_destroy(dev_class,dev+i);
cdev_del(*(cdd_cdevp[i].cdev));
}
/*从内核中删除设备类*/
class_destroy(dev_class);
kfree(cdd_cdevp);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
自动创建设备节点文件的方式
用户态的程序创建的设备节点文件
udev(mdev嵌入式使用),根据/sys/的变化,动态在目录下
创建设备节点文件。
(pc环境下)
udev ,后台守护进程接收uevent事件,
device_create会发出该事件
udev会根据事件信息创建/dev/cdd0
(嵌入式环境下)
mdev,device_create函数会直接调用/sbin/mdev程序下
来创建设备节点文件。
/proc ->procfs 导出内核运行状态信息
/sys ->sysfs 重点在于导出内核中所有硬件设备的结构层次图
这两个目录都是虚拟目录
--------------------------------------------------------------------------------
支持多设备去驱动
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#inlcude<linux/device.h>
//动态申请的头文件
#include<linux/slab.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 10
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
struct class *dev_class=NULL;
//struct device *dev_device=NULL;
struct cdd_cdev{
struct cdev cdev;
struct device *dev_device;
u8 led;
}
struct cdd_cdev *cdd_cdevp=NULL;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
printk("enter cdd_read\n");
return 0;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
return 0;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
int i;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =all_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
cdd_cdevp=kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(cdd_cdevp)){
printk("kzalloc fail");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"cdd_class");
if(IS_ERR(dev_class)){
printk("class_create failed!\n");
ret=PTR_ERR(dev_class);
goto failure_dev_class;
}
for(i=0;i<CDD_COUNT;i++){
/*初始化cdev*/
cdev_init(&(cdd_cdevp[i].cdev),&cdd_fops);
/*添加cdev到内核*/
cdev_add(&(cdd_cdevp[i].cdev),dev+i,1);
/*"/dev/xxx"*/
device_create(dev_class,NULL,dev+i,NULL,"cdd%d",i);
}
return 0;
failure_dev_class:
kfree(cdd_cdevp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
int i=0;
for(i=0;i<CDD_COUNT;i++){
device_destroy(dev_class,dev+i);
cdev_del(*(cdd_cdevp[i].cdev));
}
/*从内核中删除设备类*/
class_destroy(dev_class);
kfree(cdd_cdevp);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
添加修改
设备节点文件 内核中
/dev/cdd0 cdev0 led=0
/dev/cdd1 cdev1 led=1
...
...
...
/dev/cdd9 cdev9 led=9
open("/dev/cdd0")
cdd_open(struct inode *inode,struct file *filp )
uc中打开一个文件
推荐一本书<unix高级环境编程>
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#inlcude<linux/device.h>
//动态申请的头文件
#include<linux/slab.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 10
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
struct class *dev_class=NULL;
//struct device *dev_device=NULL;
struct cdd_cdev{
struct cdev cdev;
struct device *dev_device;
u8 led;
}
struct cdd_cdev *cdd_cdevp=NULL;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
printk("enter cdd_read\n");
return 0;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
return 0;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
int i;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =all_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
cdd_cdevp=kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(cdd_cdevp)){
printk("kzalloc fail");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"cdd_class");
if(IS_ERR(dev_class)){
printk("class_create failed!\n");
ret=PTR_ERR(dev_class);
goto failure_dev_class;
}
for(i=0;i<CDD_COUNT;i++){
/*初始化cdev*/
cdev_init(&(cdd_cdevp[i].cdev),&cdd_fops);
/*添加cdev到内核*/
cdev_add(&(cdd_cdevp[i].cdev),dev+i,1);
/*"/dev/xxx"*/
device_create(dev_class,NULL,dev+i,NULL,"cdd%d",i);
cdd_cdevp[i].led=i;
}
return 0;
failure_dev_class:
kfree(cdd_cdevp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
int i=0;
for(i=0;i<CDD_COUNT;i++){
device_destroy(dev_class,dev+i);
cdev_del(*(cdd_cdevp[i].cdev));
}
/*从内核中删除设备类*/
class_destroy(dev_class);
kfree(cdd_cdevp);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
文件表
struct inode
{
dev_t i_rdev;//记录设备号
union{
struct pipe_inode_info *i_pipe;
struct cdev *i_cdev;//指向了cdev_add时添加的cdev
}
}
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#inlcude<linux/device.h>
//动态申请的头文件
#include<linux/slab.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 10
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
struct class *dev_class=NULL;
//struct device *dev_device=NULL;
struct cdd_cdev{
struct cdev cdev;
struct device *dev_device;
u8 led;
}
struct cdd_cdev *cdd_cdevp=NULL;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
struct cdd_cdev* pcdevp=NULL;
printk("enter cdd_open\n");
pcdevp = container_of(inode->i_cdev,struct cdd_cdev,cdev);
printk("led=%d\n",pcdevp->led);
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
printk("enter cdd_read\n");
return 0;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
return 0;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
int i;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =all_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
cdd_cdevp=kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(cdd_cdevp)){
printk("kzalloc fail");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"cdd_class");
if(IS_ERR(dev_class)){
printk("class_create failed!\n");
ret=PTR_ERR(dev_class);
goto failure_dev_class;
}
for(i=0;i<CDD_COUNT;i++){
/*初始化cdev*/
cdev_init(&(cdd_cdevp[i].cdev),&cdd_fops);
/*添加cdev到内核*/
cdev_add(&(cdd_cdevp[i].cdev),dev+i,1);
/*"/dev/xxx"*/
device_create(dev_class,NULL,dev+i,NULL,"cdd%d",i);
cdd_cdevp[i].led=i;
}
return 0;
failure_dev_class:
kfree(cdd_cdevp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
int i=0;
for(i=0;i<CDD_COUNT;i++){
device_destroy(dev_class,dev+i);
cdev_del(*(cdd_cdevp[i].cdev));
}
/*从内核中删除设备类*/
class_destroy(dev_class);
kfree(cdd_cdevp);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
上面代码在open中确定用户中打开哪个设备
--------------------------------------------------------------------
用户空间操作的设备在read函数中实现知道那个设备
struct filp{
loff_t f_ops;
}
fd5=open("/dev/cdd5") struct file filp5
read(fd5,....)
cdd_read()
cdd_open中添加
filp->private_data = pcdevp
;
cdd_read
-----------------------------------------------------------------------
4.内核空间和用户空间数据交互问题
内核态数据向用户态拷贝 copy_to_user(.....)
用户态数据向内核态拷贝 copy_from_user(....)
定义在arch/arm/include/asm/uaccess.h
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#inlcude<linux/device.h>
#include<asm/uaccess.h>//用户空间拷贝头文件
//动态申请的头文件
#include<linux/slab.h>
MODULE_LICENSE("GPL");
#define CDD_MAJOR 200
#define CDD_MINOR 0
#define CDD_COUNT 10
dev_t dev=0;
u32 cdd_major=0;
u32 cdd_minor=0;
/*定义cdev类型的变量*/
struct cdev cdd_cdev;
struct class *dev_class=NULL;
//struct device *dev_device=NULL;
#define BUF_SIZE 100
struct cdd_cdev{
struct cdev cdev;
struct device *dev_device;
u8 led;
char kbuf[BUF_SIZE];
}
struct cdd_cdev *cdd_cdevp=NULL;
int cdd_open(struct inode *inode,struct file *filp){
printk("enter cdd_open\n");
struct cdd_cdev* pcdevp=NULL;
printk("enter cdd_open\n");
pcdevp = container_of(inode->i_cdev,struct cdd_cdev,cdev);
printk("led=%d\n",pcdevp->led);
filp->private_data = pcdevp;
return 0;
}
int cdd_read(struct file* filp,char __user *buf,size_t count,
loff_t *offset){
int ret=0
struct cdd_cdev* pcdevp = filp->private_data;
printk("LED%d\n",pcdevp->led);
//copy_to_user(to,from,n);
ret=copy_to_user(buf,pcdevp->kbuf,count);
return ret;
}
int cdd_write(struct file *filp,const char __user *buf,
size_t count,loff_t *offset){
printk("enter cdd_write!\n");
int ret=0;
copy_from_user(pcdevp->kbuf,buf,count);
return ret;
}
int cdd_ioctl(struct inode *inode,struct file *filp,
unsigned int cmd ,unsigned data){
printk("enter cdd_ioctl!\n");
return 0;
}
int cdd_release(struct inode *inode,struct file *filp){
printk("enter cdd_release!\n");
return 0;
}
struct file_operations cdd_fops={
.owner = THIS_MODULE,
.open=cdd_open,
.read=cdd_read,
.write=cdd_write,
.ioctl=cdd_ioctl,
.release=cdd_release,
};
int __init cdd_init(void){
int ret =0;
int i;
if(cdd_major){
//静态方式分配设备号
dev=MKDEV(CDD_MAJOR,CDD_MINOR);
ret =register_chrdev_region(dev,CDD_COUNT,cdd_demo);
}else{
/*动态分配设备号*/
ret =all_chrdev_region(&dev,cdd_minor,CDD_COUNT,cdd_demo);
}
if(ret<0){
prink("register_chrdev_region failed!\n");
goto failure_register_chrdev;
}
/*获取主设备号*/
cdd_major=MAJOR(dev);
cdd_cdevp=kzalloc(sizeof(struct cdd_cdev)*CDD_COUNT,GFP_KERNEL);
if(IS_ERR(cdd_cdevp)){
printk("kzalloc fail");
goto failure_kzalloc;
}
/*创建设备类*/
dev_class = class_create(THIS_MODULE,"cdd_class");
if(IS_ERR(dev_class)){
printk("class_create failed!\n");
ret=PTR_ERR(dev_class);
goto failure_dev_class;
}
for(i=0;i<CDD_COUNT;i++){
/*初始化cdev*/
cdev_init(&(cdd_cdevp[i].cdev),&cdd_fops);
/*添加cdev到内核*/
cdev_add(&(cdd_cdevp[i].cdev),dev+i,1);
/*"/dev/xxx"*/
device_create(dev_class,NULL,dev+i,NULL,"cdd%d",i);
cdd_cdevp[i].led=i;
}
return 0;
failure_dev_class:
kfree(cdd_cdevp);
failure_kzalloc:
unregister_chrdev_region(dev,CDD_COUNT);
failure_register_chrdev:
return ret;
}
void __exit cdd_exit(void){
int i=0;
for(i=0;i<CDD_COUNT;i++){
device_destroy(dev_class,dev+i);
cdev_del(*(cdd_cdevp[i].cdev));
}
/*从内核中删除设备类*/
class_destroy(dev_class);
kfree(cdd_cdevp);
/*注销设备号*/
unregister_chrdev_region(dev,CDD_COUNT);
}
module_init(cdd_init);
moudle_exit(cdd_exit);
编写测试程序
#include<stdio.h>
#inlcude<fcntl.h>
#inlcude<stdlib.h>
int fd =0;
char rbuf[100];
char wbuf[100]="nihao!\n"
int main(void){
char ch;
fd=open("/dev/cdd5",O_RDWR);
if(fd<0){
printf("open failed");
return -1;
}
printf("open successed fd=%d\n",fd);
while(1){
ch=getchar()
getchar();
switch(ch){
case 'r':
read(fd,rbuf,100);
printf("%s",rbuf);
break;
case 'w':
write(fd,wbuf,100);
break;
case 'o':
ioctl(fd,0,0);
break;
default:
break;
}
}
}