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

vxBus 总线结构的分析与应用

vxWorks驱动框架目前提供两种不同的版本,分别是:VxBus 模式 和传统模式。

对于 SMP(多处理器架构)系统,vxWorks建议采用 VxBus 模式注册设备驱动。因为,VxBus 可提供统一,安全的标准接口。

VxBus 6.2 版本之前以组件形式使用;6.2 版本之后则绑定到内核中。

设备初始化分为 5 个阶段:

注册 --> 探测/匹配 --> 设备实例初始化 --> 设备实例初始化 2 --> 设备实例关联

上述 5 个阶段在系统初始流程中进行。

sysInit --> usrInit --> sysHwInit

sysHwInit --> hardWareInterFaceInit --> hardWareInterFaceBusInit

vxbDevRegister --> vxbDeviceAnnounce --> probe --> vxbDevInitRun --> devInstanceInit

sysHwInit2 --> vxbDevInit --> devInstanceConnect

驱动注册结构体:

struct vxbDevRegInfo {
	struct vxbDevRegInfo *pNext;						//注意:vxWorks 允许驱动中的同一个操作存在多个入口。

	UINT32 devID;
	UINT32 busID;										//总线 ID,vxWorks 设计为总线关联多个驱动与设备,通过总线设备可匹配到正确的驱动,反之亦然。
	UINT32 vxbVersion;

	char drvName[MAX_DRV_NAME_LEN + 1];

	struct drvBusFuncs *pDrvBusFuncs;
	struct vxbDeviceMethod *pMethods;

	BOOL (*devProbe)(struct vxbDev *pDevInfo);			// probe 函数存在时,需确保驱动探测设备成功;probe 函数不存在,系统默认返回正常,后续设备可链接驱动

	struct vxbParams *pParamDefaults;
};
/*
 * vxWorks 提供了虚拟的 processor local bus,其作用类似于 Linux 中设备树所使用的 platform bus。
 * vxWorks 与 Linux 相同,将总线也视为设备。
 */
void hardWareInterFaceBusInit(void)
{
	vxbLibInit();

	...

#ifdef INCLUDE_PLB_BUS
	plbRegister();									//注册 PLB 总线
#endif

	...

	vxbInit();
}

//全局变量声明
LOCAL struct vxbDevRegInfo plbRegInfo =
{
	NULL,
	VXB_DEVID_BUSCTRL,								// PLB 视为总线控制器
	VXB_BUSID_PLB,
	VXB_VER_5_0_0,
	"plbCtrl",
	&plbBusfFuncs,									//提供总线操作接口
	NULL,
	NULL
};

struct vxbDeviceMethod *pSysPlbMethods = NULL; 

/*
 * PLB 总线初始化
 */
void plbRegister(void)
{
	int plbMethodCount = NELEMENTS(plbMethodList);
	int sysMethodCount;
	struct vxbDeviceMethod *pSysMeth;
	struct vxbDeviceMethod *pSysMethDest;
	struct vxbDeivceMethod *pSysMethHead = NULL;
	int i = 0;
	
	if (plbBusLibInitialized)							//检测 PLB 总线是否已完成注册
		return;

	plbInitStage = 1;
	plbBusLibInitialized = TRUE;

	...

	vxbDevRegister(&plbRegInfo);						//注册 PLB 虚拟总线驱动

	(void)vxbBusTypeRegitser(&plbBusType);				//注册 PLB 虚拟总线

	vxbDeviceAnnounce(&plbCtrl);						//以设备形式注册 PLB 虚拟总线控制器并关联驱动

	(void)vxbBusAnnounce(&plbCtrl, VXB_BUSID_PLB);

	...

	return;
}

/*
 * 注册设备驱动
 */
