一、编码思维导图
二、编写代码
memdev.c
-
#include <linux/module.h>
-
#include <linux/init.h>
-
#include <linux/cdev.h>
-
#include <linux/fs.h>
-
#include <asm/uaccess.h>
-
-
struct cdev mdev; //1.静态分配cdev
-
dev_t devno;
-
-
int dev1_regs[5];
-
int dev2_regs[5];
-
-
loff_t mem_lseek(struct file *filep, loff_t offset, int whence)
-
{
-
loff_t new_pos = 0;
-
-
switch(whence) {
-
case SEEK_SET:
-
new_pos = 0 + offset;
-
break;
-
case SEEK_CUR:
-
new_pos = filep->f_pos + offset;
-
break;
-
case SEEK_END:
-
new_pos = 5*sizeof(int) + offset;
-
break;
-
default:
-
break;
-
}
-
-
filep->f_pos = new_pos;
-
return new_pos;
-
}
-
-
size_t mem_read(struct file *filep, char __user *buf, size_t size, loff_t *ppos)
-
{
-
int *reg_base = filep->private_data;
-
-
copy_to_user(buf, reg_base+(*ppos), size);
-
-
filep->f_pos += size;
-
-
return size;
-
}
-
-
size_t mem_write(struct file *filep, const char __user *buf, size_t size, loff_t *ppos)
-
{
-
int *reg_base = filep->private_data;
-
-
copy_from_user(reg_base+(*ppos), buf, size);
-
-
filep->f_pos += size;
-
-
return size;
-
}
-
-
size_t mem_open(struct inode *node, struct file *filep)
-
{
-
int num = MINOR(node->i_rdev);
-
if(num == 0)
-
filep->private_data = dev1_regs;
-
else if(num == 1)
-
filep->private_data = dev2_regs;
-
-
return 0;
-
}
-
-
int mem_close (struct inode *node, struct file *filep)
-
{
-
return 0;
-
}
-
-
struct file_operations memfops =
-
{
-
.llseek = mem_lseek,
-
.open = mem_open,
-
.write = mem_write,
-
.read = mem_read,
-
.release = mem_close,
-
};
-
-
int memdev_init()
-
{
-
cdev_init(&mdev, &memfops); //2.初始化cdev
-
-
alloc_chrdev_region(&devno, 0, 2, "memdev"); //3.动态分配设备号到devno
-
cdev_add(&mdev, devno, 2); //4.注册cdev
-
return 0;
-
}
-
-
void memdev_exit()
-
{
-
cdev_del(&mdev); //5.设备注销
-
unregister_chrdev_region(devno, 2); //6.设备号注销
-
}
-
-
module_init(memdev_init); //初始化入口
-
module_exit(memdev_exit); //模块退出
三、函数学习
设备初始化:cdev_init
原型:void cdev_init(struct cdev *cdev, const struct file_operations *fops);
cdev:待初始化的cdev结构
fops:设备对应的操作函数集
动态分配设备号:alloc_chrdev_region
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name);
dev:分配后设备号的地址
baseminor:起始地设备序号
count:分配的个数
name:分配后的设备别名
设备注册:cdev_add
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
p:待添加的字符设备结构
dev:设备号
count:该类设备的设备个数
注销设备:cdev_del
void cdev_del(struct cdev *p);
p:待注销的设备结构
释放设备号:unregister_chrdev_region
void unregister_chrdev_region(dev_t from, unsigned count);
from:待释放设备号
count:释放的设备个数
四、驱动访问模型
1.应用程序访问read
arm-linux-objdump -d read_mem
-
00008228 <main>:
-
8228: e92d4800 push {fp, lr}
-
822c: e28db004 add fp, sp, #4 ; 0x4
-
8230: e24dd008 sub sp, sp, #8 ; 0x8
-
8234: e3a03000 mov r3, #0 ; 0x0
-
8238: e50b3008 str r3, [fp, #-8]
-
823c: e3a03000 mov r3, #0 ; 0x0
-
8240: e50b300c str r3, [fp, #-12]
-
8244: e59f0044 ldr r0, [pc, #68] ; 8290 <main+0x68>
-
8248: e3a01002 mov r1, #2 ; 0x2
-
824c: eb0028a3 bl 124e0 <__libc_open>
-
8250: e1a03000 mov r3, r0
-
8254: e50b3008 str r3, [fp, #-8]
-
8258: e24b300c sub r3, fp, #12 ; 0xc
-
825c: e51b0008 ldr r0, [fp, #-8]
-
8260: e1a01003 mov r1, r3
-
8264: e3a02004 mov r2, #4 ; 0x4
-
8268: eb0028c0 bl 12570 <__libc_read>
>>libc_read:
-
00012570 <__libc_read>:
-
12570: e51fc028 ldr ip, [pc, #-40] ; 12550 <__libc_open+0x70>
-
12574: e79fc00c ldr ip, [pc, ip]
-
12578: e33c0000 teq ip, #0 ; 0x0
-
1257c: 1a000006 bne 1259c <__libc_read+0x2c>
-
12580: e1a0c007 mov ip, r7
-
12584: e3a07003 mov r7, #3 ; 0x3
-
12588: ef000000 svc 0x00000000
将3放入r7寄存器中
调用svc,进入内核空间
通过查表找到read并使用
在entry-common.S中
-
ENTRY(sys_call_table)
-
#include "calls.S"
-
#undef ABI
-
#undef OBSOLETE
-
-
/*============================================================================
-
* Special system call wrappers
-
*/
-
@ r0 = syscall number
-
@ r8 = syscall table
-
sys_syscall:
-
bic scno, r0, #__NR_OABI_SYSCALL_BASE
-
cmp scno, #__NR_syscall - __NR_SYSCALL_BASE
-
cmpne scno, #NR_syscalls @ check range
-
stmloia sp, {r5, r6} @ shuffle args
-
movlo r0, r1
-
movlo r1, r2
-
movlo r2, r3
-
movlo r3, r4
-
ldrlo pc, [tbl, scno, lsl #2]
-
b sys_ni_syscall
-
ENDPROC(sys_syscall)
利用3这个编号找到sys_read
>>>read_write.c
-
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
-
{
-
ssize_t ret;
-
-
if (!(file->f_mode & FMODE_READ))
-
return -EBADF;
-
if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
-
return -EINVAL;
-
if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))
-
return -EFAULT;
-
-
ret = rw_verify_area(READ, file, pos, count);
-
if (ret >= 0) {
-
count = ret;
-
if (file->f_op->read)
-
ret = file->f_op->read(file, buf, count, pos); //这里调用了file_operations的read
-
else
-
ret = do_sync_read(file, buf, count, pos);
-
if (ret > 0) {
-
fsnotify_access(file->f_path.dentry);
-
add_rchar(current, ret);
-
}
-
inc_syscr(current);
-
}
-
-
return ret;
-
}
阅读(552) | 评论(0) | 转发(0) |