您的位置:首页 > 其它

摘要:0 设备驱动模型

2016-11-08 13:50 162 查看

DTS

general

                http://bbs.elecfans.com/jishu_454965_1_1.html
 

GPIO  :http://blog.csdn.net/luyejie8888/article/details/38172705      (shell命令控制)

             http://bbs.ednchina.com/BLOG_ARTICLE_3027425.HTM               (dts配置)

I2C   :http://blog.csdn.net/trbbadboy/article/details/17302357        (python)

                http://bbs.elecfans.com/jishu_454960_1_1.html                  (shell命令控制)

                http://stackoverflow.com/questions/24834174/enabling-i2c1-on-beaglebone-black-using-dtb   (dts配置)

SPI   :      http://www.cnblogs.com/dolphi/p/3662297.html                   (dts配置)

                                 

设备关键结构

struct bus_type {

 char *                                            name;

 struct subsystem                         subsys;

 struct kset                                    drivers;

 struct kset                                    devices;

 int (*match)(struct device *dev, structdevice_driver *drv);

 struct device *(*add)(struct device * parent,char * bus_id);

 int (*hotplug) (struct device *dev, char**envp,  int num_envp, char *buffer, intbuffer_size);

 /* Some fields omitted */ };

struct bus_type ldd_bus_type = {

 .name      = "ldd",

 .match     = ldd_match,

 .hotplug  = ldd_hotplug, };

bus_register(&ldd_bus_type);

match方法

一个新设备或者驱动被添加给这个总线. 它应当返回一个非零值如果给定的设备可被给定的驱动处理。

hotplug方法

                允许总线在产生一个热插拔事件在用户空间之前,添加变量到环境中。

struct device {

 struct device *                      parent;

 struct kobject                       kobj;

 char                                        bus_id[BUS_ID_SIZE];

 struct bus_type *                 bus;

 struct device_driver *         driver;

 void *                                     driver_data;

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

 /* Several fields omitted */ };

struct device ldd_bus = {

 .bus_id = "ldd0",

 .release = ldd_bus_release

};   

device_register(&ldd_bus);                                                                            注册总线

struct ldd_device  {                                              继承device

 char *                          name;

 struct ldd_driver *    driver;

 struct device             dev; 

};

int register_ldd_device(struct ldd_device *ldddev)                                belong to bus?什么时候调用?

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

returndevice_register(&ldddev->dev);                                            注册设备

struct device_driver {

 char *                                 name;

 struct bus_type *              bus;

 struct kobject                    kobj;

 struct list_head                 devices;

 int (*probe)(struct device *dev);

 int (*remove)(struct device *dev);

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

};

struct ldd_driver{

 char *version;

 struct module *module;

 struct device_driverdriver;              继承device_driver

 struct driver_attribute version_attr; 

};

static struct ldd_driver sculld_driver = {

.version = "$Revision:1.1$",

 .module = THIS_MODULE,

.driver = { .name ="sculld", }, };

设备添加过程

struct bus_type pci_bus_type= {

                .name                   = "pci",

                .match                  = pci_bus_match,

                .uevent                                = pci_uevent,

                .probe                  = pci_device_probe,

                .remove               = pci_device_remove,

                .shutdown          = pci_device_shutdown,

                .dev_attrs           = pci_dev_attrs,

                .bus_attrs           = pci_bus_attrs,

                .pm                        = PCI_PM_OPS_PTR,

};

Step1:PCI 子系统通过对 bus_register 的调用被加载入内核时. 当这个发生时, 驱动核心创建一个 sysfs 目录在/sys/bus/pci 里,它包含2 个目录:devices 和drivers.

 

struct pci_driver{

                structlist_head node;

                constchar *name;

                conststruct pci_device_id *id_table;     

                int  (*probe) (struct pci_dev *dev, const struct pci_device_id *id);

                void(*remove) (struct pci_dev *dev);  

                int  (*suspend) (struct pci_dev *dev, pm_message_tstate);     