STATUS vxbDevRegister(struct vxbRegInfo *pDevInfo)
{
	struct vxbDevRegInfo *pListEnd;
	struct vxbDevRegInfo *pCurrent;

	VXB_ASSERT(pDevInfo != NULL, ERROR);

	if (vxbDrvVerCheck(pDevInfo) != OK)
		return (ERROR);

	pListEnd = pDevInfo;
	while (pListEnd->pNext != NULL)
		pListEnd = pListEnd->pNext;

	VXB_DEBUG_MSG(2, "vxbDevRegister() regitsering new driver @ %p\n", pDevInfo, 2, 3, 4, 5, 6);

	vxbLockTake(&vxbGlobalListsLock, VXB_LOCK_WRITER);				/* 操作全局变量时使用读写锁,加锁 */

	pListEnd->pNext = pDriverListHead;								/* 注册驱动时,将现有的驱动链以头插方式插入到 pDriverListHead 全局链表中 */
	pDriverListHead = pDevInfo;

	vxbLockGive(&vxbGlobalListsLock, VXB_LOCK_WRITER);				/* 操作全局变量时使用读写锁,解锁 */

	pListEnd = pListEnd->pNext;

	if (vxbInitPhase < 1)											/* 如果处于 vxBus 初始化第一初始阶段,退出并返回正常 */
		return OK;

	VXB_DEBUG_MSG(2, "vxbDevRegister(): pDevInfo @ %p, pListEnd @ %p\n", pDevInfo, pListEnd, 3, 4, 5, 6);

	pCurrent = pDevInfo;
	while (pCurrent != pListEnd) {
		VXB_DEBUG_MSG(2, "vxbDevRegister() checking for orphans on %s\n", vxbBusTypeString(pCurrent->busID), 2, 3, 4, 5, 6);
		
		vxbDevIterate(vxbNewDriver, pCurrent, VXB_ITERATE_ORPHANS);
		pCurrent = pCurrent->pNext;
	}

	return OK;
}

/*
 * 注册总线
 */
STATUS vxbBusTypeRegister(struct vxbBusTypeInfo *pBusType)
{
	struct vxbBusTypeInfo *pTempPtr;

	VXB_ASSERT(pBusType != NULL, ERROR)

	vxbLockTake(&vxbGlobalListsLock, VXB_LOCK_WRITER);

	pTempPtr = pBusListHead;

	if (pBusListHead != NULL) {								/* 检查总线是否已经注册 */
		while (pTempPtr != NULL) {
			if (pTempPtr->busID == pBusType->busID) {
				vxbLockGive(&vxbGlobalListsLock, VXB_LOCK_WRITER);
				return ERROR;
			}
	
			pTempPtr = pTempPtr->pNext;
		}
	}

	pBusType->pNext = pBusListHead;							/* 以头插方式将总线注册到 pBusListHead 全局链表中 */
	pBusListHead = pBusType;

	vxbLockGive(&vxbGlobalListsLock, VXB_LOCK_WRITER);

	return OK;
}

/*
 * 声明设备,vxWorks 系统开始为设备匹配对应的驱动
 */
