Linux 驱动开发 四十四:platform 设备驱动实验(二)
驅(qū)動(dòng)測(cè)試通過(guò)操作 led 完成。
一、原理圖
二、無(wú)設(shè)備樹(shù)源碼實(shí)現(xiàn)
無(wú)設(shè)備樹(shù)時(shí)候通過(guò) platform_device.name 和 platform_driver.driver.name 進(jìn)行匹配。
1、makefile
KERNELDIR := /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga CURRENT_PATH := $(shell pwd) obj-m := led_device.o obj-m += led_driver.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean2、device
1、搭建框架
思路:
1、驅(qū)動(dòng)加載函數(shù) led_device_init 調(diào)用 platform_device_register 進(jìn)行注冊(cè)設(shè)備。
2、platform_device_register 函數(shù)將 platform_device 結(jié)構(gòu)體變量注冊(cè)到系統(tǒng)。
3、platform_device 結(jié)構(gòu)體使用 resource 結(jié)構(gòu)體變量指定資源信息。
源碼:
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h"/* * 設(shè)備資源信息,也就是LED0所使用的所有寄存器*/ static struct resource led_resources[] = {};/* @description : 釋放flatform設(shè)備模塊的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : 要釋放的設(shè)備* @return : 無(wú)*/ static void led_release(struct device *dev) {printk("led device released!\r\n"); }/** platform設(shè)備結(jié)構(gòu)體 */ static struct platform_device led_device = {.name = "imx6ul-led",.id = -1,.dev = {.release = &led_release,},.num_resources = ARRAY_SIZE(led_resources),.resource = led_resources, };/** @description : 設(shè)備模塊加載 * @param : 無(wú)* @return : 無(wú)*/ static int __init led_device_init(void) {return platform_device_register(&led_device); }/** @description : 設(shè)備模塊注銷(xiāo)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_device_exit(void) {platform_device_unregister(&led_device); }module_init(led_device_init); module_exit(led_device_exit); MODULE_LICENSE("GPL");編譯:
onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_driver.c Makefile onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ make make -C /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/onlylove/linux/driver/linux_driver/9_platform modules make[1]: Entering directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga'CC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.oCC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.oBuilding modules, stage 2.MODPOST 2 modulesCC /home/onlylove/linux/driver/linux_driver/9_platform/led_device.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.koCC /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.ko make[1]: Leaving directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga' onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_device.mod.c led_device.o led_driver.ko led_driver.mod.o Makefile Module.symvers led_device.ko led_device.mod.o led_driver.c led_driver.mod.c led_driver.o modules.order onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$測(cè)試:
/ # ls bin led_device.ko mnt sbin usr dev lib proc sys etc linuxrc root tmp / # lsmod Module Size Used by Not tainted / # cd /sys/bus/platform/devices/ /sys/bus/platform/devices # ls 1804000.dma-apbh 2184000.usb 2000000.aips-bus 2184200.usb 2000000.aips-bus:tempmon 2184800.usbmisc 2000000.spba-bus 2188000.ethernet 2020000.serial 2190000.usdhc 202c000.sai 2194000.usdhc 2034000.asrc 21a0000.i2c 2040000.tsc 21a4000.i2c 2080000.pwm 21ac000.romcp 2084000.pwm 21b0000.mmdc 2088000.pwm 21b8000.weim 208c000.pwm 21bc000.ocotp-ctrl 2090000.can 21c4000.csi 2094000.can 21c8000.lcdif 2098000.gpt 21cc000.pxp 209c000.gpio 21e0000.qspi 20a0000.gpio 21e8000.serial 20a4000.gpio 2200000.aips-bus 20a8000.gpio 2280000.dcp 20ac000.gpio 2284000.rngb 20b0000.snvs 2290000.iomuxc-snvs 20b4000.ethernet 2294000.snvs-gpr 20bc000.wdog 900000.sram 20c4000.ccm 904000.sram 20c406c.lq-led 905000.sram 20c8000.anatop Vivante GCCore 20c8000.anatop:regulator-3p0@120 a01000.interrupt-controller 20c8000.anatop:regulator-vddcore@140 alarmtimer 20c8000.anatop:regulator-vddsoc@140 backlight 20c9000.usbphy ci_hdrc.0 20ca000.usbphy ci_hdrc.1 20cc000.snvs gpioled 20cc000.snvs:snvs-powerkey imx6q-cpufreq 20cc000.snvs:snvs-poweroff lq-key 20cc000.snvs:snvs-rtc-lp pxp_v4l2 20d8000.src reg-dummy 20dc000.gpc regulators 20e0000.iomuxc regulators:regulator-gpio 20e4000.iomuxc-gpr regulators:regulator@0 20e8000.gpt regulators:regulator@1 20ec000.sdma regulatory.0 20f0000.pwm snd-soc-dummy 20f4000.pwm soc 20f8000.pwm soc:busfreq 20fc000.pwm sound 2100000.aips-bus spi4 /sys/bus/platform/devices # cd / # ls bin led_device.ko mnt sbin usr dev lib proc sys etc linuxrc root tmp / # insmod led_device.ko / # lsmod Module Size Used by Tainted: G led_device 1266 0 / # cd /sys/bus/platform/devices/ /sys/bus/platform/devices # ls 1804000.dma-apbh 2184200.usb 2000000.aips-bus 2184800.usbmisc 2000000.aips-bus:tempmon 2188000.ethernet 2000000.spba-bus 2190000.usdhc 2020000.serial 2194000.usdhc 202c000.sai 21a0000.i2c 2034000.asrc 21a4000.i2c 2040000.tsc 21ac000.romcp 2080000.pwm 21b0000.mmdc 2084000.pwm 21b8000.weim 2088000.pwm 21bc000.ocotp-ctrl 208c000.pwm 21c4000.csi 2090000.can 21c8000.lcdif 2094000.can 21cc000.pxp 2098000.gpt 21e0000.qspi 209c000.gpio 21e8000.serial 20a0000.gpio 2200000.aips-bus 20a4000.gpio 2280000.dcp 20a8000.gpio 2284000.rngb 20ac000.gpio 2290000.iomuxc-snvs 20b0000.snvs 2294000.snvs-gpr 20b4000.ethernet 900000.sram 20bc000.wdog 904000.sram 20c4000.ccm 905000.sram 20c406c.lq-led Vivante GCCore 20c8000.anatop a01000.interrupt-controller 20c8000.anatop:regulator-3p0@120 alarmtimer 20c8000.anatop:regulator-vddcore@140 backlight 20c8000.anatop:regulator-vddsoc@140 ci_hdrc.0 20c9000.usbphy ci_hdrc.1 20ca000.usbphy gpioled 20cc000.snvs imx6q-cpufreq 20cc000.snvs:snvs-powerkey imx6ul-led 20cc000.snvs:snvs-poweroff lq-key 20cc000.snvs:snvs-rtc-lp pxp_v4l2 20d8000.src reg-dummy 20dc000.gpc regulators 20e0000.iomuxc regulators:regulator-gpio 20e4000.iomuxc-gpr regulators:regulator@0 20e8000.gpt regulators:regulator@1 20ec000.sdma regulatory.0 20f0000.pwm snd-soc-dummy 20f4000.pwm soc 20f8000.pwm soc:busfreq 20fc000.pwm sound 2100000.aips-bus spi4 2184000.usb /sys/bus/platform/devices # /sys/bus/platform/devices # cd / # lsmod Module Size Used by Tainted: G led_device 1266 0 / # ls bin led_device.ko mnt sbin usr dev lib proc sys etc linuxrc root tmp / # rmmod led_device.ko led device released! / # lsmod Module Size Used by Tainted: G / #通過(guò)測(cè)試,imx6ul-led 設(shè)備信息出現(xiàn)在 /sys/bus/platform/devices 目錄下,說(shuō)明 led_device 加載成功。
2、添加資源信息
思路:
1、定義使用到的寄存器信息(主要是寄存器地址)
2、完善 resource 數(shù)組
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h"/* * 寄存器地址定義*/ #define CCM_CCGR1_BASE (0X020C406C) #define SW_MUX_GPIO1_IO03_BASE (0X020E0068) #define SW_PAD_GPIO1_IO03_BASE (0X020E02F4) #define GPIO1_DR_BASE (0X0209C000) #define GPIO1_GDIR_BASE (0X0209C004) #define REGISTER_LENGTH 4/* * 設(shè)備資源信息,也就是LED0所使用的所有寄存器*/ static struct resource led_resources[] = {[0] = {.start = CCM_CCGR1_BASE,.end = (CCM_CCGR1_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,}, [1] = {.start = SW_MUX_GPIO1_IO03_BASE,.end = (SW_MUX_GPIO1_IO03_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,},[2] = {.start = SW_PAD_GPIO1_IO03_BASE,.end = (SW_PAD_GPIO1_IO03_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,},[3] = {.start = GPIO1_DR_BASE,.end = (GPIO1_DR_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,},[4] = {.start = GPIO1_GDIR_BASE,.end = (GPIO1_GDIR_BASE + REGISTER_LENGTH - 1),.flags = IORESOURCE_MEM,}, };/* @description : 釋放flatform設(shè)備模塊的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : 要釋放的設(shè)備* @return : 無(wú)*/ static void led_release(struct device *dev) {printk("led device released!\r\n"); }/** platform設(shè)備結(jié)構(gòu)體 */ static struct platform_device led_device = {.name = "imx6ul-led",.id = -1,.dev = {.release = &led_release,},.num_resources = ARRAY_SIZE(led_resources),.resource = led_resources, };/** @description : 設(shè)備模塊加載 * @param : 無(wú)* @return : 無(wú)*/ static int __init led_device_init(void) {return platform_device_register(&led_device); }/** @description : 設(shè)備模塊注銷(xiāo)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_device_exit(void) {platform_device_unregister(&led_device); }module_init(led_device_init); module_exit(led_device_exit); MODULE_LICENSE("GPL");3、driver
1、搭建框架
源碼:
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h"/** @description : flatform驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_probe(struct platform_device *dev) {printk("led probe!\r\n");return 0; }/** @description : platform驅(qū)動(dòng)的remove函數(shù),移除platform驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_remove(struct platform_device *dev) {printk("led remove!\r\n");return 0; }/* platform驅(qū)動(dòng)結(jié)構(gòu)體 */ static struct platform_driver led_driver = {.driver = {.name = "imx6ul-led", /* 驅(qū)動(dòng)名字,用于和設(shè)備匹配 */},.probe = led_probe,.remove = led_remove, };/** @description : 驅(qū)動(dòng)模塊加載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static int __init led_driver_init(void) {return platform_driver_register(&led_driver); }/** @description : 驅(qū)動(dòng)模塊卸載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_driver_exit(void) {platform_driver_unregister(&led_driver); }module_init(led_driver_init); module_exit(led_driver_exit); MODULE_LICENSE("GPL");編譯:
onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_driver.c Makefile onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ make make -C /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/onlylove/linux/driver/linux_driver/9_platform modules make[1]: Entering directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga'CC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.oCC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.oBuilding modules, stage 2.MODPOST 2 modulesCC /home/onlylove/linux/driver/linux_driver/9_platform/led_device.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.koCC /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.ko make[1]: Leaving directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga' onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_device.mod.c led_device.o led_driver.ko led_driver.mod.o Makefile Module.symvers led_device.ko led_device.mod.o led_driver.c led_driver.mod.c led_driver.o modules.order onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$測(cè)試:
/ # ls bin led_device.ko linuxrc root tmp dev led_driver.ko mnt sbin usr etc lib proc sys / # lsmod Module Size Used by Not tainted / # insmod led_device.ko / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # insmod led_driver.ko led probe! / # lsmod Module Size Used by Tainted: G led_driver 1014 0 led_device 1410 0 / # / # rmmod led_driver.ko led remove! / # ls bin led_device.ko linuxrc root tmp dev led_driver.ko mnt sbin usr etc lib proc sys / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # insmod led— insmod: can't insert 'led—?': No such file or directory / # / # insmod led_driver.ko led probe! / # / # lsmod Module Size Used by Tainted: G led_driver 1014 0 led_device 1410 0 / # / # rmmod led_device.ko led remove! led device released! / # / # lsmod Module Size Used by Tainted: G led_driver 1014 0 / # / # insmod led_device.ko led probe! / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 led_driver 1014 0 / # / # rmmod led_driver.ko led remove! / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # rmmod led_driver.ko rmmod: can't unload module 'led_driver': No such file or directory / # / # rmmod led_device.ko led device released! / # / # lsmod Module Size Used by Tainted: G / #2、完善驅(qū)動(dòng)框架
思路:
1、在 probe 函數(shù)中對(duì)驅(qū)動(dòng)進(jìn)行初始化。
2、在 remove 函數(shù)中完成卸載。
源碼:
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/fs.h" #include "linux/kdev_t.h" #include "linux/printk.h"#define NEWCHRDEV_MAJOR 0 /* 主設(shè)備號(hào)(如果為0則讓系統(tǒng)自動(dòng)分配,如果大于0則使用指定設(shè)備號(hào)) */ #define NEWCHRDEV_MINOR 0 /* 次設(shè)備號(hào) */ #define NEWCHRDEV_COUNT 1 /* 設(shè)備號(hào)個(gè)數(shù) */ #define NEWCHRDEV_NAME "imx6ul-led" /* 名子 */typedef struct{struct cdev dev; /* cdev 結(jié)構(gòu)體 (聲明在 "linux/cdev.h")*/int major; /* 主設(shè)備號(hào) */int minor; /* 次設(shè)備號(hào) */dev_t devid; /* 設(shè)備號(hào) */struct class *class; /* 類(lèi) (聲明在 "linux/device.h")*/struct device *device; /* 設(shè)備 (聲明在 "linux/device.h") */ }newchrdev_t;newchrdev_t newchrdev;static const struct file_operations newchrdevops = {.owner = THIS_MODULE, };/** @description : flatform驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_probe(struct platform_device *dev) {int ret;/* 1、字符設(shè)備號(hào)分配 */newchrdev.major = NEWCHRDEV_MAJOR;if(newchrdev.major){/* 指定設(shè)備號(hào) */newchrdev.minor = NEWCHRDEV_MINOR;newchrdev.devid = MKDEV(newchrdev.major, newchrdev.minor);ret = register_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);printk("newchrdev.major > 0!\r\n");}else{/* 系統(tǒng)分配設(shè)備號(hào) */ret = alloc_chrdev_region(&newchrdev.devid,0,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);newchrdev.major = MAJOR(newchrdev.devid);newchrdev.minor = MINOR(newchrdev.devid);printk("newchrdev.major = 0!\r\n");}if(ret < 0){printk("newchrdev xxx_chrdev_region failed!\r\n");goto newchrdev_chrdev_region_failed;}printk("newchrdev devid = %d newchrdev major=%d,minor=%d\r\n",newchrdev.devid,newchrdev.major,newchrdev.minor);/* 2、注冊(cè)字符設(shè)備 */newchrdev.dev.owner = THIS_MODULE;cdev_init(&newchrdev.dev,&newchrdevops);ret = cdev_add(&newchrdev.dev,newchrdev.devid,NEWCHRDEV_COUNT);if(ret < 0){printk("newchrdev cdev_add failed!\r\n");goto newchrdev_cdev_add_failed;}/* 3、創(chuàng)建類(lèi) */newchrdev.class = class_create(THIS_MODULE,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.class)) {printk("newchrdev class_create failed!\r\n");goto newchrdev_class_create_failed;}/* 4、創(chuàng)建設(shè)備 */newchrdev.device = device_create(newchrdev.class,NULL,newchrdev.devid,NULL,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.device)){printk("newchrdev device_create failed!\r\n");goto neschrdev_device_creat_failed;}return 0;//neschrdev_device_xxx_failed: /* 其他操作失敗(添加其他文件時(shí),打開(kāi)此選項(xiàng)) */ // device_destroy(newchrdev.class,newchrdev.devid); neschrdev_device_creat_failed: /* 刪除類(lèi) */class_destroy(newchrdev.class); newchrdev_class_create_failed: /*注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev); newchrdev_cdev_add_failed: /* 釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT); newchrdev_chrdev_region_failed: /* 字符設(shè)備號(hào)分配失敗處理函數(shù)(未分配資源,因此不做處理) */printk("failed!\r\n");return ret; }/** @description : platform驅(qū)動(dòng)的remove函數(shù),移除platform驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_remove(struct platform_device *dev) {/* 4、刪除設(shè)備 */device_destroy(newchrdev.class,newchrdev.devid);/* 3、刪除類(lèi) */class_destroy(newchrdev.class);/* 2、注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev);/* 1、釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT);printk("led remove!\r\n");return 0; }/* platform驅(qū)動(dòng)結(jié)構(gòu)體 */ static struct platform_driver led_driver = {.driver = {.name = "imx6ul-led", /* 驅(qū)動(dòng)名字,用于和設(shè)備匹配 */},.probe = led_probe,.remove = led_remove, };/** @description : 驅(qū)動(dòng)模塊加載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static int __init led_driver_init(void) {return platform_driver_register(&led_driver); }/** @description : 驅(qū)動(dòng)模塊卸載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_driver_exit(void) {platform_driver_unregister(&led_driver); }module_init(led_driver_init); module_exit(led_driver_exit); MODULE_LICENSE("GPL");編譯:
onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_driver.c Makefile onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ make make -C /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/onlylove/linux/driver/linux_driver/9_platform modules make[1]: Entering directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga'CC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.oCC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.oBuilding modules, stage 2.MODPOST 2 modulesCC /home/onlylove/linux/driver/linux_driver/9_platform/led_device.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.koCC /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.ko make[1]: Leaving directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga' onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_device.c led_device.mod.c led_device.o led_driver.ko led_driver.mod.o Makefile Module.symvers led_device.ko led_device.mod.o led_driver.c led_driver.mod.c led_driver.o modules.order onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$測(cè)試:
/ # ls bin led_device.ko linuxrc root tmp dev led_driver.ko mnt sbin usr etc lib proc sys / # / # lsmod Module Size Used by Not tainted / # / # insmod led_device.ko / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # ls /dev/imx6ul-led -l ls: /dev/imx6ul-led: No such file or directory / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 07:39 /dev/imx6ul-led / # random: nonblocking pool is initialized/ # / # rmmod led_driver.ko led remove! / # / # ls /dev/imx6ul-led -l ls: /dev/imx6ul-led: No such file or directory / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 / # / # lsmod Module Size Used by Tainted: G led_driver 2126 0 led_device 1410 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 07:39 /dev/imx6ul-led / # / # rmmod led_device.ko led remove! led device released! / # lsmod Module Size Used by Tainted: G led_driver 2126 0 / # / # ls /dev/imx6ul-led -l ls: /dev/imx6ul-led: No such file or directory / # / # insmod led_device.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 led_driver 2126 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 07:40 /dev/imx6ul-led / # / #3、添加 led 相關(guān)操作
源碼:
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/fs.h" #include "linux/kdev_t.h" #include "linux/printk.h" #include "asm/io.h" #include "linux/types.h" #include "linux/compiler.h" #include "linux/types.h" #include "asm/uaccess.h"#define NEWCHRDEV_MAJOR 0 /* 主設(shè)備號(hào)(如果為0則讓系統(tǒng)自動(dòng)分配,如果大于0則使用指定設(shè)備號(hào)) */ #define NEWCHRDEV_MINOR 0 /* 次設(shè)備號(hào) */ #define NEWCHRDEV_COUNT 1 /* 設(shè)備號(hào)個(gè)數(shù) */ #define NEWCHRDEV_NAME "imx6ul-led" /* 名子 */#define LEDOFF 0 /* 關(guān)燈 */ #define LEDON 1 /* 開(kāi)燈 *//* 寄存器名 */ static void __iomem *IMX6U_CCM_CCGR1; static void __iomem *SW_MUX_GPIO1_IO03; static void __iomem *SW_PAD_GPIO1_IO03; static void __iomem *GPIO1_DR; static void __iomem *GPIO1_GDIR;typedef struct{struct cdev dev; /* cdev 結(jié)構(gòu)體 (聲明在 "linux/cdev.h")*/int major; /* 主設(shè)備號(hào) */int minor; /* 次設(shè)備號(hào) */dev_t devid; /* 設(shè)備號(hào) */struct class *class; /* 類(lèi) (聲明在 "linux/device.h")*/struct device *device; /* 設(shè)備 (聲明在 "linux/device.h") */ }newchrdev_t;newchrdev_t newchrdev;int imx6ull_led_init(struct platform_device *dev) {int i = 0;int ressize[5];u32 val = 0;struct resource *ledsource[5];/* 1、獲取資源 */for (i = 0; i < 5; i++) {ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i); /* 依次MEM類(lèi)型資源 */if (!ledsource[i]) {dev_err(&dev->dev, "No MEM resource for always on\n");return 1;}ressize[i] = resource_size(ledsource[i]); } /* 2、初始化LED *//* 寄存器地址映射 */IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start, ressize[0]);SW_MUX_GPIO1_IO03 = ioremap(ledsource[1]->start, ressize[1]);SW_PAD_GPIO1_IO03 = ioremap(ledsource[2]->start, ressize[2]);GPIO1_DR = ioremap(ledsource[3]->start, ressize[3]);GPIO1_GDIR = ioremap(ledsource[4]->start, ressize[4]);val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26); /* 清除以前的設(shè)置 */val |= (3 << 26); /* 設(shè)置新值 */writel(val, IMX6U_CCM_CCGR1);/* 設(shè)置GPIO1_IO03復(fù)用功能,將其復(fù)用為GPIO1_IO03 */writel(5, SW_MUX_GPIO1_IO03);writel(0x10B0, SW_PAD_GPIO1_IO03);/* 設(shè)置GPIO1_IO03為輸出功能 */val = readl(GPIO1_GDIR);val &= ~(1 << 3); /* 清除以前的設(shè)置 */val |= (1 << 3); /* 設(shè)置為輸出 */writel(val, GPIO1_GDIR);/* 默認(rèn)關(guān)閉LED1 */val = readl(GPIO1_DR);val |= (1 << 3) ; writel(val, GPIO1_DR);printk("imx6ull led init!\r\n");return 0; }int imx6ull_led_exit(void) {iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);printk("imx6ull led exit!\r\n");return 0; }/** @description : LED打開(kāi)/關(guān)閉* @param - sta : LEDON(0) 打開(kāi)LED,LEDOFF(1) 關(guān)閉LED* @return : 無(wú)*/ void led_switch(u8 sta) {u32 val = 0;if(sta == LEDON) {val = readl(GPIO1_DR);val &= ~(1 << 3); writel(val, GPIO1_DR);}else if(sta == LEDOFF) {val = readl(GPIO1_DR);val|= (1 << 3); writel(val, GPIO1_DR);} }// struct inode 聲明在 linux/fs.h 中 // struct file 聲明在 linux/fs.h 中 int led_open (struct inode *i, struct file *f) {return 0; }int led_release (struct inode *i, struct file *f) {return 0; }// ssize_t 定義在 linux/types.h 中 // __user 定義在 linux/compiler.h 中 // size_t 定義在 linux/types.h 中 // loff_t 定義在 linux/types.h 中 ssize_t led_read (struct file *f, char __user *b, size_t c, loff_t * l) {printk("led read!\r\n");return 0; }/** @description : 向設(shè)備寫(xiě)數(shù)據(jù) * @param - f : 設(shè)備文件,表示打開(kāi)的文件描述符* @param - b : 要寫(xiě)給設(shè)備寫(xiě)入的數(shù)據(jù)* @param - c : 要寫(xiě)入的數(shù)據(jù)長(zhǎng)度* @param - l : 相對(duì)于文件首地址的偏移* @return : 寫(xiě)入的字節(jié)數(shù),如果為負(fù)值,表示寫(xiě)入失敗*/ ssize_t led_write (struct file *f, const char __user *b, size_t c, loff_t *l) {int retvalue;unsigned char databuf[1];unsigned char ledstat;printk("led write!\r\n");retvalue = copy_from_user(databuf, b, c);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0]; /* 獲取狀態(tài)值 */if(ledstat == LEDON) { led_switch(LEDON); /* 打開(kāi)LED燈 */} else if(ledstat == LEDOFF) {led_switch(LEDOFF); /* 關(guān)閉LED燈 */}return 0; }static const struct file_operations newchrdevops = {.owner = THIS_MODULE,.open = led_open,.release = led_release,.read = led_read,.write = led_write, };/** @description : flatform驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_probe(struct platform_device *dev) {int ret;/* 1、字符設(shè)備號(hào)分配 */newchrdev.major = NEWCHRDEV_MAJOR;if(newchrdev.major){/* 指定設(shè)備號(hào) */newchrdev.minor = NEWCHRDEV_MINOR;newchrdev.devid = MKDEV(newchrdev.major, newchrdev.minor);ret = register_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);printk("newchrdev.major > 0!\r\n");}else{/* 系統(tǒng)分配設(shè)備號(hào) */ret = alloc_chrdev_region(&newchrdev.devid,0,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);newchrdev.major = MAJOR(newchrdev.devid);newchrdev.minor = MINOR(newchrdev.devid);printk("newchrdev.major = 0!\r\n");}if(ret < 0){printk("newchrdev xxx_chrdev_region failed!\r\n");goto newchrdev_chrdev_region_failed;}printk("newchrdev devid = %d newchrdev major=%d,minor=%d\r\n",newchrdev.devid,newchrdev.major,newchrdev.minor);/* 2、注冊(cè)字符設(shè)備 */newchrdev.dev.owner = THIS_MODULE;cdev_init(&newchrdev.dev,&newchrdevops);ret = cdev_add(&newchrdev.dev,newchrdev.devid,NEWCHRDEV_COUNT);if(ret < 0){printk("newchrdev cdev_add failed!\r\n");goto newchrdev_cdev_add_failed;}/* 3、創(chuàng)建類(lèi) */newchrdev.class = class_create(THIS_MODULE,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.class)) {printk("newchrdev class_create failed!\r\n");goto newchrdev_class_create_failed;}/* 4、創(chuàng)建設(shè)備 */newchrdev.device = device_create(newchrdev.class,NULL,newchrdev.devid,NULL,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.device)){printk("newchrdev device_create failed!\r\n");goto newchrdev_device_creat_failed;}ret = imx6ull_led_init(dev);if(ret != 0){goto newchrdev_device_xxx_failed;}return 0;newchrdev_device_xxx_failed: /* 其他操作失敗(添加其他文件時(shí),打開(kāi)此選項(xiàng)) */device_destroy(newchrdev.class,newchrdev.devid); newchrdev_device_creat_failed: /* 刪除類(lèi) */class_destroy(newchrdev.class); newchrdev_class_create_failed: /*注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev); newchrdev_cdev_add_failed: /* 釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT); newchrdev_chrdev_region_failed: /* 字符設(shè)備號(hào)分配失敗處理函數(shù)(未分配資源,因此不做處理) */printk("failed!\r\n");return ret; }/** @description : platform驅(qū)動(dòng)的remove函數(shù),移除platform驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_remove(struct platform_device *dev) {imx6ull_led_exit();/* 4、刪除設(shè)備 */device_destroy(newchrdev.class,newchrdev.devid);/* 3、刪除類(lèi) */class_destroy(newchrdev.class);/* 2、注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev);/* 1、釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT);printk("led remove!\r\n");return 0; }/* platform驅(qū)動(dòng)結(jié)構(gòu)體 */ static struct platform_driver led_driver = {.driver = {.name = "imx6ul-led", /* 驅(qū)動(dòng)名字,用于和設(shè)備匹配 */},.probe = led_probe,.remove = led_remove, };/** @description : 驅(qū)動(dòng)模塊加載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static int __init led_driver_init(void) {return platform_driver_register(&led_driver); }/** @description : 驅(qū)動(dòng)模塊卸載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_driver_exit(void) {platform_driver_unregister(&led_driver); }module_init(led_driver_init); module_exit(led_driver_exit); MODULE_LICENSE("GPL");編譯:
onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ make make -C /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/onlylove/linux/driver/linux_driver/9_platform modules make[1]: Entering directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga'CC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.oCC [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.oBuilding modules, stage 2.MODPOST 2 modulesCC /home/onlylove/linux/driver/linux_driver/9_platform/led_device.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_device.koCC /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/9_platform/led_driver.ko make[1]: Leaving directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga' onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$ ls led_app.c led_device.ko led_device.mod.o led_driver.c led_driver.mod.c led_driver.o modules.order led_device.c led_device.mod.c led_device.o led_driver.ko led_driver.mod.o Makefile Module.symvers onlylove@ubuntu:~/linux/driver/linux_driver/9_platform$測(cè)試:
/ # ls bin led_app lib proc sys dev led_device.ko linuxrc root tmp etc led_driver.ko mnt sbin usr / # lsmod Module Size Used by Not tainted / # / # insmod led_device.ko / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! / # lsmod Module Size Used by Tainted: G led_driver 3854 0 led_device 1410 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 00:24 /dev/imx6ul-led / # / # rmmod led_device.ko imx6ull led exit! led remove! led device released! / # lsmod Module Size Used by Tainted: G led_driver 3854 0 / # ls /dev/imx6ul-led -l ls: /dev/imx6ul-led: No such file or directory / # / # insmod led_device.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 led_driver 3854 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 00:24 /dev/imx6ul-led / # / # rmmod led_driver.ko imx6ull led exit! led remove! / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # ls /dev/imx6ul-led -l ls: /dev/imx6ul-led: No such file or directory / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! / # / # lsmod Module Size Used by Tainted: G led_driver 3854 0 led_device 1410 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 00:26 /dev/imx6ul-led / #4、app程序
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "stdio.h"int main(int argc, char *argv[]) {int fd = 0, retvalue = 0;char writebuf[1] = "";fd = open(argv[1],O_RDWR);if(fd < 0){printf("Can't open file %s\r\n", argv[1]);return -1;}writebuf[0] = atoi(argv[2]);// 打開(kāi) ledwrite(fd, writebuf, 1);retvalue = close(fd);if(retvalue < 0){printf("Can't close file %s\r\n", argv[1]);return -1;}return 0; }編譯:
arm-linux-gnueabihf-gcc led_app.c -o led_app5、測(cè)試
思路:
1、加載設(shè)備。
2、加載驅(qū)動(dòng)。
3、執(zhí)行app程序。
測(cè)試過(guò)程:
/ # ls bin led_app lib proc sys dev led_device.ko linuxrc root tmp etc led_driver.ko mnt sbin usr / # lsmod Module Size Used by Not tainted / # / # insmod led_device.ko / # / # lsmod Module Size Used by Tainted: G led_device 1410 0 / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! / # / # lsmod Module Size Used by Tainted: G led_driver 3854 0 led_device 1410 0 / # / # ls /dev/imx6ul-led -l crw-rw---- 1 0 0 248, 0 Jan 1 00:30 /dev/imx6ul-led / # / # ./led_app /dev/imx6ul-led 1 led write! / # / # ./led_app /dev/imx6ul-led 0 led write! / # / # random: nonblocking pool is initialized / # ./led_app /dev/imx6ul-led 1 led write! / # / # ./led_app /dev/imx6ul-led 0 led write! / # / # rmmod led_driver.ko imx6ull led exit! led remove! / # / # rmmod led_device.ko led device released! / # / # lsmod Module Size Used by Tainted: G / #通過(guò)以上測(cè)試,開(kāi)發(fā)板上 led 燈可以正常點(diǎn)亮和關(guān)閉。
三、有設(shè)備樹(shù)源碼實(shí)現(xiàn)
有設(shè)備樹(shù)時(shí),通過(guò) platform_driver.driver.of_match_table.compatible 和 設(shè)備樹(shù)中 compatible 進(jìn)行匹配。
1、設(shè)備樹(shù)
支持設(shè)備樹(shù)驅(qū)動(dòng)不需要 device 源碼,設(shè)備信息由設(shè)備樹(shù)提供。
gpioled {compatible = "gpioled";status = "okay";pinctrl-names = "default";pinctrl-0 = <&pinctrl_led>;led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; };2、driver
1、搭建架構(gòu)
源碼:
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/fs.h" #include "linux/kdev_t.h" #include "linux/printk.h"#define NEWCHRDEV_MAJOR 0 /* 主設(shè)備號(hào)(如果為0則讓系統(tǒng)自動(dòng)分配,如果大于0則使用指定設(shè)備號(hào)) */ #define NEWCHRDEV_MINOR 0 /* 次設(shè)備號(hào) */ #define NEWCHRDEV_COUNT 1 /* 設(shè)備號(hào)個(gè)數(shù) */ #define NEWCHRDEV_NAME "imx6ull-led" /* 名子 */typedef struct{struct cdev dev; /* cdev 結(jié)構(gòu)體 (聲明在 "linux/cdev.h")*/int major; /* 主設(shè)備號(hào) */int minor; /* 次設(shè)備號(hào) */dev_t devid; /* 設(shè)備號(hào) */struct class *class; /* 類(lèi) (聲明在 "linux/device.h")*/struct device *device; /* 設(shè)備 (聲明在 "linux/device.h") */ }newchrdev_t;newchrdev_t newchrdev;// struct inode 聲明在 linux/fs.h 中 // struct file 聲明在 linux/fs.h 中 int led_open (struct inode *i, struct file *f) {return 0; }int led_release (struct inode *i, struct file *f) {return 0; }// ssize_t 定義在 linux/types.h 中 // __user 定義在 linux/compiler.h 中 // size_t 定義在 linux/types.h 中 // loff_t 定義在 linux/types.h 中 ssize_t led_read (struct file *f, char __user *b, size_t c, loff_t * l) {printk("led read!\r\n");return 0; }/** @description : 向設(shè)備寫(xiě)數(shù)據(jù) * @param - f : 設(shè)備文件,表示打開(kāi)的文件描述符* @param - b : 要寫(xiě)給設(shè)備寫(xiě)入的數(shù)據(jù)* @param - c : 要寫(xiě)入的數(shù)據(jù)長(zhǎng)度* @param - l : 相對(duì)于文件首地址的偏移* @return : 寫(xiě)入的字節(jié)數(shù),如果為負(fù)值,表示寫(xiě)入失敗*/ ssize_t led_write (struct file *f, const char __user *b, size_t c, loff_t *l) {printk("led write!\r\n");return 0; }static const struct file_operations newchrdevops = {.owner = THIS_MODULE,.open = led_open,.release = led_release,.read = led_read,.write = led_write, };/** @description : flatform驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_probe(struct platform_device *dev) {int ret;/* 1、字符設(shè)備號(hào)分配 */newchrdev.major = NEWCHRDEV_MAJOR;if(newchrdev.major){/* 指定設(shè)備號(hào) */newchrdev.minor = NEWCHRDEV_MINOR;newchrdev.devid = MKDEV(newchrdev.major, newchrdev.minor);ret = register_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);printk("newchrdev.major > 0!\r\n");}else{/* 系統(tǒng)分配設(shè)備號(hào) */ret = alloc_chrdev_region(&newchrdev.devid,0,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);newchrdev.major = MAJOR(newchrdev.devid);newchrdev.minor = MINOR(newchrdev.devid);printk("newchrdev.major = 0!\r\n");}if(ret < 0){printk("newchrdev xxx_chrdev_region failed!\r\n");goto newchrdev_chrdev_region_failed;}printk("newchrdev devid = %d newchrdev major=%d,minor=%d\r\n",newchrdev.devid,newchrdev.major,newchrdev.minor);/* 2、注冊(cè)字符設(shè)備 */newchrdev.dev.owner = THIS_MODULE;cdev_init(&newchrdev.dev,&newchrdevops);ret = cdev_add(&newchrdev.dev,newchrdev.devid,NEWCHRDEV_COUNT);if(ret < 0){printk("newchrdev cdev_add failed!\r\n");goto newchrdev_cdev_add_failed;}/* 3、創(chuàng)建類(lèi) */newchrdev.class = class_create(THIS_MODULE,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.class)) {printk("newchrdev class_create failed!\r\n");goto newchrdev_class_create_failed;}/* 4、創(chuàng)建設(shè)備 */newchrdev.device = device_create(newchrdev.class,NULL,newchrdev.devid,NULL,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.device)){printk("newchrdev device_create failed!\r\n");goto newchrdev_device_creat_failed;}printk("led probe!\r\n");return 0;//newchrdev_device_xxx_failed: /* 其他操作失敗(添加其他文件時(shí),打開(kāi)此選項(xiàng)) */ // device_destroy(newchrdev.class,newchrdev.devid); newchrdev_device_creat_failed: /* 刪除類(lèi) */class_destroy(newchrdev.class); newchrdev_class_create_failed: /*注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev); newchrdev_cdev_add_failed: /* 釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT); newchrdev_chrdev_region_failed: /* 字符設(shè)備號(hào)分配失敗處理函數(shù)(未分配資源,因此不做處理) */printk("failed!\r\n");return ret; }/** @description : platform驅(qū)動(dòng)的remove函數(shù),移除platform驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_remove(struct platform_device *dev) {/* 4、刪除設(shè)備 */device_destroy(newchrdev.class,newchrdev.devid);/* 3、刪除類(lèi) */class_destroy(newchrdev.class);/* 2、注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev);/* 1、釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT);printk("led remove!\r\n");return 0; }/* 匹配列表 */ static const struct of_device_id led_of_match[] = {{ .compatible = "gpioled" },{ /* Sentinel */ } };/* platform驅(qū)動(dòng)結(jié)構(gòu)體 */ static struct platform_driver led_driver = {.driver = {.name = "imx6ul-led", /* 驅(qū)動(dòng)名字,用于和設(shè)備匹配 */.of_match_table = led_of_match, /* 設(shè)備樹(shù)匹配表 */},.probe = led_probe,.remove = led_remove, };/** @description : 驅(qū)動(dòng)模塊加載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static int __init led_driver_init(void) {return platform_driver_register(&led_driver); }/** @description : 驅(qū)動(dòng)模塊卸載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_driver_exit(void) {platform_driver_unregister(&led_driver); }module_init(led_driver_init); module_exit(led_driver_exit); MODULE_LICENSE("GPL");編譯:
onlylove@ubuntu:~/linux/driver/linux_driver/10_platform_dts$ ls led_driver.c Makefile onlylove@ubuntu:~/linux/driver/linux_driver/10_platform_dts$ make make -C /home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga M=/home/onlylove/linux/driver/linux_driver/10_platform_dts modules make[1]: Entering directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga'CC [M] /home/onlylove/linux/driver/linux_driver/10_platform_dts/led_driver.oBuilding modules, stage 2.MODPOST 1 modulesCC /home/onlylove/linux/driver/linux_driver/10_platform_dts/led_driver.mod.oLD [M] /home/onlylove/linux/driver/linux_driver/10_platform_dts/led_driver.ko make[1]: Leaving directory '/home/onlylove/linux/linux/lq_linux/linux-imx-rel_imx_4.1.15_2.1.0_ga' onlylove@ubuntu:~/linux/driver/linux_driver/10_platform_dts$ ls led_driver.c led_driver.ko led_driver.mod.c led_driver.mod.o led_driver.o Makefile modules.order Module.symvers onlylove@ubuntu:~/linux/driver/linux_driver/10_platform_dts$測(cè)試:
/ # ls bin led_driver.ko mnt sbin usr dev lib proc sys etc linuxrc root tmp / # lsmod Module Size Used by Not tainted / # cd /sys/firmware/devicetree/base/ /sys/firmware/devicetree/base # ls #address-cells lq-led #size-cells memory aliases model backlight name chosen pxp_v4l2 clocks regulators compatible reserved-memory cpus soc gpioled sound interrupt-controller@00a01000 spi4 lq-key /sys/firmware/devicetree/base # cd gpioled/ /sys/firmware/devicetree/base/gpioled # ls compatible name pinctrl-names led-gpio pinctrl-0 status /sys/firmware/devicetree/base/gpioled # cat compatible gpioled /sys/firmware/devicetree/base/gpioled #通過(guò)以上日志可以確定,設(shè)備樹(shù) gpioled 節(jié)點(diǎn)成功加載。
/ # ls /sys/bus/platform/drivers/imx6ul-led -l ls: /sys/bus/platform/drivers/imx6ul-led: No such file or directory / # / # ls /dev/imx6ull-led -l ls: /dev/imx6ull-led: No such file or directory / # / # lsmod Module Size Used by Not tainted / # / # ls bin led_driver.ko mnt sbin usr dev lib proc sys etc linuxrc root tmp / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 led probe! / # / # lsmod Module Size Used by Tainted: G led_driver 2880 0 / # ls /sys/bus/platform/drivers/imx6ul-led -l total 0 --w------- 1 0 0 4096 Jan 1 06:21 bind lrwxrwxrwx 1 0 0 0 Jan 1 06:21 gpioled -> ../../../../devices/platform/gpioled lrwxrwxrwx 1 0 0 0 Jan 1 06:21 module -> ../../../../module/led_driver --w------- 1 0 0 4096 Jan 1 06:20 uevent --w------- 1 0 0 4096 Jan 1 06:21 unbind / # ls /dev/imx6ull-led -l crw-rw---- 1 0 0 248, 0 Jan 1 06:20 /dev/imx6ull-led / # / # rmmod led_driver.ko led remove! / # / # lsmod Module Size Used by Tainted: G / # / # ls /sys/bus/platform/drivers/imx6ul-led -l ls: /sys/bus/platform/drivers/imx6ul-led: No such file or directory / # ls /dev/imx6ull-led -l ls: /dev/imx6ull-led: No such file or directory / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 led probe! / # / # lsmod Module Size Used by Tainted: G led_driver 2880 0 / # / # ls /sys/bus/platform/drivers/imx6ul-led -l total 0 --w------- 1 0 0 4096 Jan 1 06:21 bind lrwxrwxrwx 1 0 0 0 Jan 1 06:21 gpioled -> ../../../../devices/platform/gpioled lrwxrwxrwx 1 0 0 0 Jan 1 06:21 module -> ../../../../module/led_driver --w------- 1 0 0 4096 Jan 1 06:21 uevent --w------- 1 0 0 4096 Jan 1 06:21 unbind / # / # ls /dev/imx6ull-led -l crw-rw---- 1 0 0 248, 0 Jan 1 06:21 /dev/imx6ull-led / # / # rmmod led_driver.ko led remove! / # / # ls /sys/bus/platform/drivers/imx6ul-led -l ls: /sys/bus/platform/drivers/imx6ul-led: No such file or directory / # / # ls /dev/imx6ull-led -l ls: /dev/imx6ull-led: No such file or directory / # / #通過(guò)以上日志可以確定,驅(qū)動(dòng)沒(méi)有問(wèn)題。
2、完善驅(qū)動(dòng)
#include "linux/init.h" #include "linux/module.h" #include "linux/platform_device.h" #include "linux/cdev.h" #include "linux/device.h" #include "linux/fs.h" #include "linux/kdev_t.h" #include "linux/printk.h" #include "linux/of.h" #include "asm/uaccess.h" #include "linux/of_gpio.h" #include "linux/gpio.h"#define NEWCHRDEV_MAJOR 0 /* 主設(shè)備號(hào)(如果為0則讓系統(tǒng)自動(dòng)分配,如果大于0則使用指定設(shè)備號(hào)) */ #define NEWCHRDEV_MINOR 0 /* 次設(shè)備號(hào) */ #define NEWCHRDEV_COUNT 1 /* 設(shè)備號(hào)個(gè)數(shù) */ #define NEWCHRDEV_NAME "imx6ull-led" /* 名子 */#define LEDOFF 0 #define LEDON 1typedef struct{struct cdev dev; /* cdev 結(jié)構(gòu)體 (聲明在 "linux/cdev.h")*/int major; /* 主設(shè)備號(hào) */int minor; /* 次設(shè)備號(hào) */dev_t devid; /* 設(shè)備號(hào) */struct class *class; /* 類(lèi) (聲明在 "linux/device.h")*/struct device *device; /* 設(shè)備 (聲明在 "linux/device.h") */struct device_node *node; /* LED設(shè)備節(jié)點(diǎn) (聲明在 "linux/of.h")*/int led0; /* LED燈GPIO標(biāo)號(hào) */ }newchrdev_t;newchrdev_t newchrdev;// EINVAL 定義在 "uapi/asm-generic/erron-base.h" // of_find_node_by_path 聲明在 "linux/of.h" // of_get_named_gpio 聲明在 "linux/of_gpio.h" // gpio_request 聲明在 "linux/gpio.h" // gpio_direction_output 聲明在 "linux/gpio.h" int imx6ull_led_init(void) {newchrdev.node = of_find_node_by_path("/gpioled");if (newchrdev.node == NULL){printk("gpioled node nost find!\r\n");return -EINVAL;} newchrdev.led0 = of_get_named_gpio(newchrdev.node, "led-gpio", 0);if (newchrdev.led0 < 0) {printk("can't get led-gpio\r\n");return -EINVAL;}gpio_request(newchrdev.led0, "led0");gpio_direction_output(newchrdev.led0, 1); /* led0 IO設(shè)置為輸出,默認(rèn)高電平 */printk("imx6ull led init!\r\n");return 0; }int imx6ull_led_exit(void) {gpio_set_value(newchrdev.led0, 1); /* 卸載驅(qū)動(dòng)的時(shí)候關(guān)閉LED */printk("imx6ull led exit!\r\n");return 0; }/** @description : LED打開(kāi)/關(guān)閉* @param - sta : LEDON(0) 打開(kāi)LED,LEDOFF(1) 關(guān)閉LED* @return : 無(wú)*/ void led0_switch(u8 sta) {if (sta == LEDON )gpio_set_value(newchrdev.led0, 0);else if (sta == LEDOFF)gpio_set_value(newchrdev.led0, 1); }// struct inode 聲明在 linux/fs.h 中 // struct file 聲明在 linux/fs.h 中 int led_open (struct inode *i, struct file *f) {return 0; }int led_release (struct inode *i, struct file *f) {return 0; }// ssize_t 定義在 linux/types.h 中 // __user 定義在 linux/compiler.h 中 // size_t 定義在 linux/types.h 中 // loff_t 定義在 linux/types.h 中 ssize_t led_read (struct file *f, char __user *b, size_t c, loff_t * l) {printk("led read!\r\n");return 0; }/** @description : 向設(shè)備寫(xiě)數(shù)據(jù) * @param - f : 設(shè)備文件,表示打開(kāi)的文件描述符* @param - b : 要寫(xiě)給設(shè)備寫(xiě)入的數(shù)據(jù)* @param - c : 要寫(xiě)入的數(shù)據(jù)長(zhǎng)度* @param - l : 相對(duì)于文件首地址的偏移* @return : 寫(xiě)入的字節(jié)數(shù),如果為負(fù)值,表示寫(xiě)入失敗*/ ssize_t led_write (struct file *f, const char __user *b, size_t c, loff_t *l) {int retvalue;unsigned char databuf[2];unsigned char ledstat;retvalue = copy_from_user(databuf, b, c);if(retvalue < 0) {printk("kernel write failed!\r\n");return -EFAULT;}ledstat = databuf[0];if (ledstat == LEDON) {led0_switch(LEDON);} else if (ledstat == LEDOFF) {led0_switch(LEDOFF);}printk("led write!\r\n");return 0; }static const struct file_operations newchrdevops = {.owner = THIS_MODULE,.open = led_open,.release = led_release,.read = led_read,.write = led_write, };/** @description : flatform驅(qū)動(dòng)的probe函數(shù),當(dāng)驅(qū)動(dòng)與設(shè)備匹配以后此函數(shù)就會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_probe(struct platform_device *dev) {int ret;/* 1、字符設(shè)備號(hào)分配 */newchrdev.major = NEWCHRDEV_MAJOR;if(newchrdev.major){/* 指定設(shè)備號(hào) */newchrdev.minor = NEWCHRDEV_MINOR;newchrdev.devid = MKDEV(newchrdev.major, newchrdev.minor);ret = register_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);printk("newchrdev.major > 0!\r\n");}else{/* 系統(tǒng)分配設(shè)備號(hào) */ret = alloc_chrdev_region(&newchrdev.devid,0,NEWCHRDEV_COUNT,NEWCHRDEV_NAME);newchrdev.major = MAJOR(newchrdev.devid);newchrdev.minor = MINOR(newchrdev.devid);printk("newchrdev.major = 0!\r\n");}if(ret < 0){printk("newchrdev xxx_chrdev_region failed!\r\n");goto newchrdev_chrdev_region_failed;}printk("newchrdev devid = %d newchrdev major=%d,minor=%d\r\n",newchrdev.devid,newchrdev.major,newchrdev.minor);/* 2、注冊(cè)字符設(shè)備 */newchrdev.dev.owner = THIS_MODULE;cdev_init(&newchrdev.dev,&newchrdevops);ret = cdev_add(&newchrdev.dev,newchrdev.devid,NEWCHRDEV_COUNT);if(ret < 0){printk("newchrdev cdev_add failed!\r\n");goto newchrdev_cdev_add_failed;}/* 3、創(chuàng)建類(lèi) */newchrdev.class = class_create(THIS_MODULE,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.class)) {printk("newchrdev class_create failed!\r\n");goto newchrdev_class_create_failed;}/* 4、創(chuàng)建設(shè)備 */newchrdev.device = device_create(newchrdev.class,NULL,newchrdev.devid,NULL,NEWCHRDEV_NAME);if(IS_ERR(newchrdev.device)){printk("newchrdev device_create failed!\r\n");goto newchrdev_device_creat_failed;}ret = imx6ull_led_init();if(ret != 0){goto newchrdev_device_xxx_failed;}printk("led probe!\r\n");return 0;newchrdev_device_xxx_failed: /* 其他操作失敗(添加其他文件時(shí),打開(kāi)此選項(xiàng)) */device_destroy(newchrdev.class,newchrdev.devid); newchrdev_device_creat_failed: /* 刪除類(lèi) */class_destroy(newchrdev.class); newchrdev_class_create_failed: /*注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev); newchrdev_cdev_add_failed: /* 釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT); newchrdev_chrdev_region_failed: /* 字符設(shè)備號(hào)分配失敗處理函數(shù)(未分配資源,因此不做處理) */printk("failed!\r\n");return ret; }/** @description : platform驅(qū)動(dòng)的remove函數(shù),移除platform驅(qū)動(dòng)的時(shí)候此函數(shù)會(huì)執(zhí)行* @param - dev : platform設(shè)備* @return : 0,成功;其他負(fù)值,失敗*/ static int led_remove(struct platform_device *dev) {imx6ull_led_exit();/* 4、刪除設(shè)備 */device_destroy(newchrdev.class,newchrdev.devid);/* 3、刪除類(lèi) */class_destroy(newchrdev.class);/* 2、注銷(xiāo)字符設(shè)備 */cdev_del(&newchrdev.dev);/* 1、釋放設(shè)備號(hào) */unregister_chrdev_region(newchrdev.devid,NEWCHRDEV_COUNT);printk("led remove!\r\n");return 0; }/* 匹配列表 */ static const struct of_device_id led_of_match[] = {{ .compatible = "gpioled" },{ /* Sentinel */ } };/* platform驅(qū)動(dòng)結(jié)構(gòu)體 */ static struct platform_driver led_driver = {.driver = {.name = "imx6ul-led", /* 驅(qū)動(dòng)名字,用于和設(shè)備匹配 */.of_match_table = led_of_match, /* 設(shè)備樹(shù)匹配表 */},.probe = led_probe,.remove = led_remove, };/** @description : 驅(qū)動(dòng)模塊加載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static int __init led_driver_init(void) {return platform_driver_register(&led_driver); }/** @description : 驅(qū)動(dòng)模塊卸載函數(shù)* @param : 無(wú)* @return : 無(wú)*/ static void __exit led_driver_exit(void) {platform_driver_unregister(&led_driver); }module_init(led_driver_init); module_exit(led_driver_exit); MODULE_LICENSE("GPL");3、app 測(cè)試
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include "stdio.h"int main(int argc, char *argv[]) {int fd = 0, retvalue = 0;char writebuf[1] = "";fd = open(argv[1],O_RDWR);if(fd < 0){printf("Can't open file %s\r\n", argv[1]);return -1;}writebuf[0] = atoi(argv[2]);// 打開(kāi) ledwrite(fd, writebuf, 1);retvalue = close(fd);if(retvalue < 0){printf("Can't close file %s\r\n", argv[1]);return -1;}return 0; }編譯:
arm-linux-gnueabihf-gcc led_app.c -o led_app4、測(cè)試
思路:
1、加載驅(qū)動(dòng)。
2、執(zhí)行app程序。
測(cè)試過(guò)程:
/ # ls bin led_app linuxrc root tmp dev led_driver.ko mnt sbin usr etc lib proc sys / # ls /dev/imx6ull-led -l ls: /dev/imx6ull-led: No such file or directory / # / # lsmod Module Size Used by Not tainted / # / # insmod led_driver.konewchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! led probe! / # / # / # lsmod Module Size Used by Tainted: G led_driver 3845 0 / # / # rmmod led_driver.ko imx6ull led exit! led remove! / # / # lsmod Module Size Used by Tainted: G / # / # insmod led_driver.ko newchrdev.major = 0! newchrdev devid = 260046848 newchrdev major=248,minor=0 imx6ull led init! led probe! / # / # ls /dev/imx6ull-led -l crw-rw---- 1 0 0 248, 0 Jan 1 07:31 /dev/imx6ull-led / # / # ./led_app /dev/imx6ull-led 1 led write! / # / # ./led_app /dev/imx6ull-led 0 led write! / # / # ./led_app /dev/imx6ull-led 1 led write! / # / # ./led_app /dev/imx6ull-led 0 led write! / #通過(guò)以上測(cè)試,開(kāi)發(fā)板上 led 燈可以正常點(diǎn)亮和關(guān)閉。
總結(jié)
以上是生活随笔為你收集整理的Linux 驱动开发 四十四:platform 设备驱动实验(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: pandas绘图函数
- 下一篇: linux压缩命令-----zip