大端模式:低字节存高地址,高字节存低地址
小端模式:高字节存高地址,低字节存低地址
Mkfile:
1,多个源文件编译成一个ko
Eg:obj-m+= hello.o
Hello-objs +=test.o add.o
一设备文件
1,设备文件手动创建:如:mknod /dev/XX c 250 0
2,得到设备号:MKDEV(主号,次号);
自动创建:class_create();
Driver_create();
生成设备文件有两种方法:
1)新:定义主次设备号----->定义设备名------->MKDEV(主,次)------>定义文件集(file_operations)------>初始化文件集------>
申请设备号[1,静态:register_chrdev_region(设备号,次数,设备名); 2,动态:alloc_chrdev_region(设备号,次设备号,次数,设备名);主设备号=MAJOR(设备号))]------>设备初始化(void cdev_init())----->释放unregister_chrdev_region------>注册:cdev_add()------>释放cdev_del();
2)定义文件集------>初始化文件集------>注册:register_chrdev():自己给定主设备号的值,设备名----->释放:unregister_chrdev
二IO内存
1,地址方式访问硬件:IO内存操作
2,端口方式访问硬件:IO端口操作
一:IO端口和IO内存
1,mmap:映射一个设备,用户的一段空间地址映射到设备上,再对用户地址操作时,也就是对设备进行操作。
二,IO端口:cat /proc/ioports:查看IO口
1,申请端口:#include <linux/ioport.h>
Struct resource *request_region(unsigned long first, unsigned long n, const char *name)
释放端口:void release_region(unsigned long start, unsigned long n)
2,IO口操作:unsigned inb(unsigned port)读
Void outb(unsigned char byte, unsigned port)写
B:8位。W:16位 。 L:32位
三,IO内存:
1,IO内存申请:#include<linux/ioport.h>
struct resource *request_mem_region(unsigned long start, unsigned long len, char *name)
释放内存:void release_mem_region(unsigned long start, unsigned long len)
2,内存映射:#include<asm/io.h>
Void *ioremap(unsigned long phy_addr, unsigned long size)
Void *ioremap_nocache(unsigned long phys_addr, unsigned long size)
成功时返回虚拟地址,否则NULL;
释放映射:void iounmap(void *addr);
3,内存访问:#include<asm/io.h>
读:unsigned int ioread8(volatile void __iomem *addr) 8/16/32位
写:void iowrite8(u8 value, volatile void __iomem *addr) 8/16/32位
或:ioreadb/ioreadw/ioreadl
Iowrite8/iowrite16/iowrite32
四,实现GPIO驱动方法:
1,IO内存动态映射
2,GPIO标准接口函数:不需要知道物理地址和内存映射(只能用于GPIO,中断,时钟)
1)int gpio_request(unsigned gpio, const char *label)
2)Void gpio_free(unsigned gpio)
3)IO方向:int gpio_direction_input(unsigned gpio)
Int gpio_direction_output(unsigned gpio, int value)
4)输入则:gpio_get_value(unsigned gpio)
输出则:gpio_set_value(unsigned gpio, int value)
三,驱动编译进内核
1,将源码加进内核:/driver/char/新建目录
2,新目录下新建:Makefile和Kconfig
Makefile:obj-$(XXX)+= XX.o(目标文件)
Kconfig:在配置make menuconfig可以看到添加的驱动
例:menu “驱动名”
Config 驱动
Tristate “beep driver for GEC210”
Depends on cpu_s5pv210
Default y
Help(自己解释)
Endmenu
3,在上级目录Makefile、Kconfig修改
Makefile:仿造修改
Kconfig:使驱动生效:source “driver/char/XXX/Kconfig”
四, 杂项设备
杂项设备:只是创建字符设备文件的一种
Misc_register()
Misc_deregister()
在内核中查找驱动
1, arch/arm/mach-smdkc110.c中查找.init_machine-----得到platform_add_device--------第一个参数得到smkc110_devices(列表)
2, 1,中的不到结果,则在arch/arm/mach-smdkc110.c中查找*smkc110_devices[]_initdata----得到.device--------同名得到.driver(CONFIG在.config中可以找到)
Platform的模型使用:
Platform bus:平台初始化,创建总线
Platform device:总线上挂载硬件资源(中断号、物理地址、GPIO)
Platform driver:总线上挂载一个针对device(设备)的driver(驱动):内存申请、建立字符设备文件(新、旧、misc)、内存映射、文件操作集
1,platform device:
1): 平台资源定义:
Static struct resource XX_resource[]={
[]={
.start
.end
.name
.flags
},
};(获取硬件信息)
2): 平台设备定义:struct platform_device XX={
.name=必须和driver相同
.id = -1 (自动分配设备ID)
.dev={.relesae = XX_release},
.num_resources = ARRY_SIZE(XX_resource),
.resource = XX_resource,
};
3):安装:int platform_device_register(struct platform_device *pdev)
卸载:void platform_device_unresgister(struct platform_device *pdev)
2, platform_driuver:
1): driver初始化:
Static int __devinit XX_probe():先获取device资源,字符设备,IO内存映射/gpio初始化
字符设备:文件集提供接口给应用层调用
2)driver卸载函数:
Static init __devexit XX_remove():初始化的设备进行卸载
3)platform_driver XX_driver={
.probe = XX_probe,
.remove = __devexit_p(XX_remove),
.driver = {
.name = 和device相同
.owner = THIS_MODULE,
},
};
4)注册:
Int platform_driver_register()
Void platform_driver_unregister()
六,输入子系统设备
一:基本概念:和misc类似
1,输入设备驱动,设计成输入子系统设备:驱动接口标准化
2,查看设备名称:cat /proc/devices
3,查看设备文件:ls /dev -l
4,输入设备信息:cat /proc/bus/input/devices
5,读驱动:cat /dev/XX(设备文件)
二:输入子系统使用
1,输入子系统分为三层:1):设备驱动层(只需设计此)
2): 核心层
3):事件处理层
过程:设备驱动层检测到输入事件的发生(按键按下,鼠标移动,触摸屏触发...)--->将报告事件发送给核心层------>发送给事件处理层---->事件进行封装----->input_event----->VFS------>系统调用----->应用层----->读input_event------>解析(type:类型,code:按键值,value:按键状态---->按下,松开)
2,输入子系统设备设计:
1)定义子系统设备:struct input_dev *XX ---->include<linux/input.h>
2)初始化子系统设备:struct input_dev * input_allocate_device(void)
初始化就是对定义的结构体进行赋值
Input_free_device():释放申请空间,在申请失败是使用或者没调用input_register_device前使用
例:
*gec_key = input_allocate_device();
初始化gec_key结构体的内容:
gec_key->name = "gec_input"; //#cat /proc/bus/input/devices
gec_key->id.bustype = 0x1;
gec_key->id.product = 0x2;
gec_key->id.vendor = 0x3;
gec_key->id.version = 0x4;
gec_key->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY); //设置输入设备的类型:type=EV_KEY
gec_key->keybit[BIT_WORD(KEY_C)] = BIT_MASK(KEY_C); //在EV_KEY下,code=KEY_C
注意:
如果一个输入设备驱动程序中,设计了4个按键的驱动,按键值分别:KEY_A、KEY_B、KEY_C、KEY_D
gec_key->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY);
gec_key->keybit[BIT_WORD(KEY_A)] = BIT_MASK(KEY_A);
gec_key->keybit[BIT_WORD(KEY_B)] |= BIT_MASK(KEY_B);
gec_key->keybit[BIT_WORD(KEY_C)] |= BIT_MASK(KEY_C);
gec_key->keybit[BIT_WORD(KEY_D)] |= BIT_MASK(KEY_D);
3)注册到内核:
Input_register_device()
释放:input_unregister_device()---->使用其,则input_free_device不使用
七, 杂项设备
杂项设备:只是创建字符设备文件的一种
Misc_register()
Misc_deregister()
12,在内核中查找驱动
1, arch/arm/mach-smdkc110.c中查找.init_machine-----得到platform_add_device--------得到platform_device_register(检查有没有结果)
2, 1,中的不到结果,则在arch/arm/mach-smdkc110.c中查找*smkc110_devices[]_initdata----得到.device--------同名得到.driver(CONFIG在.config中可以找到)
Platform的模型使用:
Platform bus:平台初始化,创建总线
Platform device:总线上挂载硬件资源(中断号、物理地址、GPIO)
Platform driver:总线上挂载一个针对device(设备)的driver(驱动):内存申请、建立字符设备文件(新、旧、misc)、内存映射、文件操作集
1,platform device:
1): 平台资源定义:
Static struct resource XX_resource[]={
[]={
.start
.end
.name
.flags
},
};(获取硬件信息)
2): 平台设备定义:struct platform_device XX={
.name=必须和driver相同
.id = -1 (自动分配设备ID)
.dev={.relesae = XX_release},
.num_resources = ARRY_SIZE(XX_resource),
.resource = XX_resource,
};
3):安装:int platform_device_register(struct platform_device *pdev)
卸载:void platform_device_unresgister(struct platform_device *pdev)
2, platform_driuver:
1): driver初始化:
Static int __devinit XX_probe():先获取device资源,字符设备,IO内存映射/gpio初始化
字符设备:文件集提供接口给应用层调用
2)driver卸载函数:
Static init __devexit XX_remove():初始化的设备进行卸载
3)platform_driver XX_driver={
.probe = XX_probe,
.remove = __devexit_p(XX_remove),
.driver = {
.name = 和device相同
.owner = THIS_MODULE,
},
};
4)注册:
Int platform_driver_register()
Void platform_driver_unregister()