STATUS vxbDeviceAnnounce(struct vxbDev *pDev)
{
	struct vxbBusTypeInfo *pBusEntry;
	struct vxbBusTypeInfo *busMatch = NULL;
	BOOL drvFound = FALSE;
	struct vxbDevRegInfo *pDrv;
	struct vxbBusPresent *pBus;
	FUNCPTR pMethod;

	if (pPlbDev == NULL && pDev->busID == VXB_BUSID_LOCAL) {								//若注册的设备为 PLB,则直接赋值全局变量并返回
		pPlbDev = pDev;
		return (OK);
	}

	VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(%p(%s))\n", pDev, pDev->pName, 3, 4, 5, 6);

	if (pPlbDev != NULL) {
		pMethod = vxbDevMethodGet(pPlbDev, DEVMETHOD_CALL(sysBspDevFilter));
		if (pMethod != NULL) {
			if ((*pMethod)(pDev) != OK) {
				VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(%p(%s)) excluded by BSP\n", pDev, pDev->pName, 3, 4, 5, 6);
				return ERROR;
			}
		}
	}

	if (pDev->pParentBus == NULL) {															/* 设备为孤立设备时,注册到 pLostDevHead 全局链表中 */
#ifdef VXB_PERFORM_SANITY_CHECKS
		vxbLockTake(&vxbLostDevListLock, VXB_LOCK_WRITER);
		vxbInstInsert(&pLostDevHead, pDev);
		vxbLockGive(&vxbLostDevListLock, VXB_LOCK_WRITER);
#endif
		return ERROR;
	}

	vxbLockTake(&vxbGlobalListsLock, VXB_LOCK_READER);
	for (pBusEntry = pBusListHead; pBusEntry != NULL; pBusEntry = pBusEntry->pNext) {		/* 遍历总线,获取设备挂载的总线对象 */
		if (pBusEntry->busID != pDev->busID)
			continue;

		for (pDrv = pDriverListHead; pDrv != NULL; pDrv = pDrv->pNext) {					/* 遍历驱动,获取设备对应的驱动 */
			VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(): checking %p (%s) against %s\n", pDev, pDev->pName, &pDrv->drvName[0], 4, 5, 6);

			if (pDrv->busID != pDev->busID) {
				VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(): %s@%p failed type check\n", pDev->pName, pDev, 3, 4, 5, 6);
				continue;
			}

			drvFound = (*(pBusEntry->vxbDevMatch))(pDrv, pDev);								//执行总线匹配接口,验证设备与驱动的匹配性
			if (!drvFound) {
				VXB_DEBUG_MSG("vxbDeviceAnnounce(): %s@%p failed bus match\n", pDev->pName, pDev, 3, 4, 5, 6);
				continue;
			}

			busMatch = pBusEntry;
			
			if (pDrv->devProbe == NULL) {
				VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(): no driver probe available\n", 1, 2, 3, 4, 5, 6);
				drvFound = TRUE;
			} else {
				VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(): calling driver probe\n", 1, 2, 3, 4, 5, 6);
				drvFound = (*(pDrv->devProbe))(pDev);										//执行驱动提供的 probe 接口,需确保返回值为 TRUE;probe 为空也可。
				if (drvFound == FALSE) {
					VXB_DEBUG_MSG(1, "vxbDeviceAnounce(): driver probe failed\n", 1, 2, 3, 4, 5, 6);
					continue;
				}
			}

			VXB_DEBUG_MSG(1, "vxbDeviceAnnounce(): found match, driver @ %p\n", pDrv, 2, 3, 4, 5, 6);

			pDev->pDriver = pDrv;

			if (pDev->pName == NULL)
				pDev->pName = &pDrv->drvName[0];

			pBus = (struct vxbBusPresent *)pDev->pParentBus;								/* 为总线创建设备的实例化对象 */

			vxbLockTake(&pBus->listLock, VXB_LOCK_WRITER);
			vxbInstInsert(&pBus->instList, pDev);
			vxbLockGive(&pBus->listLock, VXB_LOCK_WRITER);

			vxbDevInitRun(pDev, pDrv);
			
			break;
		}
	}

	vxbLockGive(&vxbGlobalListsLock, VXB_LOCK_READER);

	if (drvFound == FALSE) {
		pBus = (struct vxbBusPresent *)pDev->pParentBus;
		pDev->pDriver = NULL;
		vxbLockTake(&pBus->listLock, VXB_LOCK_WRITER);
		vxbInstInsert(&pBus->devList, pDev);
		vxbLockGive(&pBus->listLock, VXB_LOCK_WRITER);
	}

	return OK;
}

/*
 * 总线声明
 */
