设为首页 收藏本站
查看: 775|回复: 0

[经验分享] linux 驱动学习

[复制链接]

尚未签到

发表于 2018-5-22 11:19:55 | 显示全部楼层 |阅读模式
  

  
  大端模式:低字节存高地址,高字节存低地址
  小端模式:高字节存高地址,低字节存低地址
  
  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()
  
  
  
  
  


  
  

  
  
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-479056-1-1.html 上篇帖子: linux之sort用法 linux之sort用法 下篇帖子: linux共享库
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表