- 論壇徽章:
- 0
|
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
Normal
0
7.8 磅
0
2
false
false
false
MicrosoftInternetExplorer4
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:普通表格;
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin:0cm;
mso-para-margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:10.0pt;
font-family:"Times New Roman";
mso-fareast-font-family:"Times New Roman";
mso-ansi-language:#0400;
mso-fareast-language:#0400;
mso-bidi-language:#0400;}
在前面一篇
linux設(shè)備模型深探(1)
我們詳細(xì)了解了底層元素kset,kobject,ktype之間的關(guān)系后,本節(jié)講解下驅(qū)動模型中另外幾個概念(bus、driver、device)為后面具體分析特定驅(qū)動(platform,pci)模型打個基礎(chǔ)。
BUS
在設(shè)備模型中,所有的device都是通過總線bus 連接,這里的bus包括通常意義的總線如usb,pci,也包括虛擬的platform總線。
[root@wangp bus]#
pwd
/sys/bus
[root@wangp bus]#
ls
ac97 acpi
bluetooth gameport i2c
ide pci pci_express
pcmcia platform pnp scsi serio usb
[root@wangp
platform]# pwd
/sys/bus/platform
[root@wangp
platform]# ls
devices drivers
struct bus_type {
const
char * name;
struct
module * owner;
struct
kset subsys;
struct kset drivers;
struct
kset devices;
struct
klist klist_devices;
struct
klist klist_drivers;
struct
blocking_notifier_head bus_notifier;
struct
bus_attribute * bus_attrs;
struct
device_attribute * dev_attrs;
struct
driver_attribute * drv_attrs;
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
(*suspend)(struct device * dev, pm_message_t state);
int
(*suspend_late)(struct device * dev, pm_message_t state);
int
(*resume_early)(struct device * dev);
int
(*resume)(struct device * dev);
unsigned
int drivers_autoprobe:1;
};
name是總線的名字,每個總線下都有自己的子系統(tǒng),其中包含2個kset,deviece和driver,分別代表已知總線的驅(qū)動和插入總線的設(shè)備
如platform總線的聲明如下:
struct bus_type
platform_bus_type = {
.name =
"platform",
.dev_attrs = platform_dev_attrs,
.match =
platform_match,
.uevent =
platform_uevent,
.suspend =
platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume =
platform_resume,
};
只有很少的bus_type成員需要初始化,大部分交給kernel來處理
關(guān)于總線的操作常用的如下:
int
bus_register(struct bus_type * bus);
void
bus_unregister(struct bus_type * bus);
/* iterator helpers
for buses */
列舉總線上從start之后的每個設(shè)備,并進(jìn)行fn操作,通常用途是對bus上的設(shè)備和驅(qū)動進(jìn)行綁定
int
bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int
(*fn)(struct device *, void *));
int
driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus,
NULL, drv, __driver_attach);
}
static int
__driver_attach(struct device * dev, void * data)
{
struct device_driver * drv = data;
/*
*
Lock device and try to bind to it. We drop the error
*
here and always return 0, because we need to keep trying
*
to bind to devices and some drivers will return an error
*
simply if it didn't support the device.
*
*
driver_probe_device() will spit a warning if there
*
is an error.
*/
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
down(&dev->sem);
if (!dev->driver)
driver_probe_device(drv, dev);
up(&dev->sem);
if (dev->parent)
up(&dev->parent->sem);
return 0;
}
幾乎linux設(shè)備模型的每一層都提供了添加屬性的函數(shù),總線也不例外
struct bus_attribute
{
struct attribute attr;
ssize_t (*show)(struct bus_type *, char *
buf); //顯示屬性
ssize_t (*store)(struct bus_type *, const
char * buf, size_t count); //設(shè)置屬性
};
創(chuàng)建屬于一個總線的屬性使用(在模塊的加載時間完成)
int bus_create_file(struct bus_type *,struct
bus_attribute *);
void
bus_remove_file(struct bus_type *, struct bus_attribute *);
在說明下bus在sysfs里面的結(jié)構(gòu),剛才已經(jīng)講過,bus_type中有2個kset結(jié)構(gòu)對應(yīng)于device和driver,也就是說每個bus下面都會有device何driver2個文件夾。
首先在總線上注冊的驅(qū)動會得到一個文件夾driver,如platform驅(qū)動
[root@wangp
platform]# pwd
/sys/bus/platform
[root@wangp
platform]# ls
devices drivers
[root@wangp
drivers]# pwd
/sys/bus/platform/drivers
[root@wangp
drivers]# ls
i8042 pcspkr
serial8250 vesafb
而任何在總線/sys/bus/xxx/上發(fā)現(xiàn)的設(shè)備會得到一個symlink(符號鏈接)即/sys/bus/xxx/device指向/sys/device/xxx下面的文件夾
[root@wangp
devices]# pwd
/sys/bus/platform/devices
[root@wangp
devices]# ls -l
total 0
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 bluetooth ->
../../../devices/platform/bluetooth
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 floppy.0 ->
../../../devices/platform/floppy.0
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 i8042 ->
../../../devices/platform/i8042
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 pcspkr ->
../../../devices/platform/pcspkr
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 serial8250 ->
../../../devices/platform/serial8250
lrwxrwxrwx 1 root
root 0 Jun 6 10:37 vesafb.0 ->
../../../devices/platform/vesafb.0
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; //該設(shè)備所屬的設(shè)備
struct kobject kobj;
char bus_id[BUS_ID_SIZE]; /* position on parent bus */
struct device_type *type;
unsigned is_registered:1;
unsigned uevent_suppress:1;
struct semaphore sem; /* semaphore to
synchronize calls to
* its driver.
*/
struct bus_type * bus; /* type
of bus device is on */
struct device_driver *driver; /* which driver has allocated this device */
void *driver_data; /* data private to the driver */
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);
};
這個結(jié)構(gòu)相當(dāng)于一個基類,對于基于特定總線的設(shè)備,會派生出特定的device結(jié)構(gòu)(linux的驅(qū)動模型有很多結(jié)構(gòu)都可以基于類來看待)
struct
platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource * resource;
};
一個總線設(shè)備用如下函數(shù)注冊(注冊總線類型)
int
device_register(struct device *dev)
{
device_initialize(dev);
return device_add(dev);
}
以完成parent name bus_id bus幾個成員的初始化,注冊后可以在/sys/devices下面看到
void
device_unregister(struct device *dev);
同時和其相關(guān)的屬性為
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);
};
int
device_create_file(struct device *device,struct device_attribute * entry);
device_remove_file(struct
device * dev, struct device_attribute * attr);
以下完成一個總線設(shè)備的注冊:
static void
simple_bus_release(struct device *dev)
{
printk("simple bus release\n");
}
struct device
simple_bus = {
.bus_id ="simple_bus",
.release = simple_bus_release
}
ret =
device_register(&simple_bus);
if(ret)
pritnk("unable
to register simple_bus\n");
完成注冊后,simple_bus就可以再sysfs中/sys/devices下面看見,任何掛載這個bus上的device都會在/sys/devices/simple_bus下看到
DEVICE_DRIVER
struct device_driver
{
const char * name;//在sysfs下顯示
struct bus_type * bus;
struct kobject kobj;
struct klist klist_devices;
struct klist_node knode_bus;
struct module * owner;
const char * mod_name; /* used
for built-in modules */
struct module_kobject * mkobj;
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);
};
由于大多數(shù)驅(qū)動都會帶有特有的針對某種特定總線的信息,因此一般都是基于device_driver來派生出自己
特有的驅(qū)動,如
struct
platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device
*);
int (*suspend)(struct platform_device *,
pm_message_t state);
int (*suspend_late)(struct
platform_device *, pm_message_t state);
int (*resume_early)(struct
platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
};
比較xxx_driver 和device_driver我們可以發(fā)現(xiàn),結(jié)構(gòu)體所帶的方法基本相同,在具體應(yīng)該用的時候是可以轉(zhuǎn)換的。
驅(qū)動的注冊
int
driver_register(struct device_driver * drv);
void
driver_unregister(struct device_driver * drv);
而大多數(shù)驅(qū)動會調(diào)用針對特定總線的諸如platform_driver_register,pci_driver_register之類的函數(shù)去注冊
總線(bus)可以掛接一類設(shè)備(device)
驅(qū)動(driver)可以驅(qū)動一類設(shè)備(device)
因此和bus一樣,device_driver也有一個函數(shù)為某個驅(qū)動來遍歷所有設(shè)備
int
driver_for_each_dev(struct device_driver *drv, void *data,int
(*callback)(struct device *dev,void *data);
所有device_driver完成注冊后,會在/sys/bus/xxx/driver目錄下看到驅(qū)動信息
同時相應(yīng)的屬性內(nèi)容
struct
driver_attribute {
struct attribute attr;
ssize_t (*show)(struct device_driver *,
char * buf);
ssize_t (*store)(struct device_driver *,
const char * buf, size_t count);
};
int driver_create_file(struct device_driver
*,struct driver_attribute *);
void
driver_remove_file(struct device_driver *, struct driver_attribute *);
說了這么多,現(xiàn)在來理一理kobject kset,subsys,sysfs,bus之間的關(guān)系
上圖反映了繼承體系的一個基本結(jié)構(gòu),kset是一組相同的kobject的集合,kernel可以通過跟蹤kset來跟蹤所用的特定類型設(shè)備,platform、pci、i2c等,kset起到連接作用將設(shè)備模型和sysfs聯(lián)系在一起。每個kset自身都包含一個kobject,這個kobject將作為很多其他的kobject的父類,從sys上看,某個kobject的父類是某個目錄,那么它就是那個目錄的子目錄,parent指針可以代表目錄層次,這樣典型的設(shè)備模型層次就建立起來了,從面向?qū)ο蟮挠^點(diǎn)看,kset是頂層的容器類,kset繼承他自己的kobject,并且可以當(dāng)做kobject來處理
![]()
如圖:kset把它的子類kobject放在鏈表里面,kset子類鏈表里面那些kobject的kset指針指向上面的kset,parent指向父類。
struct kobject {
const char * k_name;
struct kref kref;
struct list_head entry;
struct kobject * parent;
struct kset * kset;
struct kobj_type * ktype;
struct sysfs_dirent * sd;
};
struct kset {
struct kobj_type *ktype;
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
struct kset_uevent_ops *uevent_ops;
};
![]()
![]()
有了這些基本單元,就可以派生出許多其他的新類別
![]()
了解了驅(qū)動模型的構(gòu)架后,我們就可以分析具體的驅(qū)動(platform,pci)。
本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u2/72003/showart_1958091.html |
|