天津制作个人建站,选服务好的佛山网站建设,封丘有做网站的吗,新乡建设企业网站目录
前言
一、重要结构体
二、编程思路
1.platform_driver结构体
2.probe
三、使用设备树
1.步进电机
2.红外遥控
四、代码示例 前言
在这里主要记录学习韦东山老师Linux驱动人入门实验班的笔记#xff0c;韦东山老师的驱动课程讲的非常好#xff0c;想要学习驱动…目录
前言
一、重要结构体
二、编程思路
1.platform_driver结构体
2.probe
三、使用设备树
1.步进电机
2.红外遥控
四、代码示例 前言
在这里主要记录学习韦东山老师Linux驱动人入门实验班的笔记韦东山老师的驱动课程讲的非常好想要学习驱动的小伙伴可以去b站学习他的课程。
一、重要结构体
platfrom_driver结构体 platform_driver 结构体是在 Linux 内核中定义的一个结构体用于在驱动程序中注册和管理平台设备驱动。它包含以下字段 struct device_driver driver指向 struct device_driver 结构体的指针表示该平台驱动程序所属的设备驱动。 const struct platform_device_id *id_table一个指向 struct platform_device_id 结构体数组的指针用于匹配与该平台驱动程序相匹配的设备。 int (*probe)(struct platform_device *pdev)一个函数指针指向设备的探测函数用于在设备被注册到系统后执行特定的操作。 int (*remove)(struct platform_device *pdev)一个函数指针指向设备的移除函数用于在设备被注销时执行特定的操作。 void (*shutdown)(struct platform_device *pdev)一个函数指针指向设备的关机函数用于在系统关机时执行特定的操作。 struct device_driver driver用于表示该平台驱动程序的设备驱动。 struct list_head driver_entry用于将平台驱动程序添加到全局驱动程序链表中的链表节点。 二、编程思路
在原来第一个模板的基础上
1.platform_driver结构体
还需要构造platform_driver结构体和of_device_id结构体
static struct platform_driver gpio_platfrom_drive {.driver {.name 100ask_gpio_plat_drv,.of_match_table gpio_dt_ids,},.probe gpio_drv_probe,.remove gpio_drv_remove,
};
struct of_device_id { char name[32]; char type[32]; char compatible[128]; const void *data; };在Linux内核中of_device_id结构体用于存储设备树绑定信息用于设备与驱动程序之间的匹配。它包含以下字段name设备树绑定的名称。
type设备树绑定的类型。
compatible设备树绑定的兼容字符串用于指定设备与驱动程序之间的兼容关系。
data指向附加数据的指针可以在设备树绑定中使用。
gpio_drv_probe和gpio_drv_remove分别代替了原来init入口函数和exit出口函数的作用而在原来的这两个函数中是注册和反注册platform_driver结构体。
使用的函数为
platform_driver_register 是一个函数用于注册平台设备驱动程序。它将驱动程序与平台设备进行绑定使得驱动程序能够管理其对应的平台设备。函数原型为int platform_driver_register(struct platform_driver *drv);参数说明drv指向平台驱动程序的指针其类型为 struct platform_driver。平台驱动程序是一个结构体包含了驱动程序的各种回调函数和其他属性。定义了平台设备和驱动程序之间的关联关系。
返回值成功注册平台驱动程序时返回 0注册失败时返回负数错误代码。
使用 platform_driver_register 函数可以将平台驱动程序注册到内核中以便在加载平台设备时自动调用相应的驱动程序。注册平台驱动程序后内核会通过设备树 (Device Tree) 或 ACPI (Advanced Configuration and Power Interface) 系统启动方法来查找并匹配平台设备并自动加载和绑定对应的驱动程序。注册平台驱动程序时需要确保驱动程序的结构体中的回调函数和其他属性正确设置以便驱动程序能够正确地管理和操作平台设备。
2.probe
static int gpio_drv_probe(struct platform_device *pdev) gpio_drv_probe中使用到的结构体
struct device_node *np pdev-dev.of_node;
platform_device 结构体包含的重要成员包括name设备的名称用于唯一标识设备。
id设备的 ID用于区分同一类型的不同设备。
num_resources设备所需的资源数量。
resource用于描述设备的资源信息如内存范围、中断、I/O 端口等。
dev指向设备所属的 struct device 结构体的指针用于与设备的核心操作进行交互。
pdata设备特定的数据用于向设备驱动程序传递设备特定的信息。
driver_data指向设备驱动程序特定数据的指针用于与设备驱动程序交互。
struct device_node {const char *name; // 设备节点名称const char *type; // 设备节点类型const char *fullname; // 设备节点完整路径名称struct device_node *parent; // 父设备节点struct device_node *child; // 子设备节点struct device_node *sibling; // 兄弟设备节点void *data; // 设备节点特定数据// 其他成员...
};
struct resource {resource_size_t start; // 资源起始地址resource_size_t end; // 资源结束地址包含resource_size_t flags; // 资源标志const char *name; // 资源名称struct resource *parent; // 父资源struct resource *sibling; // 兄弟资源struct resource *child; // 子资源
}; gpio_drv_probe中使用到的函数
of_gpio_count
of_gpio_count 是一个函数用于获取设备的GPIO数量。它是在Device Tree中使用的用于解析设备节点中定义的GPIO信息。函数原型为int of_gpio_count(struct device_node *np);参数说明struct device_node *np指向设备节点的指针。
返回值返回设备节点中定义的GPIO数量。如果没有定义GPIO则返回0。
使用 of_gpio_count 函数可以确定设备节点中定义的GPIO数量从而在设备驱动程序中进行相应的GPIO初始化和管理操作。
kmalloc
kmalloc 是一个内核函数用于动态分配内核空间的连续内存块。它可以用于分配任意大小的内存区域。函数原型为void *kmalloc(size_t size, gfp_t flags);参数说明size要分配的内存块的大小以字节为单位。
flags分配内存的标志用于指定分配内存的行为。
返回值返回指向分配的内存块的指针如果分配失败则返回NULL。 platform_get_resource
platform_get_resource 是一个函数用于获取给定平台设备的资源信息。它可以用于获取平台设备上的寄存器地址、中断号、IO地址等资源的信息。函数原型为struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);参数说明dev指向平台设备的指针。
type要获取的资源类型可以是 IORESOURCE_MEM、IORESOURCE_IO 或 IORESOURCE_IRQ。这些类型定义在 include/linux/ioport.h 和 include/linux/irq.h 头文件中。
num要获取的资源号资源号从 0 开始计数。
返回值返回指向资源的 struct resource 结构体指针如果获取失败则返回 NULL。
使用 platform_get_resource 函数可以获取平台设备上的资源信息。例如可以使用它来获取平台设备上的寄存器地址以便进行寄存器访问。需要注意的是资源的类型和编号需要事先了解以便正确地调用 platform_get_resource 函数。
三、使用设备树
1.步进电机 修改设备树arch/arm/boot/dts/100ask_imx6ull-14x14.dts
添加节点
motor {compatible 100ask,gpiodemo;gpios gpio4 19 GPIO_ACTIVE_HIGH, gpio4 20 GPIO_ACTIVE_HIGH,gpio4 21 GPIO_ACTIVE_HIGH,gpio4 22 GPIO_ACTIVE_HIGH;
}; 编译make dtbs 复制到单板上 ubuntu:cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/ 开发板:mount -t nfs -o nolock,vers3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/100ask_imx6ull-14x14.dtb /boot
reboot 测试 insmod gpio_drv.ko
./button_test /dev/motor ... 2.红外遥控 修改设备树arch/arm/boot/dts/100ask_imx6ull-14x14.dts
添加节点
irda {compatible 100ask,gpiodemo;gpios gpio4 19 GPIO_ACTIVE_HIGH;
}; 编译make dtbs 复制到单板上 PC:
cp arch/arm/boot/dts/100ask_imx6ull-14x14.dtb ~/nfs_rootfs/
开发板:
mount -t nfs -o nolock,vers3 192.168.5.11:/home/book/nfs_rootfs /mnt
cp /mnt/100ask_imx6ull-14x14.dtb /boot
reboot 测试 insmod gpio_drv.ko
./button_test /dev/irda
四、代码示例
static int irda_drv_probe(struct platform_device *pdev)
{int err 0;int i;struct device_node *np pdev-dev.of_node;struct resource *res;if (np){count of_gpio_count(np);if (!count){return -EINVAL;}gpios kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i 0; i count; i){gpios[i].gpio of_get_gpio(np, i);sprintf(gpios[i].name, %s_pin_%d, np-name, i);}}else{count 0;while (1){res platform_get_resource(pdev, IORESOURCE_IRQ, count);if (res){count;}else{break;}}if(!count){return -EINVAL;}gpios kmalloc(count * sizeof(struct gpio_desc), GFP_KERNEL);for (i 0; i count; i){res platform_get_resource(pdev, IORESOURCE_IRQ, count);gpios[i].gpio res-start;sprintf(gpios[i].name, %s_pin_%d, pdev-name, i);}}for (i 0; i count; i){gpios[i].irq gpio_to_irq(gpios[i].gpio);setup_timer(gpios[i].irda_timer, irda_timer_expire, (unsigned long)gpios[i]);err request_irq(gpios[i].irq, irda_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, gpios[i].name, gpios[i]);}major register_chrdev(0, irda_drv, irda_drv);irda_class class_create(THIS_MODULE, irda_class);device_create(irda_class, NULL, MKDEV(major, 0), NULL, irda_drv);return err;
}static int irda_drv_remove(struct platform_device *pdev)
{int i;device_destroy(irda_class, MKDEV(major, 0));class_destroy(irda_class);unregister_chrdev(major, irda_drv);for (i 0; i count; i){free_irq(gpios[i].irq, gpios[i]);del_timer(gpios[i].irda_timer);}return 0;
}static struct of_device_id irda_dt_ids[] {{.compatible irda,demo,},
};static struct platform_driver irda_platform_driver {.driver {.name irda_plat_drive,.of_match_table irda_dt_ids,},.probe irda_drv_probe,.remove irda_drv_remove,
};