当前位置: 首页 > news >正文

网站建设常出现的问题营销策略都有哪些

网站建设常出现的问题,营销策略都有哪些,郴州网站推广公司排名,哪些网站有好的营销案例本文有部分借鉴 wowo tech ,感谢作者的无私分享 目录 1、简介 2、Platform 软件架构 3、Platform 模块向其它模块提供的 APIs 3.1、数据结构 3.1.1、platform_device 3.1.2、platform_driver 3.2、APIs 3.2.1、Platform Device 提供的 APIs 3.2.2、Platfor…

本文有部分借鉴 wowo tech ,感谢作者的无私分享

 

目录

1、简介

2、Platform 软件架构

3、Platform 模块向其它模块提供的 APIs

3.1、数据结构

3.1.1、platform_device

3.1.2、platform_driver

3.2、APIs

3.2.1、Platform Device 提供的 APIs

3.2.2、Platform Driver 提供的 APIs

4、Platform 初始化

4.1、Platform 总线初始化

5、Device 和 Driver 匹配执行 probe

5.1、platform_driver_register 情况

5.2、platform_device_register 情况

5.3、小结


 

1、简介

在Linux设备模型的抽象中,存在着一类称作“Platform Device”的设备,内核是这样描述它们的(Documentation/driver-model/platform.txt):

Platform devices are devices that typically appear as autonomous entities in the system. This includes legacy port-based devices and host bridges to peripheral buses, and most controllers integrated into system-on-chip platforms.  What they usually have in common is direct addressing from a CPU bus.  Rarely, a platform_device will be connected through a segment of some other kind of bus; but its registers will still be directly addressable.

概括来说,Platform设备包括:基于端口的设备(已不推荐使用,保留下来只为兼容旧设备,legacy);连接物理总线的桥设备;集成在SOC平台上面的控制器;连接在其它bus上的设备(很少见)。等等。

这些设备有一个基本的特征:可以通过CPU bus直接寻址(例如在嵌入式系统常见的“寄存器”)。因此,由于这个共性,内核在设备模型的基础上(device和device_driver),对这些设备进行了更进一步的封装,抽象出paltform bus、platform device和platform driver,以便驱动开发人员可以方便的开发这类设备的驱动。

platform总线是虚拟的平台总线,是linux设备驱动模型为了保持设备驱动的统一性而虚拟出来的总线。 
总线将设备和驱动绑定,系统每注册一个设备的时候,会寻找与之匹配的驱动;相反,系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

可以说,paltform设备对Linux驱动工程师是非常重要的,因为我们编写的大多数设备驱动,都是为了驱动plaftom设备。本文我们就来看看Platform设备在内核中的实现。

 

2、Platform 软件架构

内核中Platform设备有关的实现位于 include/linux/platform_device.h 和 drivers/base/platform.c 两个文件中,它的软件架构如下:

 

由图片可知,Platform设备在内核中的实现主要包括三个部分:

Platform Bus:基于底层bus模块,抽象出一个虚拟的Platform bus,用于挂载Platform设备; 
Platform Device:基于底层device模块,抽象出Platform Device,用于表示Platform设备; 
Platform Driver:基于底层device_driver模块,抽象出Platform Driver,用于驱动Platform设备。

 

3、Platform 模块向其它模块提供的 APIs

Platform 提供的接口包括:Platform Device 和 Platform Driver 两个数据结构,以及它们的操作函数。

3.1、数据结构

3.1.1、platform_device

platform_device 代表了一种 device,定义在 include/linux/platform_device.h 文件

struct platform_device {const char	* name;int		id;struct device	dev;u32		num_resources;struct resource	* resource;const struct platform_device_id	*id_entry;/* MFD cell pointer */struct mfd_cell *mfd_cell;/* arch specific additions */struct pdev_archdata	archdata;
};

它的字段解释如下:

dev:真正的设备(Platform设备只是一个特殊的设备,因此其核心逻辑还是由底层的模块实现)。

name:设备的名称,和 struct device 结构中的 init_name 一样。实际上,该名称在设备注册时,会拷贝到 dev.init_name中。

id:用于表示该设备的 ID。

id_auto:指示在注册设备时,是否自动赋予ID值(不需要人为指定啦,可以懒一点啦)。

num_resources、resource:该设备的资源描述,由struct resource(include/linux/ioport.h)结构抽象。

