/** * 初始化文件日志。4个参数 * 在使用该日志模块时在写日志之前要调用该函数进行初始化,在中间任何地方都可以对日志文件进行写入日志信息,当写完日志后,不再调用该函数写日志,那么要调用LogUninitialize进行清理。 */ void LogInitialize(ULONG loglevel,WCHAR* logfilename,LONGLONG filesize,USHORT strategy) { size_t flength; NTSTATUS ntStatus = RtlStringCchLengthW(logfilename,(MAX_PATH-2),&flength); if(!NT_SUCCESS(ntStatus) ) { KdPrint( ("Filename too long!\n") ); return; } KdPrint( ("Filename length:%d\n",flength) ); //将文件名记录在g_LogFileName中,注意Unicode_String不是以0为结束,以Length作为计算标准 g_logFileName.Buffer = (PWSTR)ExAllocatePool(NonPagedPool,MAX_PATH*sizeof(WCHAR));//申请双倍内存 RtlZeroMemory(g_logFileName.Buffer,MAX_PATH*sizeof(WCHAR));//清0,为了下面的操作顺利 g_logFileName.MaximumLength = MAX_PATH*sizeof(WCHAR); RtlCopyMemory(g_logFileName.Buffer,logfilename,flength*sizeof(WCHAR)); g_logFileName.Length = flength*sizeof(WCHAR); KdPrint( ("Filename:%wZ\n",&g_logFileName) ); g_logLevel = loglevel; g_logFileMaxSize = filesize; g_logWriteTime = 0; g_logStrategy = strategy; //初始化处理互斥体 KeInitializeMutex(&g_logMutex,0); KdPrint( ("Log Init Sucsess!\n") ); }
////////////////////////////////////////////////////////////////////////// // // Event log // static VOID _WriteLogErrorEntry( IN PDEVICE_OBJECT DeviceObject, IN PLSU_ERROR_LOG_ENTRY LogEntry ){ PIO_ERROR_LOG_PACKET errorLogEntry; WCHAR strBuff[16]; NTSTATUS status; ULONG stringOffset; ULONG_PTR stringLen; ULONG idx_dump; // // Parameter to unicode string // ASSERT(LogEntry->DumpDataEntry <= LSU_MAX_ERRLOG_DATA_ENTRIES); ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); status = RtlStringCchPrintfW(strBuff, 16, L"%u", LogEntry->Parameter2); if(!NT_SUCCESS(status)) { KDPrint(1, ("RtlStringCchVPrintfW() failed.\n")); return; } status = RtlStringCchLengthW(strBuff, 16, &stringLen); if(!NT_SUCCESS(status)) { KDPrint(1, ("RtlStringCchLengthW() failed.\n")); return; } // // Translate unicode length into byte length including NULL termination. // stringLen = ( stringLen + 1 ) * sizeof(WCHAR); stringOffset = FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData) + LogEntry->DumpDataEntry * sizeof(ULONG); errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry( DeviceObject, (sizeof(IO_ERROR_LOG_PACKET) + (LogEntry->DumpDataEntry * sizeof(ULONG)) + (UCHAR)stringLen)); if(errorLogEntry == NULL) { KDPrint(1, ("Could not allocate error log entry.\n")); ASSERT(FALSE); return ; } errorLogEntry->ErrorCode = LogEntry->ErrorCode; errorLogEntry->MajorFunctionCode = LogEntry->MajorFunctionCode; errorLogEntry->IoControlCode = LogEntry->IoctlCode; errorLogEntry->EventCategory; errorLogEntry->SequenceNumber = LogEntry->SequenceNumber; errorLogEntry->RetryCount = (UCHAR) LogEntry->ErrorLogRetryCount; errorLogEntry->UniqueErrorValue = LogEntry->UniqueId; errorLogEntry->FinalStatus = STATUS_SUCCESS; errorLogEntry->DumpDataSize = LogEntry->DumpDataEntry * sizeof(ULONG); for(idx_dump=0; idx_dump < LogEntry->DumpDataEntry; idx_dump++) { errorLogEntry->DumpData[idx_dump] = LogEntry->DumpData[idx_dump]; } errorLogEntry->NumberOfStrings = 1; errorLogEntry->StringOffset = (USHORT)stringOffset; RtlCopyMemory((PUCHAR)errorLogEntry + stringOffset, strBuff, stringLen); IoWriteErrorLogEntry(errorLogEntry); return; }
/** * 写日志函数 * @param iLevel:ULONG,要写入日志信息的等级,请参考LogConst.h文件内等级。 * @param format:NTSTRSAFE_PSTR*,输入信息的格式,此格式参考printf。 * @param ...:变参,参考printf,要写入的信息。 * 写日志信息接口,写日志信息大小请不要超过规定长度的大小!最大暂时为256字节!! */ void _cdecl WriteSysLog(ULONG iLevel, NTSTRSAFE_PWSTR format,...) { //判断记录日志级别 if(iLevel > g_logLevel) return; //获得互斥体,在下面的调用中,所有的函数退出部分都要进行释放互斥体 KeWaitForSingleObject(&g_logMutex, Executive, KernelMode, FALSE, NULL); HANDLE logfile; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatus; NTSTATUS ntStatus; InitializeObjectAttributes(&objectAttributes,&g_logFileName,OBJ_CASE_INSENSITIVE,NULL, NULL); ntStatus = ZwCreateFile(&logfile,FILE_READ_ATTRIBUTES | FILE_APPEND_DATA | SYNCHRONIZE, &objectAttributes,&ioStatus,NULL,FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE,FILE_OPEN_IF,FILE_SYNCHRONOUS_IO_NONALERT,NULL,0); if(!NT_SUCCESS(ntStatus) ) { KeReleaseMutex(&g_logMutex,FALSE); KdPrint( ("Strategy:%d:Init Open file error!\n",g_logStrategy) ); return; } //判断文件大小处理的函数 if(g_logWriteTime >= CHECK_TIME) { if(g_logStrategy == 1) { ntStatus = CheckLogFileSizeAndReCreateLogFile(&g_logFileName,1,logfile); if(!NT_SUCCESS(ntStatus) ) { KeReleaseMutex(&g_logMutex,FALSE); KdPrint( ("Strategy:%d:Init Open file error!\n",g_logStrategy) ); return; } } g_logWriteTime = 0; } TIME_FIELDS ctime; ctime = GetLocalTime(); ULONG pid = (ULONG)PsGetCurrentProcessId(); PWCHAR ptype; switch(iLevel) { case LOG_TYPE_ERROR: ptype = L"ERROR";break; case LOG_TYPE_WARN: ptype = L"WARNING";break; case LOG_TYPE_INFO: ptype = L"INFO";break; default: ptype = L"DEBUG";break; } WCHAR strTemp[MAX_INFO_LENGTH]; RtlZeroMemory(strTemp, MAX_INFO_LENGTH); NTSTRSAFE_PWSTR pinfo = strTemp; va_list args; va_start(args,format); ntStatus =::RtlStringCchVPrintfW(pinfo,MAX_INFO_LENGTH*sizeof(WCHAR),format,args); if( !NT_SUCCESS(ntStatus) ) { DbgPrint( ("Log info conversion error1!\n") ); ZwClose(logfile); KeReleaseMutex(&g_logMutex,FALSE); //在函数所有的出口释放互斥体 return; } va_end(args); WCHAR cinfo[MAX_INFO_LENGTH*2]; RtlZeroMemory(cinfo,MAX_INFO_LENGTH*2*sizeof(WCHAR));//清0,为了下面的操作顺利 ntStatus = RtlStringCchPrintfW(cinfo,MAX_INFO_LENGTH*2*sizeof(WCHAR), L"%04d-%02d-%02d %02d:%02d:%02d.%03d\t%d\t%s\t%s\r\n", ctime.Year, ctime.Month, ctime.Day, ctime.Hour, ctime.Minute, ctime.Second, ctime.Milliseconds,pid,ptype,pinfo); if( !NT_SUCCESS(ntStatus) ) { DbgPrint( ("Log info conversion error2!\n") ); //在函数所有的出口释放互斥体 ZwClose(logfile); KeReleaseMutex(&g_logMutex,FALSE); return; } size_t length; ntStatus = RtlStringCchLengthW(cinfo,MAX_INFO_LENGTH*2,&length); if( !NT_SUCCESS(ntStatus) ) { DbgPrint( ("Log info conversion error3!\n") ); //在函数所有的出口释放互斥体 ZwClose(logfile); KeReleaseMutex(&g_logMutex,FALSE); return; } ntStatus = ZwWriteFile(logfile,NULL,NULL,NULL,&ioStatus,cinfo,length*sizeof(WCHAR),NULL,NULL); if( !NT_SUCCESS(ntStatus) ) { DbgPrint( ("Write log error!\n") ); ZwClose(logfile); //在函数所有的出口释放互斥体 KeReleaseMutex(&g_logMutex,FALSE); return; } g_logWriteTime ++;//增加写入次数 ZwClose(logfile); KeReleaseMutex(&g_logMutex,FALSE); //KdPrint( ("write log successful!\n") ); }
// handles operations that must be performed when an application requests access to a device. VOID vJoy_EvtDeviceFileCreate( __in WDFDEVICE Device, __in WDFREQUEST Request, __in WDFFILEOBJECT FileObject ) { WDFFILEOBJECT FileObj; PCUNICODE_STRING pName; UNICODE_STRING TmpUstr; NTSTATUS status = STATUS_SUCCESS; int id=0; WCHAR RefStr[100]; PFILEOBJECT_EXTENSION pExtension=NULL; PDEVICE_EXTENSION pDevContext = NULL; PRPDO_DEVICE_DATA pPdoData=NULL; size_t len; DWORD_PTR ProcessId; PAGED_CODE (); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "Entered vJoy_EvtDeviceFileCreate\n"); // Get file object then get its filename FileObj = WdfRequestGetFileObject(Request); if (!FileObj) goto going_out; pName = WdfFileObjectGetFileName(FileObj); if (!pName) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: File name=%wZ\n", pName); // Extract id from interface number status = RtlStringCchLengthW(VJOY_INTERFACE, 100, &len); if (!NT_SUCCESS(status)) goto going_out; status = RtlStringCchCopyNW(RefStr, 100, pName->Buffer+len+1,4); // Copy the numeric part of the string (000) if (!NT_SUCCESS(status)) goto going_out; RtlInitUnicodeString(&TmpUstr, RefStr); // Convert "000" to UNICODE_STRING status = RtlUnicodeStringToInteger(&TmpUstr, 10, &id); // Convert "000" to integer (0) if (!NT_SUCCESS(status)) goto going_out; if (id>0) { // Verify that this interface has a corresponding device TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: ID=%d\n", id); pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; if (!pDevContext->positions[id - 1]) goto going_out; // Get the file object context space // Test that this interface is not in use // and store there the parent (Raw PDO) context pExtension = GetFileObjectContext(FileObject); if (!pExtension) goto going_out; pExtension->pParentRawDeviceContext = pPdoData; if (pPdoData->UsedInterfacesMask & (1 << (id - 1))) { WdfRequestComplete(Request, STATUS_ACCESS_DENIED); ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Access Denied)\n", ProcessId); return; } ///// This is a successful file creation - Now record the file details // vJoy Device ID else pPdoData->UsedInterfacesMask |= 1 << (id - 1); // Put id in file object context space pExtension->id = id; // Update // Get the id of the calling process ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); pExtension->CallingProcessId = (DWORD)(ProcessId & 0xFFFFFFFF); TraceEvents(TRACE_LEVEL_WARNING, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d\n", pExtension->CallingProcessId); // Put the file object in the FDO extension pDevContext->DeviceFileObject[id - 1] = FileObject; // Activate FFB Queues FfbActiveSet(TRUE, id, pDevContext); WdfRequestComplete(Request, status); return; } // if (id>0) // Case of General purpose and non device-specific Interface else // if (id<1) { TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): ID=%d\n", id); #if 0 pPdoData = PdoGetData(Device); pDevContext = GetDeviceContext(pPdoData->hParentDevice); if (!pDevContext) goto going_out; TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate(2nd case): Completing Request\n"); #endif // 0 WdfRequestComplete(Request, status); return; }; // if (id<1) going_out: ProcessId = (DWORD_PTR)PsGetCurrentProcessId(); TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "vJoy_EvtDeviceFileCreate: PID=%d Failed (Invalid Handle)\n", ProcessId); WdfRequestComplete(Request, STATUS_INVALID_HANDLE); }
// 并行处理 VOID CY001Drv::DeviceIoControlParallel(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { NTSTATUS status = STATUS_SUCCESS; ULONG ulRetLen = 0; size_t size = 0; void* pBufferInput = NULL; void* pBufferOutput = NULL; KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlParallel] CtlCode:0x%0.8X", IoControlCode); // 取得输入缓冲区,判断其有效性 if(InputBufferLength){ status = WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size); if(status != STATUS_SUCCESS || pBufferInput == NULL || size < InputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // 取得输出缓冲区,判断其有效性 if(OutputBufferLength){ status = WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size); if(status != STATUS_SUCCESS || pBufferOutput == NULL || size < OutputBufferLength){ WdfRequestComplete(Request, STATUS_INVALID_PARAMETER); return; } } // // 下面是主处理过程。 // switch(IoControlCode) { // 取得驱动的版本信息 case IOCTL_GET_DRIVER_VERSION: { PDRIVER_VERSION pVersion = (PDRIVER_VERSION)pBufferOutput; ULONG length; char tcsBuffer[120]; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_GET_DRIVER_VERSION"); if(OutputBufferLength < sizeof(DRIVER_VERSION)){ status = STATUS_BUFFER_TOO_SMALL; break; } pVersion->DriverType = DR_WDF; pVersion->FirmwareType = FW_NOT_CY001; ulRetLen = sizeof(DRIVER_VERSION);// 告示返回长度 // 根据String描述符,判断Firmware代码是否已经被加载。 GetStringDes(2, 0, tcsBuffer, 120, &length); if(length){ WCHAR* pCyName = L"CY001 V"; size_t len; int nIndex; if(length < 8) break; RtlStringCchLengthW(pCyName, 7, &len); for(nIndex = 0; nIndex < len; nIndex++){ if(pCyName[nIndex] != ((WCHAR*)tcsBuffer)[nIndex]) break; } if(nIndex == len) pVersion->FirmwareType = FW_CY001; // 完全相符,说明新版Firmware已经加载到开发板。 } break; } // 收到App发送过来的一个同步Request,我们应该把它保存到同步Queue中,等到有同步事件发生的时候再从Queue中取出并完成。 case IOCTL_USB_SYNC: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); status = WdfRequestForwardToIoQueue(Request, m_hAppSyncManualQueue); // 直接返回,不调用WdfRequestComplete函数。 // 请求者将不会为此而等待;请求的完成在将来的某个时刻。 // 这就是所谓的异步处理之要义了。 if(NT_SUCCESS(status)) return; break; // 清空同步队列中的所有请求 case IOCTL_USB_SYNC_RELEASE: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SYNC"); ClearSyncQueue(); break; // 应用程序退出,取消所有被阻塞的请求。 case IOCTL_APP_EXIT_CANCEL: // 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。 //WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo); break; // 取得当前的配置号.总是设置为0,因为在WDF框架中,0以外的配置是不被支持的。 case IOCTL_USB_GET_CURRENT_CONFIG: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CURRENT_CONFIG"); if(InputBufferLength < 4){ status = STATUS_INVALID_PARAMETER; break; } *(PULONG)pBufferInput = 0;// 直接赋值0,即总是选择0号配置。也可以发送URB到总线获取当前配置选项。 ulRetLen = sizeof(ULONG); break; } case IOCTL_USB_ABORTPIPE: { ULONG pipenum = *((PULONG) pBufferOutput); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_ABORTPIPE"); status = AbortPipe(pipenum); } break; // 获取Pipe信息 case IOCTL_USB_GET_PIPE_INFO: { // 遍历获取Pipe信息,复制到输出缓冲中。 BYTE byCurSettingIndex = 0; BYTE byPipeNum = 0; BYTE index; USB_INTERFACE_DESCRIPTOR interfaceDescriptor; WDF_USB_PIPE_INFORMATION pipeInfor; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_PIPE_INFO"); // 取得Pipe数。根据Pipe数计算缓冲区长度 byCurSettingIndex = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); WdfUsbInterfaceGetDescriptor(m_hUsbInterface, byCurSettingIndex, &interfaceDescriptor); byPipeNum = WdfUsbInterfaceGetNumConfiguredPipes(m_hUsbInterface); if(OutputBufferLength < byPipeNum * sizeof(pipeInfor)){ status = STATUS_BUFFER_TOO_SMALL; // 缓冲区不足 }else{ ulRetLen = byPipeNum*sizeof(pipeInfor); // 遍历获取全部管道信息,拷贝到输出缓冲中。 // 应用程序得到输出缓冲的时候,也应该使用WDF_USB_PIPE_INFORMATION结构体解析缓冲区。 for(index = 0; index < byPipeNum; index++) { WDF_USB_PIPE_INFORMATION_INIT(&pipeInfor); WdfUsbInterfaceGetEndpointInformation(m_hUsbInterface, byCurSettingIndex, index, &pipeInfor); RtlCopyMemory((PUCHAR)pBufferOutput + index*pipeInfor.Size, &pipeInfor, sizeof(pipeInfor)); } } } break; // 获取设备描述符 case IOCTL_USB_GET_DEVICE_DESCRIPTOR: { USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor; WdfUsbTargetDeviceGetDeviceDescriptor(m_hUsbDevice, &UsbDeviceDescriptor); KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DEVICE_DESCRIPTOR"); // 判断输入缓冲区的长度是否足够长 if(OutputBufferLength < UsbDeviceDescriptor.bLength) status = STATUS_BUFFER_TOO_SMALL; else{ RtlCopyMemory(pBufferOutput, &UsbDeviceDescriptor, UsbDeviceDescriptor.bLength); ulRetLen = UsbDeviceDescriptor.bLength; } break; } // 获取字符串描述符 case IOCTL_USB_GET_STRING_DESCRIPTOR: { PGET_STRING_DESCRIPTOR Input = (PGET_STRING_DESCRIPTOR)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_STRING_DESCRIPTOR"); status = GetStringDes(Input->Index, Input->LanguageId, pBufferOutput, OutputBufferLength, &ulRetLen); // 由字符长度调整为字节长度 if(NT_SUCCESS(status) && ulRetLen > 0) ulRetLen *= (sizeof(WCHAR)/sizeof(char)); break; } // 获取配置描述信息。 case IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_CONFIGURATION_DESCRIPTOR"); // 首先获得配置描述符的长度。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, NULL, (USHORT*)&size); if(!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) break; // 输出缓冲区不够长 if(OutputBufferLength < size) break; // 正式取得配置描述符。 status = WdfUsbTargetDeviceRetrieveConfigDescriptor(m_hUsbDevice, pBufferOutput, (USHORT*)&size); if(!NT_SUCCESS(status)) break; ulRetLen = size; break; } // 根据可选值配置接口 case IOCTL_USB_SET_INTERFACE: { BYTE byAlterSetting = *(BYTE*)pBufferInput; BYTE byCurSetting = WdfUsbInterfaceGetConfiguredSettingIndex(m_hUsbInterface); // 当前Alternate值 KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SETINTERFACE"); if(InputBufferLength < 1 || OutputBufferLength < 1) { status = STATUS_BUFFER_TOO_SMALL; break; } // 如果传入的可选值与当前的不同,则重新配置接口; // 否则直接返回。 if(byCurSetting != byAlterSetting) { WDF_USB_INTERFACE_SELECT_SETTING_PARAMS par; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&par, byAlterSetting); status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, NULL, &par); } *(BYTE*)pBufferOutput = byCurSetting; break; } // 固件Rest。自定义命令,与Port Rest是两码事。 case IOCTL_USB_FIRMWRAE_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_FIRMWRAE_RESET"); if(InputBufferLength < 1 || pBufferInput == NULL) status = STATUS_INVALID_PARAMETER; else status = FirmwareReset(*(char*)pBufferInput); break; } // 重置USB总线端口 case IOCTL_USB_PORT_RESET: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PORT_RESET"); WdfUsbTargetDeviceResetPortSynchronously(m_hUsbDevice); break; } // 管道重置 case IOCTL_USB_PIPE_RESET: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_RESET"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeResetSynchronously(pipe, NULL, NULL); break; } // 中断管道,放弃管道当前正在进行的操作 case IOCTL_USB_PIPE_ABORT: { UCHAR uchPipe; WDFUSBPIPE pipe = NULL; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_PIPE_ABORT"); if(InputBufferLength < 1){ status = STATUS_INVALID_PARAMETER; break; } // 根据ID找到对应的Pipe uchPipe = *(UCHAR*)pBufferInput; pipe = WdfUsbInterfaceGetConfiguredPipe(m_hUsbInterface, uchPipe, NULL); if(pipe == NULL){ status = STATUS_INVALID_PARAMETER; break; } status = WdfUsbTargetPipeAbortSynchronously(pipe, NULL, NULL); break; } // 取得驱动错误信息,驱动总是把最后一次发现的错误保存在设备对象的环境块中。 // 这个逻辑虽然实现了,但目前的版本中,应用程序并没有利用这个接口。 case IOCTL_USB_GET_LAST_ERROR: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LAST_ERROR"); if (OutputBufferLength >= sizeof(ULONG)) *((PULONG)pBufferOutput) = m_ulLastUSBErrorStatusValue; else status = STATUS_BUFFER_TOO_SMALL; ulRetLen = sizeof(ULONG); break; } // Clear feature命令 case IOCTL_USB_SET_CLEAR_FEATURE: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_CLEAR_FEATURE"); status = UsbSetOrClearFeature(Request); break; } // 为USB设备加载固件程序。带有偏移量参数,用这个分支;不带偏移量,可用下一个分支。 // 带偏移量的情况下,固件代码是一段一段地加载; // 不带偏移量的情况,固件代码作为一整块一次性被加载。 case IOCTL_FIRMWARE_UPLOAD_OFFSET: { void* pData = pBufferOutput; WORD offset = 0; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD_OFFSET"); if(InputBufferLength < sizeof(WORD)){ status = STATUS_INVALID_PARAMETER; break; } offset = *(WORD*)pBufferInput; status = FirmwareUpload((PUCHAR)pData, OutputBufferLength, offset); break; } // 为USB设备加载固件程序。 case IOCTL_FIRMWARE_UPLOAD: { void* pData = pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_UPLOAD"); status = FirmwareUpload((PUCHAR)pData, InputBufferLength, 0); break; } // 读取开发板设备的RAM内容。RAM也就是内存。 // 每次从同一地址读取的内容可能不尽相同,开发板中固件程序在不断运行,RAM被用来储数据(包括临时数据)。 case IOCTL_FIRMWARE_READ_RAM: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_FIRMWARE_READ_RAM"); status = ReadRAM(Request, &ulRetLen);// inforVal中保存读取的长度 break; } // 其他的请求 default: { // 一律转发到SerialQueue中去。 WdfRequestForwardToIoQueue(Request, m_hIoCtlSerialQueue); // 命令转发之后,这里必须直接返回,千万不可调用WdfRequestComplete函数。 // 否则会导致一个Request被完成两次的错误。 return; } } // 完成请求 WdfRequestCompleteWithInformation(Request, status, ulRetLen); }
VOID DokanPrintToSysLog(__in PDRIVER_OBJECT DriverObject, __in UCHAR MajorFunctionCode, __in NTSTATUS MessageId, __in NTSTATUS Status, __in LPCTSTR Format, __in va_list Args) { NTSTATUS status = STATUS_SUCCESS; PIO_ERROR_LOG_PACKET packet = NULL; WCHAR *message = NULL; size_t messageCapacity = DOKAN_LOG_MAX_CHAR_COUNT; size_t messageCharCount = 0; size_t messageCharsWritten = 0; size_t packetCount = 0; size_t i = 0; UCHAR packetCharCount = 0; UCHAR packetSize = 0; __try { message = ExAllocatePool(sizeof(WCHAR) * messageCapacity); if (message == NULL) { DDbgPrint("Failed to allocate message of capacity %d\n", messageCapacity); __leave; } status = RtlStringCchVPrintfW(message, messageCapacity, Format, Args); if (status == STATUS_BUFFER_OVERFLOW) { // In this case we want to at least log what we can fit. DDbgPrint("Log message was larger than DOKAN_LOG_MAX_CHAR_COUNT." " Format: %S\n", Format); } else if (status != STATUS_SUCCESS) { DDbgPrint("Failed to generate log message with format: %S; status: %x\n", Format, status); __leave; } status = RtlStringCchLengthW(message, messageCapacity, &messageCharCount); if (status != STATUS_SUCCESS) { DDbgPrint("Failed to determine message length, status: %x\n", status); __leave; } packetCount = messageCharCount / DOKAN_LOG_MAX_PACKET_NONNULL_CHARS; if (messageCharCount % DOKAN_LOG_MAX_PACKET_NONNULL_CHARS != 0) { ++packetCount; } for (i = 0; i < packetCount; i++) { packetCharCount = (UCHAR)min(messageCharCount - messageCharsWritten, DOKAN_LOG_MAX_PACKET_NONNULL_CHARS); packetSize = sizeof(IO_ERROR_LOG_PACKET) + sizeof(WCHAR) * (packetCharCount + 1); packet = IoAllocateErrorLogEntry(DriverObject, packetSize); if (packet == NULL) { DDbgPrint("Failed to allocate packet of size %d\n", packetSize); __leave; } RtlZeroMemory(packet, packetSize); packet->MajorFunctionCode = MajorFunctionCode; packet->NumberOfStrings = 1; packet->StringOffset = (USHORT)((char *)&packet->DumpData[0] - (char *)packet); packet->ErrorCode = MessageId; packet->FinalStatus = Status; RtlCopyMemory(&packet->DumpData[0], message + messageCharsWritten, sizeof(WCHAR) * packetCharCount); IoWriteErrorLogEntry(packet); // Destroys packet. packet = NULL; messageCharsWritten += packetCharCount; } } __finally { if (message != NULL) { ExFreePool(message); } } }