STATUS vxbBusAnnounce(struct vxbDev *pBusDev, UINT32 busID)
{
	struct vxbBusPresent *pBusEnt;
	struct vxbBusPresent *pParent;
	struct vxbBusTypeInfo *pType;
	struct vxbDev *pTempDev;

	pParent = pBusDev->pParentBus;

	if (parent != NULL) {
		vxbLockTake(&pParent->listLock, VXB_LOCK_WRITER);

		if (pBusDev->pDriver != NULL)
			pTempDev = pParent->instList;
		else
			pTempDev = pParent->devList;

		while (pTempDev != NULL) {
			if (pTempDev == pBusDev)
				break;

			pTempDev = pTempDev->pNext;
		}

		vxbLockGive(&pParent->listLock, VXB_LOCK_WRITER);

		if (pTempDev == NULL)
			return ERROR;
	}

	pBusEnt = (struct vxbBusPresent *)hwMemAlloc(sizeof(*pBusEnt));
	if (pBusEnt == NULL)
		return (ERROR);

	if (pPlbBus == NULL && busID == VXB_BUSID_LOCAL) {
		pPlbBus = pBusEnt;
		pPlbDev->pParentBus = NULL;
	}

	if (vxbInitPhase > 1)
		vxbLockInit(&pBusEnt->listLock);

	pBusEnt->pBusType = NULL;

	vxbLockTake(&vxbGlobalListsLock, VXB_LOCK_READER);

	for (pType = pBusListHead; pType != NULL; pType = pType->pNext) {
		if (pType->busID == busID) {
			pBusEnt->pBusType = pType;
			break;
		}
	}

	vxbLockGive(&vxbGlobalListsLock, VXB_LOCK_READER);

	if (pType == NULL) {
		if (pPlbBus == pBusEnt)
			pPlbBus = NULL;

#ifndef _VXBUS_BASIC_HWMEMLIB
		hwMemFree((char *)pBusEnt);
#endif

		return ERROR;
	}

	pBusEnt->pCtrl = pBusDev;

	pBusEnt->instList = NULL;
	pBusEnt->devList = NULL;

	pParent = pBusEnt->pCtrl->pParentBus;

	if (pParent != NULL) {
		void *pParentDevId = (void *)&pParent;

		vxbLockTake(&vxbBusListLock, VXB_LOCK_WRITER);
		vxbInstInsert((VXB_DEVICE_ID *)pParentDevId, (VXB_DEVICE_ID)pBusEnt);
		vxbLockGive(&vxbBusListLock, VXB_LOCK_WRITER);
	}
	
	pBusDev->u.pSubordinateBus = pBusEnt;

	if ((pParent == NULL) && (pPlbDev != pBusDev)) {
#ifdef VXB_PERFORM_SANITY_CHECKS
		vxbLockTake(&vxbLostDevListLock, VXB_LOCK_WRITER);
		pBusEnt->pNext = pLostBusHead;
		pLostBusHead = pBusEnt;
		vxbLockGive(&vxbLostDevListLock, VXB_LOCK_WRITER);
#endif
		return ERROR;
	}

	return (OK);
}

// PLB 虚拟总线初始化结束,开始遍历 hcfDeviceList 数组,关联设备与驱动
STATUS vxbInit(void) 
{
	vxbInitPhase = 1;

	plbInit1(plbDev);
	return (ok);
}

STATUS plbInit1(struct vxbDev *pCtrl)
{
	int i, j;
	char regBase[] = "regBase0";
	struct vxbDev *pDev;
	HCF_DEVICE *pHcf;
	UINT32 regBase32;

	VXBPLB_DEBUG_MSG("plbInit1() called\n", 1, 2, 3, 4, 5, 6);

#ifdef VXB_LEGACY_ACCESS
	plbAccessInit();
#endif

	for (i = 0; i < hcfDeviceNum; i++) {
		if (hcfDeviceList[i].busType != VXB_BUSID_PLB) {
			VXBPLB_DEBUG_MSG1("plbInit1(): skipping non-PLB device %s\n", (int)hcfDeviceList[i].devName, 2, 3, 4, 5, 6);
		} else {
			VXBPLB_DEBUG_MSG1("plbInit1(): processing device %s\n", (int)hcfDeviceList[i].devName, 2, 3, 4, 5, 6);

			pHcf = &hcfDeviceList[i];

			pDev = vxbDevStructAlloc(WAIT_FOREVER);
			if (pDev == NULL) {
				return (ERROR);
			}

			pDev->busId = VXB_BUSID_PLB;
			pDev->pNext = NULL;

			pDev->pBusSpecificDevInfo = (void *)&hcfDeviceList[i];

#ifdef VXB_LEGACY_ACCESS
			pDev->pAccess = (pVXB_ACCESS_LIST)hwMemAlloc(sizeof(VXB_ACCESS_LIST));
			if (pDev->pAccess == NULL) {
				vxbDevStructFree(pDev);
				return (ERROR);
			}

			vxbPlbAccessCopy(pDev->pAccess);
#endif	
			if (devResourceGet(pHcf, "regBase", HCF_RES_INT, (void *)&regBase32) == OK)
				pDev->pRegBase[0] = (void *)((ULONG)regBase32);
			else
				(void)devResourceGet(pHcf, "regBase", HCF_RES_ADDR, (void *)&(pDev->pRegBase[0]));

			for (j = 0; j < VXB_MAXBARS; j++) {
				regBase[7] = (char)('0' + j);

				if (devResourceGet(pHcf, regBase, HCF_RES_INT, (void *)&regBase32) == OK)
					pDev->pRegBase[j] = (void *)((ULONG)regBase32);
				else
					devResourceGet(pHcf, regBase, HCF_RES_ADDR, (void *)&(pDev->pRegBase[j]));

				...
			}

			...
			vxbDeviceAnnounce(pDev);
		}
	}
}

