Идея - дистанционно управлять ПК подобно тому как мы управляем TV. В качестве ПДУ - ИК пульт от бытовой техники. В качестве приёмника - устройство USB-IrDA. Программа, которая будет управлять ПО компьютера - SlyControl (http://slydiman.narod.ru/scr/slycontrol2.htm). Вообщем то я уже закончил этот проект. Писал на скоряк так что кол-во багов может быть много, но вообщем вполне стабильно работает. Тестировал с использованием ИК-Приёмника: Sigmatel USB-IrDA и простой USB-Мыши. В последнем варианте при отсоединении мыши от компа возникает синий экран. ------------------------------ Помогите отыскать и исправить любые баги, приводящие (могущие привести) к синему эрану или хоть как то затормозить работу компьютера. ------------------------------- Стек драйверов для ИК-устройств, подключенных к usb порту будет примерно таким: =IrRemote.sys= < вершина стека > =Драйвер ИК-устройства USB-IrDA= =USBD.sys= < дно стека > Драйвер USB-IrDA постоянно опрашивает своё устройство на предмет, например, приёма данных. Для этого он посылает IRP-пакет драйверу USB шины - USBD. Драйвер USBD возвращает принятый IRP-пакет с принятыми данными, которые пришли на ИК-устройство (либо пустой пакет, т.е. данные не пришли). Идея в нем такая: 1) Установить свой фильтр-драйвер "IrRemote.sys" в приведенный выше стек для перехвата принятых данных. Таким образом он приобритёт следующий вид: =IrRemote.sys= < вершина стека > =Драйвер ИК-устройства USB-IrDA= =IrRemote.sys= <Драйвер для перехвата принятых данных> =USBD.sys= < дно стека > 2) С помощью плагина к программе SlyControl - "UsbIrRemote.dll" принимать данные от драйвера IrRemote.sys
Драйвер IrRemote.sys Файл init.cpp Код (Text): #include "driver.h" #include "usbioctl.h" #include "usbdi.h" #include "usbdlib.h" NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo); VOID DriverUnload(IN PDRIVER_OBJECT fido); NTSTATUS DispatchAny(IN PDEVICE_OBJECT fido, IN PIRP Irp); NTSTATUS DispatchPower(IN PDEVICE_OBJECT fido, IN PIRP Irp); NTSTATUS DispatchPnp(IN PDEVICE_OBJECT fido, IN PIRP Irp); NTSTATUS DispatchWmi(IN PDEVICE_OBJECT fido, IN PIRP Irp); NTSTATUS DispatchInternalIOCTL(IN PDEVICE_OBJECT fido, IN PIRP Irp); #pragma LOCKEDDATA UCHAR CODE[32]; UCHAR ToUser[32]; ULONG nSendBytes; ULONG nBytesRead; ULONG CountNullBytes; KEVENT Done; //------------------------------------------------------------------------------- #pragma INITCODE extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { nBytesRead=0; nSendBytes=0; CountNullBytes=0; // Операционка должна поддерживать модель драйвера WDM 1.0 (Win98 DDK) и выше if (!IoIsWdmVersionAvailable(1, 0)) { /*DEBUG*/ KdPrint(("UsbIrDA_RC - Expected version of WDM (%d.%2.2d) not available\n", 1, 0)); return STATUS_UNSUCCESSFUL; } DriverObject->DriverUnload = DriverUnload; //Для выгрузки драйвера DriverObject->DriverExtension->AddDevice = AddDevice; //Для использования WDM модели for (int i = 0; i < arraysize(DriverObject->MajorFunction); ++i) DriverObject->MajorFunction[i] = DispatchAny; DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower; //Диспетчер энергобережения DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp; //Диспетчер PnP DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi; //Диспетчер WMI DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = DispatchInternalIOCTL; return STATUS_SUCCESS; } //------------------------------------------------------------------------------- #pragma PAGEDCODE // Процедура выгрузки драйвера VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) { PAGED_CODE(); /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DriverUnload] DriverObject %8.8lX\n", DriverObject)); } //------------------------------------------------------------------------------- NTSTATUS AddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT pdo) { PAGED_CODE(); NTSTATUS status; UNICODE_STRING LinkName, devName; // Создание буферов для имен RtlInitUnicodeString(&LinkName, L"\\DosDevices\\IR_REMOTE"); RtlInitUnicodeString(&devName, L"\\Device\\devIR_REMOTE"); // Создаем объект UsbIrDA_RC чтобы перехватывать irp-запросы. PDEVICE_OBJECT fido; // Объект фильтра для устройства PDEVICE_OBJECT edo; // Именнованный объект устройства status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, 0, FALSE, &fido); if (!NT_SUCCESS(status)) { // Объект устройства не был создан KdPrint(("UsbIrDA_RC - FIDO IoCreateDevice failed - %X\n", status)); return status; } PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; __try { MyIoInitializeRemoveLock(&pdx->RemoveLock, 0, 0, 255); pdx->DeviceObject = fido; pdx->Pdo = pdo; pdx->flag=FIDO_EXTENSION; // Объект устройства, подключенный к стеку // Вставляем фильтр драйвер в стек нижележайшего драйвера PDEVICE_OBJECT fdo = IoAttachDeviceToDeviceStack(fido, pdo); pdx->LowerDeviceObject = fdo; fido->Flags |= fdo->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO | DO_POWER_PAGABLE | DO_POWER_INRUSH); fido->DeviceType = fdo->DeviceType; fido->Flags &= ~DO_DEVICE_INITIALIZING; } __finally { if (!NT_SUCCESS(status)) // В случае сбоя { IoDeleteDevice(fido); // Удаляем фильтр return status; } } // Создаем именнованный объект устройства фильтр-драйвера // для связи с пользовательским приложением status = IoCreateDevice(DriverObject, sizeof(EXTRA_DEVICE_EXTENSION), &devName, FILE_DEVICE_UNKNOWN, 0, FALSE, &edo); if (!NT_SUCCESS(status)) { // Объект устройства не был создан /*DEBUG*/ KdPrint(("UsbIrDA_RC - EDO IoCreateDevice failed - %X\n", status)); return status; } PEXTRA_DEVICE_EXTENSION edx = (PEXTRA_DEVICE_EXTENSION) edo->DeviceExtension; edx->flag = EDO_EXTENSION; // Объект устройства для связи с пользовательскм приложением edx->pdx = pdx; pdx->edx = edx; edx->DeviceObject = edo; edo->Flags |= DO_BUFFERED_IO; edo->Flags &= ~DO_DEVICE_INITIALIZING; // Создание символьного имени драйвера status = IoCreateSymbolicLink (&LinkName, &devName); if (!NT_SUCCESS(status))return status; KeInitializeEvent(&Done,SynchronizationEvent,FALSE); /*DEBUG*/ KdPrint(("UsbIrDA_RC - I s L O A D E D")); return status; } //------------------------------------------------------------------------------- #pragma LOCKEDCODE NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info) { Irp->IoStatus.Status = status; Irp->IoStatus.Information = info; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } //------------------------------------------------------------------------------- #pragma LOCKEDCODE NTSTATUS DispatchAny(IN PDEVICE_OBJECT fido, IN PIRP Irp) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); NTSTATUS status = STATUS_SUCCESS; if(pdx->flag==FIDO_EXTENSION) { status = MyIoAcquireRemoveLock(&pdx->RemoveLock, Irp); if (!NT_SUCCESS(status)) return CompleteRequest(Irp, status, 0); IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pdx->LowerDeviceObject, Irp); MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); } else { ULONG info = 0; PCHAR ToUserBuffer; NTSTATUS stRead; LARGE_INTEGER Delay = {10000000}; // 1 секунда switch(stack->MajorFunction) { case IRP_MJ_CREATE: case IRP_MJ_CLOSE: break; case IRP_MJ_READ: /*DEBUG*/ KdPrint(("UsbIrDA_RC - [IRP_MJ_READ] WAITING...")); stRead = KeWaitForSingleObject(&Done,Executive, KernelMode, FALSE, &Delay); //Ждём 1 секунду if (!NT_SUCCESS(stRead)) {// KdPrint(("UsbIrDA_RC - IRP_MJ_READ Time is exceeded...")); info = 0; // Хотя это не обязательно break; } /*DEBUG*/ KdPrint(("UsbIrDA_RC - [IRP_MJ_READ] DONE...")); ToUserBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer; if(stack->Parameters.Read.Length<nSendBytes) { status = STATUS_BUFFER_TOO_SMALL; break; } /*DEBUG*/ KdPrint(("UsbIrDA_RC - nSendBytes=%i...",nSendBytes)); for(ULONG i=0; i<nSendBytes; i++)ToUserBuffer[i] = ToUser[i]; info = nSendBytes; nSendBytes=0; break; default: status = STATUS_INVALID_DEVICE_REQUEST; } CompleteRequest(Irp, status, info); } return status; } //------------------------------------------------------------------------------- NTSTATUS InternalIOCTLCompletion(IN PDEVICE_OBJECT fido, IN PIRP Irp, IN PVOID Context) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); if(Irp->PendingReturned)IoMarkIrpPending( Irp ); ULONG uSequenceNumber = (ULONG)Context; ULONG dwControlCode = stack->Parameters.DeviceIoControl.IoControlCode; if(IOCTL_INTERNAL_USB_SUBMIT_URB == dwControlCode) { PURB pUrb = (PURB)stack->Parameters.Others.Argument1; if(pUrb==0) return STATUS_SUCCESS; if(pUrb->UrbHeader.Function==URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) { struct _URB_BULK_OR_INTERRUPT_TRANSFER *pBulkOrInterruptTransfer = (struct _URB_BULK_OR_INTERRUPT_TRANSFER *) pUrb; if(pBulkOrInterruptTransfer->TransferBufferLength==0) { CountNullBytes++; if(CountNullBytes>=5 && nBytesRead>0) { KeSetEvent(&Done, IO_NO_INCREMENT, FALSE); CountNullBytes=0; for(ULONG n=0; n<nBytesRead; n++) { if(nSendBytes==0)ToUser[n]=CODE[n]; /*DEBUG*/ KdPrint(("UsbIrDA_RC - %02x", CODE[n])); } /*DEBUG*/ KdPrint(("UsbIrDA_RC - [INCOMMING PACKET] DONE...")); nSendBytes = nBytesRead; nBytesRead=0; } return STATUS_SUCCESS; } BOOLEAN bReadFromDevice = (BOOLEAN)(pBulkOrInterruptTransfer->TransferFlags & USBD_TRANSFER_DIRECTION_IN); if(bReadFromDevice && pBulkOrInterruptTransfer->TransferBufferMDL) { PUCHAR pMDLBuf = (PUCHAR)MmGetSystemAddressForMdl(pBulkOrInterruptTransfer->TransferBufferMDL); if(pMDLBuf) { for(ULONG b=0; b<pBulkOrInterruptTransfer->TransferBufferLength; b++) { // ОГРАНИЧЕНИЕ: длина пакета до 32 байт if(b<32 && nBytesRead<32)CODE[nBytesRead++]=pMDLBuf[b]; } /*DEBUG*/ KdPrint(("UsbIrDA_RC - [INCOMMING PACKET] SIZE = %i", pBulkOrInterruptTransfer->TransferBufferLength)); /*DEBUG*/ KdPrint(("UsbIrDA_RC - [INCOMMING PACKET] nBytesRead = %i", nBytesRead)); } } } } return STATUS_SUCCESS; } //------------------------------------------------------------------------------- NTSTATUS DispatchInternalIOCTL(IN PDEVICE_OBJECT fido, IN PIRP Irp) { PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG dwControlCode = stack->Parameters.DeviceIoControl.IoControlCode; NTSTATUS status; status = MyIoAcquireRemoveLock(&pdx->RemoveLock, Irp); if(!NT_SUCCESS(status))return CompleteRequest(Irp, status, 0); if(IOCTL_INTERNAL_USB_SUBMIT_URB == dwControlCode) { ULONG uSequenceNumber = InterlockedIncrement((PLONG)&pdx->uSequenceNumber); IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, InternalIOCTLCompletion, (PVOID)uSequenceNumber, TRUE, TRUE, TRUE); status = IoCallDriver(pdx->LowerDeviceObject, Irp); MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); } else { IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pdx->LowerDeviceObject, Irp); MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); } return status; } //------------------------------------------------------------------------------- NTSTATUS DispatchPower(IN PDEVICE_OBJECT fido, IN PIRP Irp) { /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchPower] Enter...")); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; PoStartNextPowerIrp(Irp); // must be done while we own the IRP NTSTATUS status; status = MyIoAcquireRemoveLock(&pdx->RemoveLock, Irp); if(!NT_SUCCESS(status))return CompleteRequest(Irp, status, 0); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(pdx->LowerDeviceObject, Irp); MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchPower] Quit...")); return status; } //------------------------------------------------------------------------------- NTSTATUS DispatchPnp(IN PDEVICE_OBJECT fido, IN PIRP Irp) { /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchPnp] Enter...")); PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp); ULONG fcn = stack->MinorFunction; NTSTATUS status; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; status = MyIoAcquireRemoveLock(&pdx->RemoveLock, Irp); if(!NT_SUCCESS(status))return CompleteRequest(Irp, status, 0); IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pdx->LowerDeviceObject, Irp); if(fcn == IRP_MN_REMOVE_DEVICE) { /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchPnp] IRP_MN_REMOVE_DEVICE...")); MyIoReleaseRemoveLockAndWait(&pdx->RemoveLock, Irp); RemoveDevice(fido); } else MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchPnp] Quit...")); return status; } //------------------------------------------------------------------------------- NTSTATUS DispatchWmi(IN PDEVICE_OBJECT fido, IN PIRP Irp) { // DispatchWmi /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchWmi] Enter...")); NTSTATUS status; PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fido->DeviceExtension; status = MyIoAcquireRemoveLock(&pdx->RemoveLock, Irp); if (!NT_SUCCESS(status)) { /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchWmi] Error(%i)...", status)); return CompleteRequest(Irp, status, 0); } IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(pdx->LowerDeviceObject, Irp); MyIoReleaseRemoveLock(&pdx->RemoveLock, Irp); /*DEBUG*/ KdPrint(("UsbIrDA_RC - [DispatchWmi] Quit...")); return status; } //------------------------------------------------------------------------------- #pragma PAGEDCODE VOID RemoveDevice(IN PDEVICE_OBJECT fido) { PAGED_CODE(); UNICODE_STRING LinkName; // Создание буферов для имен RtlInitUnicodeString(&LinkName, L"\\DosDevices\\IR_REMOTE"); IoDeleteSymbolicLink(&LinkName); PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fido->DeviceExtension; if(pdx->LowerDeviceObject)IoDetachDevice(pdx->LowerDeviceObject); IoDeleteDevice(pdx->edx->DeviceObject); IoDeleteDevice(fido); /*DEBUG*/ KdPrint(("UsbIrDA_RC - I S U N L O A D E D")); } //------------------------------------------------------------------------------- #pragma LOCKEDCODE extern "C" void __declspec(naked) __cdecl _chkesp() { _asm je okay ASSERT(!"Stack pointer mismatch!"); okay: _asm ret } Файл Driver.h Код (Text): #ifndef _DRIVER_H_04802_BASHBD_1UIWQ1_8239_1NJKDH832_901_ #define _DRIVER_H_04802_BASHBD_1UIWQ1_8239_1NJKDH832_901_ #ifdef __cplusplus extern "C" { #endif #include "wdm.h" #ifdef __cplusplus } #endif /////////////////////////////////////////////////////////////////////////////// #define PAGEDCODE code_seg("page") #define LOCKEDCODE code_seg() #define INITCODE code_seg("init") //------------------------------------------------------------------------------- #define PAGEDDATA data_seg("page") #define LOCKEDDATA data_seg() #define INITDATA data_seg("init") //------------------------------------------------------------------------------- #define arraysize(p) (sizeof(p)/sizeof((p)[0])) //------------------------------------------------------------------------------- #if DBG && defined(_X86_) #undef ASSERT #define ASSERT(e) if(!(e)){DbgPrint("Assertion failure in "\ __FILE__ ", line %d: " #e "\n", __LINE__);\ _asm int 1\ } #endif /////////////////////////////////////////////////////////////////////////////// typedef struct _MY_IO_REMOVE_LOCK { LONG usage; // reference count BOOLEAN removing; // true if removal is pending KEVENT evRemove; // event to wait on } MY_IO_REMOVE_LOCK, *PMY_IO_REMOVE_LOCK; VOID MyIoInitializeRemoveLock(PMY_IO_REMOVE_LOCK lock, ULONG tag, ULONG minutes, ULONG maxcount); NTSTATUS MyIoAcquireRemoveLock(PMY_IO_REMOVE_LOCK lock, PVOID tag); VOID MyIoReleaseRemoveLock(PMY_IO_REMOVE_LOCK lock, PVOID tag); VOID MyIoReleaseRemoveLockAndWait(PMY_IO_REMOVE_LOCK lock, PVOID tag); /////////////////////////////////////////////////////////////////////////////// // Device extension structure typedef struct _COMMON_DEVICE_EXTENSION{ ULONG flag; }COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION; typedef struct _DEVICE_EXTENSION: public _COMMON_DEVICE_EXTENSION { struct _EXTRA_DEVICE_EXTENSION* edx; PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT LowerDeviceObject; // next lower driver in same stack PDEVICE_OBJECT Pdo; // the PDO MY_IO_REMOVE_LOCK RemoveLock; ULONG uSequenceNumber; }DEVICE_EXTENSION, *PDEVICE_EXTENSION; typedef struct _EXTRA_DEVICE_EXTENSION: public _COMMON_DEVICE_EXTENSION{ PDEVICE_OBJECT DeviceObject; PDEVICE_EXTENSION pdx; }EXTRA_DEVICE_EXTENSION, *PEXTRA_DEVICE_EXTENSION; #define FIDO_EXTENSION 0 #define EDO_EXTENSION 1 /////////////////////////////////////////////////////////////////////////////// // Global functions VOID RemoveDevice(IN PDEVICE_OBJECT fdo); NTSTATUS CompleteRequest(IN PIRP Irp, IN NTSTATUS status, IN ULONG_PTR info); extern UCHAR CODE[32]; extern ULONG nBytesRead; extern ULONG CountNullBytes; extern KEVENT Done; #endif // DRIVER_H Файл RemoveLoc.cpp Код (Text): #include "Driver.h" //------------------------------------------------------------------------------- #pragma PAGEDCODE VOID MyIoInitializeRemoveLock(PMY_IO_REMOVE_LOCK lock, ULONG tag, ULONG minutes, ULONG maxcount) { PAGED_CODE(); KeInitializeEvent(&lock->evRemove, NotificationEvent, FALSE); lock->usage = 1; lock->removing = FALSE; } //------------------------------------------------------------------------------- #pragma LOCKEDCODE NTSTATUS MyIoAcquireRemoveLock(PMY_IO_REMOVE_LOCK lock, PVOID tag) { LONG usage = InterlockedIncrement(&lock->usage); if (lock->removing) { // removal in progress if (InterlockedDecrement(&lock->usage) == 0) KeSetEvent(&lock->evRemove, 0, FALSE); return STATUS_DELETE_PENDING; } // removal in progress return STATUS_SUCCESS; } //------------------------------------------------------------------------------- VOID MyIoReleaseRemoveLock(PMY_IO_REMOVE_LOCK lock, PVOID tag) { if (InterlockedDecrement(&lock->usage) == 0) KeSetEvent(&lock->evRemove, 0, FALSE); } //------------------------------------------------------------------------------- #pragma PAGEDCODE VOID MyIoReleaseRemoveLockAndWait(PMY_IO_REMOVE_LOCK lock, PVOID tag) { PAGED_CODE(); lock->removing = TRUE; MyIoReleaseRemoveLock(lock, tag); MyIoReleaseRemoveLock(lock, NULL); KeWaitForSingleObject(&lock->evRemove, Executive, KernelMode, FALSE, NULL); } //------------------------------------------------------------------------------- Файл Sources Код (Text): TARGETNAME=IrRemote TARGETPATH=obj TARGETTYPE=DRIVER SOURCES= init.cpp \ RemoveLock.cpp