控制一个芯片首先要知道它的地址,大多数PC上的8259键盘控制器在地址0x60和0x64上是可寻址的,这些位置有时称为端口(port),因为它们提供了进入硬件芯片的入口。
在使用DDK时,有多个宏可以读写这些端口:
READ_PORT_UCHAR ();
WRITE_PORT_UCHAR();
另外也可以使用汇编指令.
示例代码如下所示,感兴趣的话可以自己试试:
#include "ntddk.h" #include "stdio.h" // use for _snprintf //#include //#define RTL_STRING_CONST(x) \ // (sizeof(L##x)-2, sizeof(L##x), L##x) PKTIMER gTimer; PKDPC gDPCP; UCHAR g_key_bits = 0; // command bytes #define SET_LEDS 0xED #define KEY_RESET 0xFF
// responses from keyboard #define KEY_ACK 0xFA // ack #define KEY_AGAIN 0xFE // send again
// 8042 ports // When you read from port 60, this is called STATUS_BYTE. // When you write to port 60, this is called COMMAND_BYTE/ // Read and write on port 64 is called DATA_BYTE. PUCHAR KEYBOARD_PORT_60 = ( PUCHAR )0x60; PUCHAR KEYBOARD_PORT_64 = ( PUCHAR )0x64;
// status register bits #define IBUFFER_FULL 0x02 #define OBUFFER_FULL 0x01
// flags for keyboard LEDS #define SCROLL_LOCK_BIT (0x01 << 0) #define NUMLOCK_BIT (0x01 << 1) #define CAPS_LOCK_BIT (0x01 << 2)
ULONG WaitForKeyboard() { char _t[255]; int i = 100; // number of times to loop UCHAR mychar; DbgPrint("waiting for keyboard to become accessible\n"); do { mychar = READ_PORT_UCHAR ( KEYBOARD_PORT_64 ); KeStallExecutionProcessor(50); _snprintf(_t, 253, "WatiForKeyboard::read byte %02X from port 0x64\n", mychar); DbgPrint(_t); if(!(mychar & IBUFFER_FULL)) break; // if the flag is clear, we go ahead } while (i--); if(i) return TRUE; return FALSE; }
// Call WaitForKeyboard before calling this function void DrainOutputBuffer() { char _t[255]; int i = 100; // number of times to loop UCHAR c; DbgPrint("draining keyboard buffer\n"); do { c = READ_PORT_UCHAR(KEYBOARD_PORT_64); KeStallExecutionProcessor(666); _snprintf(_t, 253, "DrainOutputBuffer::read byte %02X from port 0x64\n", c); DbgPrint(_t); if(!(c & OBUFFER_FULL)) break; // if the flag is clear, we go ahead.
// Gobble up the byte in the output buffer. c = READ_PORT_UCHAR(KEYBOARD_PORT_60); _snprintf(_t, 253, "DrainOutputBuffer::read byte %02X from port 0x60\n", c); DbgPrint(_t); } while (i--); }
// Write a byte to the data port at 0x60 ULONG SendKeyboardCommand ( IN UCHAR theCommand) { char _t[255]; if ( TRUE == WaitForKeyboard ( ) ) { DrainOutputBuffer(); _snprintf(_t, 253, "SendKeyboardCommand::sending byte %02X to port 0x60\n", theCommand); DbgPrint(_t); WRITE_PORT_UCHAR ( KEYBOARD_PORT_60, theCommand ); DbgPrint("SendKeyboardCommand::sent\n"); } else { DbgPrint("SendKeyboardCommand::timeout waiting for keyboard\n"); return FALSE; }
return TRUE; }
void SetLEDS ( UCHAR theLEDS) { // setup for setting LEDS if ( FALSE == SendKeyboardCommand ( 0xED ) ) { DbgPrint("SetLEDS::error sending keyboard command\n"); } // send the flags for the LEDS if ( FALSE == SendKeyboardCommand ( theLEDS ) ) { DbgPrint("SetLEDS::error sending keyboard command\n"); } }
// called perodically VOID timerDPC ( IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID sys1, IN PVOID sys2 ) { // WRITE_PORT_UCHAR ( KEYBOARD_PORT_64, 0xFE ); SetLEDS ( g_key_bits++ ); if ( g_key_bits > 0x07 ) g_key_bits = 0; }
// End keyboar code
void Example1Unload(IN PDRIVER_OBJECT pDrvobj) { UNICODE_STRING usDosDevName; DbgPrint("Example1: Driver is being unload.\n");
RtlInitUnicodeString(&usDosDevName, L"\\DosDevices\\ExampleLINK2"); IoDeleteSymbolicLink(&usDosDevName); IoDeleteDevice(pDrvobj->DeviceObject);
// Keyboard unload code KeCancelTimer ( gTimer ); ExFreePool ( gTimer ); ExFreePool ( gDPCP ); // Keyboard end }
NTSTATUS ExampleIrp(IN PDEVICE_OBJECT device, IN PIRP pIrp) { // pDev; // pIrp; DbgPrint("An driver routine is called.\n"); return STATUS_SUCCESS; }
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDrvObj, IN PUNICODE_STRING pUsRegPath) { NTSTATUS status = STATUS_UNSUCCESSFUL; UNICODE_STRING usDevName; UNICODE_STRING usDosDevName; PDEVICE_OBJECT pDevObj = NULL; unsigned int nIndex; LARGE_INTEGER timeout; DbgPrint("Example: Driver entry is called. \n");
// Keyboard code start // WRITE_PORT_UCHAR ( 0x60, 0xED ); // WRITE_PORT_UCHAR ( 0x60, 0x0000111b);
timeout.QuadPart = -10;
// These objects must be non-paged gTimer = ExAllocatePool ( NonPagedPool, sizeof ( KTIMER ) ); gDPCP = ExAllocatePool ( NonPagedPool, sizeof ( KDPC ) );
KeInitializeTimer ( gTimer ); KeInitializeDpc ( gDPCP, timerDPC, NULL ); if ( TRUE == KeSetTimerEx ( gTimer, timeout, 1000, gDPCP ) ) { DbgPrint("Timer was already queued .. "); }
// usDevName = RTL_CONSTANT_STRING(L"\\Device\\Example3"); // usDosDevName = RTL_CONSTANT_STRING(L"\\DosDevice\\Example3"); RtlInitUnicodeString(&usDevName, L"\\Device\\Example3"); RtlInitUnicodeString(&usDosDevName, L"\\DosDevices\\ExampleLINK2");
// Create Device status = IoCreateDevice(pDrvObj, 0, &usDevName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDevObj);
if(NT_SUCCESS(status)) { for(nIndex = 0; nIndex < IRP_MJ_MAXIMUM_FUNCTION; ++nIndex) pDrvObj->MajorFunction[nIndex] = ExampleIrp;
pDrvObj->DriverUnload = Example1Unload;
// 把ã?创ä¡ä建¡§的Ì?设¦¨¨备À?保À¡ê存ä?起e来¤¡ä,ê?否¤?则¨°以°?后¨®不?能¨¹引°y用®? pDrvObj->DeviceObject = pDevObj; status = IoCreateSymbolicLink(&usDosDevName, &usDevName); if(!NT_SUCCESS(status)) { DbgPrint("IoCreateSymbolicLink failed.\n"); IoDeleteDevice(pDevObj);
} else { DbgPrint("Successed!.\n"); }
} else { DbgPrint("IoCreateDevice failed\n"); }
return status;
}
|