在Linux中,系统资源包括I/O、Memory、Register、IRQ、DMA、Bus等多种类型。这些资源大多具有独占性,不允许多个设备同时使用,因此Linux内核提供了一些API,用于分配、管理这些资源。 
当某个设备需要使用某些资源时,只需利用struct resource组织这些资源(如名称、类型、起始、结束地址等),并保存在该设备的resource指针中即可。然后在设备probe时,设备需求会调用资源管理接口,分配、使用这些资源。而内核的资源管理逻辑,可以判断这些资源是否已被使用、是否可被使用等等。

id_entry:和内核模块相关的内容,暂不说明。

mfd_cell:和MFD设备相关的内容,暂不说明。

archdata:不管它了

可以看出 platform_device 其实是裹了一层 struct device 的一种设备的抽象。

 

3.1.2、platform_driver

platform_driver 是一种特殊的 driver,它定义在 include/linux/platform_device.h 文件:

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 (*resume)(struct platform_device *);struct device_driver driver;const struct platform_device_id *id_table;
};

struct platform_driver结构和struct device_driver非常类似,无非就是提供probe、remove、suspend、resume等回调函数,这里不再细说。

另外这里有一个 id_table 的指针,该指针和 of_match_table、acpi_match_table 的功能类似:提供其它方式的设备probe。 内核会在合适的时机检查device和device_driver的名字,如果匹配,则执行probe。其实除了名称之外,还有一些宽泛的匹配方式,例如这里提到的各种match table,具体原理就先不罗嗦了,徒添烦恼!就当没看见,呵呵。 

 

3.2、APIs

3.2.1、Platform Device 提供的 APIs

Platform Device主要提供设备的分配、注册等接口,供其它driver使用,常用的包括:

1、注册/注销一个 Platform 设备:

int platform_device_register(struct platform_device *);
void platform_device_unregister(struct platform_device *);int platform_add_devices(struct platform_device **, int); // 增加多个 devices

2、获取资源:

struct resource *platform_get_resource(struct platform_device *,unsigned int, unsigned int);struct resource *platform_get_resource_byname(struct platform_device *,unsigned int,const char *);

3、获取 irq:

int platform_get_irq(struct platform_device *, unsigned int);
int platform_get_irq_byname(struct platform_device *, const char *);

4、向 platform_device 增加资源:

int platform_device_add_resources(struct platform_device *pdev,const struct resource *res,unsigned int num);

5、向 platform device 中添加自定义的数据(保存在pdev->dev.platform_data指针中)

int platform_device_add_data(struct platform_device *pdev,const void *data, size_t size);

 

3.2.2、Platform Driver 提供的 APIs

Platform Driver提供struct platform_driver的分配、注册等功能,常用的包括:

1、注册/注销 platform_driver 接口:

int platform_driver_register(struct platform_driver *);
void platform_driver_unregister(struct platform_driver *);

2、主动执行 probe 动作接口:

int platform_driver_probe(struct platform_driver *driver,int (*probe)(struct platform_device *));

3、设置/获取私有数据接口:

inline void *platform_get_drvdata(const struct platform_device *pdev);
inline void platform_set_drvdata(struct platform_device *pdev,void *data)

 

4、Platform 初始化

platform驱动工作流程: 

1. 系统开机内核初始化阶段,初始化 platform 总线; 

2. platform_device 初始化调用 platform_add_devices(一次注册多个设备)或者 platform_device_register(一次注册单个设备),这部分一般在 arch/arm/mach 配置文件中,在上电开机的时候完成 platform_device 初始化

3. platform_driver 的初始化调用 platform_driver_register 或者 driver_register,该过程一般在驱动程序的 init 函数中;

 

4.1、Platform 总线初始化

内核在启动过程中,会调用到  kernel_init() –> do_basic_setup() –> driver_init() –> platform_bus_init()  相关的东西就在这里初始化的 driver/base/platform.c

int __init platform_bus_init(void)
{int error;early_platform_cleanup();error = device_register(&platform_bus); ------- (1)if (error)return error;error =  bus_register(&platform_bus_type);  --- (2)if (error)device_unregister(&platform_bus);return error;
}

先看(1)部分,通过 device_register 它注册了一个 platform_bus 的设备,它的定义在 driver/base ,是:

