赞
踩
1)Linux内核和驱动程序运行在内核空间,应用程序运行在用户空间
2)应用程序访问内核空间的三种方式:系统调用 软件中断 硬件中断
1)linux驱动可以编译到kernel中,也就是zImage,也可以编译为模块.ko,测试的时候只需要加载模块
1)驱动加载:insmod和modprobe
insmod加载简单驱动,
modprobe加载有依赖关系的驱动,在新linux系统内加载时,要先运行depmod命令
2)卸载命令:rmmod
3)查看加载的驱动命令:lsmod
4)查看内存缓存信息:dmesge |tail -10 查看最后十条缓存信息
5)printk打印级别:
如果不设置打印级别默认级别是4
#define KERN_SOH "\001"
#define KERN_EMERG KERN_SOH "0" /* 紧急事件,一般是内核崩溃 */
#define KERN_ALERT KERN_SOH "1" /* 必须立即采取行动 */
#define KERN_CRIT KERN_SOH "2" /* 临界条件,比如严重的软件或硬件错误*/
#define KERN_ERR KERN_SOH "3" /* 错误状态,一般设备驱动程序中使用KERN_ERR 报告硬件错误 */
#define KERN_WARNING KERN_SOH "4" /* 警告信息,不会对系统造成严重影响 */
#define KERN_NOTICE KERN_SOH "5" /* 有必要进行提示的一些信息 */
#define KERN_INFO KERN_SOH "6" /* 提示性的信息 */
#define KERN_DEBUG KERN_SOH "7" /* 调试信息 */
一共定义了 8 个级别,其中 0 的优先级最高,7 的优先级最低。如果要设置消息级别,参
考如下示例:
printk(KERN_EMERG "gsmi: Log Shutdown Reason\n");
1)我们想系统注册一个字符设备,使用函数
int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops);
注销字符设备,使用函数
void unregister_chrdev(unsigned int major, const char *name)
Linux 中每个设备都有一个设备号,设备号由主设备号和次设备号两部分组成,主设备号表示某一个具体的驱动,次设备号表示使用这个驱动的各个设备。Linux 提供了一个名为 dev_t 的数据类型表示设备号,dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。这 32 位的数据构成了主设备号和次设备号两部分,其中高 12 位为主设备号,低 20 位为次设备号。主设备号是2^(12)=4096,范围[0,4095]。
在include/linux/kdev_t.h中定义了设备号的操作
#define MINORBITS 20 //宏 MINORBITS 表示次设备号位数,一共是 20 位。
#define MINORMASK ((1U << MINORBITS) - 1)//宏 MINORMASK 表示次设备号掩码。
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))//宏 MAJOR 用于从 dev_t 中获取主设备号,将 dev_t 右移 20 位即可。
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))//宏 MINOR 用于从 dev_t 中获取次设备号,取 dev_t 的低 20 位的值即可。
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))//宏 MKDEV 用于将给定的主设备号和次设备号的值组合成 dev_t 类型的设备号。
1、设备号分配
1)静态分配设备号
先用cat /proc/devices查看系统中已使用的设备号
struct file_operations { struct module *owner; 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 (*readdir) (struct file *, void *, filldir_t); 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 (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); 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); };
man手册:
1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9、其他(Linux特定的), 用来存放内核例行程序的文档。
要求:应用程序可以对驱动进行读写操作,读的话就是应用程序从驱动里读取数据,写的话就是向驱动里写入数据
1)char chrdevbase_read驱动函数编写
驱动给应用传递数据的时候用到copy_to_user函数。
从用户空间向内核空间写数据操作cpoy_form_user函数
argv[]内的对象都是字符串,字符串转int用到了函数atoi()
函数
/******* kernel driver ******/ #include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> /*************************************************************** 文件名 : chrdevbase.c 作者 : chise0519 描述 : chrdevbase驱动框架文件。 说明 : 部分代码复制byzuozhongkai老师 ***************************************************************/ #define CHRDEVBASE_MAJOR 200 /* 主设备号 */ #define CHRDEVBASE_NAME "chrdevbase" /* 设备名 */ static char readbuf[100] = {0}; /* 读缓冲区 */ static char writebuf[100] = {0}; /* 写缓冲区 */ static char kerneldata[] = {"kernel data"}; /*kernel data */ /* * @description : 打开设备 * @param - inode : 传递给驱动的inode * @param - filp : 设备文件,file结构体有个叫做private_data的成员变量 * 一般在open的时候将private_data指向设备结构体。 * @return : 0 成功;其他 失败 */ static int chrdevbase_open(struct inode *inode, struct file *filp) { printk("chrdevbase open!\r\n"); return 0; } /* * @description : 从设备读取数据 * @param - filp : 要打开的设备文件(文件描述符) * @param - buf : 返回给用户空间的数据缓冲区 * @param - count : 要读取的数据长度 * @param - offt : 相对于文件首地址的偏移 * @return : 读取的字节数,如果为负值,表示读取失败 */ static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t count, loff_t *offt) { int ret = 0; memcpy(readbuf,kerneldata,sizeof(kerneldata)); ret = copy_to_user(buf,readbuf,count); if(ret == 0) { printk("read kernel data sucess!"); }else{ printk("read kernel data failed!"); } //printk("chrdevbase read!\r\n"); return 0; } /* * @description : 向设备写数据 * @param - filp : 设备文件,表示打开的文件描述符 * @param - buf : 要写给设备写入的数据 * @param - count : 要写入的数据长度 * @param - offt : 相对于文件首地址的偏移 * @return : 写入的字节数,如果为负值,表示写入失败 */ static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t count, loff_t *offt) { int ret = 0; ret = copy_from_user(writebuf,buf,count); if(ret == 0) { printk("write to kernel data sucess"); }else{ printk("write to kernel data failed"); } //printk("chrdevbase write!\r\n"); return 0; } /* * @description : 关闭/释放设备 * @param - filp : 要关闭的设备文件(文件描述符) * @return : 0 成功;其他 失败 */ static int chrdevbase_release(struct inode *inode, struct file *filp) { printk("chrdevbase release!\r\n"); return 0; } /* * 设备操作函数结构体 */ static struct file_operations chrdevbase_fops = { .owner = THIS_MODULE, .open = chrdevbase_open, .read = chrdevbase_read, .write = chrdevbase_write, .release = chrdevbase_release, }; /* * @description : 驱动入口函数 * @param : 无 * @return : 0 成功;其他 失败 */ static int __init chrdevbase_init(void) { int retvalue = 0; /* 注册字符设备驱动 */ retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops); if(retvalue < 0){ printk("chrdevbase driver register failed\r\n"); } printk("chrdevbase init!\r\n"); return 0; } /* * @description : 驱动出口函数 * @param : 无 * @return : 无 */ static void __exit chrdevbase_exit(void) { /* 注销字符设备驱动 */ unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME); printk("chrdevbase exit!\r\n"); } /* * 将上面两个函数指定为驱动的入口和出口函数 */ module_init(chrdevbase_init); module_exit(chrdevbase_exit); /* * LICENSE和作者信息 */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("chise0519");
/******* Makefile ******/
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
else
obj-m := chrdevbase.o
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module* modules*
/******* application source core ******/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> /* *argc:参数个数 *argv[1]:驱动文件 cd /dev *argv[2]:读是1,写是2 */ int main(int argc,char *argv[]) { int fd = 0; int ret = 0; char *filename = argv[1]; char readbuf[100] = {0}; char writebuf[100] = {0}; char usrdata[20] = "this is usrdata!"; fd = open(filename, O_RDWR); /* open */ if(fd < 0) { printf("%s file open failed!\r\n",filename); return fd; } if(atoi(argv[2]) == 1) { /* read */ ssize_t ret = 0; ret = read(fd, readbuf, 20); if(ret == 0) { printf("%s file read sucess!\r\n",filename); return -1; }else{ printf("APP read data:%s\r\n",readbuf); } } if(atoi(argv[2]) == 2) { /* write */ memcpy(writebuf,usrdata,sizeof(usrdata)); ret = write(fd, writebuf, 20); if(ret < 0) { printf("%s file write failed!\r\n",filename); return -1; }else{ printf("write into kernel data :%s\r\n",usrdata); } } /* close */ ret = close(fd); if(ret < 0) { printf("%s file close failed!\r\n",filename); return -1; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。