IoAttachDeviceToDeviceStack(myDevice, tmpDevice);
DeviceExtension = (PMY_DEVICE_EXTENSION)myDevice->DeviceExtension;
DeviceExtension->AttachedTo = tmpDevice;
/* Setup my device */
myDevice->StackSize = tmpDevice->StackSize + 1;
myDevice->Flags |= (tmpDevice->Flags & (DO_BUFFERED_IO)); // 在 IoCreateDevice 时 Flags 会被赋于一些标志,这里应该保留这些标志,(如 DO_DEVICE_HAS_NAME 等,牵涉到引用计数)
tmpDevice = tmpDevice->NextDevice;
}
ObDereferenceObject(KbdDriver);
return STATUS_SUCCESS;
}
NTSTATUS KMRead(DEVICE_OBJECT *DeviceObject, IRP *Irp)
{
PMY_DEVICE_EXTENSION myDeviceExtension;
//KdPrint(("KMRead.\n"));
myDeviceExtension = (PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
IoCopyCurrentIrpStackLocationToNext(Irp);
/* 只有驱动可以保证在完成例程被调用之前不被卸载的情况下,可以使用 IoSetCompletionRoutine,
如果你不能保证,那么就需要用 IoSetCompletionRoutineEx,让内核来使驱动不被卸载*/
/*IoSetCompletionRoutine(Irp,
KMReadCompletion,
NULL,
TRUE,
TRUE,
TRUE);*/
IoSetCompletionRoutineEx(DeviceObject,
Irp,
KMReadCompletion,
NULL,
TRUE,
TRUE,
TRUE);
myDeviceExtension->IslCompletion = IoGetNextIrpStackLocation(Irp);
return IoCallDriver(((PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->AttachedTo, Irp);
}
NTSTATUS KMReadCompletion(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
PMY_DEVICE_EXTENSION myDeviceExtension;
PUCHAR buff;
int len;
//KdPrint(("KMReadCompletion: Key--0x%p\n", *(PULONG)Irp->AssociatedIrp.SystemBuffer));
/* 该次 IRP 的完成例程已执行,栈会在该函数执行完时自动清空,所以不应该在引用该栈 */
myDeviceExtension = (PMY_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
myDeviceExtension->IslCompletion = NULL;
if (NT_SUCCESS(Irp->IoStatus.Status)) {
// 由于设备标志为 DO_BUFFERED_IO, 内核分配了该缓冲区
buff = Irp->AssociatedIrp.SystemBuffer;
// 返回值一般都保存在 Information 中,即长度
len = Irp->IoStatus.Information;
if (buff[4] == 0) {
/* 键盘被按下 */
switch (buff[2]) {
case 0x3A:
g_caps = (g_caps == 1)?0:1;
break;
case 0x2A:
case 0x36:
g_shift = 1;
break;
case 0x45:
g_num = (g_num == 1)?0:1;
break;
default:
KMPrintKey(buff[2]);
break;
}
} else if (buff[4] == 1) {
/* 键盘被释放 */
switch (buff[2]) {
case 0x2A:
case 0x36:
g_shift = 0;
break;
default: break;
}
}
}
if (Irp->PendingReturned) {
IoMarkIrpPending(Irp);
}
return Irp->IoStatus.Status;
}