收藏 分销(赏)

vxworks-usb-mouse-driver分析.doc

上传人:xrp****65 文档编号:6663204 上传时间:2024-12-19 格式:DOC 页数:19 大小:66.83KB 下载积分:10 金币
下载 相关 举报
vxworks-usb-mouse-driver分析.doc_第1页
第1页 / 共19页
vxworks-usb-mouse-driver分析.doc_第2页
第2页 / 共19页


点击查看更多>>
资源描述
Vxworks usb mouse 驱动分析 概述: 最近在做嵌入式vxworks下usb触摸屏设计,参考了vxworks里面的usb mouse驱动的代码,分析了usb mouse驱动,根据自己的理解,写这个文档。如有任何问题请联系yxj_5421@,转载请标明出处。 系统资源: Vxworks6.7 1、USB主机驱动栈模型原理 USB主机驱动栈模型下图所示: 1.1硬件层 在USB主机驱动栈的最底部是USB主控制器(USB HC,即USB Host Controller)。目前,USB主控制器可分为三类:通用型主控制器接口(UHCI)、开放型主控制器接口(OHCI)和增强型主控制接口和增强型主控制接口(EHCI)。其中,UHCI和OHCl支持USBl.1低速接口,EHCl支持USB2.0高速接口。 1.2主控制器驱动层 对予每一类型的主控制器都有一个与硬件独立的USB主控制器驱动(Host Controller Driver,简称 HCD)。WindRiver提供了两个驱动:usbHedUheiLib (UHCI主控制器库)和usbHcdohciLib(OHCl主控制器库)。该模块向下直接与USB主控制器硬件进行交互操作,向上与USBD层的功能接口,提供各种功能函数的调用,支持对上层模块封装具体的HCD驱动的实现。 1.3 USB核心驱动层 USB核心驱动(USB host driver,简称USBD)模块实现USB的核心驱动,包括USB总线的枚举、总线带宽分配、传输控制等操作。该模块向下调用HCD接口模块,实现与HCD层的通信,将设备驱动的功能请求转化为相应功能模块的调用。USBD管理每一个与主机相连的USB设备,还负责自动处理USB电力管理和带宽管理及USB hub和设备的动态插拔。 1.4 USB设备驱动层 USB设备驱动层负责管理连接到USB上的不同类型的设备,它们依靠USBD来提供与每个设备的通信路径,主要实现USB设备的一些特定初始化工作,并将上层用户应用程序的请求转化为对相应的USBD驱动程序的调用。该层通过对应用层提供API函数,从而屏蔽USB实现的细节。 1.5应用层 应用层为用户编写的对USB设备进行读、写控制等指定功能的应用程序,应用层通过设备驱动程序和USB主机驱动程序完成指定的功能。 2、USB mouse 驱动分析 Usb mouse驱动属于设备驱动层,在vxworks里面,把usb mouse驱动设计成两层,即文件层+驱动层,文件层对上提供read、write、ioctl等接口,对下调用驱动层提供函数进行硬件初始化,对应的源代码是usrUsbMseInit.c (target\config\comps\src)。驱动层则针对具体usb设备初始化,获取数据等。 2.1 文件层usrUsbMseInit.c分析 在usrRoot (usrConfig.c (target\config\all)) 调用 #ifdef INCLUDE_USB_MOUSE_INIT usrUsbMseInit (); /* Mouse Driver Initialization */ #endif usrUsbMseInit (usrUsbMseInit.c (target\config\comps\src))驱动程序入口点, 首先检查driver是否已经安装,如果安装就退出 if (usbMseDrvNum > 0) { printf ("Mouse already initilaized.\n"); return ERROR; } 接着调用 usbMseDrvNum = iosDrvInstall ((FUNCPTR) NULL, (FUNCPTR) usbMseDevDelete, (FUNCPTR) usbMseOpen, (FUNCPTR) usbMseClose, (FUNCPTR) usbMseRead, (FUNCPTR) usbMseWrite, (FUNCPTR) usbMseIoctl); 安装驱动的I/O函数,添加驱动到驱动表里面 接着调用驱动层初始化函数 if (usbMouseDevInit () == OK) usbMouseLib.c (target\src\drv\usb) { printf ("usbMouseDevInit() returned OK\n"); 这个函数如果成功,会输出打印上面的信息表明驱动已经加载,并且和usb设备已经匹配上。 接着调用驱动层动态注册函数 if (usbMouseDynamicAttachRegister (usbMseDrvAttachCallback, (void *) NULL) != OK) usbMouseLib.c (target\src\drv\usb) 这个函数会把usbMseDrvAttachCallback保存在驱动层创建的一个队列里面,当usb设备热插拔时,都会调用这个函数。 如果已经插入了usb mouse,就会马上调用usbMseDrvAttachCallback,参数为USB_MSE_ATTACH, 如果没有插入,那么驱动加载已经完成了。 看usbMseDrvAttachCallback (usrUsbMseInit.c (target\config\comps\src)) 因为第一次参数是USB_MSE_ATTACH,就会进入if (attachCode == USB_MSE_ATTACH)这个分支: 首先调用驱动层的if (usbMouseSioChanLock (pChan) != OK),标记SIO_CHAN structure已经在使用 接着调用 sprintf (mseName, "%s%d", USB_MSE_NAME, mseCount); if (usbMseDevCreate (mseName, pChan) != OK) 创建设备文件,即创建"/usbMo/X",X由mseCount决定,同时创建文件层设备结构,并放在链表里面,调用iosDevAdd将设备添加到系统设备列表里面 接着调用 if (usbMseDevFind (pChan, &pUsbMseDev) != OK) { printf("usbMseDevFind() returned ERROR\n"); return; } 根据pchan在链表里面找到这个usb设备的文件层设备结构 接着调用 if ((*pChan->pDrvFuncs->callbackInstall) (pChan, SIO_CALLBACK_PUT_MOUSE_REPORT, (STATUS (*) (void *, ...)) usbMseRptCallback, (void *) pUsbMseDev) != OK) pChan->pDrvFuncs->callbackInstall是usbMouseLib.c里面的usbMouseCallbackInstall函数,它安装回调函数,当usb接受到数据后就会调用usbMseRptCallback这个函数。 如果上面都执行成功,会输出打印下面信息 printf("USB Mouse attached as %s\n", mseName); 至此,驱动加载完成,并且设备文件也已经创建好了。 2.2 驱动层usbMouseLib.c分析 在文件层usrUsbMseInit会调用 usbMouseDevInit----驱动层初始化入口 if (initCount == 0) 表明还没有进行初始化,初始化内部结构体,并链接在usbd上 { if (usbdClientRegister (MSE_CLIENT_NAME, &usbdHandle) != OK || usbdDynamicAttachRegister (usbdHandle, USB_CLASS_HID, USB_SUBCLASS_HID_BOOT, USB_PROTOCOL_HID_BOOT_MOUSE,FALSE, usbMouseAttachCallback) != OK) { return doShutdown (S_usbMouseLib_USBD_FAULT); } } usbdClientRegister (usbTransUnitInit.c (target\src\usb) )生成usb设备驱动的usbdHandle if ( !usbtuInitCount) { /* usbdInitialize() not called */ USBTU_LOG("usbdClientRegister returns ERROR:usbdInitialize not called\n"); return ERROR; } 检查usbd是否初始化了,如果没有就出错退出。 /* allocate structure for client */ if ( !(pDriver = OSS_CALLOC ( sizeof (USBTU_DEVICE_DRIVER)))) { USBTU_LOG ( "usbdClientRegister returns ERROR : malloc failed \n"); return ERROR; } 创建client driver结构体 if (pClientHandle != NULL) *pClientHandle = pDriver; 将client driver赋给usbdHandle usbdDynamicAttachRegister (usbTransUnitInit.c (target\src\usb) )填充usb设备驱动的usbdHandle,并且注册usbMouseAttachCallback函数,当有热插拔发生时,会调用这个函数,并且将usb设备client注册到usbd上。 这三个参数USB_CLASS_HID,USB_SUBCLASS_HID_BOOT, USB_PROTOCOL_HID_BOOT_MOUSE是类代码、子类代码和协议代码,会被填充在usbdHandle上,后面usb驱动就会根据这三个参数把驱动和相应的设备联系起来。 pDriverData->bFlagVendorSpecific = vendorSpecific; pDriverData->uVendorIDorClass = deviceClass; pDriverData->uProductIDorSubClass = deviceSubClass; pDriverData->uBCDUSBorProtocol = deviceProtocol; pDriverData->addDevice = usbtuInitDeviceAdd; pDriverData->removeDevice = usbtuInitDeviceRemove; pDriverData->suspendDevice = usbtuInitDeviceSuspend; pDriverData->resumeDevice = usbtuInitDeviceResume; 我在网上看到好多人不想用这三个参数来识别usb硬件设备,想用vid和pid来设备,那也可以,秘密就在bFlagVendorSpecific这个标志上,上面函数调用时传入的vendorSpecific参数为false,意思就是不用vid和pid,如果传入是TRUE,就是要用vid和pid来识别,看看uVendorIDorClass和uProductIDorSubClass名字就知道意思了,可能是vid或者类代码,另一个可能是pid或者子类代码,都是由bFlagVendorSpecific决定 接着调用usbHstDriverRegister (Usbd.c (target\src\hwif\usb))将usb设备client注册到usbd上 if ((NULL == pDeviceDriverInfo) || (NULL == pDeviceDriverInfo->addDevice) || (NULL == pDeviceDriverInfo->removeDevice) || (NULL == pDeviceDriverInfo->resumeDevice) || (NULL == pDeviceDriverInfo->suspendDevice)) { OS_LOG_MESSAGE_MEDIUM( USBD, "usbHstRegisterDriver() Failed: Invalid parameter Driver info.\n", 0, 0, 0, 0); return USBHST_INVALID_PARAMETER; } 判断pDeviceDriverInfo里面一些处理函数是否存在,如果没有就出错返回,从上面看到调用这个函数的函数已经把这些变量赋值了。 下面是一段处理usb hub的代码,就不分析了 /* Store the global driver list in pOldDriverList*/ pOldDriverList = gpDeviceDriverList; while (NULL != pOldDriverList) { /* * Check if the bFlagVendorSpecific, VendorIDorClass, * uProductIDorSubClass are same. */ if ((pOldDriverList->pDriver->bFlagVendorSpecific == pDeviceDriverInfo->bFlagVendorSpecific) && (pOldDriverList->pDriver->uVendorIDorClass == pDeviceDriverInfo->uVendorIDorClass) && (pOldDriverList->pDriver->uProductIDorSubClass == pDeviceDriverInfo->uProductIDorSubClass) && (pOldDriverList->pDriver->uBCDUSBorProtocol == pDeviceDriverInfo->uBCDUSBorProtocol)) { OS_LOG_MESSAGE_HIGH( USBD, "usbHstRegisterDriver() Failed: Driver is already registered.\n", 0, 0, 0, 0); return USBHST_FAILURE; } /* Get the driver in the list */ pOldDriverList = pOldDriverList->pNextDriver; } 遍历整个gpDeviceDriverList 链表,检查pDeviceDriverInfo是否已经存在,如果存在就错误返回。 pNewDriverList = (pUSBD_DEVICE_DRIVER_LIST)OS_MALLOC(sizeof(USBD_DEVICE_DRIVER_LIST)); 如果不存在,新创建一个pNewDriverList pNewDriverList->pDriver = pDeviceDriverInfo; 将pDeviceDriverInfo放在pNewDriverList里面 /* make pVxbDriverInfo point to the pDeviceDriverInfo :: vxbDriverInfo */ pVxbDriverInfo = &(pDeviceDriverInfo->vxbDriverInfo); memset (pVxbDriverInfo, 0, sizeof (DRIVER_REGISTRATION)); /* populate struct vxbDevRegInfo. The devId should be VXB_DEVID_BUSCTRL for * hub driver and VXB_DEVID_DEVICE for all other class drivers. * The vxbDevRegInfo :: drvName should be determined for the class code */ /* parent bus ID. Should always be hub bus type. */ pVxbDriverInfo->busID = VXB_BUSID_USB_HUB; if (USBHST_HUB_CLASS == pDeviceDriverInfo->uVendorIDorClass) pVxbDriverInfo->devID = VXB_DEVID_BUSCTRL; else pVxbDriverInfo->devID = VXB_DEVID_DEVICE; /* version number */ pVxbDriverInfo->vxbVersion = VXB_VER_4_0_0; /* driver name. The name of the driver should not be greater than * MAX_DRV_NAME_LEN */ for (size = 0; pDrvName[size]!= '\0'; size++) pVxbDriverInfo->drvName[size] = pDrvName[size]; pVxbDriverInfo->drvName[size] = '\0'; /* function pointer to add device */ pVxbDriverInfo->pDrvBusFuncs = &usbVxbDeviceDriverInitFuncs; /* methods */ pVxbDriverInfo->pMethods = &usbVxbDeviceDriverMethods[0]; 填充pVxbDriverInfo /* register the driver with vxBus */ if (vxbDevRegister (pVxbDriverInfo) == ERROR) { OS_LOG_MESSAGE_HIGH( USBD, "usbHstRegisterDriver() Failed: vxBus Registration failed\n",0,0, 0,0); /* free allocated memory */ OS_FREE (pNewDriverList); return USBHST_FAILURE; } 调用vxbDevRegister将usb驱动注册在vxBus上 pNewDriverList->pNextDriver = gpDeviceDriverList; /* Assign the new driver to global driver list */ gpDeviceDriverList = pNewDriverList; 将pNewDriverList放在gpDeviceDriverList链表的头部。 至此usbdDynamicAttachRegister执行完成,返回到usbMouseDevInit里面,这个函数也执行完成。驱动加载完成。 再看vxbDevRegister(vxBus.c (target\src\hwif\vxbus))函数调用 if ( vxbDrvVerCheck(pDevInfo) != OK ) return(ERROR); 先检查vxbus drv版本,vxbus drv版本上面填充VXB_VER_4_0_0 pListEnd->pNext = pDriverListHead; pDriverListHead = pDevInfo; 将pDevInfo放在链表头部 /* Check existing devices, to see if this driver matches */ pCurrent = pDevInfo; while ( pCurrent != pListEnd ) { VXB_DEBUG_MSG(2,"vxbDevRegister() checking for orphans on %s\n", (int)vxbBusTypeString(pCurrent->busID), 2,3,4,5,6); vxbDevIterate(vxbNewDriver, pCurrent, VXB_ITERATE_ORPHANS); pCurrent = pCurrent->pNext; } 这里就检查存在的usb device,看看这个驱动是否匹配。 看vxbDevIterate函数 pBusPres = pPlbBus; /* start with PLB controller */ (*func)(pBusPres->pCtlr, pArg); Func就是vxbNewDriver,pArg就是上面的pDevInfo,而pBusPres->pCtlr就是vxbus上usb设备的信息结构体 看vxbNewDriver函数 先检查dev和drv一些相关的变量 /* get bus type of current device */ pBusEntry = pDev->pParentBus->pBusType; /* check bus-specific match routine */ drvFound = (*(pBusEntry->vxbDevMatch))(pDriver, pDev); if ( drvFound == FALSE ) return(ERROR); 调用vxbus上的dev匹配函数去匹配dev和drv,vxbDevMatch 这个是vxbus注册时用usbVxbRegHubBusType结构体填充的,这个函数就是usbdFindDriver,如果匹配不成功,就停止匹配,驱动返回。 看usbdFindDriver函数 pUSBD_DEVICE_INFO pUSBDeviceInfo = (pUSBD_DEVICE_INFO) pDev->pBusSpecificDevInfo; /* extract the device information from vxBus */ /* device information */ pUSBHST_DEVICE_DRIVER pDriverInfo = (pUSBHST_DEVICE_DRIVER)pDriver; 得到pUSBD_DEVICE_INFO结构体,这是usb设备信息,这个结构体在usbHstDeviceNew里面创建,并且赋值。 /* * Check if the device has multiple configurations and is vendor * specific. If so, return error */ if ((1 < pUSBDeviceInfo->uNumConfigurations) && (USBHST_VENDOR_SPECIFIC == pUSBDeviceInfo->uDeviceClass)) { OS_LOG_MESSAGE_HIGH( USBD, "usbdFindDriver() Failed: Vendor specific \ device with multiple configurations not \ supported.\n", 0, 0, 0, 0); return FALSE; } 检查如果这个设备有多个配置,但是又指明vid,这是不支持的,出错返回。 if (USBHST_VENDOR_SPECIFIC == pUSBDeviceInfo->uDeviceClass) { if (0 == pUSBDeviceInfo->uVendorID) { OS_LOG_MESSAGE_MEDIUM( USBD, "usbdFindDriver() Failed: Invalid parameter Device Info.\n", 0, 0, 0, 0); return FALSE; } /* Find the matching driver for the device */ if (usbdMatchDriver (TRUE, pUSBDeviceInfo->uVendorID, pUSBDeviceInfo->uDeviceID, pUSBDeviceInfo->uBCDDevice, pDriverInfo) == TRUE) { /* Store the driver info in the device info*/ pUSBDeviceInfo->pDriver = pDriverInfo; return TRUE; } } if (0 != pUSBDeviceInfo->uDeviceClass) { /* Find the matching driver for the device */ if (usbdMatchDriver (FALSE, pUSBDeviceInfo->uDeviceClass, pUSBDeviceInfo->uDeviceSubClass, pUSBDeviceInfo->uDeviceProtocol, pDriverInfo) == TRUE) { /* Store the driver info in the device info*/ pUSBDeviceInfo->pDriver = pDriverInfo; return TRUE; } } 如果usb 设备类代码是0xff,就必须有vid,如果vid为0,出错返回,如果不为0,调用usbdMatchDriver用设备的vid和pid去匹配driver,driver也得提供vid和pid,如果类代码不是0xff,也不为0,调用usbdMatchDriver用设备的类代码和子类代码,协议代码去匹配driver,driver也得提供相应的代码,如果类代码等于0,接着判断interface描述符的类代码是否为0xff,如果是0xff,调用usbdMatchDriver用设备的vid和pid去匹配driver,driver也得提供vid和pid,如果不是0xff,调用usbdMatchDriver用设备的类代码和子类代码,协议代码去匹配driver,driver也得提供相应的代码。 前面讲到有网友不想用类代码来进行设备和驱动的匹配,那就要满足两个条件: usb硬件满足类代码为0xff,vid不为0,或者类代码为0,接口描述符类代码为0xff,vid不为0 usb驱动调用usbdDynamicAttachRegister时,第五个参数为true,第二个参数为usb硬件的vid,第三个参数为usb硬件的pid 看usbdMatchDriver 这个函数就是根据dev和drv的类代码或者id进行匹配,如果匹配成功,就返回true,同时把drv结构体放在pUSBDeviceInfo->pDriver或者pInterfaceInfo->pDriver里面。 if ( pDriver->devProbe == NULL ) { drvFound = TRUE; } else { drvFound = (*(pDriver->devProbe))(pDev); if ( drvFound == FALSE ) return(ERROR); } 执行drv的probe函数,这也是个空函数 /* attach driver */ pDev->pDriver = pDriver; /* adjust name */ pDev->pName = &pDriver->drvName[0]; 把drv赋给dev /* perform initialization */ vxbDevInitRun(pDev, pDriver); 执行usb dev的初始化 看vxbDevInitRun函数 /* first pass */ if (!(devID->flags & VXB_INST_INIT_DONE)) { if ( pDrv->pDrvBusFuncs->devInstanceInit != NULL ) (*(pDrv->pDrvBusFuncs->devInstanceInit))(devID); devID->flags |= VXB_INST_INIT_DONE; } /* second pass */ if (vxbInitPhase >= 2 && !(devID->flags & VXB_INST_INIT2_DONE)) { if ( pDrv->pD
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服