目录
Makefile编译脚本
obj-m := standard_module.o
KERNELDIR ?= /home/tanyaduckal/a9rootfs/linux-3.14 #需要修改成你的内核源代码路径,成功编译过的那个
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
make clean
clean:
rm Module.symvers modules.order *.mod.c *.o #*.ko
模块
#include<linux/module.h>
/*模块许可证声明*/
MODULE_LICENSE("Dual BSD/GPL");
static int xxx_init(void){return 0;}
static void xxx_exit(void){}
/*模块加载组测函数*/
module_init(xxx_init);
/*模块移除组测函数*/
module_exit(xxx_exit);
example
#include<linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("tanyaduckal");
MODULE_DESCRIPTION("my module");
static int mymodule_init(void)
{
printk("mymodule loading\n");
return 0;
}
static void mymodule_exit(void)
{
printk("mymodule exited\n");
}
module_init(mymodule_init);
module_exit(mymodule_exit);
字符设备驱动
#include<linux/module.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#define BASEMINOR 0
#define COUNT 1
MODULE_LICENSE("Dual BSD/GPL");
loff_t llseek(struct file *, loff_t, int);
ssize_t read(struct file *, char __user *, size_t, loff_t *);
ssize_t write (struct file *, const char __user *, size_t, loff_t *);
ssize_t aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
ssize_t aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
int iterate(struct file *, struct dir_context *);
unsigned int poll(struct file *, struct poll_table_struct *);
long unlocked_ioctl(struct file *, unsigned int, unsigned long);
long compat_ioctl(struct file *, unsigned int, unsigned long);
int mmap(struct file *, struct vm_area_struct *);
int open(struct inode *, struct file *);
int release(struct inode *, struct file *);
int flush(struct file *, fl_owner_t id);
int fsync(struct file *, loff_t, loff_t, int datasync);
int aio_fsync(struct kiocb *, int datasync);
int fasync(int, struct file *, int);
int lock(struct file *, int, struct file_lock *);
ssize_t sendpage(struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
int check_flags(int);
int flock(struct file *, int, struct file_lock *);
ssize_t splice_write(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
int setlease(struct file *, long, struct file_lock **);
long fallocate(struct file *file, int mode, loff_t offset, loff_t len);
int show_fdinfo(struct seq_file *m, struct file *f);
struct {
struct cdev *cdev;
dev_t dev;
unsigned baseminor;
unsigned count;
}DEV;
struct file_operations fs = {
.owner = THIS_MODULE,
.llseek = llseek,
.read = read,
.write = write,
.aio_read = aio_read,
.aio_write = aio_write,
.iterate = iterate,
.poll = poll,
.unlocked_ioctl = unlocked_ioctl,
.compat_ioctl = compat_ioctl,
.mmap = mmap,
.open = open,
.flush = flush,
.release = release,
.fsync = fsync,
.aio_fsync = aio_fsync,
.fasync = fasync,
.lock = lock,
.sendpage = sendpage,
.get_unmapped_area = get_unmapped_area,
.check_flags = check_flags,
.flock = flock,
.splice_write = splice_write,
.splice_read = splice_read,
.setlease = setlease,
.fallocate = fallocate,
.show_fdinfo = show_fdinfo
};
loff_t llseek(struct file *f, loff_t l, int whence){return 0;}
ssize_t read(struct file *f, char __user *u, size_t size, loff_t *l){return size;}
ssize_t write (struct file *f, const char __user *u, size_t size, loff_t *l){return size;}
ssize_t aio_read(struct kiocb *k, const struct iovec *i, unsigned long o, loff_t l){return 0;}
ssize_t aio_write(struct kiocb *k, const struct iovec *i, unsigned long o, loff_t l){return 0;}
int iterate(struct file *f, struct dir_context *d){return 0;}
unsigned int poll(struct file *f, struct poll_table_struct *p){return 0;}
long unlocked_ioctl(struct file *f, unsigned int cmd, unsigned long arg){return 0;}
long compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg){return 0;}
int mmap(struct file *f, struct vm_area_struct *v){return 0;}
int open(struct inode *i, struct file *f){return 0;}
int release(struct inode *i, struct file *f){return 0;}
int flush(struct file *f, fl_owner_t id){return 0;}
int fsync(struct file *f, loff_t ll, loff_t lr, int datasync){return 0;}
int aio_fsync(struct kiocb *k, int datasync){return 0;}
int fasync(int l, struct file *f, int r){return 0;}
int lock(struct file *f, int n, struct file_lock * fl){return 0;}
ssize_t sendpage(struct file *f, struct page *p, int n, size_t size, loff_t *l, int m){return 0;}
unsigned long get_unmapped_area(struct file *f, unsigned long e, unsigned long b, unsigned long l, unsigned long s){return 0;}
int check_flags(int n){return 0;}
int flock(struct file *f, int o, struct file_lock *fl){return 0;}
ssize_t splice_write(struct pipe_inode_info *p, struct file *f, loff_t *lp, size_t size, unsigned int l){return 0;}
ssize_t splice_read(struct file *f, loff_t *lp, struct pipe_inode_info *p, size_t size, unsigned int l){return 0;}
int setlease(struct file *f, long n, struct file_lock **fl){return 0;}
long fallocate(struct file *file, int mode, loff_t offset, loff_t len){return 0;}
int show_fdinfo(struct seq_file *m, struct file *f){return 0;}
static int xxx_init(void){
DEV.baseminor = BASEMINOR;
DEV.count = COUNT;
/*从DEV.baseminor开始申请DEV.count个设备号*/
if(0 != alloc_chrdev_region(&DEV.dev, DEV.baseminor, DEV.count, "my module devnum....."))
return -1;
/*创建设备数据结构结点*/
if(NULL != (DEV.cdev = cdev_alloc()))
return -1;
/*初始化该设备结点*/
cdev_init(DEV.cdev, &fs);
/*将该结点加入kernel设备数据结构*/
if(0 != cdev_add(DEV.cdev, DEV.dev, DEV.count))
return -1;
return 0;
}
static void xxx_exit(void)
{
/*从kernel设备数据结构移除该结点*/
cdev_del(DEV.cdev);
/*释放该设备结点*/
kfree(DEV.cdev);
/*释放申请的DEV.count个设备号*/
unregister_chrdev_region(DEV.dev, DEV.count);
}
module_init(xxx_init);
module_exit(xxx_exit);