Linux设备模型(总线、设备、驱动程序和类)之二:device
2012-10-01 17:04
435 查看
设备
在最底层, Linux 系统中的每个设备由一个 struct device 代表:
设备注册
设备的注册和注销函数为:
一个实际的总线也是一个设备,所以必须单独注册,以下为 lddbus 在编译时注册它的虚拟总线设备源码:
设备属性
sysfs 中的设备入口可有属性,相关的结构是:
设备结构的嵌入
device 结构包含设备模型核心用来模拟系统的信息。但大部分子系统记录了关于它们又拥有的设备的额外信息,所以很少单纯用 device 结构代表设备,而是,通常将其嵌入一个设备的高层表示中。底层驱动几乎不知道 struct device。
lddbus 驱动创建了它自己的 device 类型,并期望每个设备驱动使用这个类型来注册它们的设备:
lddbus 导出的注册和注销接口如下:
sculld 驱动添加一个自己的属性到它的设备入口,称为 dev, 仅包含关联的设备号,源码如下:
在最底层, Linux 系统中的每个设备由一个 struct device 代表:
struct device { struct klist klist_children; struct klist_node knode_parent; /* node in sibling list */ struct klist_node knode_driver; struct klist_node knode_bus; struct device *parent;/* 设备的 "父" 设备,该设备所属的设备,通常一个父设备是某种总线或者主控制器. 如果 parent 是 NULL, 则该设备是顶层设备,较少见 */ struct kobject kobj;/*代表该设备并将其连接到结构体系中的 kobject; 注意:作为通用的规则, device->kobj->parent 应等于 device->parent->kobj*/ char bus_id[BUS_ID_SIZE];/*在总线上唯一标识该设备的字符串;例如: PCI 设备使用标准的 PCI ID 格式, 包含:域, 总线, 设备, 和功能号.*/ struct device_type *type; unsigned is_registered:1; unsigned uevent_suppress:1; struct device_attribute uevent_attr; struct device_attribute *devt_attr; struct semaphore sem; /* semaphore to synchronize calls to its driver. */ struct bus_type * bus; /*标识该设备连接在何种类型的总线上*/ struct device_driver *driver; /*管理该设备的驱动程序*/ void *driver_data; /*该设备驱动使用的私有数据成员*/ void *platform_data; /* Platform specific data, device core doesn't touch it */ struct dev_pm_info power; #ifdef CONFIG_NUMA int numa_node; /* NUMA node this device is close to */ #endif 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. */ struct list_head dma_pools; /* dma pools (if dma'ble) */ struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */ /* arch specific additions */ struct dev_archdata archdata; spinlock_t devres_lock; struct list_head devres_head; /* class_device migration path */ struct list_head node; struct class *class; dev_t devt; /* dev_t, creates the sysfs "dev" */ struct attribute_group **groups; /* optional groups */ void (*release)(struct device * dev);/*当这个设备的最后引用被删除时,内核调用该方法; 它从被嵌入的 kobject 的 release 方法中调用。所有注册到核心的设备结构必须有一个 release 方法, 否则内核将打印错误信息*/ }; /*在注册 struct device 前,最少要设置parent, bus_id, bus, 和 release 成员*/ |
设备的注册和注销函数为:
int device_register(struct device *dev); void device_unregister(struct device *dev); |
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 }; /*这是顶层总线,parent 和 bus 成员为 NULL*/ /*作为第一个(并且唯一)总线, 它的名字为 ldd0,这个总线设备的注册代码如下:*/ ret = device_register(&ldd_bus); if (ret) printk(KERN_NOTICE "Unable to register ldd0/n"); /*一旦调用完成, 新总线会在 sysfs 中 /sys/devices 下显示,任何挂到这个总线的设备会在 /sys/devices/ldd0 下显示*/ |
sysfs 中的设备入口可有属性,相关的结构是:
/* interface for exporting device attributes 这个结构体和《LDD3》中的不同,已经被更新过了,请特别注意!*/ 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); /*这个宏声明一个结构, 将 dev_attr_ 作为给定 _name 的前缀来命名设备属性 /*属性文件的实际处理使用以下函数:*/ int device_create_file(struct device *device, struct device_attribute * entry); void device_remove_file(struct device * dev, struct device_attribute * attr); |
device 结构包含设备模型核心用来模拟系统的信息。但大部分子系统记录了关于它们又拥有的设备的额外信息,所以很少单纯用 device 结构代表设备,而是,通常将其嵌入一个设备的高层表示中。底层驱动几乎不知道 struct device。
lddbus 驱动创建了它自己的 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); |
/* * LDD devices. */ /* * For now, no references to LDDbus devices go out which are not * tracked via the module reference count, so we use a no-op * release function. */ static void ldd_dev_release(struct device *dev) { } int register_ldd_device(struct ldd_device *ldddev) { ldddev->dev.bus = &ldd_bus_type; ldddev->dev.parent = &ldd_bus; ldddev->dev.release = ldd_dev_release; strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE); return device_register(&ldddev->dev); } EXPORT_SYMBOL(register_ldd_device); void unregister_ldd_device(struct ldd_device *ldddev) { device_unregister(&ldddev->dev); } EXPORT_SYMBOL(unregister_ldd_device); |
static ssize_t sculld_show_dev(struct device *ddev, struct device_attribute *attr, char*buf) { struct sculld_dev *dev = ddev->driver_data; return print_dev_t(buf, dev->cdev.dev); } static DEVICE_ATTR(dev, S_IRUGO, sculld_show_dev, NULL); /*接着, 在初始化时间, 设备被注册, 并且 dev 属性通过下面的函数被创建:*/ static void sculld_register_dev(struct sculld_dev *dev, int index) { sprintf(dev->devname, "sculld%d", index); dev->ldev.name = dev->devname; dev->ldev.driver = &sculld_driver; dev->ldev.dev.driver_data = dev; register_ldd_device(&dev->ldev); if (device_create_file(&dev->ldev.dev, &dev_attr_dev)) printk( "Unable to create dev attribute ! /n"); } /*注意:程序使用 driver_data 成员来存储指向我们自己的内部的设备结构的指针。请检查 device_create_file 的返回值,否则编译时会有警告。*/ |
相关文章推荐
- Linux设备模型(总线、设备、驱动程序和类)之二:device
- Linux设备模型(总线、设备、驱动程序和类)之二:device
- Linux设备模型(总线、设备、驱动程序和类)之三:device_driver && 多厂家驱动自动识别
- Linux设备模型(总线、设备、驱动程序和类)之三:device_driver && 多厂家驱动自动识别
- Linux设备模型(总线、设备、驱动程序和类)之三:device_driver && 多厂家驱动自动识别
- Linux设备模型(总线、设备、驱动程序和类)之一:bus_type
- Linux设备模型(总线、设备、驱动程序和类)之四:class_register
- Linux设备模型(总线、设备、驱动程序和类)
- Linux设备模型(总线、设备、驱动程序和类)
- Linux设备模型(总线、设备、驱动程序和类)
- Linux设备模型(总线、设备、驱动程序和类)之一:bus_type
- Linux设备模型中三个很重要的概念: 总线,设备,驱动.即bus,device,driver
- (收藏) Linux设备驱动程序学习-Linux设备模型(总线、设备、驱动程序和类)
- Linux设备驱动程序学习(13)-Linux设备模型(总线、设备、驱动程序和类)
- Linux设备模型 -- 总线、设备、驱动程序和类(机制理解)
- 转载_Linux设备模型(总线、设备、驱动程序和类)
- Linux设备模型(总线、设备、驱动程序和类) (个人认为网上写的层次最清楚的资料)
- Linux设备模型<三>总线、设备、驱动程序
- Linux设备模型(总线、设备、驱动程序和类)
- Linux 设备模型之(总线、设备和驱动程序)(三)