Linux設備驅動程序學習-Linux設備模型(總線、設備、驅動程序和類)_第1頁
Linux設備驅動程序學習-Linux設備模型(總線、設備、驅動程序和類)_第2頁
Linux設備驅動程序學習-Linux設備模型(總線、設備、驅動程序和類)_第3頁
Linux設備驅動程序學習-Linux設備模型(總線、設備、驅動程序和類)_第4頁
Linux設備驅動程序學習-Linux設備模型(總線、設備、驅動程序和類)_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

1、Linux設備驅動程序學習(13)-Linux設備模型(總線、設備、驅動程序和類)Linux設備驅動程序學習(13)-Linux設備模型(總線、設備、驅動程序和類)文章的例子和實驗使用LDD3所配的lddbus模塊(稍作修改)。提示:在學習這部分內(nèi)容是一定要分析所有介紹的源代碼,知道他們與上一部分內(nèi)容(kobject、kset、attribute等等)的關系,最好要分析一個實際的“flatform device”設備,不然會只學到表象,到后面會不知所云的??偩€總線是處理器和一個或多個設備之間的通道,在設備模型中, 所有的設備都通過總線相連, 甚至是內(nèi)部的虛擬platform總線??偩€可以相互插

2、入。設備模型展示了總線和它們所控制的設備之間的實際連接。在 Linux 設備模型中, 總線由 bus_type 結構表示, 定義在 : struct bus_type const char* name;/*總線類型名稱*/struct module* owner;/*指向模塊的指針(如果有), 此模塊負責操作這個總線*/struct ksetsubsys;/*與該總線相關的子系統(tǒng)*/struct ksetdrivers;/*總線驅動程序的kset*/struct ksetdevices;/* 掛在該總線的所有設備的kset*/struct klistklist_devices;/*與該總線相關

3、的驅動程序鏈表*/struct klistklist_drivers;/*掛接在該總線的設備鏈表*/struct blocking_notifier_head bus_notifier;struct bus_attribute* bus_attrs; /*總線屬性*/struct device_attribute * dev_attrs; /*設備屬性,指向為每個加入總線的設備建立的默認屬性鏈表*/struct driver_attribute * drv_attrs; /*驅動程序屬性*/struct bus_attribute drivers_autoprobe_attr;/*驅動自動探測

4、屬性*/struct bus_attribute drivers_probe_attr;/*驅動探測屬性*/int(*match)(struct device * dev, struct device_driver * drv);int(*uevent)(struct device *dev, char *envp, int num_envp, char *buffer, int buffer_size);int(*probe)(struct device * dev);int(*remove)(struct device * dev);void(*shutdown)(struct devic

5、e * 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);nt (*resume)(struct device * dev);/*處理熱插拔、電源管理、探測和移除等事件的方法*/unsigned int drivers_autoprobe:1;在更新的內(nèi)核里,這個結構體變得更簡潔了,隱藏了無需驅動編程人員知道的一些成員:/

6、*in Linux */structbus_typeconstchar*name;structbus_attribute*bus_attrs;structdevice_attribute*dev_attrs;structdriver_attribute*drv_attrs;int(*match)(structdevice*dev,structdevice_driver*drv);int(*uevent)(structdevice*dev,structkobj_uevent_env*env);int(*probe)(structdevice*dev);int(*remove)(s

7、tructdevice*dev);void(*shutdown)(structdevice*dev);int(*suspend)(structdevice*dev,pm_message_t state);int(*suspend_late)(structdevice*dev,pm_message_t state);int(*resume_early)(structdevice*dev);int(*resume)(structdevice*dev);structbus_type_private*p;structbus_type_privatestructkset subsys;structkse

8、t*drivers_kset;structkset*devices_kset;structklist klist_devices;structklist klist_drivers;structblocking_notifier_head bus_notifier;unsignedintdrivers_autoprobe:1;structbus_type*bus;總線的注冊和刪除總線的主要注冊步驟:(1)申明和初始化 bus_type 結構體。只有很少的 bus_type 成員需要初始化,大部分都由設備模型核心控制。但必須為總線指定名字及一些必要的方法。例如: struct bus_type