struct device platform_bus = {.init_name	= "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

定义一个名为 platform 的总线设备,其他的platform设备都是它的子设备,所以这里先注册这个设备!

在看(2)部分,通过 bus_register 注册了一个 platform_bus_type 的 bus,它定义是:

struct bus_type platform_bus_type = {.name		= "platform",.dev_attrs	= platform_dev_attrs,.match		= platform_match,.uevent		= platform_uevent,.pm		= &platform_dev_pm_ops,
};

 

注册平台类型的 bus,将出现 sys 文件系统在 bus 目录下,创建一个 platform 的目录,以及相关属性文件。

这里创建好 platform 的 bus 了,就等相关的设备驱动去注册自己的 platform_device 和 platform_driver;

这里我们着重关心一下 probe 的执行时机。

 

5、Device 和 Driver 匹配执行 probe

现在 platform_bus 已经 Ready,那么我们的 device 和 driver 是如何 match 上,并且执行 driver 的 probe 的呢?

在总线上 device 和 driver 的名字匹配,就会调用 driver 的 probe 函数

那么就会存在一个问题,到底是先有 device 还是先有 driver,因为他们俩注册肯定是有先后顺序的,所以需要看看源代码

 

5.1、platform_driver_register 情况

platform_driver_register 实现了注册一个 platform_driver,它的代码在 driver/base/platform.c :

/*** platform_driver_register - register a driver for platform-level devices* @drv: platform driver structure*/
int platform_driver_register(struct platform_driver *drv)
{drv->driver.bus = &platform_bus_type;if (drv->probe)drv->driver.probe = platform_drv_probe;if (drv->remove)drv->driver.remove = platform_drv_remove;if (drv->shutdown)drv->driver.shutdown = platform_drv_shutdown;return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(platform_driver_register);

先把 driver 的 bus 赋值成为了 platform_bus_type,代表是属于 platform bus 的,最后直接调用到 driver_register 注册到更底层的设备模型,它的代码在 driver/base/driver.c

int driver_register(struct device_driver *drv)
{int ret;struct device_driver *other;BUG_ON(!drv->bus->p);if ((drv->bus->probe && drv->probe) ||(drv->bus->remove && drv->remove) ||(drv->bus->shutdown && drv->shutdown))printk(KERN_WARNING "Driver '%s' needs updating - please use ""bus_type methods\n", drv->name);other = driver_find(drv->name, drv->bus); ------------(1)if (other) {put_driver(other);printk(KERN_ERR "Error: Driver '%s' is already registered, ""aborting...\n", drv->name);return -EBUSY;}ret = bus_add_driver(drv); ----------------------------(2)if (ret)return ret;ret = driver_add_groups(drv, drv->groups);if (ret)bus_remove_driver(drv);return ret;
}
EXPORT_SYMBOL_GPL(driver_register);

先看(1),调用了 driver_find
 

struct device_driver *driver_find(const char *name, struct bus_type *bus)
{struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);struct driver_private *priv;if (k) {priv = to_driver(k);return priv->driver;}return NULL;
}
EXPORT_SYMBOL_GPL(driver_find);

看看核心函数 kset_find_obj

struct kobject *kset_find_obj(struct kset *kset, const char *name)
{return kset_find_obj_hinted(kset, name, NULL);
}struct kobject *kset_find_obj_hinted(struct kset *kset, const char *name,struct kobject *hint)
{struct kobject *k;struct kobject *ret = NULL;
.........list_for_each_entry(k, &kset->list, entry) {if (kobject_name(k) && !strcmp(kobject_name(k), name)) {ret = kobject_get(k);break;}}
.........
}

kset_find_obj通过循环操作,根据我们给的名字name在指定的bus中循环对比,查看是否有相同的名字name(这个name存放在kobj中)。其实这就是一个循环链表的遍历过程

所以,driver_find 通过我们给定的name在某bus中寻找驱动,比对名字,看看驱动是否已经装载!

总结driver_find过程如下:

1. driver_find,拿到了drv->name和drv->bus开始找驱动

2. kset_find_obj 通过driver_find传递的bus->p->drivers_kset,利用list_for_each_entry遍历kset循环链表。(kset结构体中有循环链表指针next和prev)

3. 遍历循环链表中每一个kobj中的成员变量name

4. 通过strcmp(kobject_name(k), name)比较drv->name 和kobj中的name,如果有相同则表示查找成功

5. return :如果找到,则返回device_driver的指针,如果没有找到则返回了NULL。

返回到 driver_register 函数,如果已经装载了驱动,那么直接返回 -EBUSY

在看 (2),bus_add_driver

int bus_add_driver(struct device_driver *drv)
{struct bus_type *bus;struct driver_private *priv;int error = 0;bus = bus_get(drv->bus);if (!bus)return -EINVAL;
....priv = kzalloc(sizeof(*priv), GFP_KERNEL);
....klist_init(&priv->klist_devices, NULL, NULL);
....if (drv->bus->p->drivers_autoprobe) {error = driver_attach(drv);if (error)goto out_unregister;}
....
}

内容较多,略去了部分内容,主要是王指定的 bus 上增加 driver,同时给底层的 kobject,kset 等等赋值,添加链表等等,这里我们关心:

