linux 驱动学习


 

大端模式:低字节存高地址,高字节存低地址

小端模式:高字节存高地址,低字节存低地址

 

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内存

1mmap:映射一个设备,用户的一段空间地址映射到设备上,再对用户地址操作时,也就是对设备进行操作。

 

二,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)

2IO口操作:unsigned inb(unsigned port)

   Void outb(unsigned char byte, unsigned port)

B8位。W16位 。 L32

 

三,IO内存:

1IO内存申请:#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驱动方法:

1IO内存动态映射

2GPIO标准接口函数:不需要知道物理地址和内存映射(只能用于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,新目录下新建:MakefileKconfig

Makefile:obj-$(XXX)+= XX.o(目标文件)

Kconfig:在配置make menuconfig可以看到添加的驱动

例:menu 驱动名

 Config 驱动

Tristate beep driver for GEC210

Depends on cpu_s5pv210

Default y

Help(自己解释)

Endmenu

3,在上级目录MakefileKconfig修改

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初始化

字符设备:文件集提供接口给应用层调用

2driver卸载函数:

Static init __devexit XX_remove():初始化的设备进行卸载

3platform_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_AKEY_BKEY_CKEY_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初始化

字符设备:文件集提供接口给应用层调用

2driver卸载函数:

Static init __devexit XX_remove():初始化的设备进行卸载

3platform_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()

 

 

 

 



 

 

 

 

 


你可能感兴趣的:(linux,源文件)