// Bulk管道读操作的完成函数 // VOID BulkReadComplete(IN WDFREQUEST Request, IN WDFIOTARGET Target, IN PWDF_REQUEST_COMPLETION_PARAMS Params, IN WDFCONTEXT Context) { PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; NTSTATUS ntStatus; ULONG_PTR ulLen; LONG* lpBuf; UNREFERENCED_PARAMETER(Context); UNREFERENCED_PARAMETER(Target); KDBG(DPFLTR_INFO_LEVEL, "[BulkReadComplete]"); usbCompletionParams = Params->Parameters.Usb.Completion; ntStatus = Params->IoStatus.Status; ulLen = usbCompletionParams->Parameters.PipeRead.Length; lpBuf = WdfMemoryGetBuffer(usbCompletionParams->Parameters.PipeRead.Buffer, NULL); if(NT_SUCCESS(ntStatus)) KDBG(DPFLTR_INFO_LEVEL, "%d bytes readen from USB device successfully.", ulLen); else KDBG(DPFLTR_INFO_LEVEL, "Failed to read: 0x%08x!!!", ntStatus); // 完成操作 // 应用程序将收到通知。 WdfRequestCompleteWithInformation(Request, ntStatus, ulLen); }
mach_msg_return_t mach_msg_send_from_kernel_with_options( mach_msg_header_t *msg, mach_msg_size_t send_size, mach_msg_option_t option, mach_msg_timeout_t timeout_val) { ipc_kmsg_t kmsg; mach_msg_return_t mr; KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } /* * Until we are sure of its effects, we are disabling * importance donation from the kernel-side of user * threads in importance-donating tasks - unless the * option to force importance donation is passed in, * or the thread's SEND_IMPORTANCE option has been set. * (11938665 & 23925818) */ if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) option &= ~MACH_SEND_NOIMPORTANCE; else if ((option & MACH_SEND_IMPORTANCE) == 0) option |= MACH_SEND_NOIMPORTANCE; mr = ipc_kmsg_send(kmsg, option, timeout_val); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } return mr; }
// 中断Pipe回调函数。这样一旦设备产生了中断信息,驱动就能够读取到。 // VOID InterruptRead(WDFUSBPIPE Pipe, WDFMEMORY Buffer, size_t NumBytesTransferred, WDFCONTEXT Context) { NTSTATUS status; size_t size = 0; PDEVICE_CONTEXT pContext = (PDEVICE_CONTEXT)Context; WDFREQUEST Request = NULL; CHAR *pchBuf = NULL; KDBG(DPFLTR_INFO_LEVEL, "[InterruptRead]"); UNREFERENCED_PARAMETER(Pipe); // Read数据缓冲区。注意到,缓冲区长度总是管道最大包长度的倍数。 // 我们这里只用缓冲区的第一个有效字节。 pchBuf = (CHAR*)WdfMemoryGetBuffer(Buffer, &size); if(pchBuf == NULL || size == 0) return; // 第一个字节为确认字节,一定是0xD4 //if(pchBuf[0] != 0xD4)return; // 从队列中提取一个未完成请求 status = WdfIoQueueRetrieveNextRequest(pContext->InterruptManualQueue, &Request); if(NT_SUCCESS(status)) { CHAR* pOutputBuffer = NULL; status = WdfRequestRetrieveOutputBuffer(Request, 1, &pOutputBuffer, NULL); if(NT_SUCCESS(status)) { // 把结果返回给应用程序 pOutputBuffer[0] = pchBuf[1]; WdfRequestCompleteWithInformation(Request, status, 1); } else { // 返回错误 WdfRequestComplete(Request, status); } KDBG(DPFLTR_INFO_LEVEL, "Get and finish an interrupt read request."); }else{ // 队列空,将放弃从设备获取的数据。 KDBG(DPFLTR_INFO_LEVEL, "Manual interrupt queue is empty!!!"); } }
// // 创建队列。 NTSTATUS DrvClass::CreateWDFQueues() { NTSTATUS status = STATUS_SUCCESS; WDF_IO_QUEUE_CONFIG ioQConfig; KDBG(DPFLTR_INFO_LEVEL, "[CreateWDFQueues]"); // 创建默认并发队列,处理DeviceIOControl命令。 WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQConfig, WdfIoQueueDispatchParallel); ioQConfig.EvtIoDefault = EventDefault_sta; status = WdfIoQueueCreate(m_hDevice, &ioQConfig, WDF_NO_OBJECT_ATTRIBUTES, &m_hDefQueue); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfIoQueueCreate failed with status 0x%08x\n", status); } return status; }
// Bulk管道读操作 // VOID BulkRead(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status = STATUS_SUCCESS; PDEVICE_CONTEXT pContext = NULL; WDFUSBPIPE BulkInputPipe; WDFMEMORY hMem; WDFDEVICE hDevice = WdfIoQueueGetDevice(Queue); KDBG(DPFLTR_INFO_LEVEL, "[BulkRead] size: %d", Length); // 取管道 pContext = GetDeviceContext(hDevice); BulkInputPipe = GetBulkPipe(TRUE, hDevice); if(NULL == BulkInputPipe){ WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); return; } status = WdfRequestRetrieveOutputMemory(Request, &hMem); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfRequestRetrieveOutputMemory failed with status 0x%0.8x!!!", status); WdfRequestComplete(Request, status); return; } // 和写一样,仍然是对Request对象的重利用 // 除了重利用外,也可以新建一个Request对象。新建的方法在本工程其他地方用得较多。 status = WdfUsbTargetPipeFormatRequestForRead(BulkInputPipe, Request, hMem, NULL); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetPipeFormatRequestForRead failed with status 0x%08x\n", status); WdfRequestComplete(Request, status); return; } WdfRequestSetCompletionRoutine(Request, BulkReadComplete, BulkInputPipe); if(FALSE == WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(pContext->UsbBulkInPipe), NULL)) { status = WdfRequestGetStatus(Request); KDBG(DPFLTR_INFO_LEVEL, "WdfRequestSend failed with status 0x%08x\n", status); WdfRequestComplete(Request, status); } }
/*============================================================================== * __davros_init - initialise all DAVROS data structures *============================================================================== */ void __davros_init ( memaddr_t membot, /* Bottom of free memory */ memaddr_t memtop /* Top of free memory */ ) { KDBG(1, KDBG_BASIC, "__davros_init(0x%08x, 0x%08x)\n", membot, memtop); __davros.membot = membot; __davros.memtop = memtop; __davros.numproc = 0; __davros.clkpres = TRUE; __davros.frc = 0; /* The process entry and stack for the null process is carved out * of the bottom of free memory. */ __davros.currpid = (__davros_process_t *)membot; membot += sizeof(__davros_process_t)+__DAVROS_NULLSTACK+__DAVROS_EXTRASTACK; __davros.memhead.next = (__davros_mblock_t *)membot; __davros.memhead.len = 0; __davros.memhead.next->next = NULL; __davros.memhead.next->len = memtop - membot; __davros_initqueue(&__davros.proctab); __davros_initqueue(&__davros.readyqueue); __davros_initqueue(&__davros.sleepqueue); __davros_initqueue(&__davros.devtab); __davros.sleepcount = NULL; #ifdef __ARCH_KERNEL_DATA __arch_initkernel(&__davros); #endif __davros_initproc(__davros.currpid); __davros_enqueue(&__davros.currpid->proctab_entry, &__davros.proctab); __davros.currpid->stacksize = __DAVROS_NULLSTACK + __DAVROS_EXTRASTACK; __davros.currpid->state = __DAVROS_PRCURR; strncpy(__davros.currpid->name, "_null", __DAVROS_PNMLEN); __davros_insert(&__davros.currpid->queue_entry, &__davros.readyqueue, 0); __arch_setstack(((memaddr_t)__davros.currpid) + sizeof(__davros_process_t) + __davros.currpid->stacksize); __arch_init(); __user_init(); while (1) { __user_nullproc(); } }
mach_msg_return_t mach_msg_send_from_kernel_proper( mach_msg_header_t *msg, mach_msg_size_t send_size) { ipc_kmsg_t kmsg; mach_msg_return_t mr; KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } mr = ipc_kmsg_copyin_from_kernel(kmsg); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } /* * respect the thread's SEND_IMPORTANCE option to force importance * donation from the kernel-side of user threads * (11938665 & 23925818) */ mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT; if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) option &= ~MACH_SEND_NOIMPORTANCE; mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); } return mr; }
// Bulk管道写操作 // VOID BulkWrite(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t Length) { NTSTATUS status = STATUS_SUCCESS; WDFMEMORY hMem = NULL; WDFDEVICE hDevice = NULL; WDFUSBPIPE BulkOutputPipe = NULL; UCHAR* lpBuf; UNREFERENCED_PARAMETER(Length); KDBG(DPFLTR_INFO_LEVEL, "[BulkWrite] size: %d", Length); // 获取管道句柄 hDevice = WdfIoQueueGetDevice(Queue); BulkOutputPipe = GetBulkPipe(FALSE, hDevice); if(NULL == BulkOutputPipe) { KDBG(DPFLTR_ERROR_LEVEL, "BulkOutputPipe = NULL"); WdfRequestComplete(Request, STATUS_UNSUCCESSFUL); return; } status = WdfRequestRetrieveInputMemory(Request, &hMem); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestRetrieveInputMemory failed(status = 0x%0.8x)!!!", status); WdfRequestComplete(Request, status); return; } // 打印出offset值。 // 在写缓冲的前两个字节中存有write offset的值 lpBuf = (UCHAR*)WdfMemoryGetBuffer(hMem, 0); KDBG(DPFLTR_TRACE_LEVEL, "write offset: %hd", *(WORD*)lpBuf); // 把当前的Request对象进行重利用,发送给USB总线。 // 格式化Request对象,设置Pipe句柄、完成函数等。 status = WdfUsbTargetPipeFormatRequestForWrite(BulkOutputPipe, Request, hMem, NULL); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_ERROR_LEVEL, "WdfUsbTargetPipeFormatRequestForWrite(status 0x%0.8x)!!!", status); WdfRequestComplete(Request, status); return; } WdfRequestSetCompletionRoutine(Request, BulkWriteComplete, BulkOutputPipe); if(FALSE == WdfRequestSend(Request, WdfUsbTargetPipeGetIoTarget(BulkOutputPipe), NULL)) { status = WdfRequestGetStatus(Request); KDBG(DPFLTR_ERROR_LEVEL, "WdfRequestSend failed with status 0x%0.8x\n", status); WdfRequestComplete(Request, status); } }
// 此函数类似于WDM中的PNP_MN_STOP_DEVICE函数,在设备移除时被调用。 // 当个函数被调用时候,设备仍处于工作状态。 NTSTATUS DrvClass::PnpReleaseHardware(IN WDFCMRESLIST ResourceListTranslated) { KDBG(DPFLTR_INFO_LEVEL, "[PnpReleaseHardware]"); // 如果PnpPrepareHardware调用失败,UsbDevice为空; // 这时候直接返回即可。 if (m_hUsbDevice == NULL) return STATUS_SUCCESS; // 取消USB设备的所有IO操作。它将连带取消所有Pipe的IO操作。 WdfIoTargetStop(WdfUsbTargetDeviceGetIoTarget(m_hUsbDevice), WdfIoTargetCancelSentIo); // Deconfiguration或者“反配置” WDF_USB_DEVICE_SELECT_CONFIG_PARAMS configParams; WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_DECONFIG(&configParams); return WdfUsbTargetDeviceSelectConfig(m_hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &configParams); }
// 配置设备驱动的电源管理功能 NTSTATUS DrvClass::InitPowerManagement() { NTSTATUS status = STATUS_SUCCESS; WDF_USB_DEVICE_INFORMATION usbInfo; KDBG(DPFLTR_INFO_LEVEL, "[InitPowerManagement]"); // 获取设备信息 WDF_USB_DEVICE_INFORMATION_INIT(&usbInfo); WdfUsbTargetDeviceRetrieveInformation(m_hUsbDevice, &usbInfo); // USB设备信息以掩码形式被保存在Traits中。 KDBG( DPFLTR_INFO_LEVEL, "Device self powered: %s", usbInfo.Traits & WDF_USB_DEVICE_TRAIT_SELF_POWERED ? "TRUE" : "FALSE"); KDBG( DPFLTR_INFO_LEVEL, "Device remote wake capable: %s", usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE ? "TRUE" : "FALSE"); KDBG( DPFLTR_INFO_LEVEL, "Device high speed: %s", usbInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED ? "TRUE" : "FALSE"); m_bIsDeviceHighSpeed = usbInfo.Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED; // 设置设备的休眠和远程唤醒功能 if(usbInfo.Traits & WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE) { WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS wakeSettings; // 设置设备为闲时休眠。闲时超过10S,自动进入休眠状态。 WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleUsbSelectiveSuspend); idleSettings.IdleTimeout = 10000; status = WdfDeviceAssignS0IdleSettings(m_hDevice, &idleSettings); if(!NT_SUCCESS(status)) { KDBG( DPFLTR_ERROR_LEVEL, "WdfDeviceAssignS0IdleSettings failed with status 0x%0.8x!!!", status); return status; } // 设置为可远程唤醒。包含设备自身醒来,已经当PC系统进入休眠后,设备可以将系统唤醒,两个方面。 WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_INIT(&wakeSettings); status = WdfDeviceAssignSxWakeSettings(m_hDevice, &wakeSettings); if(!NT_SUCCESS(status)) { KDBG( DPFLTR_ERROR_LEVEL, "WdfDeviceAssignSxWakeSettings failed with status 0x%0.8x!!!", status); return status; } } return status; }
// 此函数类似于WDM中的PNP_MN_START_DEVICE函数,紧接着PnpAdd之后被调用。 // 此时PNP管理器经过甄别之后,已经决定将那些系统资源分配给当前设备。 // 参数ResourceList和ResourceListTranslated代表了这些系统资源。 // 当个函数被调用时候,设备已经进入了D0电源状态;函数完成后,设备即正式进入工作状态。 NTSTATUS DrvClass::PnpPrepareHardware(IN WDFCMRESLIST ResourceList, IN WDFCMRESLIST ResourceListTranslated) { NTSTATUS status; PDEVICE_CONTEXT pContext = NULL; ULONG ulNumRes = 0; ULONG ulIndex; CM_PARTIAL_RESOURCE_DESCRIPTOR* pResDes = NULL; KDBG(DPFLTR_INFO_LEVEL, "[PnpPrepareHardware]"); pContext = GetDeviceContext(m_hDevice); // 配置设备 status = ConfigureUsbDevice(); if(!NT_SUCCESS(status)) return status; // 获取Pipe句柄 status = GetUsbPipes(); if(!NT_SUCCESS(status)) return status; // 初始电源策略, status = InitPowerManagement(); // 获取USB总线驱动接口。总线接口中包含总线驱动提供的回调函数和其他信息。 // 总线接口由系统共用GUID标识。 status = WdfFdoQueryForInterface( m_hDevice, &USB_BUS_INTERFACE_USBDI_GUID1, // 总线接口ID (PINTERFACE)&m_busInterface, // 保存在设备环境块中 sizeof(USB_BUS_INTERFACE_USBDI_V1), 1, NULL); // 调用接口函数,判断USB版本。 if(NT_SUCCESS(status) && m_busInterface.IsDeviceHighSpeed){ if(m_busInterface.IsDeviceHighSpeed(m_busInterface.BusContext)) KDBG(DPFLTR_INFO_LEVEL, "USB 2.0"); else KDBG(DPFLTR_INFO_LEVEL, "USB 1.1"); } // 对系统资源列表,我们不做实质性的操作,仅仅打印一些信息。 // 读者完全可以把下面的这些代码都注释掉。 ulNumRes = WdfCmResourceListGetCount(ResourceList); KDBG(DPFLTR_INFO_LEVEL, "ResourceListCount:%d\n", ulNumRes); // 下面我们饶有兴致地枚举这些系统资源,并打印出它们的相关名称信息。 for(ulIndex = 0; ulIndex < ulNumRes; ulIndex++) { pResDes = WdfCmResourceListGetDescriptor(ResourceList, ulIndex); if(!pResDes)continue; // 取得失败,则跳到下一个 switch (pResDes->Type) { case CmResourceTypeMemory: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypeMemory\n"); break; case CmResourceTypePort: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypePort\n"); break; case CmResourceTypeInterrupt: KDBG(DPFLTR_INFO_LEVEL, "System Resource:CmResourceTypeInterrupt\n"); break; default: KDBG(DPFLTR_INFO_LEVEL, "System Resource:Others %d\n", pResDes->Type); break; } } return STATUS_SUCCESS; }
// // 作用相当于WDM中的AddDevice函数。 // 他是PNP过程中首当其冲被调用的回调函数。主要任务是创建设备对象。 // 设备对象在系统中以软件形式,代表外部的某个物理硬件设备。 //NTSTATUS PnpAdd(IN WDFDRIVER Driver, IN PWDFDEVICE_INIT DeviceInit) NTSTATUS DrvClass::PnpAdd(IN PWDFDEVICE_INIT DeviceInit) { NTSTATUS status; WDFDEVICE device; int nInstance = 0; PDEVICE_CONTEXT pContext = NULL; UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; UNICODE_STRING RefString; WDFSTRING SymbolName; WDF_OBJECT_ATTRIBUTES attributes; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_DEVICE_PNP_CAPABILITIES pnpCapabilities; WCHAR wcsDeviceName[] = L"\\Device\\CY001-0"; // 设备名 WCHAR wcsDosDeviceName[] = L"\\DosDevices\\CY001-0";// 符号链接名 WCHAR wcsRefString[] = L"CY001-0"; // 符号链接名 int nLen = wcslen(wcsDeviceName); KDBG(DPFLTR_INFO_LEVEL, "[PnpAdd]"); RtlInitUnicodeString(&DeviceName, wcsDeviceName) ; RtlInitUnicodeString(&DosDeviceName, wcsDosDeviceName); RtlInitUnicodeString(&RefString, wcsRefString); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); InitPnpPwrEvents(&pnpPowerCallbacks); WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // 读、写请求的缓冲方式 // 默认为Buffered方式,另外两种方式是Direct和Neither。 WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // 设定设备环境块长度 // 宏内部会调用sizeof(DEVICE_CONTEXT)求结构体长度 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT); // 驱动支持最多8个实例,即当多个开发板连到PC上时,驱动对它们给予并行支持。 // 不同的设备对象,各以其名称的尾数(0-7)相别,并将此尾数称作设备ID。 // 下面的代码逻辑为当前设备对象寻找一个可用ID。 for(nInstance = 0; nInstance < MAX_INSTANCE_NUMBER; nInstance++) { // 修改设备ID wcsDeviceName[nLen-1] += nInstance; // 尝试命名;命名可能失败,失败的原因包括:名称无效、名称已存在等 WdfDeviceInitAssignName(DeviceInit, &DeviceName); // 创建WDF设备 // 如能成功,则命名亦成功。 status = WdfDeviceCreate(&DeviceInit, &attributes, &device); if(!NT_SUCCESS(status)) { if(status == STATUS_OBJECT_NAME_COLLISION)// 名字冲突 { KDBG(DPFLTR_ERROR_LEVEL, "Already exist: %wZ", &DeviceName); } else { KDBG(DPFLTR_ERROR_LEVEL, "WdfDeviceCreate failed with status 0x%08x!!!", status); return status; } }else { KdPrint(("Device name: %wZ", &DeviceName)); break; } } // 如失败,可能是连接的开发板数量太多; // 建议使用WinOBJ查看系统中的设备名称。 if (!NT_SUCCESS(status)) return status; m_hDevice = device;// 保存设备对象句柄 // 创建符号链接,应用程序根据符号链接查看并使用内核设备。 // 除了创建符号链接外,现在更好的方法是使用WdfDeviceCreateDeviceInterface创建设备接口。 // 设备接口能保证名字不会冲突,但不具有可读性,所以我们仍采用符号链接形式。 nLen = wcslen(wcsDosDeviceName); wcsDosDeviceName[nLen-1] += nInstance; status = WdfDeviceCreateSymbolicLink(device, &DosDeviceName); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "Failed to create symbol link: 0x%08X", status); return status; } // 初始化环境块 // GetDeviceContext是一个函数指针,由宏WDF_DECLARE_CONTEXT_TYPE_WITH_NAME定义。 // 参看pulibc.h中的说明。 pContext = GetDeviceContext(device); RtlZeroMemory(pContext, sizeof(DEVICE_CONTEXT)); pContext->par1 = this; // 通过this指针可以得到一切 // PNP属性。允许设备异常拔除,系统不会弹出错误框。 WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCapabilities); InitPnpCap(&pnpCapabilities); WdfDeviceSetPnpCapabilities(device, &pnpCapabilities); status = CreateWDFQueues(); if(!NT_SUCCESS(status)) return status; return status; }
// 并行处理 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); }
// 设备配置 // 按照WDF框架,设备配置选项默认为1;如存在多个配置选项,需要切换选择的话,会比较麻烦。 // 一种办法是:使用初始化宏:WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_INTERFACES_DESCRIPTORS // 使用这个宏,需要首先获取配置描述符,和相关接口描述符。 // 另一种办法是:使用WDM方法,先构建一个配置选择的URB,然后要么自己调用IRP发送到总线驱动, // 要么使用WDF方法调用WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_URB初始化宏。 // NTSTATUS DrvClass::ConfigureUsbDevice() { WDF_USB_DEVICE_SELECT_CONFIG_PARAMS usbConfig; WDF_USB_INTERFACE_SELECT_SETTING_PARAMS interfaceSelectSetting; KDBG(DPFLTR_INFO_LEVEL, "[ConfigureUsbDevice]"); // 创建Usb设备对象。 // USB设备对象是我们进行USB操作的起点。大部分的USB接口函数,都是针对它进行的。 // USB设备对象被创建后,由驱动自己维护;框架本身不处理它,也不保持它。 NTSTATUS status = WdfUsbTargetDeviceCreate(m_hDevice, WDF_NO_OBJECT_ATTRIBUTES, &m_hUsbDevice); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetDeviceCreate failed with status 0x%08x\n", status); return status; } // 接口配置 // WDF提供了多种接口配置的初始化宏,分别针对单一接口、多接口的USB设备, // 初始化宏还提供了在多个配置间进行切换的途径,正如上面所讲过的。 // 在选择默认配置的情况下,设备配置将无比简单,简单到令长期受折磨的内核程序员大跌眼镜; // 因为WDM上百行的代码逻辑,这里只要两三行就够了。 UCHAR numInterfaces = WdfUsbTargetDeviceGetNumInterfaces(m_hUsbDevice); if(1 == numInterfaces) { KDBG(DPFLTR_INFO_LEVEL, "There is one interface.", status); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_SINGLE_INTERFACE(&usbConfig); } else// 多接口 { KDBG(DPFLTR_INFO_LEVEL, "There are %d interfaces.", numInterfaces); PWDF_USB_INTERFACE_SETTING_PAIR settingPairs = (WDF_USB_INTERFACE_SETTING_PAIR*) ExAllocatePoolWithTag(PagedPool, sizeof(WDF_USB_INTERFACE_SETTING_PAIR) * numInterfaces, POOLTAG); if (settingPairs == NULL) return STATUS_INSUFFICIENT_RESOURCES; int nNum = InitSettingPairs(m_hUsbDevice, settingPairs, numInterfaces); WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_INIT_MULTIPLE_INTERFACES(&usbConfig, nNum, settingPairs); } status = WdfUsbTargetDeviceSelectConfig(m_hUsbDevice, WDF_NO_OBJECT_ATTRIBUTES, &usbConfig); if(!NT_SUCCESS(status)) { KDBG(DPFLTR_INFO_LEVEL, "WdfUsbTargetDeviceSelectConfig failed with status 0x%08x\n", status); return status; } // 保存接口 if(1 == numInterfaces) { m_hUsbInterface = usbConfig.Types.SingleInterface.ConfiguredUsbInterface; // 使用SINGLE_INTERFACE接口配置宏,接口的AltSetting值默认为0。 // 下面两行代码演示了如何手动修改某接口的AltSetting值(此处为1). WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_INIT_SETTING(&interfaceSelectSetting, 1); status = WdfUsbInterfaceSelectSetting(m_hUsbInterface, WDF_NO_OBJECT_ATTRIBUTES, &interfaceSelectSetting); } else { int i; m_hUsbInterface = usbConfig.Types.MultiInterface.Pairs[0].UsbInterface; for(i = 0; i < numInterfaces; i++) m_hMulInterfaces[i] = usbConfig.Types.MultiInterface.Pairs[i].UsbInterface; } return status; }
//下面两个Power回调,和WDM中的PnpSetPower类似。 NTSTATUS DrvClass::PwrD0Entry(IN WDF_POWER_DEVICE_STATE PreviousState) { KDBG(DPFLTR_INFO_LEVEL, "[PwrD0Entry] from %s", PowerName(PreviousState)); return STATUS_SUCCESS; }
// 离开D0状态 NTSTATUS DrvClass::PwrD0Exit(IN WDF_POWER_DEVICE_STATE TargetState) { KDBG(DPFLTR_INFO_LEVEL, "[PwrD0Exit] to %s", PowerName(TargetState)); return STATUS_SUCCESS; }
mach_msg_return_t mach_msg_rpc_from_kernel_body( mach_msg_header_t *msg, mach_msg_size_t send_size, mach_msg_size_t rcv_size, #if !IKM_SUPPORT_LEGACY __unused #endif boolean_t legacy) { thread_t self = current_thread(); ipc_port_t reply; ipc_kmsg_t kmsg; mach_port_seqno_t seqno; mach_msg_return_t mr; assert(msg->msgh_local_port == MACH_PORT_NULL); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_START); mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); if (mr != MACH_MSG_SUCCESS) { KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } reply = self->ith_rpc_reply; if (reply == IP_NULL) { reply = ipc_port_alloc_reply(); if ((reply == IP_NULL) || (self->ith_rpc_reply != IP_NULL)) panic("mach_msg_rpc_from_kernel"); self->ith_rpc_reply = reply; } /* insert send-once right for the reply port */ kmsg->ikm_header->msgh_local_port = reply; kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); #if IKM_SUPPORT_LEGACY if(legacy) mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); else mr = ipc_kmsg_copyin_from_kernel(kmsg); #else mr = ipc_kmsg_copyin_from_kernel(kmsg); #endif if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_free(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } /* * respect the thread's SEND_IMPORTANCE option to force importance * donation from the kernel-side of user threads * (11938665 & 23925818) */ mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT; if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) option &= ~MACH_SEND_NOIMPORTANCE; mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE); if (mr != MACH_MSG_SUCCESS) { ipc_kmsg_destroy(kmsg); KDBG(MACHDBG_CODE(DBG_MACH_IPC,MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr); return mr; } for (;;) { ipc_mqueue_t mqueue; assert(reply->ip_in_pset == 0); assert(ip_active(reply)); /* JMM - why this check? */ if (!self->active && !self->inspection) { ipc_port_dealloc_reply(reply); self->ith_rpc_reply = IP_NULL; return MACH_RCV_INTERRUPTED; } self->ith_continuation = (void (*)(mach_msg_return_t))0; mqueue = &reply->ip_messages; ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE, MACH_MSG_SIZE_MAX, MACH_MSG_TIMEOUT_NONE, THREAD_INTERRUPTIBLE); mr = self->ith_state; kmsg = self->ith_kmsg; seqno = self->ith_seqno; if (mr == MACH_MSG_SUCCESS) { break; } assert(mr == MACH_RCV_INTERRUPTED); assert(reply == self->ith_rpc_reply); if (self->ast & AST_APC) { ipc_port_dealloc_reply(reply); self->ith_rpc_reply = IP_NULL; return(mr); } } /* * Check to see how much of the message/trailer can be received. * We chose the maximum trailer that will fit, since we don't * have options telling us which trailer elements the caller needed. */ if (rcv_size >= kmsg->ikm_header->msgh_size) { mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) { /* Enough room for a maximum trailer */ trailer->msgh_trailer_size = MAX_TRAILER_SIZE; } else if (rcv_size < kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size) { /* no room for even the basic (default) trailer */ trailer->msgh_trailer_size = 0; } assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0); rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size; mr = MACH_MSG_SUCCESS; } else { mr = MACH_RCV_TOO_LARGE; } /* * We want to preserve rights and memory in reply! * We don't have to put them anywhere; just leave them * as they are. */ #if IKM_SUPPORT_LEGACY if(legacy) ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply); else ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); #else ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); #endif ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); return mr; }
// IRP_MJ_DEVICE_CONTROL处理函数 NTSTATUS DispatchDispatchIoControl( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { PDEVICE_EXTENSION pContext; PIO_STACK_LOCATION irpStack; NTSTATUS status; PFILE_CONTEXT fileContext; PVOID lpInBuf; PVOID lpOutBuf; ULONG ulInLen, ulOutLen; pContext = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(Irp); ASSERT(irpStack->FileObject != NULL); fileContext = irpStack->FileObject->FsContext; status = IoAcquireRemoveLock( &fileContext->FileRundownLock, Irp); if (!NT_SUCCESS(status)) { Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } lpInBuf = irpStack->Parameters.DeviceIoControl.Type3InputBuffer; lpOutBuf = Irp->UserBuffer; ulInLen = irpStack->Parameters.DeviceIoControl.InputBufferLength; ulOutLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; status = STATUS_INVALID_PARAMETER; switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_ASIO_START: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_ASIO_START"); status = AsioStart(DeviceObject); break; } case IOCTL_ASIO_STOP: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_ASIO_STOP"); status = AsioStop(DeviceObject); break; } case IOCTL_ASIO_BUFFERS: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_ASIO_BUFFERS"); if(ulOutLen == sizeof(BOOLEAN)) { BOOLEAN bSet = *(BOOLEAN*)lpOutBuf; if(bSet) { if(ulInLen == sizeof(BUFPOINTERSTRUCT)) status = AsioSetBuffers(DeviceObject, lpInBuf); } else { AsioReleaseBuffers(DeviceObject); status = STATUS_SUCCESS; } } break; } case IOCTL_ASIO_BUFFER_READY: { if(ulInLen == sizeof(ULONG)) status = AsioBufReady(DeviceObject, *(ULONG*)lpInBuf); break; } case IOCTL_ASIO_BUFFER_SIZE: { status = STATUS_SUCCESS; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_ASIO_BUFFER_SIZE %d %d (%p %p) %d %d", ulInLen, ulOutLen, lpInBuf, lpOutBuf, sizeof(BOOLEAN), sizeof(ULONG)); if(ulInLen == sizeof(BOOLEAN) && ulOutLen == sizeof(ULONG) && lpInBuf && lpOutBuf) { BOOLEAN bSet = *(BOOLEAN*)lpInBuf; if(bSet){ pContext->ulLatency = *(ULONG*)lpOutBuf; KDBG(DPFLTR_INFO_LEVEL, "%d", pContext->ulLatency); } else{ *(ULONG*)lpOutBuf = pContext->ulLatency; KDBG(DPFLTR_INFO_LEVEL, "%d", pContext->ulLatency); } } break; } case IOCTL_ASIO_EVENT: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_ASIO_EVENT"); if(ulOutLen == sizeof(BOOLEAN)) { BOOLEAN bSet = *(BOOLEAN*)lpOutBuf; if(bSet) { if(ulInLen == 2 * sizeof(HANDLE)) status = AsioSetEvent(DeviceObject, (HANDLE*)lpInBuf); } else { AsioReleaseEvent(DeviceObject); status = STATUS_SUCCESS; } } break; } default: status = STATUS_NOT_IMPLEMENTED; break; } Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); IoReleaseRemoveLock(&fileContext->FileRundownLock, Irp); return status; }
// 这里面的IO操作是经过序列化的。一个挨着一个,所以绝不会发生重入问题。 // VOID CY001Drv::DeviceIoControlSerial(IN WDFQUEUE Queue, IN WDFREQUEST Request, IN size_t OutputBufferLength, IN size_t InputBufferLength, IN ULONG IoControlCode) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulRetLen = 0; size_t size; void* pBufferInput = NULL; void* pBufferOutput = NULL; KDBG(DPFLTR_INFO_LEVEL, "[DeviceIoControlSerial]"); // 取得输入/输出缓冲区 if(InputBufferLength)WdfRequestRetrieveInputBuffer(Request, InputBufferLength, &pBufferInput, &size); if(OutputBufferLength)WdfRequestRetrieveOutputBuffer(Request, OutputBufferLength, &pBufferOutput, &size); switch(IoControlCode) { // 设置数码管 case IOCTL_USB_SET_DIGITRON: { CHAR ch = *(CHAR*)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_DIGITRON"); SetDigitron(ch); break; } // 读数码管 case IOCTL_USB_GET_DIGITRON: { UCHAR* pCh = (UCHAR*)pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_DIGITRON"); GetDigitron(pCh); ulRetLen = 1; break; } // 设置LED灯(共4盏) case IOCTL_USB_SET_LEDs: { CHAR ch = *(CHAR*)pBufferInput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_SET_LEDs"); SetLEDs(ch); break; } // 读取LED灯(共4盏)的当前状态 case IOCTL_USB_GET_LEDs: { UCHAR* pCh = (UCHAR*)pBufferOutput; KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_GET_LEDs"); GetLEDs(pCh); ulRetLen = 1; break; } // 控制命令。 // 分为:USB协议预定义命令、Vendor自定义命令、特殊类(class)命令。 case IOCTL_USB_CTL_REQUEST: { KDBG(DPFLTR_INFO_LEVEL, "IOCTL_USB_CTL_REQUEST"); ntStatus = UsbControlRequest(Request); if(NT_SUCCESS(ntStatus))return; break; } // 开启中断读 case IOCTL_START_INT_READ: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_START_INT_READ"); ntStatus = InterruptReadStart(); break; // 控制程序发送读请求。它们是被阻塞的,放至Queue中排队,所以不要即可完成他们。 case IOCTL_INT_READ_KEYs: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_INT_READ_KEYs"); ntStatus = WdfRequestForwardToIoQueue(Request, m_hInterruptManualQueue); if(NT_SUCCESS(ntStatus)) return;// 成功,直接返回;异步完成。 break; // 终止中断读 case IOCTL_STOP_INT_READ: KDBG(DPFLTR_INFO_LEVEL, "IOCTL_STOP_INT_READ"); InterruptReadStop(); ntStatus = STATUS_SUCCESS; break; default: // 不应该到这里。 // 对于不能识别的IO控制命令,这里做错误处理。 KDBG(DPFLTR_INFO_LEVEL, "Unknown Request: %08x(%d)!!!", IoControlCode, IoControlCode); ntStatus = STATUS_INVALID_PARAMETER; break; } WdfRequestCompleteWithInformation(Request, ntStatus, ulRetLen); return; }