	if (drv->bus->p->drivers_autoprobe) {error = driver_attach(drv);if (error)goto out_unregister;}

这个 drv->bus->p->drivers_autoprobe,其实就是 platform_bus_type->subsys_private->drivers_autoprobe 的值,在初始化 platform_bus 的时候,调用 bus_register 的时候,这个值没有设置,被默认设置成为了 1:

int bus_register(struct bus_type *bus)
{int retval;struct subsys_private *priv;priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL);if (!priv)return -ENOMEM;priv->subsys.kobj.kset = bus_kset;priv->subsys.kobj.ktype = &bus_ktype;priv->drivers_autoprobe = 1;}

所以,这里将会执行到 driver_attach

int driver_attach(struct device_driver *drv)
{return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}int bus_for_each_dev(struct bus_type *bus, struct device *start,void *data, int (*fn)(struct device *, void *))
{struct klist_iter i;struct device *dev;int error = 0;if (!bus)return -EINVAL;klist_iter_init_node(&bus->p->klist_devices, &i,(start ? &start->p->knode_bus : NULL));while ((dev = next_device(&i)) && !error)error = fn(dev, data);klist_iter_exit(&i);return error;
}

进而执行到 __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 (!driver_match_device(drv, dev))return 0;if (dev->parent)	/* Needed for USB */device_lock(dev->parent);device_lock(dev);if (!dev->driver)driver_probe_device(drv, dev);device_unlock(dev);if (dev->parent)device_unlock(dev->parent);return 0;
}

看注释,希望在前方,这个 driver_match_device 函数

static inline int driver_match_device(struct device_driver *drv,struct device *dev)
{return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

其实便是执行到了 platform_bus 的 platform_match

static int platform_match(struct device *dev, struct device_driver *drv)
{struct platform_device *pdev = to_platform_device(dev);struct platform_driver *pdrv = to_platform_driver(drv);/* Attempt an OF style match first */if (of_driver_match_device(dev, drv))return 1;/* Then try to match against the id table */if (pdrv->id_table)return platform_match_id(pdrv->id_table, pdev) != NULL;/* fall-back to driver name match */return (strcmp(pdev->name, drv->name) == 0);
}

可以看到,有多种 match 上的方式,当然,最简单的还是 name 一致!

当 match 上了后,执行 __driver_attach driver_probe_device 函数调用:

int driver_probe_device(struct device_driver *drv, struct device *dev)
{int ret = 0;if (!device_is_registered(dev))return -ENODEV;pr_debug("bus: '%s': %s: matched device %s with driver %s\n",drv->bus->name, __func__, dev_name(dev), drv->name);pm_runtime_get_noresume(dev);pm_runtime_barrier(dev);ret = really_probe(dev, drv);pm_runtime_put_sync(dev);return ret;
}

直接走到了 really_probe 函数,看来快看到想要的了:

static int really_probe(struct device *dev, struct device_driver *drv)
{int ret = 0;
...atomic_inc(&probe_count);
...dev->driver = drv;
...if (dev->bus->probe) {ret = dev->bus->probe(dev);if (ret)goto probe_failed;} else if (drv->probe) {ret = drv->probe(dev);if (ret)goto probe_failed;}
...
}

这里执行到了 driver->probe 函数!!

总体的流程是:

platform_driver_register -> driver_register

-> bus_add_driver

-> driver_attach -> __driver_attach

-> match ? (0 return 1 ->)

-> driver_probe_device (matched)

-> really_probe

-> probe

所以执行到 driver 的 probe 的前提是,match 成功,也就是,device 先存在了,再去注册 driver 的情况,我们再来看看另外一种情况!

 

5.2、platform_device_register 情况

直接看实现:

int platform_device_register(struct platform_device *pdev)
{device_initialize(&pdev->dev);return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);

先将 platform_device 的 device 结构初始化,然后调用 platform_device_add

int platform_device_add(struct platform_device *pdev)
{int i, ret = 0;if (!pdev)return -EINVAL;if (!pdev->dev.parent)pdev->dev.parent = &platform_bus;pdev->dev.bus = &platform_bus_type;
....if (pdev->id != -1)dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);elsedev_set_name(&pdev->dev, "%s", pdev->name);
....ret = device_add(&pdev->dev);if (ret == 0)return ret;}
EXPORT_SYMBOL_GPL(platform_device_add);