/*
 * PLB 虚拟总线提供的设备与驱动匹配接口
 */
LOCAL BOOL plbDevMatch(struct vxbDevRegInfo *pDriver, struct vxbDev *pDev)
{
	VXPLB_DEBUG_MSG1("plbDevMatch((0x%08x, %s), (0x%08x, 0x%08x)) called\n",
					(int)pDriver, (int)pDriver->drvName,
					(int)pDev, (int)pDev->pRegBase[0],
					4, 5);

	if (pDev->busID != VXB_BUSID_PLB) {				/* 检查设备总线是否为 plb */
		if (plbInitStage > 2)
			VXBPLB_DEBUG_MSG();
		return (FALSE);
	}

	if (strcmp(pDriver->drvName, pDev->pName) != 0) {				/* 检查驱动名称是否与设备名称一致 */
		if (plbInitStage > 2)
			VXBPLB_DEBUG_MSG
		return (FALSE);
	}

	VXBPLB_DEBUG_MSG1("\tcheck OK, dev=%s drv=%s\n", (int)pDev->pName, (int)pDriver->drvName, 3, 4, 5, 6);

	return (TRUE);
}

vxBus 的使用如下:

LOCAL struct drvBusFuncs xxxDrvFuncs =
{
	...
};

LOCAL struct vxbDeviceMethod xxxDrv_methods[] =
{
	...
};

LOCAL struct vxbDevRegInfo xxxDrvRegistration =
{
	...,
	xxxDrvFuncs,
	...
};


void xxxDrvRegister (void) {
	vxbDevRegister(xxxDrvRegistration);
}

/* 注意事项 */
LOCAL struct vxbDev xxxDev = 
{
	...
};

/*
 * 接口与 hcfDeviceList 全局变量相关,如果在 hcfDeviceList 变量中修改,则确保驱动注册在 PLB 初始化之前即可。否则,需进行特殊处理并进行调用。
 */
vxbDevAnnounce(&xxxDev);

http://www.kler.cn/a/537781.html

相关文章:

  • 面向对象程序设计-实验3
  • 2025年02月08日Github流行趋势
  • 理解UML中的四种关系:依赖、关联、泛化和实现
  • 深入解析 FFmpeg 的 AAC 编解码过程
  • OpenCV:图像修复
  • DeepSeek底层揭秘——多模态融合引擎
  • 人工智能-A* 算法与机器学习算法结合
  • HTMLCSSJS
  • LeetCodeHot 100 第一天
  • ubuntu conda运行kivy时报“No matching FB config found”
  • java文件上传粗糙版
  • 《PYTHON语言程序设计》(2018版)1.20修改这道题,利用类的方式(二) 接近成功....(上)
  • 云原生后端|实践?
  • 安装指定版本的pnpm
  • vue知识补充
  • 多光谱技术在华为手机上的应用发展历史
  • Android 问题01_AGP_Kotlin_Compiler_Mapping
  • 地基JVM中的强引用、软引用、弱引用、虚引用的区别
  • 【高级架构师】多线程和高并发编程(一):线程的基础概念
  • Beta分布
  • 深入解析:React 事件处理的秘密与高效实践
  • STM32的HAL库开发---高级定时器
  • 【填坑】新能源汽车三电设计之常用半导体器件系统性介绍
  • 实在RPA案例|视源股份:驱动20+核心场景数字化升级,组织效能提升超80%
  • maven-依托管理
  • 使用springAI实现图片相识度搜索