| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 系统运维 -> linux 驱动开发-杂烩 -> 正文阅读 |
|
[系统运维]linux 驱动开发-杂烩 |
里面图片上传不了,完整的见 上传的附件 Linux drv 一篇杂烩 一 ?平台设备总线:
drv通用代码 dev 硬件资源。 比如i2c-bus: 2. 平台设备驱动和直接采用字符设备file_operaiton的写法的区别:
分层dev和drv 引脚资源获取 ----- hello_dev static struct resource hello_dev_res[] = { { .start = 2, /* pin2 */ .end ??= 2, /* pin2 */ .flags = IORESOURCE_TYPE_BITS, }, }; static struct platform_device hello_dev = { ????????.name = "100ask_hello", ????????.dev = { ????????????????.release = hello_dev_release, ?????????}, ????????.num_resources = 1, ????????.resource ?????= hello_dev_res, }; ----hello_drv static int hello_probe(struct platform_device *pdev) { printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__); /* 1. 获得资源 */ pin = pdev->resource[0].start; /* 2. 注册file_operatoins */ major = register_chrdev(0, "hello_drv", &hello_fops); ????return 0; } static struct platform_driver hello_driver = { ????.probe ?????= hello_probe, ????.remove ????= hello_remove, ????.driver ????= { ????????.name ??= "100ask_hello", ????}, };
Return (strcmp(pdev->name,drv->name)==0)
If(pdev->id_table) return platform_match_id(pdev->id_table,pdev)!=NULL;
当一个设备接入进来,设备会放入bus的设备链表,然后与bus的drv链表一一比较,直到找到匹配的驱动为止。 当一个驱动接入进来,驱动会放入bus的drv链表,然后与bus的drv会一一比较bus的dev链表,是否能枚举该设备。 一个dev只能由一个drv来匹配,但是一个drv可以支持多个设备。比如一个usb鼠标驱动可以支持多个鼠标,但是一个鼠标只需要一个驱动支持。 ????????????????????? ??????????????????.probe ??????????????????????????比较 ?????????????????????不匹配,比较下一个 ???????????????????????????????????????????????????????????????????????? 新接入dev 匹配过程。
static void dev_set_drvdata(struct device *dev,void *data) { ??dev->driver_data=data; }
modprobe led_device //加载设备模块 modprobe led_driver //加载驱动模块 驱动加载成功后, ls ?/sys/bus/platform/drivers ???查看是否生成平台设备驱动 ls ?/sys/bus/platform/devices ???查看总线下的设备 匹配成功就会调用 driver 的 .probe 函数. 查看设备相关情况 Ls /dev/ Ls /dev/100as*_led cd /sys/ Ls 输出:blocks bus class dev devices firemaware fs hypervisor kernel module ?power 根据不同类型的设备 可以进一步进入到 bus ?class dev ?devices 等模块进一步查看设备驱动信息。 Insmod -f led_driver.ko ????-f 表示强制加载。
随着接入的硬件设备种类越来越多,,linus本人也越来越难以忍受。各大厂商不停地往linux内核里面注入,导致linux系统变得越来越臃肿,并且有很多可能会重复和冗余而不是精简高效的。 用hardcode方式将HW 配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。 缺点:?1. ?代码巨大
采用dts ?: ?配置文件和内核分开。 易于维护和修改。 查看设备树:
10 单片机和linux 分层区别 图2为补充图1 在文件中搜索 grep “gpio-leds”?* -nr/nwr
、 11 Dts 文件常规知识: Gpiob:gpio@5003000{ Gpio-controller; Gpio-cells=<2> ?//cells 表示 用几个int 类型来描述。 } Led0:cpu{ Label=”cpu”; Gpios=<&gpio5 3 GPIO_ACTIVE_LOW>; ?如上所述 这里的gpio 采用了两个int来描述的。 ... } @I2C3{ Clock-frequency=<100000>; Compatible=”sil,sii9022”; Reg=<0x40>; Reset-gpios=<&gpiob_10_GPIO_ACTIVE_LOW> //GPIO_ACTIVE_LOW表示低电平有效。 } 对于pinctrl 信息,厂家都有提供gui工具生成。 Grep “sai2”?* -nwr | grep imx6ull 12 对于声卡 有的接口是SAI接口 既有SAI 又有I2C接口 在 内核搜索 grep “wm8960”?* -nr 查看别人写的dts。 Cd ?linux-4.9.88/arch/arm/arm/boot/dts grep grep “wm8960”?* -nr grep “fsl,imx6ul-evk-wm8960”* -nr 驱动只提供能力,不提供策略。策略由APP决定。 13 ?App读取按键的4种方式: 举例:妈妈照看小孩
(2)休眠-唤醒方式 ?妈妈陪小孩一起睡,小孩醒了会吵醒,但是妈妈干不了活了。 (3)poll方式 ???定个闹钟。妈妈要么是被吵醒要么是被闹钟唤醒。 (4)异步通知方式 ?妈妈小孩互不干扰。 14 中断 Dtb反汇编生成.dts文件 dtc -I dtb -0 dts 中断分级: 14.1 Static int gpio_key_probe(参数...) { Irq=platform_get_resource(pdev,IORESOURCE_IRQ,0); Resquest_irq(...); } 14.2 获取中断资源。 If(!pdev->dev.of_node) ?// 没有采用了dts { ??Res=platform_get_resource(pdev,IORESOURCE_IRQ,0); Irq=res->start } Else { ??Irq=of_irq_get(pdev->dev.of_node,0); ?//从dts获取资源。 } Err=Resquest_irq(...); Poll_wait 不休眠,只是在队列中放入当前进程。 设备树: Sr501 { ??.compatible = “100as*,sr501”?;一般是公司名、设备名这样命名。 } Dht11温湿度传感器: Static int dht11_probe() { ??Dht11_data_pin=gpiod_get(&pdev->dev,NULL,GPIOD_OUT_LOW); } 在采用dth11 捕获中断时,中断里面只做数据记录,在中断底半步或者工作队列中做计算。 Copytouser的应用 可以拷贝多个字节。 获取ns Ktime_get_boot_ns(); 校准。 Ktime_get_bootime_ns(); 芯片不一样可能版本就不一样。 Irq=gpiod_to_irq(hs00038_echo); 背景说明: 通过GPIO号得到对应的软件中断号, 该中断号是request_irq()函数的第一个参数. I2C 框架 I2cdetect -y 0 address-cells 和 #size-cells 描述子节点应如何编写 reg 属性值,一般 reg 属性是某个外设的寄存器地址范围信息。 Aips1:aips-bus@2000000{ .compatible=”fsl,aips-bus”; #address-cell =<1>; #size-cell=<1>; Reg=<0x02000000 0x100000> ; reg区域 }
有了这两个属性,子节点中的"reg"就可以描述一块连续的地址区域。 Input_report_rel(); Input_report_rel(); Input_report_rel(); Input_sync(); 表示这一轮上报已经结束。上报同步。 Hexdump ??/dev/input/event0 Lcd 原理 Lcd 有屏幕自带 缓冲的 有不带的。 怎么写framebuffer驱动? 答: 分配fb_info ->设置 fb_info fb_var ??fb_fix ?->注册fb_info ->硬件操作。 Ls /dev/fb* Fb-test /dev/fb2 Oled用的是有的用的是SPI接口。也有i2c接口 LCD接口 RGB:(DPI)RGB565/RGB666/RGB888 MCU:I8080/M6800(8/9/16/18/24bit) SPI:3line/4line MIPI-DSI:Data_N/P、Clock_P/N 总结写驱动的三种方法:
工作队列: 中断的下半部采用tasklet,它们都是在中断上下文中执行,它们无法休眠。当要处理更复杂的事情时,往往更耗时,这些更耗时的操作放在定时器或者下半部中,会导致系统很卡;并且循环等待某件事情完成也很浪费cpu资源。 如果使用线程来处理耗时的工作,那就可以解决系统卡顿的问题。因为线程可以休眠。 在内核中我们并不需要自己去创建线程,可以使用“工作队列”,内核初始化工作队列,就会为他创建了内核线程。以后我们使用“工作队列”,只需要把“工作”放入“工作队列中”,对应的内核线程就会取出“工作”,执行里面的函数。 工作队列的使用场景:耗时,甚至可能需要休眠,那么可以使用工作队列。 缺点:多个工作是在某个内核线程中依序执行的,前面函数执行很慢,会影响后面的函数。在多cpu下,一个工作队列可以有多个内核线程,可以在一定程度上缓解这个问题。 设备树常用 OF 操作函数要使用 of 函数,必须先配置内核 CONFIG_OF = y,其实内核默认已经使能,所以内核移植时不需要配置这个选项。 疑问: ls ?/sys/bus/platform/drivers ls ?/sys/bus/platform/devices Ls ?/sys/devices/platform/ |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/15 15:54:00- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |