1> 思路:
分配3块内存空间,抽象为设备(u盘),对应同1套设备驱动,进行操作,就是《LDD3》中“SCULL”的实例。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
2> 源码:
-
#include <linux/init.h>
-
#include <linux/module.h>
-
#include <linux/kernel.h>
-
#include <linux/fs.h>
-
#include <asm/uaccess.h>
-
#include <linux/cdev.h>
-
#include <linux/slab.h>
-
-
#define SZ 1024
-
-
/*设备类型*/
-
typedef struct {
-
char *buf; //内存设备地址
-
u32 len;
-
struct cdev cdev;
-
}kbuf_t;
-
-
-
static int major = 0;
-
static int minor = 0;
-
static int count = 3;
-
static dev_t devnum;
-
-
static kbuf_t *kbuf;
-
-
//3步: 填写说明书
-
/*my_open, my_read, my_write*/
-
-
static int my_open (struct inode *inodp, struct file *filp)
-
{
-
printk("device %d is open!\n", iminor(inodp));
-
-
/*存入需要的数据,供后面函数使用*/
-
filp->private_data = &kbuf[iminor(inodp)];
-
-
return 0;
-
}
-
-
static ssize_t my_read (struct file *filp, char _ _user *buf, size_t count, loff_t * fpos)
-
{
-
kbuf_t *p = filp->private_data;
-
-
count = min(count, p->len);
-
-
if(copy_to_user(buf, p->buf, count)){
-
return -EAGAIN;
-
} else {
-
memcpy(p->buf, p->buf+count, p->len - count);
-
p->len -= count;
-
}
-
-
return count;
-
}
-
-
static ssize_t my_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
-
{
-
kbuf_t *p = filp->private_data;
-
-
count = min(count, (size_t)(SZ - p->len));
-
-
if(copy_from_user(p->buf+p->len, buf, count)){
-
return -EAGAIN;
-
}else{
-
p->len += count;
-
}
-
-
return count;
-
}
-
-
static int my_release (struct inode *inodep, struct file *filp)
-
{
-
return 0;
-
}
-
-
static struct file_operations fops = {
-
.owner = THIS_MODULE,
-
.open = my_open,
-
.read = my_read,
-
.write = my_write,
-
.release = my_release,
-
};
-
-
static int __init my_init(void)
-
{
-
int ret;
-
int i, j;
-
-
/*分配3个设备结构体*/
-
kbuf = kmalloc(sizeof(*kbuf)*count, GFP_KERNEL);
-
-
if(NULL == kbuf){
-
return -ENOMEM;
-
}
-
-
/*实例化3个设备,可把它想象为你现在有 3 个 U盘*/
-
for(i = 0; i < count; i++){
-
kbuf[i].buf = kzalloc(SZ, GFP_KERNEL);
-
if(kbuf[i].buf == NULL){
-
ret = -ENOMEM;
-
goto error0;
-
}
-
}
-
-
//1步:分配设备号
-
if(major){ /*静态分配设备号*/
-
devnum = MKDEV(major, minor);
-
ret = register_chrdev_region(devnum, count, "kbuf");
-
}else{ /*动态分配设备号*/
-
ret = alloc_chrdev_region(&devnum, minor, count, "kbuf");
-
major = MAJOR(devnum);
-
}
-
if(ret < 0){
-
goto error0;
-
}
-
-
for(j = 0; j < count; j++){
-
//2步:将说明书与设备绑定
-
/*cdev->ops = fops;*/
-
cdev_init(&kbuf[j].cdev, &fops);
-
-
//4步:向内核添加。这必须最后一步。
-
ret = cdev_add(&kbuf[j].cdev, MKDEV(major, j), 1);
-
if(ret < 0){
-
goto error1;
-
}
-
}
-
-
return 0;
-
-
error1:
-
while(j){
-
cdev_del(&kbuf[j-1].cdev);
-
}
-
unregister_chrdev_region(devnum, count);
-
-
error0:
-
while(i){
-
kfree(kbuf[i-1].buf);
-
i--;
-
}
-
kfree(kbuf);
-
return ret;
-
}
-
-
static void __exit my_exit(void)
-
{
-
int i;
-
-
/*释放分配的内存空间*/
-
for(i = 0; i < count; i++){
-
cdev_del(&kbuf[i].cdev);
-
kfree(kbuf[i].buf);
-
}
-
-
/*释放分配的3个设备号*/
-
unregister_chrdev_region(devnum, count);
-
-
/*释放分配的3个结构体空间*/
-
kfree(kbuf);
-
-
printk("Bye bye\n");
-
}
-
-
module_init(my_init);
-
module_exit(my_exit);
-
-
MODULE_LICENSE("GPL");
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
3> 测试:
-
# cat /pro/devices
-
251 kbuf /*主设备号*/
-
-
mknod u1 c 251 0
-
mknod u2 c 251 1
-
mknod u3 c 251 2
-
# echo 123456789 >> u1
-
device 0 is open
-
-
# echo 111111111 >> u2
-
device 1 is open
-
-
# echo 222222222 >> u3
-
device 2 is open
-
-
-
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-
# cat u1
-
device 0 is open
-
123456789
-
-
# cat u2
-
device 1 is open
-
111111111
-
-
# cat u3
-
device 2 is open
-
222222222
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
4> 原理:鉴于目前水平 删掉其中不明白的代码,只是大概理解
alloc_chrdev_region(&devnum, minor, count, "kbuf")
//@&devnum:动态分配的
设备号存入devnum
//@cout:连续分配
次设备号个数
//@minor:
次设备号起始号
//@kbuf:你猜?
………………………………………………………………………………………………………………………………
-
struct cdev {
-
-
struct module *owner;
-
const struct file_operations *ops;
-
dev_t dev;
-
unsigned int count;
-
};
-
cdev_init(&kbuf[j].cdev, &fops);
-
-
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
-
{
cdev->ops = fops;
}
-
//将设备操作函数与设备绑定
…………………………………………………………………………………………………………………………………………………………
-
cdev_add(&kbuf[j].cdev, MKDEV(major, j), 1)
-
-
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
-
{
-
p->dev = dev;
-
p->count = count;
-
return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); //不明白,
-
}
//向内核添加。
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
总结:
1> 分清设备号, 主设备号, 次设备号。
2> 主要的3大步: 分配设备号 --》说明书与设备绑定 ----》交给管家
阅读(1842) | 评论(0) | 转发(0) |