https://www.bilibili.com/video/BV14f4y1Q7ti
2 hello 驱动
- 可以参考
drivers\char\misc.c
这个是非常经典的字符设备驱动程序。 printk
打印信息,可以通过dmesg
来查看。
9 总线设备驱动模型
platform_device
用于存放设备的资源相关.struct resource
在include\linux\ioport.h
中,struct resource
给出明确的定义,需要按照这种形式去写。struct resource { resource_size_t start; resource_size_t end; const char *name; unsigned long flags; unsigned long desc; struct resource *parent, *sibling, *child; };
- 资源也可以放在
platform_device
->struct device dev
->void *platform_data
定义在include\linux\device.h
中,这个platform_data
那就是根据需要完全自己定义就行。 platform_driver
用于存放操作相关的函数。- bus 维持两个链表,一个是 device 链表,一个是 driver 链表,两个链表中有任何一个新增,就会扫描对方链表,查看是否有匹配,probe.
drivers\base\platform.c
中的struct bus_type platform_bus_type
定义了匹配用到platform_match
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, };
- 具体的匹配,可以看
drivers\base\platform.c
中的static int platform_match(struct device *dev, struct device_driver *drv)
可以看到匹配的优先级。/* When driver_override is set, only bind to the matching driver */ if (pdev->driver_override) return !strcmp(pdev->driver_override, drv->name); /* Attempt an OF style match first */ if (of_driver_match_device(dev, drv)) return 1; /* Then try ACPI style match */ if (acpi_driver_match_device(dev, drv)) return 1; /* Then try to match against the id table */ if (pdrv->id_table) return platform_match_id(pdrv->id_table, pdev) != NULL; /* fall-back to driver name match */ return (strcmp(pdev->name, drv->name) == 0);
11 设备树处理与使用
- 根节点
of_root
可以通过device_node
中的parent
child
来遍历所有节点。 - 子节点能否转换为
platform_device
, 取决于父节点的comptible
是否是 "simple-bus","simple-mfd","isa","arm,amba-bus", 而且子节点也要有comptible
- 当前设备树
/sys/firmware/devicetree/base
, 搜索ls -ld *100ask*
cd
打开设备节点文件夹,里面有comptible
,name
,pin
,可以用cat
,hexdump
来读取数据- 打开
platform_device
对应的文件夹/sys/devices/platform
或者/sys/devices/soc0
, 然后ls -ld *100ask*
也可以找到对应的设备节点。文件夹下面的of_node
指向设备树里面的节点。 - 加载驱动之后,自动 probe了,在
platform_device
对应的文件夹下,会多出来一个driver
文件夹,指向了/sys/devices/soc0/100ask_led@0/driver
这个对应的驱动文件夹。并且uevent
这个文件里面,也多了driver
这一行。 - 打开 驱动文件夹
/sys/devices/soc0/100ask_led@0/driver
,可以看到下面100ask_led@0
,100ask_led@1
, 分别指向了设备文件夹下面的设备节点。module
指向了驱动模块文件夹/sys/devices/soc0/100ask_led@0/driver/module
。
16 2gpio子系统
#gpio-cells = <2>;
值得是,除了 gpioX 这个以外,还要两个数值。gpios
或者xxx-gpios
可以指定多个引脚。led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */ <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */ <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */
- 只有一个引脚的时候,使用
gpiod_get
。多个引脚取一个的时候,使用gpiod_get_index
16_4 上机
- 设备树中新增 pinctrl 相关
&iomuxc_snvs { …… myled_for_gpio_subsys: myled_for_gpio_subsys{ fsl,pins = < MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x000110A0 >; };
- 设备树中新增节点
myled { compatible = "100ask,leddrv"; pinctrl-names = "default"; pinctrl-0 = <&myled_for_gpio_subsys>; led-gpios = <&gpio5 3 GPIO_ACTIVE_LOW>; };
- 检查这个引脚有没有其他地方使用,可以通过
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03
来查找,找到使用的设备节点后,在里面增加status = "disabled";
禁用。
18_2 中断处理的演进
中断下半部开始执行的时候,开了中断. 如果在下半部被中断了,那么第二次的中断上半部执行完后,后发现 preempt_count 不为0,就不执行下半部了。 这样就会回到第一次被中断的下半部,继续执行完成下半部的处理。
这就是上下多对一。 并且下半部会处理所有的软件中断。
18_3 中断系统数据结构
- GIC, GPIO 这些都是芯片内部的,BSP 可以直接处理,比如说,发生了一个中断,那就先去看看 GIC 里面,是哪个模块发生了中断? 如果是 GPIO 模块中断了,再去 GPIO 这边处理下。
- 实际的操作流程是,中断发生之后, GIC 的
irq_desc.handle_irq
内部分辨是哪个模块,然后自动调用 GPIO 的irq_desc.handle_irq
- gpio 会挨个调用中断引脚的处理函数。 也就是通过
irq_desc.action
链表,挨个调用链表中的irq_action.handler
irq_action.handler
上半部结束后会调用irq_action.thread_fn
下半部irq_action.thread_fn
涉及到的线程是irq_action.thread
irq_action
由request_irq()
注册的。request_irq()
用到的中断号并不是从设备树中直接拿来用的。需要irq_domain.ops.xlate
先从设备树进行解析,然后irq_domain.ops.map
对设备树中的硬件中断和request_irq()
用到的中断号进行映射。 映射关系保存在irq_domain.linear_revmap[]
中。irq_chip
里面的irq_enable()
irq_disable()
会被自动调用。
实际上,GIC 中断之后,是需要先通过 irq_desc.irq_data.domain.linear_revmap[]
来获取到中断号对应的硬件中断号,然后才能去调用 GPIO 的 irq_desc.handle_irq
。
18_4 代码中获得中断
- 设备树中,一定要看清楚
interrupt_parent
是谁,并且对应的#interrupt-cells
是多少,不同层级可能这个数目是不一样多的。 - 如果本层没有指明
interrupt_parent
,那可能是继承了上一层的,去上一层查看。
19_9 mmap 基础
cat /proc/pid/maps
可以查看进程使用的内存情况。
一般不适用 cache
- register
- framebuffer
- dma
一般不适用于 写缓冲,可能会有多个字节合并为 word 的可能。
- register
19_10 mmap 编程
mmap 函 数 MAP_SHARED
、 MAP_PRIVATE
参 数 。 MAP_PRIVATE
会导致,当对映射的 buf 进行写入,那么内核会自动复制一块内存,并让 buf 指向它,只有这个 buf 才有新的数据。就算是驱动程序也只是旧内存。非常适合需要临时修改文件内容或创建文件副本的场景。