一、编码思维导图
二、编写代码
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;
- }