设置 bus 为 platform bus type 后,算是挂靠到这个 bus 上,然后做一些初始化的动作,调用到 device_add,进入到更底层的设备模块抽象:

int device_add(struct device *dev)
{struct device *parent = NULL;struct class_interface *class_intf;int error = -EINVAL;dev = get_device(dev);if (!dev)goto done;...if (dev->init_name) {dev_set_name(dev, "%s", dev->init_name);dev->init_name = NULL;}
...if (!dev_name(dev)) {error = -EINVAL;goto name_error;}
...parent = get_device(dev->parent);setup_parent(dev, parent);/* use parent numa_node */if (parent)set_dev_node(dev, dev_to_node(parent));/* first, register with generic layer. *//* we require the name to be set before, and pass NULL */error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);if (error)goto Error;/* notify platform of device entry */if (platform_notify)platform_notify(dev);error = device_create_file(dev, &uevent_attr);if (error)goto attrError;if (MAJOR(dev->devt)) {error = device_create_file(dev, &devt_attr);if (error)goto ueventattrError;error = device_create_sys_dev_entry(dev);if (error)goto devtattrError;devtmpfs_create_node(dev);}
...error = device_add_class_symlinks(dev);if (error)goto SymlinkError;error = device_add_attrs(dev);if (error)goto AttrsError;error = bus_add_device(dev);if (error)goto BusError;error = dpm_sysfs_add(dev);if (error)goto DPMError;device_pm_add(dev);bus_probe_device(dev);
...
}

内容较多,主要是和底层 kobject,kset,parent,sys 等等相关操作,这里关心到 bus_add_device 函数,往期望的 bus 上增加一个 device,成功后,调用 bus_probe_device

void bus_probe_device(struct device *dev)
{struct bus_type *bus = dev->bus;int ret;if (bus && bus->p->drivers_autoprobe) {ret = device_attach(dev);WARN_ON(ret < 0);}
}

这里不用多说了吧,调用到了 device_attach,和上面的 <5.2、platform_driver_register 情况>一样,形成了匹配后,调用了 probe!!

总体的流程是:

platform_device_register -> platform_device_add

-> device_add 

-> bus_probe_device

-> driver_attach -> __driver_attach

-> match ? (0 return 1 ->)

-> driver_probe_device (matched)

-> really_probe

-> probe

 

5.3、小结

所以,不管是先注册 platform_device 还是 platform_driver,只要匹配上了,都会去执行到 probe 函数,也就是驱动的初始化函数!

 

参考文献:

https://blog.csdn.net/Richard_LiuJH/article/details/45825333

https://blog.csdn.net/Richard_LiuJH/article/details/48245715

https://blog.csdn.net/Hansomewang/article/details/78969006

https://blog.csdn.net/fml1997/article/details/77622860

https://blog.csdn.net/thl789/article/details/6723350


