参考: Linux Device Drivers chapter 3: scull
http://oss.org.cn/kernel-book/ldd3/ch03.html
字符设备是linux设备模型中最基本的一种。
main.c
#include "mysc.h"
MODULE_LICENSE("GPL");
struct mysc_dev scull_device;
struct class *mysc_class;
int dn_major, dn_minor;
static int mysc_init(void)
{
dev_t devno = 0;
//1. allocate dev number
dn_minor=0;
alloc_chrdev_region(&devno, dn_minor, 1, "myscull");
dn_major=MAJOR(devno);
mysc_class=class_create(THIS_MODULE, "myscull");
printk("mysc: devno: %d : %d\n", dn_major, dn_minor);
//2. init cdev
scull_device.ops=&mysc_fops;
cdev_init(&scull_device.cdev, &mysc_fops);
scull_device.cdev.owner=THIS_MODULE;
int err=cdev_add(&scull_device.cdev, devno, 1);
if (err)
printk("error %d\n", err);
//in ELDD class_device_create, now device_create --这里 在我的2.6.35内核中,函数名为device_create,参数也有所改变
device_create(mysc_class, 0, devno, 0, "myscull");
return 0;
}
static void mysc_exit(void)
{
dev_t devno = MKDEV(dn_major, dn_minor);
cdev_del(&scull_device.cdev);
unregister_chrdev_region(devno, 1);
//in ELDD class_device_destroy, now device_destroy
device_destroy(mysc_class, devno);
class_destroy(mysc_class);
printk("mysc: exiting...\n");
}
module_init(mysc_init);
module_exit(mysc_exit);
fops.c
#include "mysc.h"
struct file_operations mysc_fops=
{
.owner = THIS_MODULE,
// .llseek = mysc_llseek,
.read = mysc_read,
.write = mysc_write,
// .ioctl = mysc_ioctl,
.open = mysc_open,
.release= mysc_release
};
#define debug_inode(str) printk(KERN_ALERT "mysc: " str " i_ino = %ld\n", inode->i_ino)
ssize_t mysc_read(struct file *fp, char __user *buf, size_t count, loff_t *fpos)
{
struct mysc_dev *dev = fp->private_data;
count=min(count, MYSIZE-*fpos);
if (count>0)
{
copy_to_user(buf, &dev->buf[*fpos], count);
*fpos+=count;
}
return count;
}
ssize_t mysc_write(struct file *fp, const char __user *buf, size_t count, loff_t *fpos)
{
struct mysc_dev *dev = fp->private_data;
count=min(count, MYSIZE-*fpos);
if (count>0)
{
copy_from_user(&dev->buf[*fpos], buf, count);
*fpos+=count;
return count;
}
else return -ENOMEM;
}
int mysc_open(struct inode *inode, struct file *fp)
{
struct mysc_dev *dev = container_of(inode->i_cdev, struct mysc_dev, cdev);
fp->private_data=dev; //save mysc_dev ptr for other methods.
debug_inode("opening device.");
return 0;
}
int mysc_release(struct inode *inode, struct file *fp)
{
debug_inode("releasing device.");
return 0;
}
mysc.h
#ifndef _MYSC_H_
#define _MYSC_H_
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#define MYSIZE 1000
struct mysc_dev
{
char buf[MYSIZE];
struct file_operations *ops;
struct cdev cdev;
};
//fops.c
int mysc_open(struct inode *inode, struct file *fp);
int mysc_release(struct inode *inode, struct file *fp);
ssize_t mysc_read(struct file *fp, char __user *buf, size_t count, loff_t *fpos);
ssize_t mysc_write(struct file *fp, const char __user *buf, size_t count, loff_t *fpos);
extern struct file_operations mysc_fops;
//mysc.c
extern int dn_major, dn_minor;
extern struct class *mysc_class;
#endif
Makefile
KERNELVERSION=$(shell uname -r)
KERNELDIR=/lib/modules/$(KERNELVERSION)/build
CC=gcc
ifneq ($(KERNELRELEASE),)
mysc-objs := main.o fops.o
obj-m := mysc.o
else
PWD:=$(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
endif
用法:安装module以后,可以以sudo权限 往/dev/myscull里面读写内容。