                int  (*suspend_late) (struct pci_dev *dev,pm_message_t state);

                int  (*resume_early) (struct pci_dev *dev);

                int  (*resume) (struct pci_dev *dev);                     /* Device woken up */

                void(*shutdown) (struct pci_dev *dev);

                structpci_error_handlers *err_handler;

                structdevice_driver       driver;

                structpci_dynids dynids;

};

Step2:pci_driver被 PCI 核心初始化,当 PCI 驱动被注册时

drv->driver.name = drv->name;

drv->driver.bus = &pci_bus_type;

drv->driver.probe = pci_device_probe;

drv->driver.remove =pci_device_remove; 

drv->driver.kobj.ktype =&pci_driver_kobj_type;

Step3:PCI 核心注册 PCI 驱动到驱动核心

                driver_register(&drv->driver);

Step4:查找所有的 PCI 设备. 当一个 PCI 设备被发现, PCI 核心在内存中创建一个 struct pci_dev 类型的新变量

struct pci_dev {

 /* ... */

 unsigned int devfn;

 unsigned short vendor;

 unsigned short device;

 unsigned short subsystem_vendor;

 unsigned short subsystem_device;

 unsigned int class;

 /* ... */

 struct pci_driver *driver;

 /* ... */

 struct device dev;

 /* ... */

 

};

Step5:在 PCI 设备结构被初始化之后, 设备被注册到驱动核心

                device_register(&dev->dev);

Step6:设备接着被添加到所有设备的总线特定的列表中,接着注册到这个总线的所有驱动的列表被检查,并且总线的匹配功能被调用给每个驱动,指定这个设备(对于pci_bus_type 总线,匹配函数被PCI 核心设定为指向pci_bus_match 函数)

Step7:如果这个 probe 函数能够认领这个设备, 它做所有的需要的初始化来正确处理这个设备,驱动核心来添加设备到当前被这个特定驱动所绑定的所有设备列表,并且创建一个符号连接到这个它现在控制的设备

网络驱动

Struct net_device {

全局信息

                名称、状态、链表节点、初始化函数指针

硬件信息

                内存信息、I/O基址、中断、dma

接口信息

                具体接口类型(如ether)相关信息

设备方法

                Open/close……

}

创建net_device

net_device *alloc_netdev(intsizeof_priv, const char *name, void( *setup)(net_device *))

net_device初始化

ether_setup(dev);                                   以太网相关的缺省初始化

dev->open = snull_open;                       网络设备的处理函数

dev->stop = snull_release;

……

priv私有数据

                netdev_priv(dev)

注册网络设备

int register_netdev(net_device*dev)

模块卸载

unregister_netdev(snull_devs[i]);           从系统中删除接口

           snull_teardown_pool(snull_devs[i]);         接口内部数据清理

            free_netdev(snull_devs[i]);                         释放接口

设备方法

打开设备

                获取硬件地址       memcpy(dev->dev_addr,"\0SNUL0", ETH_ALEN);

                启动发送队列       netif_start_queue

发送

                *hard_start_xmit将sk_buff中的数据通过底层接口发送    

发送并发  

xmit_lock

netif_stop_queue、netif_wake_queue

netif_tx_disable

发送超时

*tx_timeout

发散、汇聚

避免拷贝,使用Frags数组

接收

                创建sk_buff保存报文内容

                netif_rx

接收缓解

NAPI

中断处理

                Priv->lock

                根据priv->status区分发送、接收

连接状态

Socket缓存

BOOT代码

                eth_initialize

Linux代码

                drivers/net/ethernet/ti

                drivers/net/phy

内存映射

Kobject

kobject_add

kobject_add_internal

                parent= kobject_get(kobj->parent);

                kobj_kset_join(kobj);                                                                                     //kset添加kobject

                                list_add_tail(&kobj->entry,&kobj->kset->list);

create_dir(kobj);                                                                                             //sysfs添加kobject目录

                sysfs_create_dir_ns(kobj, kobject_namespace(kobj));

                populate_dir(kobj);                                                                        //sysfs添加kobject属性文件

                                sysfs_create_file(kobj, attr);