9、ldd_bus_type = .name = ldd,.match = ldd_match,.uevent = ldd_uevent,;(2)調(diào)用bus_register函數(shù)注冊總線。 int bus_register(struct bus_type * bus)調(diào)用可能失敗, 所以必須始終檢查返回值。若成功,新的總線子系統(tǒng)將被添加進系統(tǒng),并可在 sysfs的 /sys/bus 下看到。之后可以向總線添加設備。例如: ret = bus_register(&ldd_bus_type);if (ret)return ret; 當必須從系統(tǒng)中刪除一個總線時, 調(diào)用:void bus_unregis

10、ter(struct bus_type *bus);總線方法在 bus_type 結構中定義了許多方法,它們允許總線核心作為設備核心和單獨的驅動程序之間提供服務的中介,主要介紹以下兩個方法: int (*match)(struct device * dev, struct device_driver * drv);/*當一個新設備或者驅動被添加到這個總線時,這個方法會被調(diào)用一次或多次,若指定的驅動程序能夠處理指定的設備,則返回非零值。必須在總線層使用這個函數(shù), 因為那里存在正確的邏輯,核心內(nèi)核不知道如何為每個總線類型匹配設備和驅動程序*/int (*uevent)(struct device

11、*dev, char *envp, int num_envp, char *buffer, int buffer_size);/*在為用戶空間產(chǎn)生熱插拔事件之前,這個方法允許總線添加環(huán)境變量(參數(shù)和 kset 的uevent方法相同)*/lddbus的match和uevent方法: static int ldd_match(struct device *dev, struct device_driver *driver)return !strncmp(dev-bus_id, driver-name, strlen(driver-name);/*僅簡單比較驅動和設備的名字*/*當涉及實際硬件時,

12、 match 函數(shù)常常對設備提供的硬件 ID 和驅動所支持的 ID 做比較*/static int ldd_uevent(struct device *dev, char *envp, int num_envp, char *buffer, int buffer_size)envp0 = buffer;if (snprintf(buffer, buffer_size, LDDBUS_VERSION=%s,Version) = buffer_size)return -ENOMEM;envp1 = NULL;return 0;/*在環(huán)境變量中加入 lddbus 源碼的當前版本號*/對設備和驅動的迭

13、代若要編寫總線層代碼, 可能不得不對所有已經(jīng)注冊到總線的設備或驅動進行一些操作,這可能需要仔細研究嵌入到 bus_type 結構中的其他數(shù)據(jù)結構, 但最好使用內(nèi)核提供的輔助函數(shù): int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *);int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(stru

14、ct device_driver *, void *);/*這兩個函數(shù)迭代總線上的每個設備或驅動程序, 將關聯(lián)的 device 或 device_driver 傳遞給 fn, 同時傳遞 data 值。若 start 為 NULL, 則從第一個設備開始; 否則從 start 之后的第一個設備開始。若 fn 返回非零值, 迭代停止并且那個值從 bus_for_each_dev 或bus_for_each_drv 返回。*/總線屬性幾乎 Linux 設備模型中的每一層都提供添加屬性的函數(shù), 總線層也不例外。bus_attribute 類型定義在 如下: struct bus_attribute st

