• linux驱动移植总线设备驱动


    在上一节我们介绍了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:

    参考文章

    [1]Linux驱动之platform总线详解

    [2]一张图掌握 Linux platform 平台设备驱动框架

    [3]十一、Linux驱动之platform总线设备驱动

    [4]14.linux-platform机制实现驱动层分离(详解)

    [5]linux总线、设备和设备驱动的关系

  • 相关阅读:
    搞清楚C#中的值类型(基础类型)和引用类型
    构造动态SQL语句
    Json.net API及常用方法
    泛型代码中的default有何作用
    SQL 中的for xml path()的使用
    fastJosn和JackJson的区别
    箭头函数
    3篇文章初探MVC工作流程
    MVC传递Model之TempData、ViewData、ViewBag区别和用途
    .Net 提交页面,js修改的Label值会丢掉
  • 原文地址:https://www.cnblogs.com/zyly/p/16132512.html
Copyright © 2020-2023  润新知