总纲
image.png1. 物理地址找到虚拟地址方法(ioremap)
2.cpu性能
-ARM7 处理速度为0.9MIPS/MHz, 常见的主时钟一般为20MHz-133MHz
– ARM9 处理速度为1.1MIPS/MHz, 常见的主时钟一般为100MHz-233MHz
– CORTEX-A9 处理速度2.5 MIPS/MHz ,主时钟一般为1000MHz-1600MHz
3.最简Linux驱动
• Linux头文件位置
include <linux/module.h>
include <linux/init.h>
– 入口函数module_init(x)
– 出口函数module_exit(x)
– MODULE_LICENSE("Dual BSD/GPL")添加遵循GPL协议,必须的!
– MODULE_AUTHOR(“kerwin”)代码作者
打印信息
printk(KERN_EMERG "Hello World enter!\n");
Makefile编写
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += mini_linux_module.o
#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0
#当前目录变量
PWD ?= $(shell pwd)
#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean执行的操作是删除后缀为o的文件
clean:
rm -rf *.o
4,kconfig makefile
4.1kconfig文件,配置宏vim drivers/char/Kconfig
config LEDS_CTL
bool "Enable LEDS config"
default y
help
Enable LEDS config
4.2makeconfig文件,根据宏,添加源码
vim drivers/char/Makefile
obj-$(CONFIG_LEDS_CTL) += itop4412_leds.o
5.总线设备驱动注册流程
一般的驱动是先注册设备再注册驱动
热插拔的设备是先注册驱动后注册设备
查看总线 ls /sys/bus 里面可以看到platform 总线
查看设备号 cat /proc/devices
5.1.设备注册方法
vim include/linux/platform_device.h
struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
#define platform_get_device_id(pdev) ((pdev)->id_entry)
#define to_platform_device(x) container_of((x), struct platform_device, dev)
extern int platform_device_register(struct platform_device *);
extern void platform_device_unregister(struct platform_device *);
注册设备。将设备结构体放到平台文件中,会自动注册设备,不用去调
用注册设备的函数
vim arch/arm/mach-exynos/mach-itop4412.c
#ifdef CONFIG_HELLO_CTL
struct platform_device s3c_device_hello_ctl =
{
.name = "hello",
.id = -1,
};
#endif
注册完之后在虚拟平台总线下可以查到注册的设备
– ls /sys/devices/platform/
5.2.驱动注册方法
驱动注册使用结构体platform_driver,该结构体在头文件“vim
include/linux/platform_device.h”中
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
};
extern int platform_driver_register(struct platform_driver *);
extern void platform_driver_unregister(struct platform_driver *);
probe函数
– platform_match函数匹配之后,驱动调用的初始化函数
• remove函数
– 移除驱动函数
• suspend函数
– 悬挂(休眠)驱动函数
device_driver数据结构的两个参数
– name和注册的设备name要一致
– owner一般赋值THIS_MODULE
#include <linux/init.h>
#include <linux/module.h>
/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
#define DRIVER_NAME "hello" //必须和设备注册的一致
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");
int hello_probe(struct platform_device *pdev)
{
printk(KERN_EMERG "hello_probe call \n");
return 0;
}
int hello_remove(struct platform_device *pdev)
{
printk(KERN_EMERG"remove call \n");
return 0;
}
void hello_shutdown(struct platform_device *pdev)
{
printk(KERN_EMERG"shutdown call \n");
}
int hello_suspend(struct platform_device *pdev, pm_message_t state)
{
printk(KERN_EMERG"suspend call \n");
return 0;
}
int hello_resume(struct platform_device * pdev)
{
printk(KERN_EMERG"resume call \n");
return 0;
}
struct platform_driver stu_hello={
.probe=hello_probe,
.remove=hello_remove,
.shutdown=hello_shutdown,
.suspend=hello_suspend,
.resume=hello_resume,
.driver={
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static int hello_init(void)
{
int err;
printk(KERN_EMERG "hello world enter\n");
err=platform_driver_register(&stu_hello);
printk(KERN_EMERG "register result:%d\n",err);
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "hello world exit\n");
platform_driver_unregister(&stu_hello);
}
module_init(hello_init);
module_exit(hello_exit);
网友评论