15、ruct attributeattr;ssize_t (*show)(struct bus_type *, char * buf);ssize_t (*store)(struct bus_type *, const char * buf, size_t count);可以看出struct bus_attribute 和struct attribute 很相似,其實大部分在 kobject 級上的設備模型層都是以這種方式工作。內(nèi)核提供了一個宏在編譯時創(chuàng)建和初始化 bus_attribute 結構: BUS_ATTR(_name,_mode,_show,_store)/*這個宏聲明一個結構, 將

16、bus_attr_ 作為給定 _name 的前綴來創(chuàng)建總線的真正名稱*/*總線的屬性必須顯式調(diào)用 bus_create_file 來創(chuàng)建:*/int bus_create_file(struct bus_type *bus, struct bus_attribute *attr); /*刪除總線的屬性調(diào)用:*/void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr); 例如創(chuàng)建一個包含源碼版本號簡單屬性文件方法如下: static ssize_t show_bus_version(struct bus_type

17、 *bus, char *buf)return snprintf(buf, PAGE_SIZE, %sn, Version);static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); /*在模塊加載時創(chuàng)建屬性文件:*/if (bus_create_file(&ldd_bus_type, &bus_attr_version)printk(KERN_NOTICE Unable to create version attributen);/*這個調(diào)用創(chuàng)建一個包含 lddbus 代碼的版本號的屬性文件(/sys/bus/ldd/version

18、)*/設備 在最底層, Linux 系統(tǒng)中的每個設備由一個 struct device 代表: struct device struct klistklist_children;struct klist_nodeknode_parent;/* node in sibling list */struct klist_nodeknode_driver;struct klist_nodeknode_bus;struct device*parent;/* 設備的 父 設備,該設備所屬的設備,通常一個父設備是某種總線或者主控制器. 如果 parent 是 NULL, 則該設備是頂層設備,較少見 */st

19、ruct kobject kobj;/*代表該設備并將其連接到結構體系中的 kobject; 注意:作為通用的規(guī)則, device-kobj-parent 應等于 device-parent-kobj*/charbus_idBUS_ID_SIZE;/*在總線上唯一標識該設備的字符串;例如: PCI 設備使用標準的 PCI ID 格式, 包含:域, 總線, 設備, 和功能號.*/struct device_type*type;unsignedis_registered:1;unsigneduevent_suppress:1;struct device_attribute uevent_attr;

20、struct device_attribute *devt_attr;struct semaphoresem;/* semaphore to synchronize calls to its driver. */struct bus_type* bus;/*標識該設備連接在何種類型的總線上*/struct device_driver *driver;/*管理該設備的驅動程序*/void*driver_data;/*該設備驅動使用的私有數(shù)據(jù)成員*/void*platform_data;/* Platform specific data, devicecore doesnt touch it */

21、struct dev_pm_infopower;#ifdef CONFIG_NUMAintnuma_node;/* NUMA node this device is close to */#endifu64*dma_mask;/* dma mask (if dmaable device) */u64coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such desc

22、riptors. */struct list_headdma_pools;/* dma pools (if dmable) */struct dma_coherent_mem*dma_mem; /* internal for coherent mem override */* arch specific additions */struct dev_archdataarchdata;spinlock_tdevres_lock;struct list_headdevres_head;/* class_device migration path */struct list_headnode;str

23、uct class*class;dev_tdevt;/* dev_t, creates the sysfs dev */struct attribute_group*groups;/* optional groups */void(*release)(struct device * dev);/*當這個設備的最后引用被刪除時,內(nèi)核調(diào)用該方法; 它從被嵌入的 kobject 的 release 方法中調(diào)用。所有注冊到核心的設備結構必須有一個 release 方法, 否則內(nèi)核將打印錯誤信息*/;/*在注冊 struct device 前,最少要設置parent, bus_id, bus, 和 re

24、lease 成員*/設備注冊設備的注冊和注銷函數(shù)為: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 releasen);struct device ldd_bus = .bus_id = ldd0,.release = ldd_bus_

25、release; /*這是頂層總線,parent 和 bus 成員為 NULL*/*作為第一個(并且唯一)總線, 它的名字為 ldd0,這個總線設備的注冊代碼如下:*/ret = device_register(&ldd_bus);if (ret)printk(KERN_NOTICE Unable to register ldd0n);/*一旦調(diào)用完成, 新總線會在 sysfs 中 /sys/devices 下顯示,任何掛到這個總線的設備會在 /sys/devices/ldd0 下顯示*/設備屬性sysfs 中的設備入口可有屬性,相關的結構是: /* interface for exporti

26、ng device attributes 這個結構體和LDD3中的不同,已經(jīng)被更新過了,請?zhí)貏e注意!*/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);/*設備屬性結構可在編譯時建立, 使用以下宏:*/D

27、EVICE_ATTR(_name,_mode,_show,_store);/*這個宏聲明一個結構, 將 dev_attr_ 作為給定 _name 的前綴來命名設備屬性/*屬性文件的實際處理使用以下函數(shù):*/int device_create_file(struct device *device,struct device_attribute * entry);void device_remove_file(struct device * dev, struct device_attribute * attr);設備結構的嵌入device 結構包含設備模型核心用來模擬系統(tǒng)的信息。但大部分子系統(tǒng)記

28、錄了關于它們又擁有的設備的額外信息,所以很少單純用 device 結構代表設備,而是,通常將其嵌入一個設備的高層表示中。底層驅動幾乎不知道 struct device。lddbus 驅動創(chuàng)建了它自己的 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 導出的注冊和注銷接口如

