Linux驱动基础、内核模块(一)

【1】驱动大纲

1.linux内核模块
2.字符设备驱动
3.并发和竞态的解决方法
4.IO模型
5.linux内核中断(中断底半部,linux内核定时器) 内核中不能用delay();这几秒进程就不能执行了,这就不能体现linux系统的高效,相互矛盾了所以不可能在内核中断中使用延时了
6.pltform总线驱动—虚拟总线
7.i2c总线驱动 面试常见。尤为重要
8.spi总线驱动
9.块设备驱动
10.网卡设备驱动

【2】什么是驱动?它和ARM裸机驱动的有什么区别?

	操作硬件工作这份代码就叫驱动。驱动依赖内核框架,用内核接口,
	不存在main函数没有死循环,内核工作在3G~4G虚拟空间,不是直接
	访问物理地址,而裸机直接操作寄存器,直接找地址
驱动:
	通过软件操作硬件工作这个代码

ARM裸机驱动:
	直接配置寄存器让硬件工作,由于没有内核的参与可以直接操作物理
	地址,所以的代码都在一个main函数的while(1)中实现去操作硬件。
Linux内核驱动:
	基于Linux内核来实现的驱动,必须依赖linux内核才能工作,驱动在
	驱动在内核中可以并行执行。驱动面向的是内核内核和硬件两个对象。
	在实现驱动的时候必须基于内核的框架编写驱动。

【3】驱动在内核中的层级及驱动的划分

user:(用户空间)
APP glibc [0-3G]

-------------------(系统调用swi,软中断实现)---------------------------------------------
kernel:(内核层)

	5大功能:
	内存管理:内存的申请、释放、区域划分、内存的映射等
	进程管理:管理的进程的创建,销毁,状态切换,进程间通讯 
	网络管理:通过tcp 4层模式进而将数据发送给网卡驱动实现数据收发
	文件管理:通过文件系统,jiffs,yaffs,ramdisk,ext2/ext3/ext4
			  来组织管理文件
	设备管理:设备驱动的管理
		字符设备驱动: 按照字节流访问,并且只能顺序访问 
		块设备驱动:  按照block/扇区来访问的,单位是512字节;
					  可以顺序访问也可以无序访问
		网卡设备驱动:通过网络进行数据的收发的驱动代码
		
	注:有设备节点的可以通过open read write访问,
		字符。块设备驱动都有设备节点在/dev下存在,
		网卡没有设备节点只能通过(socket来完成访问)
		因为网卡发展在一切兼文件之前

hardware: LED LCD touchscreen camera 声卡 音频
U盘 硬盘 Flash
猫 路由器 DM9000
90%属于字符设备驱动
面试问题:帧缓存设备驱动属于字符设备—>LCD

【4】linux内核模块

内核模块三要素:
1.入口:资源的申请
2.出口:资源的释放
3.许可证:遵从GPL协议
内核模块的特性:
	1.所有的驱动都需要通过内核模块才能实现
	2.内核模块不会主动运行,也不会自动运行
	3.安装内核模块的时候入口执行
	4.卸载驱动的时候出口执行

【5】模块

入口 
	static int __init demo_init(void)
	{
		return 0;
	}
	//static修饰本函数只能在本文件中使用,不能别文件调用
	//static作用修饰函数,修饰变量:延长变量生命周期;限定作用域。
	//__init告诉编译器将入口函数放到.init.text的断中
	
	module_init(demo_init);
	//将入口函数地址告给module_init
	//内核通过地址调到函数去执行
出口
	static void __exit demo_exit(void)
	{
	
	}
	module_exit(demo_exit);
许可证
MODULE_LICENSE("GPL");//遵从GPL协议
MODULE_AUTHOR("HSW_YX");

内部编译:在内核源码树内进行驱动的编译
外部编译:在内核源码树外进行驱动的编译 
静态编译:把内核模块编译到uImage中
动态编译:讲内核模块编译生成*.ko文件,需要uImage才能执行

Makefile:
	module:
		make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
	clean:
		make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
	obj-m:=demo.o
	
	=: 立即赋值
	=?询问赋值
	=+ 附加赋值

【6】模块的安装

sudo insmod demo.ko  安装驱动
lsmod				 查看模块信息
sudo dmesg -C       直接清除
sudo dmesg -c       先打印在清除
sudo rmmod demo      卸载驱动
modinfo demo.ko 查看模块信息

【7】内核打印函数

printk(级别 "打印内容");//内核中的打印级别一共8个,数字越小级别越高
printk("message");//一般打印
/proc/sys/kernel/printk
	4            4                 1     			  7
 终端级别    消息的默认级别   终端的最大级别 	 终端的最小级别 
 只有当消息的级别大于终端级别的时候消息才回被回显
 
 修改级别
 su root ==>1
 echo 4 3 1 7 > /proc/sys/kernel/printk

