建设彩票网站多少钱,手机上购物哪个平台比较好,手机网站建设 的作用,wordpress调用函数# 前置知识
总线驱动模型简介#xff1a; 总线是处理器与一个或者多个设备之间的通道#xff0c;在设备模型中#xff0c;所有的设备都是通过总线相连#xff0c;当然也包括虚拟的 platform 平台总线。
总线驱动模型中有三要素#xff1a;
1. 总线
/*** struct bus_ty…# 前置知识
总线驱动模型简介 总线是处理器与一个或者多个设备之间的通道在设备模型中所有的设备都是通过总线相连当然也包括虚拟的 platform 平台总线。
总线驱动模型中有三要素
1. 总线
/*** struct bus_type - The bus type of the device** name: The name of the bus.* dev_name: Used for subsystems to enumerate devices like (foo%u, dev-id).* dev_root: Default device to use as the parent.* dev_attrs: Default attributes of the devices on the bus.* bus_groups: Default attributes of the bus.* dev_groups: Default attributes of the devices on the bus.* drv_groups: Default attributes of the device drivers on the bus.* match: Called, perhaps multiple times, whenever a new device or driver* is added for this bus. It should return a nonzero value if the* given device can be handled by the given driver.* uevent: Called when a device is added, removed, or a few other things* that generate uevents to add the environment variables.* probe: Called when a new device or driver add to this bus, and callback* the specific drivers probe to initial the matched device.* remove: Called when a device removed from this bus.* shutdown: Called at shut-down time to quiesce the device.** online: Called to put the device back online (after offlining it).* offline: Called to put the device offline for hot-removal. May fail.** suspend: Called when a device on this bus wants to go to sleep mode.* resume: Called to bring a device on this bus out of sleep mode.* pm: Power management operations of this bus, callback the specific* device drivers pm-ops.* iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU* driver implementations to a bus and allow the driver to do* bus-specific setup* p: The private data of the driver core, only the driver core can* touch this.* lock_key: Lock class key for use by the lock validator** A bus is a channel between the processor and one or more devices. For the* purposes of the device model, all devices are connected via a bus, even if* it is an internal, virtual, platform bus. Buses can plug into each other.* A USB controller is usually a PCI device, for example. The device model* represents the actual connections between buses and the devices they control.* A bus is represented by the bus_type structure. It contains the name, the* default attributes, the bus methods, PM operations, and the driver cores* private data.*/
struct bus_type {const char *name;const char *dev_name;struct device *dev_root;struct device_attribute *dev_attrs; /* use dev_groups instead */const struct attribute_group **bus_groups;const struct attribute_group **dev_groups;const struct attribute_group **drv_groups;int (*match)(struct device *dev, struct device_driver *drv);int (*uevent)(struct device *dev, struct kobj_uevent_env *env);int (*probe)(struct device *dev);int (*remove)(struct device *dev);void (*shutdown)(struct device *dev);int (*online)(struct device *dev);int (*offline)(struct device *dev);int (*suspend)(struct device *dev, pm_message_t state);int (*resume)(struct device *dev);const struct dev_pm_ops *pm;const struct iommu_ops *iommu_ops;struct subsys_private *p;struct lock_class_key lock_key;
};
API
extern int __must_check bus_register(struct bus_type *bus);extern void bus_unregister(struct bus_type *bus);
平台总线定义
struct bus_type platform_bus_type {.name platform,.dev_groups platform_dev_groups,.match platform_match,.uevent platform_uevent,.pm platform_dev_pm_ops,
};
平台总线的注册如下
int __init platform_bus_init(void)
{int error;early_platform_cleanup();error device_register(platform_bus);if (error)return error;error bus_register(platform_bus_type);if (error)device_unregister(platform_bus);of_platform_register_reconfig_notifier();return error;
}
2. 总线设备
struct platform_device {const char *name; /* 名字 */ int id; /* 用于标识该设备的ID */bool id_auto; /* 指示在注册设备时是否自动赋予ID值 */struct device dev; /* 真正的设备Platform设备只是一个特殊的设备因此其核心逻辑还是由底层的模块实现 */u32 num_resources; /* 资源个数 */struct resource *resource; /* 该设备的资源描述 */const struct platform_device_id *id_entry;char *driver_override; /* Driver name to force a match *//* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata archdata; /* 私有数据 */
};struct resource {resource_size_t start; /* 起始地址 */resource_size_t end; /* 结束地址 */const char *name; /* 资源名字 */unsigned long flags; /* 资源标识 */struct resource *parent, *sibling, *child;
}; API
/* 注册平台设备 */
int platform_device_register(struct platform_device *);/* 注销平台设备 */
void platform_device_unregister(struct platform_device *);/* 设置platform_device变量中的archdata指针 */
void arch_setup_pdev_archdata(struct platform_device *);/* 通过资源类型获取platform_device变量中的resource信息 */
struct resource *platform_get_resource(struct platform_device *,unsigned int, unsigned int);/* 通过资源名字获取platform_device变量中的resource信息 */
struct resource *platform_get_resource_byname(struct platform_device *,unsigned int,const char *);
3. 总线驱动
struct platform_driver {int (*probe)(struct platform_device *); /* 当驱动和硬件信息匹配成功之后就会调用probe函数驱动所有的资源的注册和初始化全部放在probe函数中 */int (*remove)(struct platform_device *); /* 硬件信息被移除了或者驱动被卸载了全部要释放释放资源的操作就放在该函数中 */void (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, pm_message_t state);int (*resume)(struct platform_device *) ;struct device_driver driver; /* 内核维护的所有的驱动必须包含该成员通常driver-name用于和设备进行匹配 */const struct platform_device_id *id_table; /* 往往一个驱动可能能同时支持多个硬件这些硬件的名字都放在该结构体数组中 */bool prevent_deferred_probe;
};struct device_driver {const char *name;struct bus_type *bus;struct module *owner;const char *mod_name; /* used for built-in modules */bool suppress_bind_attrs; /* disables bind/unbind via sysfs */const struct of_device_id *of_match_table;const struct acpi_device_id *acpi_match_table;int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);const struct attribute_group **groups;const struct dev_pm_ops *pm;struct driver_private *p;
};
API
/** use a macro to avoid include chaining to get THIS_MODULE*/
/* 注册设备 */
#define platform_driver_register(drv) \__platform_driver_register(drv, THIS_MODULE)
extern int __platform_driver_register(struct platform_driver *,struct module *);/* 注销设备 */
extern void platform_driver_unregister(struct platform_driver *);/* non-hotpluggable platform devices may use this so that probe() and* its support may live in __init sections, conserving runtime memory.*/
#define platform_driver_probe(drv, probe) \__platform_driver_probe(drv, probe, THIS_MODULE)
extern int __platform_driver_probe(struct platform_driver *driver,int (*probe)(struct platform_device *), struct module *module);/* 获取设备私有资源 */
static inline void *platform_get_drvdata(const struct platform_device *pdev)
{return dev_get_drvdata(pdev-dev);
}
设备与驱动匹配过程 来自https://blog.csdn.net/qq_16504163/article/details/118562670 # 示例代码
platform_device:
#include linux/init.h
#include linux/file.h
#include linux/kernel.h
#include linux/kthread.h
#include linux/module.h
#include linux/platform_device.h
#include linux/slab.h#define CCM_CCGR1_ADDR 0x20C406C
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03_ADDR 0x20E0068
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03_ADDR 0x20E02F4
#define GPIO1_BASE_ADDR 0x209C000 static struct resource atk_led_resource[] {[0] {.start CCM_CCGR1_ADDR,.end CCM_CCGR1_ADDR 4,.name led_clock,.flags IORESOURCE_MEM,},[1] {.start IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03_ADDR,.end IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03_ADDR 4,.name led_mux_ctrl,.flags IORESOURCE_MEM,},[2] {.start IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03_ADDR,.end IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03_ADDR 4,.name led_pad_ctrl,.flags IORESOURCE_MEM,},[3] {.start GPIO1_BASE_ADDR,.end GPIO1_BASE_ADDR 4,.name led_gpio_ctrl,.flags IORESOURCE_MEM,}
};static void atk_led_release(struct device *dev)
{}static struct platform_device atk_led_dev {.name atk_led,.id -1,.resource atk_led_resource,.num_resources ARRAY_SIZE(atk_led_resource),.dev {.release atk_led_release,},
};static int __init led_device_init(void)
{int err;err platform_device_register(atk_led_dev);return 0;
}static void __exit led_device_exit(void)
{platform_device_unregister(atk_led_dev);
}module_init(led_device_init);
module_exit(led_device_exit);MODULE_LICENSE(GPL);
platform_driver:
#include linux/module.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/io.h
#include linux/platform_device.htypedef struct
{volatile uint32_t GPIO_DR;volatile uint32_t GPIO_GDIR;volatile uint32_t GPIO_PSR;volatile uint32_t GPIO_ICR1;volatile uint32_t GPIO_ICR2;volatile uint32_t GPIO_IMR;volatile uint32_t GPIO_ISR;volatile uint32_t GPIO_EDGE_SEL;
}GPIO_TypeDef;static GPIO_TypeDef *GPIO;static volatile uint32_t *CCM_CCGR;
static volatile uint32_t *IOMUXC_SW_MUX_CTL_PAD;
static volatile uint32_t *IOMUXC_SW_PAD_CTL_PAD;struct pri_led_TypeDef
{char drv_name[50]; /* 驱动名称 */int major; /* 主设备号 */int minor; /* 次设备号 */dev_t devt; /* 设备号 */struct device *device; /* 设备 */char device_name[50]; /* 设备名称 */struct class *class; /* 类 */char class_name[50]; /* 类名称 */
};static struct pri_led_TypeDef pri_led {.drv_name led_drv,.major 0,.minor 0,.devt 0,.device NULL,.device_name led_dev,.class NULL,.class_name led_class,
};static int led_open(struct inode *inode, struct file *file)
{uint32_t val;/* 使能GPIO1时钟 */*CCM_CCGR | (3 26);/* 设置IO复用 */val *IOMUXC_SW_MUX_CTL_PAD;val ~(0x0F);val | 5;*IOMUXC_SW_MUX_CTL_PAD val;/* 设置IO属性 *//* 设置IO方向,设置GPIO1_IO03为输出 */GPIO-GPIO_GDIR | (1 3);return 0;
}static int led_release(struct inode *inode, struct file *file)
{return 0;
}static ssize_t led_write(struct file *file, const char __user *buff, size_t size, loff_t *ppos)
{uint8_t status;int err;err copy_from_user(status, buff, 1);if(status 1){GPIO-GPIO_DR ~(13);}else{GPIO-GPIO_DR | (13);}return 1;
}static const struct file_operations led_op {.owner THIS_MODULE,.open led_open,.release led_release,.write led_write,
};static int atk_led_drv_probe(struct platform_device *dev)
{struct resource *res;int err;printk(atk_led_drv_probe\r\n);res platform_get_resource(dev, IORESOURCE_MEM, 0);CCM_CCGR ioremap(res-start, (res-end - res-start));res platform_get_resource(dev, IORESOURCE_MEM, 1);IOMUXC_SW_MUX_CTL_PAD ioremap(res-start, (res-end - res-start));res platform_get_resource(dev, IORESOURCE_MEM, 2);IOMUXC_SW_PAD_CTL_PAD ioremap(res-start, (res-end - res-start));res platform_get_resource(dev, IORESOURCE_MEM, 3);GPIO ioremap(res-start, sizeof(GPIO_TypeDef));pri_led.major register_chrdev(0, pri_led.drv_name, led_op);pri_led.devt MKDEV(pri_led.major, pri_led.minor);pri_led.class class_create(THIS_MODULE, pri_led.class_name);if(IS_ERR(pri_led.class)){printk(class_create error\r\n);err PTR_ERR(pri_led.class);goto err_class_create_out;}pri_led.device device_create(pri_led.class, NULL, pri_led.devt, NULL, pri_led.device_name);if(IS_ERR(pri_led.device)){printk(device_create error\r\n);err PTR_ERR(pri_led.device);goto err_device_create_out;}return 0;err_device_create_out:class_destroy(pri_led.class);
err_class_create_out:unregister_chrdev(pri_led.major, pri_led.drv_name);return err;
}static int atk_led_drv_remove(struct platform_device *dev)
{printk(atk_led_drv_remove\r\n);iounmap(GPIO);iounmap(CCM_CCGR);iounmap(IOMUXC_SW_MUX_CTL_PAD);iounmap(IOMUXC_SW_PAD_CTL_PAD);device_destroy(pri_led.class, pri_led.devt);class_destroy(pri_led.class);unregister_chrdev(pri_led.major, pri_led.drv_name);return 0;
}static struct platform_driver atk_led_driver {.probe atk_led_drv_probe,.remove atk_led_drv_remove,.driver {.name atk_led,},
};static int __init led_driver_init(void)
{int err;err platform_driver_register(atk_led_driver);return 0;
}static void __exit led_driver_exit(void)
{platform_driver_unregister(atk_led_driver);
}module_init(led_driver_init);
module_exit(led_driver_exit);MODULE_LICENSE(GPL);
# 补充知识
1. platform_match 匹配规程
static int platform_match(struct device *dev, struct device_driver *drv)
{struct platform_device *pdev to_platform_device(dev);struct platform_driver *pdrv to_platform_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);
}
最先比较platform_device.driver_override 和 platform_driver.driver.name可以设置 platform_device 的 driver_override强制选择某个 platform_driver然后比较platform_device. name 和 platform_driver.id_table[i].namePlatform_driver.id_table 是“platform_device_id”指针表示该 drv 支持若干个 device它里面列出了各个 device 的{.name, .driver_data}其中的“ name”表示该drv 支持的设备的名字 driver_data 是些提供给该 device 的私有数据最后比较platform_device.name 和 platform_driver.driver.nameplatform_driver.id_table 可能为空这时可以根据 platform_driver.driver.name 来寻找同名的 platform_device
2. struct platform_device 中 id 的作用 switch (pdev-id) {default:dev_set_name(pdev-dev, %s.%d, pdev-name, pdev-id);break;case PLATFORM_DEVID_NONE: /* -1 */dev_set_name(pdev-dev, %s, pdev-name);break;case PLATFORM_DEVID_AUTO: /* -2 *//** Automatically allocated device ID. We mark it as such so* that we remember it must be freed, and we append a suffix* to avoid namespace collision with explicit IDs.*/ret ida_simple_get(platform_devid_ida, 0, 0, GFP_KERNEL);if (ret 0)goto err_out;pdev-id ret;pdev-id_auto true;dev_set_name(pdev-dev, %s.%d.auto, pdev-name, pdev-id);break;}
id -1 时名称直接为名字id -2时名称为自动获取的id加上.auto其他为名称加上id