29、下: /* 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-d

30、ev.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_devic

31、e);sculld 驅動添加一個自己的屬性到它的設備入口,稱為 dev, 僅包含關聯(lián)的設備號,源碼如下: 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);/*接著, 在初始化時間, 設備被注冊

32、, 并且 dev 屬性通過下面的函數(shù)被創(chuàng)建:*/static void sculld_register_dev(struct sculld_dev *dev, int index) sprintf(dev-devname, sculld%d, index); = 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_

33、dev) printk( Unable to create dev attribute ! n); /*注意:程序使用 driver_data 成員來存儲指向我們自己的內(nèi)部的設備結構的指針。請檢查device_create_file的返回值,否則編譯時會有警告。*/設備驅動程序 設備模型跟蹤所有系統(tǒng)已知的驅動,主要目的是使驅動程序核心能協(xié)調(diào)驅動和新設備之間的關系。一旦驅動在系統(tǒng)中是已知的對象就可能完成大量的工作。驅動程序的結構體 device_driver 定義如下: /*定義在*/struct device_driver const char* name;/*驅動程序的名字( 在 sysfs

34、 中出現(xiàn) )*/struct bus_type* bus;/*驅動程序所操作的總線類型*/struct kobjectkobj;/*內(nèi)嵌的kobject對象*/struct klistklist_devices;/*當前驅動程序能操作的設備鏈表*/struct klist_nodeknode_bus;struct module* owner;const char * mod_name;/* used for built-in modules */struct module_kobject* mkobj;int(*probe)(struct device * dev);/*查詢一個特定設備是否存

35、在及驅動是否可以使用它的函數(shù)*/int(*remove)(struct device * dev);/*將設備從系統(tǒng)中刪除*/void(*shutdown)(struct device * dev);/*關閉設備*/int(*suspend)(struct device * dev, pm_message_t state);int(*resume)(struct device * dev);/*注冊device_driver 結構的函數(shù)是:*/int driver_register(struct device_driver *drv);void driver_unregister(struct

36、 device_driver *drv);/*driver的屬性結構在:*/struct driver_attribute struct attribute attr;ssize_t (*show)(struct device_driver *drv, char *buf);ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count);DRIVER_ATTR(_name,_mode,_show,_store)/*屬性文件創(chuàng)建的方法:*/int driver_create_file(struct device

37、_driver * drv, struct driver_attribute * attr);void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);/*bus_type 結構含有一個成員( drv_attrs ) 指向一組為屬于該總線的所有設備創(chuàng)建的默認屬性*/在更新的內(nèi)核里,這個結構體變得更簡潔了,隱藏了無需驅動編程人員知道的一些成員:/*in Linux */structdevice_driverconstchar*name;structbus_type*bus

38、;structmodule*owner;constchar*mod_name;/* used for built-in modules */int(*probe)(structdevice*dev);int(*remove)(structdevice*dev);void(*shutdown)(structdevice*dev);int(*suspend)(structdevice*dev,pm_message_t state);int(*resume)(structdevice*dev);structattribute_group*groups;structdriver_private*p;s

39、tructdriver_privatestructkobject kobj;structklist klist_devices;structklist_node knode_bus;structmodule_kobject*mkobj;structdevice_driver*driver;#defineto_driver(obj)container_of(obj,structdriver_private,kobj)驅動程序結構的嵌入對大多數(shù)驅動程序核心結構, device_driver 結構通常被嵌入到一個更高層的、總線相關的結構中。以lddbus 子系統(tǒng)為例,它定義了ldd_driver 結

40、構: struct ldd_driver char *version;struct module *module;struct device_driver driver;struct driver_attribute version_attr; ; #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver); lddbus總線中相關的驅動注冊和注銷函數(shù)是: /* Crude driver interface.*/static ssize_t show_version(struct device_driver *

41、driver, char *buf)struct ldd_driver *ldriver = to_ldd_driver(driver);sprintf(buf, %sn, ldriver-version);return strlen(buf);int register_ldd_driver(struct ldd_driver *driver)int ret;driver-driver.bus = &ldd_bus_type;ret = driver_register(&driver-driver);/*注冊底層的 device_driver 結構到核心*/if (ret)return ret

42、;driver-version_ = version;/* driver_attribute 結構必須手工填充*/driver-version_attr.attr.owner = driver-module;/*注意:設定 version 屬性的擁有者為驅動模塊, 不是 lddbus 模塊!因為 show_version 函數(shù)是使用驅動模塊所創(chuàng)建的 ldd_driver 結構,若 ldd_driver 結構在一個用戶空間進程試圖讀取版本號時已經(jīng)注銷,就會出錯*/driver-version_attr.attr.mode = S_IRUGO;driver-versio

