如果坚持不能在usb_core.c中不能修改的原则的话,
那么可以考虑在usb_prop.c中的void Joystick_Status_In(void)函数中添加代码(我用的是摇杆实例, 具体的不同程序可能有不同的Status_In处理函数,具体在DEVICE_PROP结构体中的第三个成员函数指定), 从该函数的名字来看,是处理状态输入过程的,这也正好是控制输出传输的最后一个过程,只要在这里 增加对刚刚输出的数据处理即可。 从usb_core.c中也可以推测出来,其中的u8 In0_Process(void)函数(处理端点0输入的函数)中有如下代码: else if (ControlState == WAIT_STATUS_IN) //如果是等待状态输入(也就是我前面所说的数据接收完毕) { //如果是标准的设置地址请求,那么库函数将处理它 if ((pInformation->USBbRequest == SET_ADDRESS) && (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) { SetDeviceAddress(pInformation->USBwValue0); pUser_Standard_Requests->User_SetDeviceAddress(); } //然后再转交给用户的Process_Status_IN函数(也就是前面的void Joystick_Status_In(void)函数) (*pProperty->Process_Status_IN)(); ControlState = STALLED; } 从这里可以看出,处理端点0输出(因为设置地址也是控制输出请求)可以在用户指定的pProperty->Process_Status_IN函数中处理。 对比我前面给出的方案可以看出,其实处理过程是一样的。我是在最后一个数据输出包后就处理输出数据, 而这里则是等待当主机发送最后一个输出包后再请求状态输入时才去处理数据。 那么只要在指定的Process_Status_IN函数中增加处理的代码: #define SET_REPORT 0x09 if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) && (pInformation->USBbRequest) == SET_REPORT) //如果是SET REPORT请求 { //则处理SET REPORT请求 } 那么接收的数据保存在了哪呢?这就要看前面所提到过的那个void DataStageOut(void)函数了, 在这里有如下代码: Buffer = (*pEPinfo->CopyData)(Length); pEPinfo->Usb_rLength -= Length; pEPinfo->Usb_rOffset += Length; //这里调整了Usb_rOffset 它调用了pEPinfo->CopyData这个函数来获取缓冲取的地址,所以我们需要自己写一个提供缓冲区 地址的函数。在该函数中由pInformation->Ctrl_Info.Usb_wOffset来指定当前缓冲区的地址, 增加函数代码如下: #define OUT_REPORT_LENGTH 100 u8 SetReportBuffer[OUT_REPORT_LENGTH]; //定义保存输出报告的缓冲区 //返回输出报告的缓冲区地址函数 u8 *Joystick_GetBufferForSetReport(u16 Length); //声明 u8 *Joystick_GetBufferForSetReport(u16 Length) { //根据当前偏移量返回保存报告的地址 return SetReportBuffer+(pInformation->Ctrl_Info.Usb_wOffset); } 那么这个函数该在哪里赋给上面的pEPinfo->CopyData呢?(pEPinfo其实就是&pInformation->Ctrl_Info) 这就要看usb_core.c中的void Data_Setup0(void)函数了,里面有如下代码: if (CopyRoutine) //由于在上面并没有处理SET REPORT,所以这里为假 { pInformation->Ctrl_Info.Usb_wOffset = wOffset; pInformation->Ctrl_Info.CopyData = CopyRoutine; /* sb in the original the cast to word was directly */ /* now the cast is made step by step */ (*CopyRoutine)(0); Result = USB_SUCCESS; } else //那么就会调用下面的pProperty->Class_Data_Setup函数了, { Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest); if (Result == USB_NOT_READY) { pInformation->ControlState = PAUSE; return; } } 通过查看usb_prop.c中的DEVICE_PROP Device_Property结构体,发现它就是用户函数Joystick_Data_Setup, 我们只要在该函数中初始化CopyData即可。 在Joystick_Data_Setup函数中可以找到如下代码: if (CopyRoutine == NULL) { return USB_UNSUPPORT; } 只要在这段代码之前添加初始化即可: #define SET_REPORT 0x09 if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT)) && (pInformation->USBbRequest) == SET_REPORT) //如果是SET REPORT请求 { //设置复制数据的函数 CopyRoutine=Joystick_GetBufferForSetReport; //设置要复制数据的长度 pInformation->Ctrl_Info.Usb_rLength=pInformation->USBwLength; } 接着下面就可以看到代码 pInformation->Ctrl_Info.CopyData = CopyRoutine; pInformation->Ctrl_Info.Usb_wOffset = 0; (*CopyRoutine)(0); 它将复制数据的处理函数赋给了pInformation->Ctrl_Info.CopyData,并设置了pInformation->Ctrl_Info.Usb_wOffset为0, 然后调用了复制数据的函数,也就是说,Joystick_GetBufferForSetReport函数将返回缓冲区的首地址。以后每次接收到 数据后,pInformation->Ctrl_Info.Usb_wOffset将自动增加接收数据的长度,调用Joystick_GetBufferForSetReport函数 后将获取到缓冲区的后续地址。 其中接收数据的长度由pInformation->Ctrl_Info.Usb_rLength决定,我们只需要将SETUP包中的wLength 值赋给它即可,即pInformation->Ctrl_Info.Usb_rLength=pInformation->USBwLength。当数据接收完毕后, 数据保存在SetReportBuffer中,总个数为pInformation->Ctrl_Info.Usb_wOffset。这时pInformation->Ctrl_Info.Usb_rLength 值应该为0。 以上是我对这个USB程序的分析,由于手头只有一条USB数据线,所以无法调试,楼主 可以按照这个思路去分析下,应该能解决问题。 其实如果直接在usb_core.c的void DataStageOut(void)函数中处理将不会绕这么多弯子了, 不过既然香主说了最好不要修改库文件,那还是不修改吧。祝楼主好运……晕,写了这么长, 都忘记吃饭了,先去吃个饭……