邳州微网站开发,老客外链,濮阳网站建设在哪做,wordpress左右滑动插件目录
一、使用设备树
1.1 修改设备树流程
二、手动创建平台设备
三、总结#xff08;附驱动程序#xff09; 前情提要#xff1a;【IMX6ULL驱动开发学习】07.驱动程序分离的思想之平台总线设备驱动模型和设备树_阿龙还在写代码的博客-CSDN博客
手动注册…目录
一、使用设备树
1.1 修改设备树流程
二、手动创建平台设备
三、总结附驱动程序 前情提要【IMX6ULL驱动开发学习】07.驱动程序分离的思想之平台总线设备驱动模型和设备树_阿龙还在写代码的博客-CSDN博客
手动注册平台设备和设备树的目的都是为了构造platform_device结构体
一、使用设备树
之前的驱动编写方式引脚信息在驱动程序里写死了移植性差。而使用设备树这样的程序编写方式便于在换了板子或引脚之后只要修改设备树的节点信息即可不需要看复杂的驱动程序前提是有完备的驱动程序。
在驱动程序的入口函数里注册了gpio_platform_driver
module_init(gpio_drv_init);
static int __init gpio_drv_init(void)
{/* 注册platform_driver */return platform_driver_register(gpio_platform_driver);
}
gpio_platform_driver结构体中probe函数被调用需要在设备树中找到与之匹配的设备节点信息即设备节点信息也要含有这个语句.compatible 100ask,gpiodemo
static const struct of_device_id gpio_dt_ids[] {{ .compatible 100ask,gpiodemo, },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver {.driver {.name 100ask_gpio_plat_drv,.of_match_table gpio_dt_ids,},.probe gpio_drv_probe,.remove gpio_drv_remove,
};
1.1 修改设备树流程
在内核目录下找到设备树文件以我的路径为例这里给出绝对路径
修改设备树vi /home/book/100ask_imx6ull-sdk/Linux-4.9.88/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;
};
一定要在/home/book/100ask_imx6ull-sdk/Linux-4.9.88目录下编译设备树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
查看设备树节点信息ls /sys/firmware/devicetree/base/ 查看马达节点有没有被转换成平台设备platform_devicels /sys/bus/platform/devices/ 有这个motor文件表示有了对应的平台设备。
进入motor文件查看因为还没装驱动所以没有显示驱动程序 装载驱动后查看motor文件 说明驱动和设备都匹配上了 最后就编写测试程序进行测试即可
./button_test /dev/motor ...
二、手动创建平台设备
编写dev.c文件
#include linux/module.h
#include linux/poll.h
#include linux/delay.h
#include linux/fs.h
#include linux/errno.h
#include linux/miscdevice.h
#include linux/kernel.h
#include linux/major.h
#include linux/mutex.h
#include linux/proc_fs.h
#include linux/seq_file.h
#include linux/stat.h
#include linux/init.h
#include linux/device.h
#include linux/tty.h
#include linux/kmod.h
#include linux/gfp.h
#include linux/gpio/consumer.h
#include linux/platform_device.h
#include linux/of_gpio.h
#include linux/of_irq.h
#include linux/interrupt.h
#include linux/irq.h
#include linux/slab.h
#include linux/fcntl.h
#include linux/timer.hstatic struct resource my_drv_resource[] {{.start 115,.end 115,.flags IORESOURCE_IRQ,},{.start 116,.end 116,.flags IORESOURCE_IRQ,},{.start 117,.end 117,.flags IORESOURCE_IRQ,},{.start 118,.end 118,.flags IORESOURCE_IRQ,},
};static struct platform_device gpio_platform_device {.name 100ask_gpio_plat_drv,.id 0,.num_resources ARRAY_SIZE(my_drv_resource),// 4 宏来计算数组大小.resource my_drv_resource,
};static int __init gpio_dev_init(void)
{/* 注册platform_driver */return platform_device_register(gpio_platform_device);
}static void __exit gpio_dev_exit(void)
{/* 反注册platform_driver */platform_device_unregister(gpio_platform_device);
}/* 7. 其他完善提供设备信息自动创建设备节点 */module_init(gpio_dev_init);
module_exit(gpio_dev_exit);MODULE_LICENSE(GPL); 其中由这个名字100ask_gpio_plat_drv找到与之匹配的平台驱动platform_driver
static struct platform_device gpio_platform_device {.name 100ask_gpio_plat_drv,.id 0,.num_resources ARRAY_SIZE(my_drv_resource),// 4 宏来计算数组大小.resource my_drv_resource,
}; 修改Makefile文件
KERN_DIR /home/book/100ask_imx6ull-sdk/Linux-4.9.88 # 板子所用内核源码的目录all:make -C $(KERN_DIR) Mpwd modules $(CROSS_COMPILE)gcc -o button_test button_test.c
clean:make -C $(KERN_DIR) Mpwd modules cleanrm -rf modules.order button_test# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y : a.o b.o
# obj-m ab.oobj-m gpio_drv.o
obj-m gpio_dev.o 编译make设备树节点信息取消因为内核里有了设备树节点信息需要改回去或者添加disabled状态
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;status disabled;
};
编译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
查看设备树节点信息ls /sys/firmware/devicetree/base/ 状态为禁止状态设备树节点信息被我们禁用了 查看马达节点有没有被转换成平台设备platform_devicels /sys/bus/platform/devices/这里肯定也是没有的 装载驱动程序、查看是否匹配上、查看设备节点 这个平台驱动支持名为100ask_gpio_plat_drv的设备设备节点也出来了 三、总结附驱动程序
这个驱动程序在入口函数里注册了平台驱动这个平台驱动可以支持来自设备树的平台设备.compatible 100ask,gpiodemo,和来自自己手动创建的平台设备.name 100ask_gpio_plat_drv。匹配规则有4种这里用的是最简单的。当平台driver匹配到平台device时驱动程序里的probe函数就被调用probe函数里可以从设备树里得到引脚信息也可以从手动注册的平台device里得到所谓的资源。
static const struct of_device_id gpio_dt_ids[] {{ .compatible 100ask,gpiodemo, },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver {.driver {.name 100ask_gpio_plat_drv,.of_match_table gpio_dt_ids,//设备树信息},.probe gpio_drv_probe,.remove gpio_drv_remove,
}; 驱动程序
#include linux/module.h
#include linux/poll.h
#include linux/delay.h
#include linux/fs.h
#include linux/errno.h
#include linux/miscdevice.h
#include linux/kernel.h
#include linux/major.h
#include linux/mutex.h
#include linux/proc_fs.h
#include linux/seq_file.h
#include linux/stat.h
#include linux/init.h
#include linux/device.h
#include linux/tty.h
#include linux/kmod.h
#include linux/gfp.h
#include linux/gpio/consumer.h
#include linux/platform_device.h
#include linux/of_gpio.h
#include linux/of_irq.h
#include linux/interrupt.h
#include linux/irq.h
#include linux/slab.h
#include linux/fcntl.h
#include linux/timer.hstruct gpio_desc{int gpio;int irq;char name[128];int key;struct timer_list key_timer;
} ;static struct gpio_desc *gpios;
static int count;/* 主设备号 */
static int major 0;
static struct class *gpio_class;/* 马达引脚设置数字 */
static int g_motor_pin_ctrl[8] {0x2,0x3,0x1,0x9,0x8,0xc,0x4,0x6};
static int g_motor_index 0;void set_pins_for_motor(int index)
{int i;for (i 0; i 4; i){gpio_set_value(gpios[i].gpio, g_motor_pin_ctrl[index] (1i) ? 1 : 0);}
}void disable_motor(void)
{int i;for (i 0; i 4; i){gpio_set_value(gpios[i].gpio, 0);}
}/* int buf[2];* buf[0] 步进的次数, 0 : 逆时针步进; 0 : 顺时针步进* buf[1] mdelay的时间*/
static ssize_t motor_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int ker_buf[2];int err;int step;if (size ! 8)return -EINVAL;err copy_from_user(ker_buf, buf, size);if (ker_buf[0] 0){/* 逆时针旋转 */for (step 0; step ker_buf[0]; step)
{set_pins_for_motor(g_motor_index);mdelay(ker_buf[1]);g_motor_index--;if (g_motor_index -1)g_motor_index 7;}}else{/* 顺时针旋转 */ker_buf[0] 0 - ker_buf[0];for (step 0; step ker_buf[0]; step)
{set_pins_for_motor(g_motor_index);mdelay(ker_buf[1]);g_motor_index;if (g_motor_index 8)g_motor_index 0;}
}/* 改进旋转到位后让马达不再消耗电源 */disable_motor();return 8;
}/* 定义自己的file_operations结构体 */
static struct file_operations gpio_key_drv {.owner THIS_MODULE,.write motor_write,
};/* 在入口函数 */
static int gpio_drv_probe(struct platform_device *pdev)
{int err 0;int i;struct device_node *np pdev-dev.of_node;struct resource *res;printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);/* 从platfrom_device获得引脚信息 * 1. pdev来自c文件* 2. pdev来自设备树*/if (np){/* pdev来自设备树 : 示例reg_usb_ltemodule: regulator1 {compatible 100ask,gpiodemo;gpios gpio5 5 GPIO_ACTIVE_HIGH, gpio5 3 GPIO_ACTIVE_HIGH;};*/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{/* pdev来自c文件 static struct resource omap16xx_gpio3_resources[] {{.start 115,.end 115,.flags IORESOURCE_IRQ,},{.start 118,.end 118,.flags IORESOURCE_IRQ,}, }; */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, i);gpios[i].gpio res-start;sprintf(gpios[i].name, %s_pin_%d, pdev-name, i);}}for (i 0; i count; i){err gpio_request(gpios[i].gpio, gpios[i].name);gpio_direction_output(gpios[i].gpio, 0);}/* 注册file_operations */major register_chrdev(0, 100ask_gpio_key, gpio_key_drv); /* /dev/gpio_desc */gpio_class class_create(THIS_MODULE, 100ask_gpio_key_class);if (IS_ERR(gpio_class)) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, 100ask_gpio_key);return PTR_ERR(gpio_class);}device_create(gpio_class, NULL, MKDEV(major, 0), NULL, motor); /* /dev/motor */return err;
}/* 有入口函数就应该有出口函数卸载驱动程序时就会去调用这个出口函数*/
static int gpio_drv_remove(struct platform_device *pdev)
{int i;printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);device_destroy(gpio_class, MKDEV(major, 0));class_destroy(gpio_class);unregister_chrdev(major, 100ask_gpio_key);for (i 0; i count; i){gpio_free(gpios[i].gpio);}return 0;
}static const struct of_device_id gpio_dt_ids[] {{ .compatible 100ask,gpiodemo, },{ /* sentinel */ }
};static struct platform_driver gpio_platform_driver {.driver {.name 100ask_gpio_plat_drv,.of_match_table gpio_dt_ids,//设备树信息},.probe gpio_drv_probe,.remove gpio_drv_remove,
};static int __init gpio_drv_init(void)
{/* 注册platform_driver */return platform_driver_register(gpio_platform_driver);
}static void __exit gpio_drv_exit(void)
{/* 反注册platform_driver */platform_driver_unregister(gpio_platform_driver);
}/* 7. 其他完善提供设备信息自动创建设备节点 */module_init(gpio_drv_init);
module_exit(gpio_drv_exit);MODULE_LICENSE(GPL);