1 基本模板 1.1 传统方法 在设备树出现之前, platform_device 也是需要手动去书写的.
device 代码.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <linux/module.h> #include <linux/platform_device.h> #define DEV0_BASE_ADDR 0x10000000 #define DEV1_BASE_ADDR 0x20000000 #define RES_SIZE 0x100 static struct resource dev0_res [] = { [0 ] = { .start = DEV0_BASE_ADDR, .end = DEV0_BASE_ADDR + RES_SIZE - 1 , .flags = IORESOURCE_MEM, }, }; static void release_dev (struct device *dev) { pr_info(KERN_INFO "Legacy Devs: Device released\n" ); } static struct platform_device pdev0 = { .name = "legacy-demo-device" , .id = 0 , .num_resources = ARRAY_SIZE(dev0_res), .resource = dev0_res, .dev.release = release_dev, }; static struct resource dev1_res [] = { [0 ] = { .start = DEV1_BASE_ADDR, .end = DEV1_BASE_ADDR + RES_SIZE - 1 , .flags = IORESOURCE_MEM, }, }; static struct platform_device pdev1 = { .name = "legacy-demo-device" , .id = 1 , .num_resources = ARRAY_SIZE(dev1_res), .resource = dev1_res, .dev.release = release_dev, }; static int __init legacy_devs_init (void ) { int ret; pr_info(KERN_INFO "legacy devs: Registering devices...\n" ); platform_device_register(&pdev0); platform_device_register(&pdev1); return 0 ; } static void __exit legacy_devs_exit (void ) { platform_device_unregister(&pdev0); platform_device_unregister(&pdev1); pr_info(KERN_INFO "legacy devs: Unregistered devices.\n" ); } module_init(legacy_devs_init); module_exit(legacy_devs_exit); MODULE_LICENSE("GPL" );
driver 代码.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> struct my_driver_data { int id; phys_addr_t phys_base; }; static int legacy_probe (struct platform_device *pdev) { struct my_driver_data *priv ; struct resource *res ; pr_info(KERN_INFO "legacy driver: Probing device ID = %d\n" , pdev->id); priv = devm_kzalloc(&pdev->dev, sizeof (*priv), GFP_KERNEL); if (!priv) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0 ); if (!res) { dev_err(&pdev->dev, "No memory resource found\n" ); return -EINVAL; } priv->id = pdev->id; priv->phys_base = res->start; platform_set_drvdata(pdev, priv); pr_info(KERN_INFO "legacy driver: device %d initialized at 0x%llx\n" , priv->id, (unsigned long long )priv->phys_base); return 0 ; } static void legacy_remove (struct platform_device *pdev) { struct my_driver_data *priv = platform_get_drvdata(pdev); pr_info(KERN_INFO "legacy driver: removing device %d (base: 0x%llx)\n" , priv->id, (unsigned long long )priv->phys_base); } static struct platform_driver legacy_driver = { .probe = legacy_probe, .remove = legacy_remove, .driver = { .name = "legacy-demo-device" , }, }; module_platform_driver(legacy_driver); MODULE_LICENSE("GPL" );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 sh-5.2# insmod /lib/modules/6.18.5/updates/legacy_driver.ko [ 18.451395] legacy_driver: loading out-of-tree module taints kernel. sh-5.2# insmod /lib/modules/6.18.5/updates/legacy_device.ko [ 22.298768] legacy devs: Registering devices... [ 22.299902] legacy driver: Probing device ID = 0 [ 22.300307] legacy driver: device 0 initialized at 0x10000000 [ 22.301217] legacy driver: Probing device ID = 1 [ 22.301420] legacy driver: device 1 initialized at 0x20000000 sh-5.2# rmmod /lib/modules/6.18.5/updates/legacy_device.ko [ 37.067971] legacy driver: removing device 0 (base: 0x10000000) [ 37.068557] Legacy Devs: Device released [ 37.068812] legacy driver: removing device 1 (base: 0x20000000) [ 37.069151] Legacy Devs: Device released [ 37.069395] legacy devs: Unregistered devices. sh-5.2# rmmod /lib/modules/6.18.5/updates/legacy_driver.ko
1.2 设备树方法 在设备树模式下,内核优先使用 of_match_table 来寻找硬件.
但是它对于 /sys 来说还是非常重要.
挂挂载之后我们可以看到该文件.
1 2 sh-5.2# ls /sys/bus/platform/drivers/dt-demo-driver/ 1000000000000100.demo 2000000000000100.demo bind module uevent unbind
内核程序.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <linux/module.h> #include <linux/platform_device.h> #include <linux/of.h> #include <linux/slab.h> struct my_dt_data { phys_addr_t phys_base; const char *label_name; }; static int dt_probe (struct platform_device *pdev) { struct my_dt_data *priv ; struct resource *res ; const char *label; dev_info(&pdev->dev, "DT Driver: Probing started...\n" ); priv = devm_kzalloc(&pdev->dev, sizeof (*priv), GFP_KERNEL); if (!priv) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0 ); if (res) { priv->phys_base = res->start; } if (of_property_read_string(pdev->dev.of_node, "label" , &label) == 0 ) { priv->label_name = label; } else { priv->label_name = "Unknown" ; } platform_set_drvdata(pdev, priv); dev_info(&pdev->dev, "DT Driver: Success! Addr=0x%llx, Label=%s\n" , (unsigned long long )priv->phys_base, priv->label_name); return 0 ; } static void dt_remove (struct platform_device *pdev) { struct my_dt_data *priv = platform_get_drvdata(pdev); dev_info(&pdev->dev, "DT Driver: Removing %s\n" , priv->label_name); } static const struct of_device_id my_of_match [] = { { .compatible = "example,my-demo-device" }, { } }; MODULE_DEVICE_TABLE(of, my_of_match); static struct platform_driver dt_driver = { .probe = dt_probe, .remove = dt_remove, .driver = { .name = "dt-demo-driver" , .of_match_table = my_of_match, }, }; module_platform_driver(dt_driver); MODULE_LICENSE("GPL" );
运行效果.
1 2 3 4 5 6 7 8 sh-5.2# insmod /lib/modules/6.18.5/updates/dt_driver.ko [ 347.523308] dt-demo-driver 1000000000000100.demo: DT Driver: Probing started... [ 347.523795] dt-demo-driver 1000000000000100.demo: DT Driver: Success! Addr=0x0, Label=Instance-A [ 347.525442] dt-demo-driver 2000000000000100.demo: DT Driver: Probing started... [ 347.526605] dt-demo-driver 2000000000000100.demo: DT Driver: Success! Addr=0x0, Label=Instance-B sh-5.2# rmmod /lib/modules/6.18.5/updates/dt_driver.ko [ 356.249162] dt-demo-driver 2000000000000100.demo: DT Driver: Removing Instance-B [ 356.249847] dt-demo-driver 1000000000000100.demo: DT Driver: Removing Instance-A