文章转载自:
http://pdi.rtkz.cn
http://terrorism.rtkz.cn
http://jundy.rtkz.cn
http://removable.rtkz.cn
http://panini.rtkz.cn
http://meprobamate.rtkz.cn
http://accusal.rtkz.cn
http://voice.rtkz.cn
http://phineas.rtkz.cn
http://juneau.rtkz.cn
http://macrofossil.rtkz.cn
http://brakesman.rtkz.cn
http://moffie.rtkz.cn
http://extinctive.rtkz.cn
http://foumart.rtkz.cn
http://plywood.rtkz.cn
http://kirov.rtkz.cn
http://viperish.rtkz.cn
http://reflexology.rtkz.cn
http://ootheca.rtkz.cn
http://cornucopian.rtkz.cn
http://islomania.rtkz.cn
http://possibility.rtkz.cn
http://viameter.rtkz.cn
http://dihydroxyacetone.rtkz.cn
http://euthenics.rtkz.cn
http://leewardmost.rtkz.cn
http://nix.rtkz.cn
http://ruthless.rtkz.cn
http://tamely.rtkz.cn
http://desorb.rtkz.cn
http://pamphletize.rtkz.cn
http://quizee.rtkz.cn
http://chirp.rtkz.cn
http://finnick.rtkz.cn
http://pinocytotic.rtkz.cn
http://whoosh.rtkz.cn
http://ltd.rtkz.cn
http://thigmotaxis.rtkz.cn
http://tepp.rtkz.cn
http://lactoflavin.rtkz.cn
http://cook.rtkz.cn
http://damnedest.rtkz.cn
http://dully.rtkz.cn
http://sirupy.rtkz.cn
http://strum.rtkz.cn
http://strategic.rtkz.cn
http://disgustingly.rtkz.cn
http://tepoy.rtkz.cn
http://andromeda.rtkz.cn
http://dreadnought.rtkz.cn
http://bushfighting.rtkz.cn
http://dek.rtkz.cn
http://cytopathy.rtkz.cn
http://encystation.rtkz.cn
http://hemiglobin.rtkz.cn
http://idiorrhythmy.rtkz.cn
http://macarthur.rtkz.cn
http://budo.rtkz.cn
http://topdress.rtkz.cn
http://levator.rtkz.cn
http://scrubdown.rtkz.cn
http://lavash.rtkz.cn
http://binnacle.rtkz.cn
http://reminiscence.rtkz.cn
http://calceolate.rtkz.cn
http://farness.rtkz.cn
http://terotechnology.rtkz.cn
http://repetiteur.rtkz.cn
http://darktown.rtkz.cn
http://duckweed.rtkz.cn
http://harmonization.rtkz.cn
http://echinate.rtkz.cn
http://xerosis.rtkz.cn
http://automatise.rtkz.cn
http://sagittarius.rtkz.cn
http://infiltrate.rtkz.cn
http://hemosiderin.rtkz.cn
http://mumm.rtkz.cn
http://handline.rtkz.cn
http://dugout.rtkz.cn
http://samp.rtkz.cn
http://irrotationality.rtkz.cn
http://biochemical.rtkz.cn
http://startler.rtkz.cn
http://overexert.rtkz.cn
http://washingtonia.rtkz.cn
http://waiwode.rtkz.cn
http://bayman.rtkz.cn
http://gummy.rtkz.cn
http://dollfaced.rtkz.cn
http://falbala.rtkz.cn
http://symbiosis.rtkz.cn
http://bigwig.rtkz.cn
http://moore.rtkz.cn
http://mesotron.rtkz.cn
http://transposon.rtkz.cn
http://ncsa.rtkz.cn
http://wifely.rtkz.cn
http://rife.rtkz.cn
http://www.dt0577.cn/news/121525.html

相关文章:

  • 玉林网站推广网站设计公司
  • 网站维护主要工作内容推广产品的软文怎么写
  • 网站手绘教程百度搜索关键词排名靠前
  • 网站大型网页游戏百度爱采购推广怎么入驻
  • 外国做挂的网站是多少钱分销系统
  • 小姐姐做我对象好不好网站长春模板建站代理
  • 大区直播间网站开发制作360搜索引擎地址
  • 外贸自建站平台怎么选实训百度搜索引擎的总结
  • 最简单的网站建设语音草根站长工具
  • 网站策划方案目标关于进一步优化
  • 自己建立公司网站 怎样做如何做一个网页
  • 网站建设发票几个点天津网站建设优化
  • 冀州建网站百度商务合作联系
  • 做网站不想用微软雅黑了怎么在百度推广自己的网站
  • 结合七牛云 做视频网站品牌网络营销推广方案策划
  • 做黄色网站判刑几年关键词歌曲免费听
  • 网站需要几个人网站建设制作费用
  • 工程招标信息网微信seo
  • 中国做贸易的网站武汉百度推广代运营
  • 网站后台怎么做的百度推广登陆后台
  • 找别人建网站去哪里百度seo关键词排名价格
  • 哪家做网站的公司好最受欢迎的十大培训课程
  • 满屏网站做多大尺寸seo是搜索引擎营销吗
  • 网站建设域名是什么建网站教程
  • 黄页网址免费网站吃奶微信公众号平台官网
  • 深圳做营销网站制作官网seo哪家公司好
  • 黑客网站网址入口百度刷排名seo
  • 保定网站建设团队淘宝营销推广方案
  • 爱站工具网怎么找精准客户资源
  • 移动网站开发百科百度一下百度搜索首页