微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > linux总线、设备和设备驱动的关系

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

时间:12-15 来源:互联网 点击:

个struct device 代表:

struct device

{

struct klist klist_children;

struct klist_node knode_parent;

struct klist_node knode_driver;

struct klist_node knode_bus;

struct device *parent; * 设备的 "父" 设备,该设备所属的设备,通常一个父设备是某种总线或者主控制器。如果 parent 是 NULL, 则该设备是顶层设备,较少见 */

struct kobject kobj;

char bus_id[BUS_ID_SIZE];

const char *init_name;

struct device_type *type;

unsigned uevent_suppress:1;

struct semaphore sem;

struct bus_type *bus;

struct device_driver *driver;

void *driver_data;

void *platform_data;

struct dev_pm_info power;

#ifdef CONFIG_NUMA

int numa_node;

#endif

u64 *dma_mask;

u64 coherent_dma_mask;

struct device_dma_parameters *dma_parms;

struct list_head dma_pools;

struct dma_coherent_mem *dma_mem;

struct dev_archdata archdata;

spinlock_t devres_lock;

struct list_head devres_head;

struct list_head node;

struct class *class;

dev_t devt;

struct attribute_group **groups;

void (*release)(struct device *dev);

};

(1)设备注册

在注册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");

}

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");

(2)设备属性

sysfs 中的设备入口可有属性,相关的结构是:

struct device_attribute {

struct attribute attr;

ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);

ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);

};

DEVICE_ATTR(_name,_mode,_show,_store);

int device_create_file(struct device *device, struct device_attribute * entry);

void device_remove_file(struct device * dev, struct device_attribute * attr);

一个实例是:终端执行:cd /sys/class/leds/lcd-backlight,

ls回显:

uevent

subsystem

device

power

brightness

这些属性可能都是通过device_create_file添加上去(至少brightness是这样)。进入device目录,再输入pwd,

回显:/sys/devices/platform/smdk-backlight。变换到devices目录下了,可见设备模型的不同构成是指向同一个设备的。

2.6下字符设备开始用struct cdev结构体表示,但是我想调用device_create_file(dev, &dev_attr_debug);函数在/sys中导出信息,device_create_file()的第一个入口参数类型为struct device结构体。问题是struct cdev与struct device这两个结构体没有任何联系的地方?答案是可以采用共同拥有的Kobjcet这个成员作为纽带,所以从子类cdev--->父类kobject--->子类device,推导得到:container_of(kobj)-->list_entry(entry)->(struct device*) 。因为containerof是从结构体指针成员找到结构体地址,所以从cdev的kobj可以找到父类kobject的地址,而所有的kobject的entery都是在一个链表里面,遍历这个链表,找到结构体成员为特定device结构的那一项。

(3)设备结构的嵌入

device 结构包含设备模型核心用来模拟系统的信息。但大部分子系统记录了关于它们拥有的设备的额外信息,所以很少单纯用device 结构代表设备,而是通常将其嵌入一个设备的高层结构体表示中。

lddbus 驱动创建了它自己的 device 类型(也即每类设备会建立自己的设备结构体,其中至少一个成员是struct device类型,比如video_device),并期望每个设备驱动使用这个类型来注册它们的设备:

struct ldd_device {

char *name;

struct ldd_driver *driver;

struct device dev;

};

#define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);

lddbus 导出的注册和注销接口如下:

static void ldd_dev_release(struct device *dev)

{ }

int register_ldd_device(struct ldd_device *ldddev)

{

ldddev-> ldddev->dev.bus = &ldd_bus_t

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top