【8】模块传递函数

	 vi-t module_param 查看
		
	 * Standard types are:
	 *	byte, short, ushort, int, uint, long, ulong
	 *	charp: a character pointer
	 *	bool: a bool, values 0/1, y/n, Y/N.
	 *	invbool: the above, only sense-reversed (N = true)
	 
	char-->byte
	short-->short
	int  -->int 
	unsigned int ->uint
	char *p = "hello word" ==>charp
	module_param(变量名,类型,权限);
	module_param_array(变量名,类型,长度,权限);
	MODULE_PARM_DESC(变量名,“描述字段”);
	
	module_param(name, type, perm)	
	功能:接收给驱动专递的参数
	参数:	@name :变量名
			@type :变量的类型
			@perm :权限,内核会根据变量的名字传参文件
					注意对于other不能有写的权限
				0664
				0775
				0774
				0662 错
				
	hsw@linux:~/HQ/driver/day1$ modinfo demo.ko
	filename:       /home/hsw/HQ/driver/day1/demo.ko
	license:        GPL
	depends:        
	vermagic:       3.4.39 SMP preempt mod_unload ARMv7 p2v8 
	parm:           back_light:this is back_light rang (0-255),defaulr:255 (ushort)
	
	在开发板上加载驱动
	insmod *ko 会在/sys/module/驱动名目录/parameters
	
	带参数加载驱动
		[root@iTOP-4418]# insmod demo.ko back_light=127
		[root@iTOP-4418]# cat /sys/module/demo/parameters/back_light 
		127
	不带参数加载是默认值
		[root@iTOP-4418]# cat /sys/module/demo/parameters/back_light 
		255
	
	
	若驱动不能卸载:mkdir -p /lib/modules/3.4.39
	
	MODULE_PARM_DESC(_parm, desc)
	功能:@_parm:变量名
	参数:@desc :描述字符串
	
	传递值的时候的方法:
	1.在安装的时候传递
		insmod demo.ko 变量名=值
	2.通过属性文件
		/sys/module/驱动名目录/parameters
		echo 值 >变量文件中
		
		[root@iTOP-4418]# cat back_light 
		100
		[root@iTOP-4418]# echo 255 > back_light 
		[root@iTOP-4418]# cat back_light 
		255
/*================================================================
*   Copyright (C) 2021 HSW_study Ltd. All rights reserved.
*   
*   文件名称:demo.c
*   创 建 者:HSW
*   创建日期:2021年01月12日
*   描    述:模块传递函数代码
*
================================================================*/

#include <linux/module.h>
#include <linux/init.h>
char a = 65;
module_param(a,byte,0775);
MODULE_PARM_DESC(a,"char a =65");

char *p = "helloewold";
module_param(p,charp,0775);
MODULE_PARM_DESC(p,"char * p = helloewold");

unsigned short back_light =255;
module_param(back_light,ushort,0664);
MODULE_PARM_DESC(back_light,"this is back_light rang (0-255),defaulr:255");

int array[10]={0};
int num ;
int i=0 ;
module_param_array(array,int,&num,0775);
MODULE_PARM_DESC(array,"this is (int [10]) array");

static int __init demo_init(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
	printk("back_light=%d\n",back_light);

	printk("init a = %c\n",a);

	printk("p =%s\n",p);

	for(i=0;i<num;i++)
	{
		printk("array[%d]\n",array[i]);
	}
	return 0;
}

static void __exit demo_exit(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

}
module_init(demo_init);
module_exit(demo_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("HSW_YX")

Makefile

#!/bin/bash
export ARCH=arm
obj-m += demo.o 
KDIR :=/home/hsw/HQ/kernel-3.4.39
PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules
		
clean:
	rm -rf *.mod.c *.o *.order *.ko *.mod.o *.symvers

【9】导出符号表

	EXPORT_SYMBOL_GPL(add);
	功能:将变量或者函数的符号表导出来
		  实际就是一个模块调用另一个模块的的函数
	
	编译的驱动会生成一个Module.symvers
	在这个文件中就是导出的符号表的信息
	0x00000000	add	/home/driver/demoB/demo	EXPORT_SYMBOL_GP
	
	1.编译的时候使用:
		先表一提供者(demoB),编译成功后会生成一个Module.symvers
		在这份文件中就有导出符号表,然后将这个文件拷贝到调用者
		目录下(demoA),编译调用者模块(如果没拷贝Module.symvers编
		译时候就会提示undefined)
	
	2.安装模块的顺序:
		先安装提供者模块,在安装调用者模块
	3.卸载模块的顺序
		先卸载调用者模块,再卸载提供者模块
	注意:如果你的驱动模块调用的是内核中的函数就不需要
		  拷贝Module.symvers,直接编译即可。编译本来依
		  赖内核中的Makefile,内核模块中已经生成符号表的
		  信息
/*================================================================
*   Copyright (C) 2021 HSW_study Ltd. All rights reserved.
*   
*   文件名称:demoA.c
*   创 建 者:HSW
*   创建日期:2021年01月12日
*   描    述:
*
================================================================*/

#include <linux/module.h>
#include <linux/init.h>

extern int add(int,int);
static int __init demoA_init(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

	return 0;
}

static void __exit demoA_exit(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
	printk("sum=%d\n",add(200,100));
}
module_init(demoA_init);
module_exit(demoA_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("HSW_YX");
/*================================================================
*   Copyright (C) 2021 HSW_study Ltd. All rights reserved.
*   
*   文件名称:demoB.c
*   创 建 者:HSW
*   创建日期:2021年01月12日
*   描    述:
*
================================================================*/

#include <linux/module.h>
#include <linux/init.h>

int  add(int a,int b)
{
	return(a+b);
}
EXPORT_SYMBOL_GPL(add);
static int __init demoB_init(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

	return 0;
}

static void __exit demoB_exit(void)
{
	printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);

}
module_init(demoB_init);
module_exit(demoB_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("HSW_YX");

Makefile

#================================================================
#   Copyright (C) 2021 HSW_study Ltd. All rights reserved.
#   
#   文件名称:Makefile
#   创 建 者:HSW
#   创建日期:20210112日
#   描    述:make后面加MODNAME=demoA或者demoB
#
#================================================================

#!/bin/bash
MODNAME?=demo
export ARCH=arm
obj-m += $(MODNAME).o 
KDIR :=/home/hsw/HQ/kernel-3.4.39
PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules
		
clean:
	rm -rf *.mod.c *.o *.order *.ko *.mod.o *.symvers
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值