在上一节我们介绍了platform总线设备驱动模型,并介绍了如何编写platform设备驱动。
在platform设备驱动编写过程中我们接触到了linux总线设备驱动模型中的提供的数据结构、以及接口。
如果我们学过面向对象编程的话,我们可以将总线-设备-驱动看做基类,而platform总线-platform设备-platform驱动看做其中的一种实现。
一、总线
1.1 总线定义
可以通过如下命令查看linux系统加载的所有总线:
root@zhengyang:/sys/bus# ls -l /sys/bus 总用量 0 drwxr-xr-x 4 root root 0 4月 11 21:38 ac97 drwxr-xr-x 4 root root 0 4月 11 21:38 acpi drwxr-xr-x 4 root root 0 4月 11 21:38 clockevents drwxr-xr-x 4 root root 0 4月 11 21:38 clocksource drwxr-xr-x 4 root root 0 4月 11 21:38 container drwxr-xr-x 4 root root 0 4月 11 21:38 cpu drwxr-xr-x 4 root root 0 4月 11 21:38 edac drwxr-xr-x 4 root root 0 4月 11 21:38 event_source drwxr-xr-x 4 root root 0 4月 11 21:38 gameport drwxr-xr-x 4 root root 0 4月 11 21:38 gpio drwxr-xr-x 4 root root 0 4月 11 21:38 hid drwxr-xr-x 4 root root 0 4月 11 21:38 i2c drwxr-xr-x 4 root root 0 4月 11 21:38 isa drwxr-xr-x 4 root root 0 4月 11 21:38 machinecheck drwxr-xr-x 4 root root 0 4月 11 21:38 mdio_bus drwxr-xr-x 4 root root 0 4月 11 21:38 memory drwxr-xr-x 4 root root 0 4月 11 21:38 mipi-dsi drwxr-xr-x 4 root root 0 4月 11 21:38 mmc drwxr-xr-x 4 root root 0 4月 11 21:38 nd drwxr-xr-x 4 root root 0 4月 11 21:38 node drwxr-xr-x 4 root root 0 4月 11 21:38 nvmem drwxr-xr-x 4 root root 0 4月 11 21:38 parport drwxr-xr-x 5 root root 0 4月 11 21:38 pci drwxr-xr-x 4 root root 0 4月 11 21:38 pci-epf drwxr-xr-x 4 root root 0 4月 11 21:38 pci_express drwxr-xr-x 4 root root 0 4月 11 21:38 platform drwxr-xr-x 4 root root 0 4月 11 21:38 pnp drwxr-xr-x 4 root root 0 4月 11 21:38 rapidio drwxr-xr-x 4 root root 0 4月 11 21:38 scsi drwxr-xr-x 4 root root 0 4月 11 21:38 sdio drwxr-xr-x 4 root root 0 4月 11 21:38 serial drwxr-xr-x 4 root root 0 4月 11 21:38 serio drwxr-xr-x 4 root root 0 4月 11 21:38 snd_seq drwxr-xr-x 4 root root 0 4月 11 21:38 spi drwxr-xr-x 4 root root 0 4月 11 21:38 usb drwxr-xr-x 4 root root 0 4月 11 21:38 virtio drwxr-xr-x 4 root root 0 4月 11 21:38 vme drwxr-xr-x 4 root root 0 4月 11 21:38 workqueue drwxr-xr-x 4 root root 0 4月 11 21:38 xen drwxr-xr-x 4 root root 0 4月 11 21:38 xen-backend
在Linux 设备模型中,总线由bus_type 结构表示,定义在 include/linux/device.h文件中:
/** * 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. * @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 positive value if the * given device can be handled by the given driver and zero * otherwise. It may also return error code if determining that * the driver supports the device is not possible. In case of * -EPROBE_DEFER it will queue the device for deferred probing. * @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 driver's 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. * @num_vf: Called to find out how many virtual functions a device on this * bus supports. * @dma_configure: Called to setup DMA configuration on a device on * this bus. * @pm: Power management operations of this bus, callback the specific * device driver's 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 * @need_parent_lock: When probing or removing a device on this bus, the * device core should lock the device's parent. * * 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 core's * private data. */ struct bus_type { const char *name; const char *dev_name; struct device *dev_root; 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); int (*num_vf)(struct device *dev); int (*dma_configure)(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; bool need_parent_lock; };
其中部分字段的含义如下:
- name:总线名称;
1.2 总线注册
总线的注册和删除,总线的主要注册步骤:
申明和初始化bus_type 结构体。只有很少的bus_type 成员需要初始化,大部分都由设备模型控制。但必须为总线指定名字及一些必要的方法。例如:
struct bus_type ldd_bus_type = { .name = "ldd", .match = ldd_match, .uevent = ldd_uevent, };
调用bus_register函数注册总线:
int bus_register(struct bus_type *bus)
该调用可能失败,所以必须始终检查返回值。
ret = bus_register(&ldd_bus_type);
if (ret)
return ret;
若成功,新的总线子系统将被添加进系统,之后可以向总线添加设备。当必须从系统中删除一个总线时,调用:
void bus_unregister(struct bus_type *bus);
二、设备
2.1 设备定义
linux 系统中每一个设备都用 device 结构的一个实例来表示,定义在 include/linux/device.h文件中:
/** * struct device - The basic device structure * @parent: The device's "parent" device, the device to which it is attached. * In most cases, a parent device is some sort of bus or host * controller. If parent is NULL, the device, is a top-level device, * which is not usually what you want. * @p: Holds the private data of the driver core portions of the device. * See the comment of the struct device_private for detail. * @kobj: A top-level, abstract class from which other classes are derived. * @init_name: Initial name of the device. * @type: The type of device. * This identifies the device type and carries type-specific * information. * @mutex: Mutex to synchronize calls to its driver. * @bus: Type of bus device is on. * @driver: Which driver has allocated this * @platform_data: Platform data specific to the device. * Example: For devices on custom boards, as typical of embedded * and SOC based hardware, Linux often uses platform_data to point * to board-specific structures describing devices and how they * are wired. That can include what ports are available, chip * variants, which GPIO pins act in what additional roles, and so * on. This shrinks the "Board Support Packages" (BSPs) and * minimizes board-specific #ifdefs in drivers. * @driver_data: Private pointer for driver specific info. * @links: Links to suppliers and consumers of this device. * @power: For device power management. * See Documentation/driver-api/pm/devices.rst for details. * @pm_domain: Provide callbacks that are executed during system suspend, * hibernation, system resume and during runtime PM transitions * along with subsystem-level and driver-level callbacks. * @pins: For device pin management. * See Documentation/driver-api/pinctl.rst for details. * @msi_list: Hosts MSI descriptors * @msi_domain: The generic MSI domain this device is using. * @numa_node: NUMA node this device is close to. * @dma_ops: DMA mapping operations for this device. * @dma_mask: Dma mask (if dma'ble device). * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all * hardware supports 64-bit addresses for consistent allocations * such descriptors. * @bus_dma_mask: Mask of an upstream bridge or bus which imposes a smaller DMA * limit than the device itself supports. * @dma_pfn_offset: offset of DMA memory range relatively of RAM * @dma_parms: A low level driver may set these to teach IOMMU code about * segment limitations. * @dma_pools: Dma pools (if dma'ble device). * @dma_mem: Internal for coherent mem override. * @cma_area: Contiguous memory area for dma allocations * @archdata: For arch-specific additions. * @of_node: Associated device tree node. * @fwnode: Associated device node supplied by platform firmware. * @devt: For creating the sysfs "dev". * @id: device instance * @devres_lock: Spinlock to protect the resource of the device. * @devres_head: The resources list of the device. * @knode_class: The node used to add the device to the class list. * @class: The class of the device. * @groups: Optional attribute groups. * @release: Callback to free the device after all references have * gone away. This should be set by the allocator of the * device (i.e. the bus driver that discovered the device). * @iommu_group: IOMMU group the device belongs to. * @iommu_fwspec: IOMMU-specific properties supplied by firmware. * * @offline_disabled: If set, the device is permanently online. * @offline: Set after successful invocation of bus type's .offline(). * @of_node_reused: Set if the device-tree node is shared with an ancestor * device. * @dma_coherent: this particular device is dma coherent, even if the * architecture supports non-coherent devices. * * At the lowest level, every device in a Linux system is represented by an * instance of struct device. The device structure contains the information * that the device model core needs to model the system. Most subsystems, * however, track additional information about the devices they host. As a * result, it is rare for devices to be represented by bare device structures; * instead, that structure, like kobject structures, is usually embedded within * a higher-level representation of the device. */ struct device { struct kobject kobj; struct device *parent; struct device_private *p; const char *init_name; /* initial name of the device */ const struct device_type *type; struct bus_type *bus; /* type of bus device is on */ struct device_driver *driver; /* which driver has allocated this device */ void *platform_data; /* Platform specific data, device core doesn't touch it */ void *driver_data; /* Driver data, set and get with dev_set_drvdata/dev_get_drvdata */ struct mutex mutex; /* mutex to synchronize calls to * its driver. */ struct dev_links_info links; struct dev_pm_info power; struct dev_pm_domain *pm_domain; #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN struct irq_domain *msi_domain; #endif #ifdef CONFIG_PINCTRL struct dev_pin_info *pins; #endif #ifdef CONFIG_GENERIC_MSI_IRQ struct list_head msi_list; #endif const struct dma_map_ops *dma_ops; u64 *dma_mask; /* dma mask (if dma'able device) */ u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */ u64 bus_dma_mask; /* upstream dma_mask constraint */ unsigned long dma_pfn_offset; struct device_dma_parameters *dma_parms; struct list_head dma_pools; /* dma pools (if dma'ble) */ #ifdef CONFIG_DMA_DECLARE_COHERENT struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ #endif #ifdef CONFIG_DMA_CMA struct cma *cma_area; /* contiguous memory area for dma allocations */ #endif /* arch specific additions */ struct dev_archdata archdata; struct device_node *of_node; /* associated device tree node */ struct fwnode_handle *fwnode; /* firmware device node */ #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif dev_t devt; /* dev_t, creates the sysfs "dev" */ u32 id; /* device instance */ spinlock_t devres_lock; struct list_head devres_head; struct class *class; const struct attribute_group **groups; /* optional groups */ void (*release)(struct device *dev); struct iommu_group *iommu_group; struct iommu_fwspec *iommu_fwspec; bool offline_disabled:1; bool offline:1; bool of_node_reused:1; #if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \ defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL) bool dma_coherent:1; #endif };
2.2 注册设备
在注册struct device 前,最少要设置parent, bus_id, bus, 和 release 成员,设备的注册和注销函数为:
int device_register(struct device *dev); void device_unregister(struct device *dev);
以下为lddbus注册它的虚拟总线设备:
static void ldd_bus_release(struct device *dev) { printk(KERN_DEBUG "lddbus release\n"); } struct device ldd_bus = { .bus_id = "ldd0", .release = ldd_bus_release }; ret = device_register(&ldd_bus); if (ret) printk(KERN_NOTICE "Unable to register ldd0\n");
三、驱动
3.1 驱动定义
驱动程序的结构体device_driver 定义如下:
/** * struct device_driver - The basic device driver structure * @name: Name of the device driver. * @bus: The bus which the device of this driver belongs to. * @owner: The module owner. * @mod_name: Used for built-in modules. * @suppress_bind_attrs: Disables bind/unbind via sysfs. * @probe_type: Type of the probe (synchronous or asynchronous) to use. * @of_match_table: The open firmware table. * @acpi_match_table: The ACPI match table. * @probe: Called to query the existence of a specific device, * whether this driver can work with it, and bind the driver * to a specific device. * @remove: Called when the device is removed from the system to * unbind a device from this driver. * @shutdown: Called at shut-down time to quiesce the device. * @suspend: Called to put the device to sleep mode. Usually to a * low power state. * @resume: Called to bring a device from sleep mode. * @groups: Default attributes that get created by the driver core * automatically. * @pm: Power management operations of the device which matched * this driver. * @coredump: Called when sysfs entry is written to. The device driver * is expected to call the dev_coredump API resulting in a * uevent. * @p: Driver core's private data, no one other than the driver * core can touch this. * * The device driver-model tracks all of the drivers known to the system. * The main reason for this tracking is to enable the driver core to match * up drivers with new devices. Once drivers are known objects within the * system, however, a number of other things become possible. Device drivers * can export information and configuration variables that are independent * of any specific device. */ 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 */ enum probe_type probe_type; 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; void (*coredump) (struct device *dev); struct driver_private *p; };
3.2 驱动注册
驱动注册driver_register定义在drivers/base/platform.c:
参考文章
[2]一张图掌握 Linux platform 平台设备驱动框架