一、基本理论
二、基本数据结构和实例
三 、总结
一、基本理论
本文实例参考《linux设备驱动开发详解第二版》
二、基本数据结构和实例
#ifndef _GLBMEM_H_
#define _GLBMEM_H_
#include <linux/cdev.h>
#include <linux/semaphore.h>
#define GLOBALMEM_SIZE 0x1000
#define GLOBALMEM_CLEAR 0x1
#define GLOBALMEM_MAJOR 0
#define GLOBALMEM_NODE_NAME "glbmem"
#define GLOBALMEM_FILE_NAME "glbmem"
#define GLOBALMEM_CLASS_NAME "glbmem"
static int globalmem_major=GLOBALMEM_MAJOR;
struct globalmem_dev{
// int val;
struct semaphore sem;
struct cdev cdev;
unsigned char mem[GLOBALMEM_SIZE];
};
#endif
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include "glbmem.h"
static struct globalmem_dev dev;
static struct class *glbmem_class;
static int glbmem_open(struct inode *inode,struct file *filp){
printk(KERN_INFO "glbmem open.\n");
return 0;
}
static void glbmem_close(struct inode *inode,struct file *filp){
printk(KERN_INFO "glbmem close.\n");
}
static ssize_t glbmem_read(struct file *filp,char __user *buffer,size_t len,loff_t *offset){
unsigned long p=*offset;
int ret=0;
if(p>GLOBALMEM_SIZE){
printk("offset is out of bounds.\n");
return 0;
}
if((len+p)>GLOBALMEM_SIZE)
len=GLOBALMEM_SIZE-p;
if(copy_to_user(buffer,(void*)(dev.mem+p),len)){
ret = - EFAULT;
}
else{
*offset +=len;
ret=len;
printk("read %s,%d bytes data.\n",(dev.mem),len);
}
return ret;
}
static ssize_t glbmem_write(struct file *filp,char __user *buffer,size_t len,loff_t *offset){
unsigned long p=*offset;
int ret=0;
if(p>GLOBALMEM_SIZE){
printk("offset is out of bounds.\n");
return 0;
}
if((p+len)>GLOBALMEM_SIZE){
len=GLOBALMEM_SIZE-p;
}
if(copy_from_user(dev.mem+p,buffer,len)){
ret=-EFAULT;
}else{
*offset +=len;
ret=len;
printk("write %s,%d bytes data.\n",dev.mem,len);
}
return ret;
}
/*
static loff_t glbmem_llseek(struct file *filp,loff_t offset,int orig){
loff_t ret;
switch(orig){
case 0:
if(offset<0){
ret= -EINVAL;
break;
}
if((unsigned int)offset>GLOBALMEM_SIZE){
ret=-EINVAL;
break;
}
filp->f_ops=(unsigned int)offset;
ret=filp->f_ops;
break;
case 1:
if((filp->f_ops+offset)<0){
ret= -EINVAL;
break;
}
if((filp->f_ops+offset)>GLOBALMEM_SIZE){
ret=-EINVAL;
break;
}
filp->f_ops+=(unsigned int)offset;
ret=filp->f_ops;
break;
default:
ret=-EINVAL;
}
return ret;
}
*/
static int glbmem_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){
switch(cmd){
case GLOBALMEM_CLEAR:
memset(dev.mem,0,GLOBALMEM_SIZE);
printk(KERN_INFO"globalmem is set to zero.\n");
break;
default:
return -EINVAL;
}
return 0;
}
static const struct file_operations glbmem_fops={
.owner=THIS_MODULE,
.open=glbmem_open,
.release=glbmem_close,
.read=glbmem_read,
.write=glbmem_write,
.unlocked_ioctl=glbmem_ioctl,
//.llseek=glbmem_llseek,
};
static void globalmem_setup_cdev(void){
int err=0;
dev_t devno=MKDEV(globalmem_major,0);
memset(dev.mem,0,GLOBALMEM_SIZE);
cdev_init(&dev.cdev,&glbmem_fops);
dev.cdev.owner=THIS_MODULE;
err=cdev_add(&dev.cdev,devno,1);
if(err)
printk(KERN_ALERT"Erro %d adding cdev.\n",err);
}
static int __init glbmem_init(void){
int ret=0;
dev_t devno=MKDEV(globalmem_major,0);
printk(KERN_ALERT "glbmem init.\n");
if(globalmem_major)
ret=register_chrdev_region(devno,1,GLOBALMEM_NODE_NAME);
else{
ret=alloc_chrdev_region(&devno,0,1,GLOBALMEM_NODE_NAME);
globalmem_major=MAJOR(devno);
}
if(ret<0)
return ret;
printk("device number register successed.\n");
printk("major number is:%d.\nminor number is:%d.\n",MAJOR(devno),MINOR(devno));
globalmem_setup_cdev();
glbmem_class=class_create(THIS_MODULE,GLOBALMEM_NODE_NAME);
device_create(glbmem_class,NULL,devno,NULL,GLOBALMEM_NODE_NAME);
printk(KERN_ALERT "glbmem init success.\n");
return 0;
}
static void __exit glbmem_exit(void){
dev_t devno=MKDEV(globalmem_major,0);
device_destroy(glbmem_class,devno);
class_destroy(glbmem_class);
cdev_del(&dev.cdev);
unregister_chrdev_region(devno,1);
}
module_init(glbmem_init);
module_exit(glbmem_exit);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("wen");
MODULE_DESCRIPTION("this is a example to display char device driver");
MODULE_VERSION("V1.0");
ifneq ($(KERNELRELEASE),)
obj-m :=glbmem.o
else
KERNELDIR :=/lib/modules/$(shell uname -r)/build
PWD :=$(shell pwd)
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
clean:
rm *.ko *.o *mod*
测试
三 、总结
.......