kobj_child_ns_ops(kobj);

sysfs_enable_ns(kobj->sd);

kobj_type {

 void (*release)(struct kobject *);

 struct sysfs_ops *sysfs_ops;

 struct attribute **default_attrs; 

};

struct sysfs_ops {

 ssize_t (*show)(structkobject *kobj, struct attribute *attr, char *buffer);

 ssize_t (*store)(structkobject *kobj, struct attribute *attr, const char *buffer, size_t  size);

};

attribute {

 char *name;                                                      //属性的名字( 如同它出现在kobject 的sysfs 目录中)

 struct module *owner;                         //一个指向模块的指针(如果有一个), 模块负责这个属性的实现

 mode_t mode; 

};

非缺省属性

int sysfs_create_file(structkobject *kobj, struct attribute *attr);

struct bin_attribute {

struct attribute attr;

size_t size;

ssize_t (*read)(struct kobject*kobj, char *buffer, loff_t pos, size_t size);

ssize_t (*write)(struct kobject*kobj, char *buffer, loff_t pos, size_t size);

};

int sysfs_create_bin_file(struct kobject *kobj, structbin_attribute *attr);

热插拔事件

                热插拔事件转变为一个对/sbin/hotplug 的调用,它响应每个事件,通过加载驱动,创建

设备节点,安装分区,或者采取任何其他的合适的动作.

kset_hotplug_ops {

 int (*filter)(structkset *kset, struct kobject *kobj);

 char *(*name)(struct kset *kset, structkobject *kobj);

 int (*hotplug)(structkset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, intbuffer_size);

};

bus_type {

 char *name;

 struct subsystemsubsys;

 struct kset drivers;

 struct kset devices;

 int (*match)(structdevice *dev, struct device_driver *drv);

 struct device*(*add)(struct device * parent, char * bus_id);

 int (*hotplug)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);

 /* Some fieldsomitted */

};

int bus_register(struct bus_type *bus)

int (*match)

(struct device *device, struct device_driver *driver);

                无论何时一个新设备或者驱动被添加给这个总线,这个方法被调用.

int (*hotplug)

(struct device *device, char **envp, int num_env p, char*buffer, int buffer_size)

                在产生一个热插拔事件在用户空间之前,允许总线添加变量到环境中.

struct bus_attribute {

 struct attribute attr;

 ssize_t (*show)(struct bus_type *bus, char*buf);

ssize_t (*store)(struct bus_type*bus, const char *buf, size_t count);

};

int bus_create_file(structbus_type *bus, struct bus_attribute *attr);

device {

struct device *parent;

struct kobject kobj;

char bus_id[BUS_ID_SIZE];

struct bus_type *bus;

struct device_driver *driver;

void *driver_data;

void (*release)(structdevice *dev);

/* Several fields omitted */

};

最少, parent, bus_id, bus, 和release 成员必须在设备结构被注册前设置.

int device_register(struct device *dev);

device_attribute {

 struct attribute attr;

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

 ssize_t (*store)(struct device *dev, constchar *buf, size_t count);

};

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

device_driver {

 char *name;

 struct bus_type *bus;

 struct kobject kobj;

 struct list_head devices;

 int (*probe)(struct device *dev);

 int (*remove)(struct device *dev);

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

};

int driver_register(struct device_driver *drv);

struct class {

char *name;

 struct class_attribute *class_attrs;

 struct class_device_attribute*class_dev_attrs;

 int (*hotplug)(struct class_device *dev, char**envp, int num_envp, char *buffer, int buffer_size);

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

 void (*class_release)(struct class *class);

 /* Some fields omitted */

};

int class_register(struct class *cls);

class_device {

struct kobject kobj;

struct class *class;

struct device *dev;

void *class_data;

char class_id[BUS_ID_SIZE];

 };

class_interface {

 struct class *class;

 int (*add) (struct class_device *cd);

 void (*remove) (struct class_device *cd); 

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: