//这个驱动网上有例子,但是很多机制在新的内核里面已经过时了,所以我重写了一下,尽量使用了一些最近内核里面的机制。
//创建设备节点,使用的udev机制;
//注册中断向量的时候使用了新的接口函数,包括了ISR的接口的改变。
#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/device.h>
//使用中断机制添加头文件
#include <linux/sched.h>
#include <asm/signal.h>
#include <linux/interrupt.h>
//使用udev机制添加的头文件
#include <linux/slab.h>
#ifdef CONFIG_SLUB
#include <linux/slub_def.h>
#elif defined CONFIG_SLOB
#include <linux/slob_def.h>
#else
#include <linux/slab_def.h>
#endif
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
//swliao:memory size 4K.
#define MEMS_SIZE 0x1000
//#define MEMS_CLEAR 0x1
#define MEMS_MAJOR 300
static struct class *my_class;
static int mems_major = MEMS_MAJOR;
static unsigned int mems_irq = 1;
static char* interface = "mems-test";
//module_param()添加模块支持参数,每行设置一个参数
module_param(mems_irq,int,S_IRUGO);
module_param(interface,charp,S_IRUGO);
//声明设备结构体
struct mems_dev
{
struct cdev cdev;
unsigned char mems[MEMS_SIZE];
};
struct mems_dev *mems_devp;
//对应的中断向量的ISR
static irqreturn_t mems_irq_handler(int irq,void *dev_id)
{
printk(KERN_INFO "Interrupt handler...............................%d\n",irq);
return IRQ_HANDLED;
}
//swliao:open function in file_operation.
int mems_open(struct inode *inode,struct file *filp)
{
filp->private_data = mems_devp;
return 0;
}
//close()
int mems_release(struct inode *inode,struct file *filp)
{
return 0;
}
//swliao:read() function in file_operations.
static ssize_t mems_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 mems_dev *dev = filp->private_data;
if(p >= MEMS_SIZE)
return count ? -ENXIO : 0;
if(count > MEMS_SIZE-p)
count = MEMS_SIZE - p;
if(copy_to_user(buf,(void *)(dev->mems + p),count))
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "Liaosw read %d bytes.\n",count);
}
return ret;
}
static ssize_t mems_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 mems_dev *dev = filp->private_data;
if(p >= MEMS_SIZE)
return count ? -ENXIO : 0;
if(count > MEMS_SIZE -p)
count = MEMS_SIZE - p;
if(copy_from_user(dev->mems+p,buf,count))
{
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
printk(KERN_INFO "Liaosw written %d bytes.\n",count);
}
return ret;
}
//swliao:very important file_operations structure.
//字符驱动的主体实现部分:对应设备文件的file_operations结构体
static const struct file_operations mems_fops =
{
.owner = THIS_MODULE,
.read = mems_read,
.write = mems_write,
.open = mems_open,
.release = mems_release,
};
static void mems_setup_cdev(struct mems_dev *dev,int index)
{
int devno = MKDEV(mems_major,index);
cdev_init(&dev->cdev,&mems_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &mems_fops;
int err = cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d addint cdev %d.\n",err,index);
}
//内核模块的入口函数
//字符设备驱动程序三步:创建分配,初始化,安装注册
int mems_init()
{
printk(KERN_INFO "Install the driver to kernel space.\n");
int result = 0;
dev_t devno = MKDEV(mems_major,0);
if(mems_major)
result = register_chrdev_region(devno,1,"mem-test");
else
{
result = alloc_chrdev_region(&devno,0,1,"mem-test");
mems_major = MAJOR(devno);
}
if(result < 0)
return result;
mems_devp = kmalloc(sizeof(struct mems_dev),GFP_KERNEL);
if(!mems_devp)
{
result = -ENOMEM;
goto fail_malloc;
}
memset(mems_devp,0,sizeof(struct mems_dev));
mems_setup_cdev(mems_devp,0);
my_class = class_create(THIS_MODULE,"my_class");
if(IS_ERR(my_class))
{
printk("Err:failed in creating class.\n");
return -1;
}
device_create(my_class,NULL,MKDEV(mems_major,0),NULL,"mem-test",0);
//register interrupt.
//请求分配中断向量
int flagnum;
if(!(flagnum = request_irq(mems_irq,&mems_irq_handler,IRQF_SHARED,interface,mems_devp)))
{
printk(KERN_INFO "Register interrupt correctly..\n");
goto fail_malloc;
}
else
printk(KERN_INFO "Error was happened here...%d\n",flagnum);
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return result;
}
void mems_exit()
{
cdev_del(&mems_devp->cdev);
//udev的退出清理
device_destroy(my_class,MKDEV(mems_major,0));
class_destroy(my_class);
kfree(mems_devp);
//释放设备号和中断向量
free_irq(mems_irq,mems_devp);
unregister_chrdev_region(MKDEV(mems_major,0),1);
printk(KERN_INFO "Test module quit kernel space.\n");
}
MODULE_AUTHOR("LiaoSW");
MODULE_LICENSE("GPL");
module_init(mems_init);
module_exit(mems_exit);
希望对大家有帮助,转载请注明出处,谢谢。
kernel-2.6.38内核驱动globalmem--添加中断机制和udev机制
最新推荐文章于 2022-09-08 16:36:51 发布