linux 驱动开发-杂烩

里面图片上传不了,完整的见 上传的附件

Linux drv 一篇杂烩

一  平台设备总线:

  1. 平台设备总线是一条虚拟总线,就是把一个设备驱动依照实际需要可以一分为二,分为platform_drv 和platform_dev 。并且可以继续一分为二。

drv通用代码 dev 硬件资源。

比如i2c-bus:

2.

平台设备驱动和直接采用字符设备file_operaiton的写法的区别:

  1. 直接 注册写file_operaiton  操作硬件的哪个引脚 是直接写死的。
  2. Hello_driver 操作哪个引脚是由hello_dev 传入的参数决定。

分层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",

    },

};

  1.  Plaform_dev 和plaform_drv 的匹配方法(常用 总共5种)
  1. 比较name

Return (strcmp(pdev->name,drv->name)==0)

  1. 比较id_idtable

If(pdev->id_table)

return platform_match_id(pdev->id_table,pdev)!=NULL;

  1. 设备找驱动和驱动找设备

当一个设备接入进来,设备会放入bus的设备链表,然后与bus的drv链表一一比较,直到找到匹配的驱动为止。

当一个驱动接入进来,驱动会放入bus的drv链表,然后与bus的drv会一一比较bus的dev链表,是否能枚举该设备。

一个dev只能由一个drv来匹配,但是一个drv可以支持多个设备。比如一个usb鼠标驱动可以支持多个鼠标,但是一个鼠标只需要一个驱动支持。

                     

                  .probe

                          比较

                     不匹配,比较下一个

                                                                        

新接入dev 匹配过程。

  1. Linux驱动 = 框架 +  硬件操作

  1. dev_set_drvdata

static void dev_set_drvdata(struct device *dev,void *data)

{

  dev->driver_data=data;

}

  1.  平台设备驱动调试

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 表示强制加载。

  1. 问:在设备树增加节点后,在 /sys/xxx 什么目录下查看这个节点?创建设备节点后,目录又在哪?
  1. /sys/firmware/devicetree/base
  2. 某个节点 -> platform_device -> /sys/bus/paltform/devices
  3. 某个节点-> i2c_client  -> /sys/bus/i2c/devices
  4. 某个节点-> spi_dev  -> /sys/bus/spi/devices

  1. 为什么要引入设备树?

随着接入的硬件设备种类越来越多,,linus本人也越来越难以忍受。各大厂商不停地往linux内核里面注入,导致linux系统变得越来越臃肿,并且有很多可能会重复和冗余而不是精简高效的。

用hardcode方式将HW 配置信息嵌入到内核代码的方法,改用bootloader传递一个DB的形式。

缺点: 1.  代码巨大

  1.         修改麻烦

采用dts  :

 配置文件和内核分开。 易于维护和修改。

查看设备树:

  1. 查看 .dtb 文件 可以通过find 命令查找
  2. Ls  /sys/firmware/devicetree/base

10 单片机和linux 分层区别

图2为补充图1

在文件中搜索 grep gpio-leds * -nr/nwr

  1.  Lcd 接线框图

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种方式:

举例:妈妈照看小孩

  1. 查询方式      简单,累。

(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);

背景说明:
  在Linux设备树(linux 3.x版本引入)中, 设备的中断号不再在"irq.h"中硬编码定义, 而是在需要时自己手动去申请获得对应的硬件中断的软件中断号.( 前提是GPIO的相关模块已经被编入内核 )

通过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区域

}

  • #address-cells,用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量
  • #size-cells,用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量

有了这两个属性,子节点中的"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

总结写驱动的三种方法:

  1. 资源和驱动写在同一个文件里。File_operation
  2.  资源用platform_device指定,驱动在platform_driver实现。
  3.  资源用dts指定。

工作队列:

中断的下半部采用tasklet,它们都是在中断上下文中执行,它们无法休眠。当要处理更复杂的事情时,往往更耗时,这些更耗时的操作放在定时器或者下半部中,会导致系统很卡;并且循环等待某件事情完成也很浪费cpu资源。

如果使用线程来处理耗时的工作,那就可以解决系统卡顿的问题。因为线程可以休眠。

在内核中我们并不需要自己去创建线程,可以使用“工作队列”,内核初始化工作队列,就会为他创建了内核线程。以后我们使用“工作队列”,只需要把“工作”放入“工作队列中”,对应的内核线程就会取出“工作”,执行里面的函数。

工作队列的使用场景:耗时,甚至可能需要休眠,那么可以使用工作队列。

缺点:多个工作是在某个内核线程中依序执行的,前面函数执行很慢,会影响后面的函数。在多cpu下,一个工作队列可以有多个内核线程,可以在一定程度上缓解这个问题。

设备树常用 OF 操作函数

要使用 of 函数,必须先配置内核 CONFIG_OF = y,其实内核默认已经使能,所以内核移植时不需要配置这个选项。

疑问:

ls  /sys/bus/platform/drivers

ls  /sys/bus/platform/devices

Ls  /sys/devices/platform/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值