43、n_attr.show = show_version;driver-version_attr.store = NULL;return driver_create_file(&driver-driver, &driver-version_attr);/*建立版本屬性,因為這個屬性在運行時被創(chuàng)建,所以不能使用 DRIVER_ATTR 宏*/void unregister_ldd_driver(struct ldd_driver *driver)driver_unregister(&driver-driver);EXPORT_SYMBOL(register_ldd_driver);EXPORT_SY

44、MBOL(unregister_ldd_driver);在sculld 中創(chuàng)建的 ldd_driver 結構如下: /* Device model stuff */static struct ldd_driver sculld_driver = .version = $Revision: 1.21 $,.module = THIS_MODULE,.driver = .name = sculld,;/*只要一個簡單的 register_ldd_driver 調(diào)用就可添加它到系統(tǒng)中。一旦完成初始化, 驅動信息可在 sysfs 中顯示*/類 子系統(tǒng)類是一個設備的高層視圖, 它抽象出了底層的實現(xiàn)細節(jié),

45、從而允許用戶空間使用設備所提供的功能, 而不用關心設備是如何連接和工作的。類成員通常由上層代碼所控制, 而無需驅動的明確支持。但有些情況下驅動也需要直接處理類。幾乎所有的類都顯示在 /sys/class 目錄中。出于歷史的原因,有一個例外:塊設備顯示在 /sys/block目錄中。在許多情況, 類子系統(tǒng)是向用戶空間導出信息的最好方法。當類子系統(tǒng)創(chuàng)建一個類時, 它將完全擁有這個類,根本不用擔心哪個模塊擁有那些屬性,而且信息的表示也比較友好。為了管理類,驅動程序核心導出了一些接口,其目的之一是提供包含設備號的屬性以便自動創(chuàng)建設備節(jié)點,所以udev的使用離不開類。 類函數(shù)和結構與設備模型的其他部分遵

46、循相同的模式,所以真正嶄新的概念是很少的。注意:class_simple 是老接口,在2.6.13中已被刪除,這里不再研究。管理類的接口類由 struct class 的結構體來定義:/* device classes*/struct class const char* name;/*每個類需要一個唯一的名字, 它將顯示在 /sys/class 中*/struct module* owner;struct ksetsubsys;struct list_headchildren;struct list_headdevices;struct list_headinterfaces;struct k

47、setclass_dirs;struct semaphoresem;/* locks both the children and interfaces lists */struct class_attribute* class_attrs;/* 指向類屬性的指針(以NULL結尾) */struct class_device_attribute* class_dev_attrs;/* 指向類中每個設備的一組默認屬性的指針 */struct device_attribute* dev_attrs;int(*uevent)(struct class_device *dev, char *envp,

48、int num_envp, char *buffer, int buffer_size);/* 類熱插拔產(chǎn)生時添加環(huán)境變量的函數(shù) */int(*dev_uevent)(struct device *dev, char *envp, int num_envp,char *buffer, int buffer_size);/* 類中的設備熱插拔時添加環(huán)境變量的函數(shù) */void(*release)(struct class_device *dev);/* 把設備從類中刪除的函數(shù) */void(*class_release)(struct class *class);/* 刪除類本身的函數(shù) */vo

49、id(*dev_release)(struct device *dev);int(*suspend)(struct device *, pm_message_t state);int(*resume)(struct device *);/*類注冊函數(shù):*/int class_register(struct class *cls);void class_unregister(struct class *cls);/*類屬性的接口:*/struct class_attribute struct attribute attr;ssize_t (*show)(struct class *cls, ch

50、ar *buf);ssize_t (*store)(struct class *cls, const char *buf, size_t count); ; CLASS_ATTR(_name,_mode,_show,_store); int class_create_file(struct class *cls, const struct class_attribute *attr);void class_remove_file(struct class *cls, const struct class_attribute *attr);在更新的內(nèi)核里,這個結構體變得簡潔了,刪除了一些成員:/*in Linux */* device classes*/structclassconstchar*name;structmodule*owner;structksetsubsys;structlist_headdevices;structlist_headinterfaces;structksetclass_dirs;structsemaphoresem;/* locks child

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論