Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

pnp.c

Go to the documentation of this file.
00001 /****************************** Module Header ******************************\ 00002 * Module Name: pnp.c 00003 * 00004 * Copyright (c) 1985 - 1999, Microsoft Corporation 00005 * 00006 * This module tracks device interface changes so we can keep track of know how many mice and 00007 * keyboards and mouse 00008 * and mouse reports. 00009 * 00010 * History: 00011 * 97-10-16 IanJa Interpreted from a dream that Ken Ray had. 00012 \***************************************************************************/ 00013 00014 #include "precomp.h" 00015 #pragma hdrstop 00016 00017 DEVICE_TEMPLATE aDeviceTemplate[DEVICE_TYPE_MAX + 1] = { 00018 // DEVICE_TYPE_MOUSE 00019 { 00020 sizeof(GENERIC_DEVICE_INFO)+sizeof(MOUSE_DEVICE_INFO), // cbDeviceInfo 00021 &GUID_CLASS_MOUSE, // pClassGUID 00022 PMAP_MOUCLASS_PARAMS, // uiRegistrySection 00023 L"mouclass", // pwszClassName 00024 DD_MOUSE_DEVICE_NAME_U L"0", // pwszDefDevName 00025 DD_MOUSE_DEVICE_NAME_U L"Legacy0", // pwszLegacyDevName 00026 IOCTL_MOUSE_QUERY_ATTRIBUTES, // IOCTL_Attr 00027 FIELD_OFFSET(DEVICEINFO, mouse.Attr), // offAttr 00028 sizeof((PDEVICEINFO)NULL)->mouse.Attr, // cbAttr 00029 FIELD_OFFSET(DEVICEINFO, mouse.Data), // offData 00030 sizeof((PDEVICEINFO)NULL)->mouse.Data, // cbData 00031 ProcessMouseInput, // Reader routine 00032 NULL // pkeHidChange 00033 }, 00034 // DEVICE_TYPE_KEYBOARD 00035 { 00036 sizeof(GENERIC_DEVICE_INFO)+sizeof(KEYBOARD_DEVICE_INFO), // cbDeviceInfo 00037 &GUID_CLASS_KEYBOARD, // pClassGUID 00038 PMAP_KBDCLASS_PARAMS, // uiRegistrySection 00039 L"kbdclass", // pwszClassName 00040 DD_KEYBOARD_DEVICE_NAME_U L"0", // pwszDefDevName 00041 DD_KEYBOARD_DEVICE_NAME_U L"Legacy0", // pwszLegacyDevName 00042 IOCTL_KEYBOARD_QUERY_ATTRIBUTES, // IOCTL_Attr 00043 FIELD_OFFSET(DEVICEINFO, keyboard.Attr), // offAttr 00044 sizeof((PDEVICEINFO)NULL)->keyboard.Attr, // cbAttr 00045 FIELD_OFFSET(DEVICEINFO, keyboard.Data), // offData 00046 sizeof((PDEVICEINFO)NULL)->keyboard.Data, // cbData 00047 ProcessKeyboardInput, // Reader routine 00048 NULL // pkeHidChange 00049 }, 00050 // Add new input device type template here 00051 }; 00052 00053 #ifdef DIAGNOSE_IO 00054 NTSTATUS gKbdIoctlLEDSStatus = -1; // last IOCTL_KEYBOARD_QUERY_INDICATORS 00055 #endif 00056 00057 typedef struct _CDROM_NOTIFY { 00058 LIST_ENTRY Entry; 00059 ULONG Size; 00060 PVOID RegistrationHandle; 00061 ULONG Event; 00062 // Must be last field 00063 MOUNTMGR_DRIVE_LETTER_TARGET DeviceName; 00064 } CDROM_NOTIFY, *PCDROM_NOTIFY; 00065 00066 LIST_ENTRY gMediaChangeList; 00067 PFAST_MUTEX gMediaChangeMutex; 00068 HANDLE gpEventMediaChange = NULL; 00069 UCHAR DriveLetterChange[26]; 00070 #define EVENT_CDROM_MEDIA_ARRIVAL 1 00071 #define EVENT_CDROM_MEDIA_REMOVAL 2 00072 00073 /***************************************************************************\ 00074 * Win32kPnPDriverEntry 00075 * 00076 * This is the callback function when we call IoCreateDriver to create a 00077 * PnP Driver Object. In this function, we need to remember the DriverObject. 00078 * 00079 * Parameters: 00080 * DriverObject - Pointer to the driver object created by the system. 00081 * RegistryPath - is NULL. 00082 * 00083 * Return Value: STATUS_SUCCESS 00084 * 00085 * History: 00086 * 10-20-97 IanJa Taken from ntos\io\pnpinit.c 00087 \***************************************************************************/ 00088 00089 NTSTATUS 00090 Win32kPnPDriverEntry( 00091 IN PDRIVER_OBJECT DriverObject, 00092 IN PUNICODE_STRING pustrRegistryPath 00093 ) 00094 00095 { 00096 TAGMSG2(DBGTAG_PNP, 00097 "Win32kPnPDriverEntry(DriverObject = %lx, pustrRegistryPath = %#p)", 00098 DriverObject, pustrRegistryPath); 00099 00100 // 00101 // File the pointer to our driver object away 00102 // 00103 gpWin32kDriverObject = DriverObject; 00104 return STATUS_SUCCESS; 00105 00106 UNREFERENCED_PARAMETER(pustrRegistryPath); 00107 } 00108 00109 00110 /***************************************************************************\ 00111 * Initialize the global event used in notifying CSR that media has changed. 00112 * 00113 * Execution Context: 00114 * 00115 * History: 00116 \***************************************************************************/ 00117 00118 VOID 00119 InitializeMediaChange(HANDLE hMediaRequestEvent) 00120 { 00121 if (!gbRemoteSession) { 00122 00123 InitializeListHead(&gMediaChangeList); 00124 00125 ObReferenceObjectByHandle(hMediaRequestEvent, 00126 EVENT_ALL_ACCESS, 00127 *ExEventObjectType, 00128 KernelMode, 00129 &gpEventMediaChange, 00130 NULL); 00131 00132 gMediaChangeMutex = UserAllocPoolNonPaged(sizeof(FAST_MUTEX), TAG_PNP); 00133 00134 if (gMediaChangeMutex) { 00135 ExInitializeFastMutex(gMediaChangeMutex); 00136 } 00137 } 00138 00139 return; 00140 } 00141 00142 __inline VOID EnterMediaCrit() { 00143 KeEnterCriticalRegion(); 00144 ExAcquireFastMutexUnsafe(gMediaChangeMutex); 00145 } 00146 00147 __inline VOID LeaveMediaCrit() { 00148 ExReleaseFastMutexUnsafe(gMediaChangeMutex); 00149 KeLeaveCriticalRegion(); 00150 } 00151 00152 00153 00154 /***************************************************************************\ 00155 * Routines to support CDROM driver letters. 00156 * 00157 * Execution Context: 00158 * 00159 * History: 00160 \***************************************************************************/ 00161 00162 ULONG GetDeviceChangeInfo() 00163 { 00164 UNICODE_STRING name; 00165 PFILE_OBJECT FileObject; 00166 PDEVICE_OBJECT DeviceObject; 00167 KEVENT event; 00168 PIRP irp; 00169 MOUNTMGR_DRIVE_LETTER_INFORMATION output; 00170 IO_STATUS_BLOCK ioStatus; 00171 NTSTATUS status; 00172 PCDROM_NOTIFY pContext = 0; 00173 00174 ULONG retval = 0; 00175 00176 if (!(ISCSRSS())) { 00177 return 0; 00178 } 00179 00180 EnterMediaCrit(); 00181 if (!IsListEmpty(&gMediaChangeList)) { 00182 pContext = (PCDROM_NOTIFY) RemoveTailList(&gMediaChangeList); 00183 } 00184 LeaveMediaCrit(); 00185 00186 if (pContext == NULL) { 00187 return 0; 00188 } 00189 00190 RtlInitUnicodeString(&name, MOUNTMGR_DEVICE_NAME); 00191 status = IoGetDeviceObjectPointer(&name, 00192 FILE_READ_ATTRIBUTES, 00193 &FileObject, 00194 &DeviceObject); 00195 00196 if (NT_SUCCESS(status)) { 00197 00198 KeInitializeEvent(&event, NotificationEvent, FALSE); 00199 irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, 00200 DeviceObject, 00201 &pContext->DeviceName, 00202 sizeof(MOUNTMGR_DRIVE_LETTER_TARGET) + 00203 pContext->DeviceName.DeviceNameLength, 00204 &output, 00205 sizeof(output), 00206 FALSE, 00207 &event, 00208 &ioStatus); 00209 if (irp) { 00210 00211 status = IoCallDriver(DeviceObject, irp); 00212 if (status == STATUS_PENDING) { 00213 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 00214 status = ioStatus.Status; 00215 } 00216 if ((status == STATUS_SUCCESS) && 00217 (output.CurrentDriveLetter)) { 00218 00219 UserAssert((output.CurrentDriveLetter - 'A') < 30); 00220 00221 retval = 1 << (output.CurrentDriveLetter - 'A'); 00222 00223 if (pContext->Event & EVENT_CDROM_MEDIA_ARRIVAL) { 00224 retval |= 0x80000000; 00225 } 00226 } 00227 } 00228 00229 ObDereferenceObject(FileObject); 00230 } 00231 00232 // 00233 // Allways free the request 00234 // 00235 00236 UserFreePool(pContext); 00237 00238 return retval; 00239 } 00240 00241 /***************************************************************************\ 00242 * Handle device notifications such as MediaChanged 00243 * 00244 * Execution Context: 00245 * 00246 * History: 00247 \***************************************************************************/ 00248 NTSTATUS DeviceCDROMNotify( 00249 IN PTARGET_DEVICE_CUSTOM_NOTIFICATION Notification, 00250 IN PCDROM_NOTIFY pContext) 00251 { 00252 PCDROM_NOTIFY pNew; 00253 00254 CheckCritOut(); 00255 00256 UserAssert(!gbRemoteSession); 00257 UserAssert(pContext); 00258 00259 if (IsEqualGUID(&Notification->Event, &GUID_IO_MEDIA_ARRIVAL)) 00260 { 00261 pContext->Event = EVENT_CDROM_MEDIA_ARRIVAL; 00262 } 00263 else if (IsEqualGUID(&Notification->Event, &GUID_IO_MEDIA_REMOVAL)) 00264 { 00265 pContext->Event = EVENT_CDROM_MEDIA_REMOVAL; 00266 } 00267 else if (IsEqualGUID(&Notification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) 00268 { 00269 IoUnregisterPlugPlayNotification(pContext->RegistrationHandle); 00270 UserFreePool(pContext); 00271 return STATUS_SUCCESS; 00272 } 00273 else 00274 { 00275 return STATUS_SUCCESS; 00276 } 00277 00278 // 00279 // Process the arrival or removal 00280 // 00281 // We must queue this otherwise we end up bugchecking on Terminal Server 00282 // This is due to opening a handle from within the system process which 00283 // requires us to do an attach process. 00284 // 00285 00286 pNew = UserAllocPoolNonPaged(pContext->Size, TAG_PNP); 00287 if (pNew) 00288 { 00289 RtlCopyMemory(pNew, pContext, pContext->Size); 00290 00291 EnterMediaCrit(); 00292 InsertHeadList(&gMediaChangeList, &pNew->Entry); 00293 LeaveMediaCrit(); 00294 00295 KeSetEvent(gpEventMediaChange, EVENT_INCREMENT, FALSE); 00296 } 00297 00298 return STATUS_SUCCESS; 00299 } 00300 00301 00302 00303 /***************************************************************************\ 00304 * DeviceClassCDROMNotify 00305 * 00306 * This gets called when CDROM appears or disappears 00307 * 00308 \***************************************************************************/ 00309 NTSTATUS 00310 DeviceClassCDROMNotify ( 00311 IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION classChange, 00312 IN PVOID Unused 00313 ) 00314 { 00315 NTSTATUS Status = STATUS_SUCCESS; 00316 PFILE_OBJECT FileObject; 00317 PDEVICE_OBJECT DeviceObject; 00318 PCDROM_NOTIFY pContext; 00319 ULONG Size; 00320 00321 UNREFERENCED_PARAMETER(Unused); 00322 00323 CheckCritOut(); 00324 00325 /* 00326 * Sanity check the DeviceType, and that it matches the InterfaceClassGuid 00327 */ 00328 UserAssert(IsEqualGUID(&classChange->InterfaceClassGuid, &CdRomClassGuid)); 00329 00330 if (IsEqualGUID(&classChange->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) { 00331 00332 Status = IoGetDeviceObjectPointer(classChange->SymbolicLinkName, 00333 FILE_READ_ATTRIBUTES, 00334 &FileObject, 00335 &DeviceObject); 00336 00337 if (NT_SUCCESS(Status)) { 00338 00339 Size = sizeof(CDROM_NOTIFY) + classChange->SymbolicLinkName->Length; 00340 00341 pContext = (PCDROM_NOTIFY) UserAllocPool(Size, TAG_PNP); 00342 00343 // 00344 // Register For MediaChangeNotifications on all the CDROMs. 00345 // 00346 00347 if (pContext) { 00348 00349 pContext->Size = Size; 00350 pContext->DeviceName.DeviceNameLength = classChange->SymbolicLinkName->Length; 00351 RtlCopyMemory(pContext->DeviceName.DeviceName, 00352 classChange->SymbolicLinkName->Buffer, 00353 pContext->DeviceName.DeviceNameLength); 00354 00355 IoRegisterPlugPlayNotification ( 00356 EventCategoryTargetDeviceChange, 00357 0, 00358 FileObject, 00359 gpWin32kDriverObject, 00360 DeviceCDROMNotify, 00361 pContext, 00362 &(pContext->RegistrationHandle)); 00363 } 00364 00365 ObDereferenceObject(FileObject); 00366 } 00367 00368 } else if (IsEqualGUID(&classChange->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) { 00369 00370 // 00371 // Do nothing - we already remove the registration. 00372 // 00373 00374 } else { 00375 RIPMSG0(RIP_ERROR, "unrecognized Event GUID"); 00376 } 00377 00378 00379 return STATUS_SUCCESS; 00380 } 00381 00382 00383 /***************************************************************************\ 00384 * CreateDeviceInfo 00385 * 00386 * This creates an instance of an input device for USER. To do this it: 00387 * - Allocates a DEVICEINFO struct 00388 * - Adds it to USER's list of input devices 00389 * - Initializes some of the fields 00390 * - Signals the input servicing thread to open and read the new device. 00391 * 00392 * Type - the device type (DEVICE_TYPE_MOUSE, DEVICE_TYPE_KEYBOARD) 00393 * Name - the device name. 00394 * When trying to open a HYDRA client's mouse, Name is NULL. 00395 * bFlags - some initial flags to set (eg: GDIF_NOTPNP) 00396 * 00397 * THIS FUNCTION IS CALLED IN THE CONTEXT OF THE KERNEL PROCESS 00398 * so we mustn't open the mouse here, else the handle we get will not belong 00399 * to the Win32k process. 00400 * 00401 * History: 00402 * 11-26-90 DavidPe Created. 00403 * 01-07-98 IanJa Plug & Play 00404 \***************************************************************************/ 00405 00406 PDEVICEINFO CreateDeviceInfo(DWORD DeviceType, PUNICODE_STRING pustrName, BYTE bFlags) 00407 { 00408 PDEVICEINFO pDeviceInfo = NULL; 00409 00410 CheckCritIn(); 00411 BEGINATOMICCHECK(); 00412 00413 UserAssert(pustrName != NULL); 00414 00415 TAGMSG3(DBGTAG_PNP, "CreateDeviceInfo(%d, %S, %x)", DeviceType, pustrName->Buffer, bFlags); 00416 00417 if (DeviceType > DEVICE_TYPE_MAX) { 00418 RIPMSG1(RIP_ERROR, "Unknown DeviceType %lx", DeviceType); 00419 } 00420 00421 pDeviceInfo = UserAllocPoolZInit(aDeviceTemplate[DeviceType].cbDeviceInfo, TAG_PNP); 00422 if (pDeviceInfo == NULL) { 00423 RIPMSG0(RIP_WARNING, "CreateDeviceInfo() out of memory allocating DEVICEINFO"); 00424 EXITATOMICCHECK(); 00425 return NULL; 00426 } 00427 00428 if (pustrName->Buffer != NULL) { 00429 pDeviceInfo->ustrName.Buffer = UserAllocPool(pustrName->Length, TAG_PNP); 00430 00431 if (pDeviceInfo->ustrName.Buffer == NULL) { 00432 RIPMSG1(RIP_WARNING, "CreateDeviceInfo: Can't duplicate string %ws", 00433 pustrName->Buffer); 00434 goto CreateFailed; 00435 } 00436 00437 pDeviceInfo->ustrName.MaximumLength = pustrName->Length; 00438 RtlCopyUnicodeString(&pDeviceInfo->ustrName, pustrName); 00439 } 00440 00441 pDeviceInfo->type = (BYTE)DeviceType; 00442 00443 /* 00444 * Create this device's HidChangeCompletion event. When the RIT completes 00445 * a synchronous ProcessDeviceChanges() it signals the HidChangeCompletion 00446 * event to wake the requesting RequestDeviceChange() which is blocking on 00447 * the event. 00448 * Each device has it's own HidChangeCompletion event, 00449 * since multiple PnP notification may arrive for several different 00450 * devices simultaneously. (see #331320 IanJa) 00451 */ 00452 pDeviceInfo->pkeHidChangeCompleted = CreateKernelEvent(SynchronizationEvent, FALSE); 00453 if (pDeviceInfo->pkeHidChangeCompleted == NULL) { 00454 RIPMSG0(RIP_WARNING, 00455 "CreateDeviceInfo: failed to create pkeHidChangeCompleted"); 00456 goto CreateFailed; 00457 } 00458 00459 /* 00460 * Link it in 00461 */ 00462 EnterDeviceInfoListCrit(); 00463 pDeviceInfo->pNext = gpDeviceInfoList; 00464 gpDeviceInfoList = pDeviceInfo; 00465 pDeviceInfo->bFlags |= bFlags; 00466 00467 /* 00468 * Tell the RIT there is a new device so that it can open it and start 00469 * reading from it. This is non-blocking (no GDIAF_PNPWAITING bit set) 00470 */ 00471 RequestDeviceChange(pDeviceInfo, GDIAF_ARRIVED, TRUE); 00472 LeaveDeviceInfoListCrit(); 00473 00474 EXITATOMICCHECK(); 00475 return pDeviceInfo; 00476 00477 CreateFailed: 00478 00479 if (pDeviceInfo) { 00480 if (pDeviceInfo->ustrName.Buffer) { 00481 UserFreePool(pDeviceInfo->ustrName.Buffer); 00482 } 00483 UserFreePool(pDeviceInfo); 00484 } 00485 00486 ENDATOMICCHECK(); 00487 return NULL; 00488 } 00489 00490 00491 /***************************************************************************\ 00492 * DeviceClassNotify 00493 * 00494 * This gets called when an input device is attached or detached. 00495 * If this happens during initialization (for mice already connected) we 00496 * come here by in the context of the RIT. If hot-(un)plugging a mouse, 00497 * then we are called on a thread from the Kernel process. 00498 * 00499 * History: 00500 * 10-20-97 IanJa Taken from some old code of KenRay's 00501 \***************************************************************************/ 00502 NTSTATUS 00503 DeviceClassNotify ( 00504 IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION classChange, 00505 IN PVOID DeviceType // (context) 00506 ) 00507 { 00508 DWORD dwDeviceType; 00509 00510 CheckCritOut(); 00511 dwDeviceType = PtrToUlong( DeviceType ); 00512 TAGMSG2(DBGTAG_PNP, "enter DeviceClassNotify(%lx, %lx)", classChange, dwDeviceType); 00513 00514 /* 00515 * Sanity check the DeviceType, and that it matches the InterfaceClassGuid 00516 */ 00517 UserAssert((dwDeviceType == DEVICE_TYPE_MOUSE) || (dwDeviceType == DEVICE_TYPE_KEYBOARD)); 00518 UserAssert(IsEqualGUID(&classChange->InterfaceClassGuid, aDeviceTemplate[dwDeviceType].pClassGUID)); 00519 00520 00521 TAGMSG3(DBGTAG_PNP | RIP_THERESMORE, " Event GUID %lx, %x, %x", 00522 classChange->Event.Data1, 00523 classChange->Event.Data2, 00524 classChange->Event.Data3); 00525 TAGMSG8(DBGTAG_PNP | RIP_THERESMORE, " %2x%2x%2x%2x%2x%2x%2x%2x", 00526 classChange->Event.Data4[0], classChange->Event.Data4[1], 00527 classChange->Event.Data4[2], classChange->Event.Data4[3], 00528 classChange->Event.Data4[4], classChange->Event.Data4[5], 00529 classChange->Event.Data4[6], classChange->Event.Data4[7]); 00530 TAGMSG4(DBGTAG_PNP | RIP_THERESMORE, " InterfaceClassGuid %lx, %lx, %lx, %lx", 00531 ((DWORD *)&(classChange->InterfaceClassGuid))[0], 00532 ((DWORD *)&(classChange->InterfaceClassGuid))[1], 00533 ((DWORD *)&(classChange->InterfaceClassGuid))[2], 00534 ((DWORD *)&(classChange->InterfaceClassGuid))[3]); 00535 TAGMSG1(DBGTAG_PNP | RIP_THERESMORE, " SymbolicLinkName %ws", classChange->SymbolicLinkName->Buffer); 00536 00537 if (IsEqualGUID(&classChange->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) { 00538 00539 // A new hid device class association has arrived 00540 EnterCrit(); 00541 CreateDeviceInfo(dwDeviceType, classChange->SymbolicLinkName, 0); 00542 LeaveCrit(); 00543 TAGMSG0(DBGTAG_PNP, "=== CREATED ==="); 00544 } 00545 00546 return STATUS_SUCCESS; 00547 } 00548 00549 /****************************************************************************\ 00550 * If a device class "all-for-one" setting (ConnectMultiplePorts) is on, 00551 * then we just open the device the old (non-PnP) way and return TRUE. (As a 00552 * safety feature we also do this if gpWin32kDriverObject is NULL, because this 00553 * driver object is needed to register for PnP device class notifications) 00554 * Otherwise, return FALSE so we can continue and register for Arrival/Departure 00555 * notifications. 00556 * 00557 * This code was originally intended to be temporary until ConnectMultiplePorts 00558 * was finally turned off. 00559 * But now I think we have to keep it for backward compatibility with 00560 * drivers that filter Pointer/KeyboardClass0 and/or those that replace 00561 * Pointer/KeyboardClass0 by putting a different name in the registry under 00562 * System\CurrentControlSet\Services\RIT\mouclass (or kbbclass) 00563 \****************************************************************************/ 00564 BOOL 00565 OpenMultiplePortDevice(DWORD DeviceType) 00566 { 00567 WCHAR awchDeviceName[MAX_PATH]; 00568 UNICODE_STRING DeviceName; 00569 PDEVICE_TEMPLATE pDevTpl; 00570 PDEVICEINFO pDeviceInfo; 00571 PWCHAR pwchNameIndex; 00572 00573 UINT uiConnectMultiplePorts = 0; 00574 00575 CheckCritIn(); 00576 00577 if (DeviceType <= DEVICE_TYPE_MAX) { 00578 pDevTpl = &aDeviceTemplate[DeviceType]; 00579 } else { 00580 RIPMSG1(RIP_ERROR, "OpenMultiplePortDevice(%d) - unknown type", DeviceType); 00581 return FALSE; 00582 } 00583 00584 /* 00585 * Note that we don't need to FastOpenUserProfileMapping() here since 00586 * uiRegistrySection (PMAP_MOUCLASS_PARAMS/PMAP_KBDCLASS_PARAMS) is a 00587 * machine setiing, not a user setting. 00588 */ 00589 uiConnectMultiplePorts = FastGetProfileDwordW(NULL, 00590 pDevTpl->uiRegistrySection, L"ConnectMultiplePorts", 0); 00591 00592 /* 00593 * Open the device for read access. 00594 */ 00595 if (uiConnectMultiplePorts || (gpWin32kDriverObject == NULL)) { 00596 /* 00597 * Find out if there is a name substitution in the registry. 00598 * Note that we don't need to FastOpenUserProfileMapping() here since 00599 * PMAP_INPUT is a machine setting, not a user setting. 00600 */ 00601 FastGetProfileStringW(NULL, 00602 PMAP_INPUT, 00603 pDevTpl->pwszClassName, 00604 pDevTpl->pwszDefDevName, // if no substitution, use this default 00605 awchDeviceName, 00606 sizeof(awchDeviceName)/sizeof(WCHAR)); 00607 00608 RtlInitUnicodeString(&DeviceName, awchDeviceName); 00609 00610 pDeviceInfo = CreateDeviceInfo(DeviceType, &DeviceName, GDIF_NOTPNP); 00611 if (pDeviceInfo) { 00612 return TRUE; 00613 } 00614 } else { 00615 DeviceName.Length = 0; 00616 DeviceName.MaximumLength = sizeof(awchDeviceName); 00617 DeviceName.Buffer = awchDeviceName; 00618 00619 RtlAppendUnicodeToString(&DeviceName, pDevTpl->pwszLegacyDevName); 00620 pwchNameIndex = &DeviceName.Buffer[(DeviceName.Length / sizeof(WCHAR)) - 1]; 00621 for (*pwchNameIndex = L'0'; *pwchNameIndex <= L'9'; (*pwchNameIndex)++) { 00622 CreateDeviceInfo(DeviceType, &DeviceName, GDIF_NOTPNP); 00623 } 00624 } 00625 00626 return FALSE; 00627 } 00628 00629 00630 /***************************************************************************\ 00631 * RegisterForDeviceClassNotifications 00632 * Get ready to receive notifications that a mouse or keyboard is plugged in 00633 * or removed, then request notifications by registering for them. 00634 * 00635 * History: 00636 * 10-20-97 IanJa Taken from ntos\io\pnpinit.c 00637 \***************************************************************************/ 00638 NTSTATUS 00639 xxxRegisterForDeviceClassNotifications() 00640 { 00641 IO_NOTIFICATION_EVENT_CATEGORY eventCategory; 00642 ULONG eventFlags; 00643 PVOID RegistrationEntry; 00644 NTSTATUS Status; 00645 UNICODE_STRING ustrDriverName; 00646 DWORD DeviceType; 00647 00648 00649 00650 CheckCritIn(); 00651 00652 TAGMSG0(DBGTAG_PNP, "enter xxxRegisterForDeviceClassNotifications()"); 00653 00654 /* 00655 * Remote hydra session indicates CreateDeviceInfo in xxxRemoteReconnect 00656 */ 00657 UserAssert(!gbRemoteSession); 00658 00659 /* 00660 * This must be done before devices are registered for device notifications 00661 * which will occur as a result of CreateDeviceInfo()... 00662 */ 00663 RtlInitUnicodeString(&ustrDriverName, L"\\Driver\\Win32k"); 00664 Status = IoCreateDriver(&ustrDriverName, Win32kPnPDriverEntry); 00665 00666 TAGMSG1(DBGTAG_PNP | RIP_THERESMORE, "IoCreateDriver returned status = %lx", Status); 00667 TAGMSG1(DBGTAG_PNP, "gpWin32kDriverObject = %lx", gpWin32kDriverObject); 00668 00669 if (!NT_SUCCESS(Status)) { 00670 RIPMSG1(RIP_ERROR, "IoCreateDriver failed, status %lx", Status); 00671 Status = STATUS_SUCCESS; 00672 } 00673 00674 UserAssert(gpWin32kDriverObject); 00675 00676 // 00677 // We are only interested in DeviceClasses changing. 00678 // 00679 eventCategory = EventCategoryDeviceInterfaceChange; 00680 00681 // 00682 // We want to be notified for all devices that are in the system. 00683 // those that are know now, and those that will arive later. 00684 // This allows us to have one code path for adding devices, and eliminates 00685 // the nasty race condition. If we were only interested in the devices 00686 // that exist at this one moment in time, and not future devices, we 00687 // would call IoGetDeviceClassAssociations. 00688 // 00689 eventFlags = PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES; 00690 00691 /* 00692 * For all input device types: 00693 * If they are Multiple Port Devices (ie: not PnP) just open them 00694 * Else Register them for PnP notifications (they will be opened when the 00695 * arrival notification arrives. 00696 * If devices are already attached, we will received immediate notification 00697 * during the call to IoRegisterPlugPlayNotification, so we must LeaveCrit 00698 * because the callback routine DeviceClassNotify expects it. 00699 */ 00700 for (DeviceType = 0; DeviceType <= DEVICE_TYPE_MAX; DeviceType++) { 00701 if (!OpenMultiplePortDevice(DeviceType)) { 00702 /* 00703 * Make the registration 00704 */ 00705 00706 TAGMSG1(DBGTAG_PNP, "Registering device type %d", DeviceType); 00707 LeaveCrit(); // for DeviceClassNotify 00708 Status = IoRegisterPlugPlayNotification ( 00709 eventCategory, 00710 eventFlags, 00711 (PVOID)aDeviceTemplate[DeviceType].pClassGUID, 00712 gpWin32kDriverObject, 00713 (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DeviceClassNotify, 00714 LongToPtr( DeviceType ), 00715 &RegistrationEntry); 00716 EnterCrit(); 00717 TAGMSG1(DBGTAG_PNP, "Registration returned status %lx", Status); 00718 if (!NT_SUCCESS(Status)) { 00719 RIPMSG2(RIP_ERROR, "IoRegisterPlugPlayNotification(%d) failed, status %lx", 00720 DeviceType, Status); 00721 } 00722 } 00723 } 00724 00725 // Now Register for CD_ROM notifications 00726 LeaveCrit(); // for DeviceClassNotify 00727 00728 Status = IoRegisterPlugPlayNotification ( 00729 eventCategory, 00730 eventFlags, 00731 (PVOID) &CdRomClassGuid, 00732 gpWin32kDriverObject, 00733 (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)DeviceClassCDROMNotify, 00734 NULL, 00735 &RegistrationEntry); 00736 EnterCrit(); 00737 00738 00739 00740 return Status; 00741 } 00742 00743 00744 00745 /***************************************************************************\ 00746 * QueryDeviceInfo 00747 * 00748 * Query the device information. This function is an async function, 00749 * so be sure any buffers it uses aren't allocated on the stack! 00750 * 00751 * If this is an asynchronous IOCTL, perhaps we should be waiting on 00752 * the file handle or on an event for it to succeed? 00753 * 00754 * This function must called by the RIT, not directly by PnP notification 00755 * (else the handle we issue the IOCTL on will be invalid) 00756 * 00757 * History: 00758 * 01-20-99 IanJa Created. 00759 \***************************************************************************/ 00760 NTSTATUS 00761 QueryDeviceInfo( 00762 PDEVICEINFO pDeviceInfo) 00763 { 00764 NTSTATUS Status; 00765 PDEVICE_TEMPLATE pDevTpl = &aDeviceTemplate[pDeviceInfo->type]; 00766 00767 #ifdef DIAGNOSE_IO 00768 pDeviceInfo->AttrStatus = 00769 #endif 00770 Status = ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 00771 &pDeviceInfo->iosb, 00772 pDevTpl->IOCTL_Attr, 00773 NULL, 0, 00774 (PVOID)((PBYTE)pDeviceInfo + pDevTpl->offAttr), 00775 pDevTpl->cbAttr); 00776 00777 if (!NT_SUCCESS(Status)) { 00778 RIPMSG2(RIP_WARNING, "QueryDeviceInfo(%p): IOCTL failed - Status %lx", 00779 pDeviceInfo, Status); 00780 } 00781 TAGMSG1(DBGTAG_PNP, "IOCTL_*_QUERY_ATTRIBUTES returns Status %lx", Status); 00782 return Status; 00783 } 00784 00785 00786 /***************************************************************************\ 00787 * OpenDevice 00788 * 00789 * This function opens an input device for USER, mouse or keyboard. 00790 * 00791 * 00792 * Return value 00793 * BOOL did the operation succeed? 00794 * 00795 * When trying to open a HYDRA client's mouse (or kbd?), pDeviceInfo->ustrName 00796 * is NULL. 00797 * 00798 * This function must called by the RIT, not directly by PnP 00799 * notification (that way the handle we are about to create will be in the right 00800 * our process) 00801 * 00802 * History: 00803 * 11-26-90 DavidPe Created. 00804 * 01-07-98 IanJa Plug & Play 00805 * 04-17-98 IanJa Only open mice in RIT context. 00806 \***************************************************************************/ 00807 BOOL OpenDevice(PDEVICEINFO pDeviceInfo) 00808 { 00809 OBJECT_ATTRIBUTES ObjectAttributes; 00810 NTSTATUS Status; 00811 00812 CheckCritIn(); 00813 UserAssert((PtiCurrentShared() == gptiRit) || (PtiCurrentShared() == gTermIO.ptiDesktop)); 00814 00815 TAGMSG3(DBGTAG_PNP, "OpenDevice(): Opening type %d (%lx %ws)", 00816 pDeviceInfo->type, pDeviceInfo->handle, pDeviceInfo->ustrName.Buffer); 00817 00818 #ifdef DIAGNOSE_IO 00819 pDeviceInfo->OpenerProcess = PsGetCurrentThread()->Cid.UniqueProcess; 00820 #endif 00821 00822 if (gbRemoteSession) { 00823 00824 /* 00825 * For other than the console, the mouse handle is 00826 * set before createwinstation. 00827 */ 00828 UserAssert(pDeviceInfo->ustrName.Buffer == NULL); 00829 00830 pDeviceInfo->bFlags |= GDIF_NOTPNP; 00831 00832 switch (pDeviceInfo->type) { 00833 case DEVICE_TYPE_MOUSE: 00834 pDeviceInfo->handle = ghRemoteMouseChannel; 00835 if (ghRemoteMouseChannel == NULL) { 00836 return FALSE; 00837 } 00838 break; 00839 case DEVICE_TYPE_KEYBOARD: 00840 pDeviceInfo->handle = ghRemoteKeyboardChannel; 00841 if (ghRemoteKeyboardChannel == NULL) { 00842 return FALSE; 00843 } 00844 break; 00845 default: 00846 RIPMSG2(RIP_ERROR, "Unknown device type %d DeviceInfo %#p", 00847 pDeviceInfo->type, pDeviceInfo); 00848 return FALSE; 00849 } 00850 } else { 00851 InitializeObjectAttributes(&ObjectAttributes, &(pDeviceInfo->ustrName), 0, NULL, NULL); 00852 00853 #ifdef DIAGNOSE_IO 00854 pDeviceInfo->OpenStatus = 00855 #endif 00856 Status = ZwCreateFile(&pDeviceInfo->handle, FILE_READ_DATA | SYNCHRONIZE, 00857 &ObjectAttributes, &pDeviceInfo->iosb, NULL, 0, FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); 00858 00859 TAGMSG2(DBGTAG_PNP, "ZwCreateFile returns handle %lx, Status %lx", 00860 pDeviceInfo->handle, Status); 00861 00862 if (!NT_SUCCESS(Status)) { 00863 if ((pDeviceInfo->bFlags & GDIF_NOTPNP) == 0) { 00864 /* 00865 * Don't warn about PS/2 mice: the PointerClassLegacy0 -9 and 00866 * KeyboardClassLegacy0 - 9 will usually fail to be created 00867 */ 00868 RIPMSG1(RIP_WARNING, "OpenDevice: ZwCreateFile failed with Status %lx", Status); 00869 } 00870 /* 00871 * Don't FreeDeviceInfo here because that alters gpDeviceInfoList 00872 * which our caller, ProcessDeviceChanges, is traversing. 00873 * Instead, let ProcessDeviceChanges do it. 00874 */ 00875 return FALSE; 00876 } 00877 } 00878 00879 Status = QueryDeviceInfo(pDeviceInfo); 00880 00881 00882 return NT_SUCCESS(Status); 00883 } 00884 00885 VOID CloseDevice(PDEVICEINFO pDeviceInfo) 00886 { 00887 NTSTATUS Status; 00888 IO_STATUS_BLOCK IoStatusBlock; 00889 CheckCritIn(); 00890 00891 00892 TAGMSG3(DBGTAG_PNP, "CloseDevice(): closing type %d (%lx %ws)", 00893 pDeviceInfo->type, pDeviceInfo->handle, pDeviceInfo->ustrName.Buffer); 00894 if (pDeviceInfo->handle) { 00895 UserAssert(pDeviceInfo->OpenerProcess == PsGetCurrentThread()->Cid.UniqueProcess); 00896 ZwCancelIoFile(pDeviceInfo->handle, &IoStatusBlock); 00897 UserAssertMsg2(NT_SUCCESS(IoStatusBlock.Status), "NtCancelIoFile handle %x failed status %#x", 00898 pDeviceInfo->handle, IoStatusBlock.Status); 00899 Status = ZwClose(pDeviceInfo->handle); 00900 UserAssertMsg2(NT_SUCCESS(Status), "ZwClose handle %x failed status %#x", 00901 pDeviceInfo->handle, Status); 00902 pDeviceInfo->handle = 0; 00903 } else { 00904 /* 00905 * Assert the IO was cancelled or we tried to read the device 00906 * after the first close (which set the handle to 0 - an invalid handle) 00907 */ 00908 UserAssert((pDeviceInfo->iosb.Status == STATUS_CANCELLED) || 00909 (pDeviceInfo->ReadStatus == STATUS_INVALID_HANDLE)); 00910 } 00911 } 00912 00913 /*****************************************************************************\ 00914 * RegisterForDeviceChangeNotifications() 00915 * 00916 * Device Notifications such as QueryRemove, RemoveCancelled, RemoveComplete 00917 * tell us what is going on with the mouse. 00918 * To register for device notifications: 00919 * (1) Obtain a pointer to the device object (pFileObject) 00920 * (2) Register for target device change notifications, saving the 00921 * notification handle (which we will need in order to deregister) 00922 * 00923 * It doesn't matter too much if this fails: we just won't be able to eject the 00924 * hardware via the UI very successfully. (We can still just yank it though). 00925 * This will also fail if the ConnectMultiplePorts was set for this device. 00926 * 00927 * 1998-10-05 IanJa Created 00928 \*****************************************************************************/ 00929 BOOL RegisterForDeviceChangeNotifications(PDEVICEINFO pDeviceInfo) 00930 { 00931 PFILE_OBJECT pFileObject; 00932 NTSTATUS Status; 00933 00934 /* 00935 * In or Out of User critical section: 00936 * In when called from RIT ProcessDeviceChanges(); 00937 * Out when called from the DeviceNotify callback 00938 */ 00939 CheckCritIn(); 00940 UserAssert((PtiCurrentShared() == gptiRit) || (PtiCurrentShared() == gTermIO.ptiDesktop)); 00941 UserAssert(pDeviceInfo->handle); 00942 UserAssert(pDeviceInfo->OpenerProcess == PsGetCurrentThread()->Cid.UniqueProcess); 00943 00944 if (pDeviceInfo->bFlags & GDIF_NOTPNP) { 00945 return TRUE; 00946 } 00947 Status = ObReferenceObjectByHandle(pDeviceInfo->handle, 00948 0, 00949 NULL, 00950 KernelMode, 00951 (PVOID)&pFileObject, 00952 NULL); 00953 if (NT_SUCCESS(Status)) { 00954 Status = IoRegisterPlugPlayNotification ( 00955 EventCategoryTargetDeviceChange, // EventCategory 00956 0, // EventCategoryFlags 00957 (PVOID)pFileObject, // EventCategoryData 00958 gpWin32kDriverObject, // DriverObject 00959 // (PDRIVER_NOTIFICATION_CALLBACK_ROUTINE) 00960 DeviceNotify, 00961 (PVOID)pDeviceInfo, // Context 00962 &pDeviceInfo->NotificationEntry); 00963 ObDereferenceObject(pFileObject); 00964 if (!NT_SUCCESS(Status)) { 00965 // This is only OK if ConnectMultiplePorts is on (ie: not a PnP device) 00966 RIPMSG3(RIP_ERROR, 00967 "IoRegisterPlugPlayNotification failed on device %.*ws, status %lx, email DoronH : #333453", 00968 pDeviceInfo->ustrName.Length / sizeof(WCHAR), 00969 pDeviceInfo->ustrName.Buffer, Status); 00970 } 00971 } else { 00972 // non-catastrophic error (won't be able to remove device) 00973 RIPMSG2(RIP_ERROR, "Can't get pFileObject from handle %lx, status %lx", 00974 pDeviceInfo->handle, Status); 00975 } 00976 00977 return NT_SUCCESS(Status); 00978 } 00979 00980 00981 BOOL UnregisterForDeviceChangeNotifications(PDEVICEINFO pDeviceInfo) 00982 { 00983 NTSTATUS Status; 00984 00985 CheckCritIn(); 00986 UserAssert((PtiCurrentShared() == gptiRit) || (PtiCurrentShared() == gTermIO.ptiDesktop)); 00987 UserAssert(pDeviceInfo->NotificationEntry); 00988 UserAssert(pDeviceInfo->OpenerProcess == PsGetCurrentThread()->Cid.UniqueProcess); 00989 00990 if (pDeviceInfo->NotificationEntry == NULL) { 00991 /* 00992 * This happens for non-PnP devices or if the earlier 00993 * IoRegisterPlugPlayNotification() failed. Return now since 00994 * IoUnregisterPlugPlayNotification(NULL) will bluescreen. 00995 */ 00996 return TRUE; 00997 } 00998 00999 // non-PnP devices should not have any NotificationEntry: 01000 UserAssert((pDeviceInfo->bFlags & GDIF_NOTPNP) == 0); 01001 01002 TAGMSG3(DBGTAG_PNP, "UnregisterForDeviceChangeNotifications(): type %d (%lx %ws)", 01003 pDeviceInfo->type, pDeviceInfo, pDeviceInfo->ustrName.Buffer); 01004 Status = IoUnregisterPlugPlayNotification(pDeviceInfo->NotificationEntry); 01005 if (!NT_SUCCESS(Status)) { 01006 RIPMSG2(RIP_ERROR, 01007 "IoUnregisterPlugPlayNotification failed Status = %lx, DEVICEINFO %lx", 01008 Status, pDeviceInfo); 01009 return FALSE; 01010 } 01011 pDeviceInfo->NotificationEntry = 0; 01012 return TRUE; 01013 } 01014 01015 01016 /***************************************************************************\ 01017 * Handle device notifications such as QueryRemove, CancelRemove etc. 01018 * 01019 * Execution Context: 01020 * when yanked: a non-WIN32 thread. 01021 * via UI: ??? (won't see this except from laptop being undocked?) 01022 * 01023 * History: 01024 \***************************************************************************/ 01025 NTSTATUS DeviceNotify( 01026 IN PPLUGPLAY_NOTIFY_HDR pNotification, 01027 IN PDEVICEINFO pDeviceInfo) // should the context be a kernel address? 01028 { 01029 USHORT usAction; 01030 01031 #if DBG 01032 { 01033 PDEVICEINFO pDeviceInfoDbg; 01034 for (pDeviceInfoDbg = gpDeviceInfoList; pDeviceInfoDbg; pDeviceInfoDbg = pDeviceInfoDbg->pNext) { 01035 if (pDeviceInfoDbg == pDeviceInfo) { 01036 break; 01037 } 01038 } 01039 UserAssertMsg1(pDeviceInfoDbg != NULL, "Notification for unlisted DEVICEINFO %lx", pDeviceInfo); 01040 } 01041 #endif 01042 01043 CheckCritOut(); 01044 01045 UserAssert(!gbRemoteSession); 01046 01047 TAGMSG1(DBGTAG_PNP | RIP_THERESMORE, "DeviceNotify >>> %lx", pDeviceInfo); 01048 01049 UserAssert(pDeviceInfo->OpenerProcess != PsGetCurrentThread()->Cid.UniqueProcess); 01050 UserAssert(pDeviceInfo->usActions == 0); 01051 01052 if (IsEqualGUID(&pNotification->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE)) { 01053 TAGMSG0(DBGTAG_PNP | RIP_NONAME, "QueryRemove"); 01054 usAction = GDIAF_QUERYREMOVE; 01055 01056 } else if (IsEqualGUID(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_CANCELLED)) { 01057 TAGMSG0(DBGTAG_PNP | RIP_NONAME, "RemoveCancelled"); 01058 usAction = GDIAF_REMOVECANCELLED; 01059 01060 } else if (IsEqualGUID(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) { 01061 TAGMSG1(DBGTAG_PNP | RIP_NONAME, "RemoveComplete (process %#x)", PsGetCurrentThread()->Cid.UniqueProcess); 01062 usAction = GDIAF_DEPARTED; 01063 01064 } else { 01065 TAGMSG4(DBGTAG_PNP | RIP_NONAME, "GUID Unknown: %lx:%lx:%lx:%x...", 01066 pNotification->Event.Data1, pNotification->Event.Data2, 01067 pNotification->Event.Data3, pNotification->Event.Data4[0]); 01068 return STATUS_UNSUCCESSFUL; 01069 } 01070 01071 /* 01072 * Signal the RIT to ProcessDeviceChanges() 01073 * Wait for completion according to the GDIAF_PNPWAITING bit 01074 */ 01075 CheckCritOut(); 01076 CheckDeviceInfoListCritOut(); 01077 RequestDeviceChange(pDeviceInfo, (USHORT)(usAction | GDIAF_PNPWAITING), FALSE); 01078 01079 return STATUS_SUCCESS; 01080 } 01081 01082 01083 /***************************************************************************\ 01084 * StartDeviceRead 01085 * 01086 * This function makes an asynchronous read request to the input device driver, 01087 * unless the device has been marked for destruction (GDIAF_FREEME) 01088 * 01089 * Returns: 01090 * The next DeviceInfo on the list if this device was freed: If the caller 01091 * was not already in the DeviceInfoList critical section, the this must be 01092 * ignored as it is not safe. 01093 * NULL if the read succeeded. 01094 * 01095 * History: 01096 * 11-26-90 DavidPe Created. 01097 * 10-20-98 IanJa Generalized for PnP input devices 01098 \***************************************************************************/ 01099 PDEVICEINFO StartDeviceRead( 01100 PDEVICEINFO pDeviceInfo) 01101 { 01102 PDEVICE_TEMPLATE pDevTpl; 01103 01104 pDeviceInfo->bFlags |= GDIF_READING; 01105 01106 /* 01107 * If this device needs freeing, abandon reading now and request the free. 01108 */ 01109 if (pDeviceInfo->usActions & GDIAF_FREEME) { 01110 BOOL fPreviouslyAcquired = ExIsResourceAcquiredExclusiveLite(gpresDeviceInfoList); 01111 if (!fPreviouslyAcquired) { 01112 EnterDeviceInfoListCrit(); 01113 } 01114 pDeviceInfo->bFlags &= ~GDIF_READING; 01115 pDeviceInfo = FreeDeviceInfo(pDeviceInfo); 01116 if (!fPreviouslyAcquired) { 01117 LeaveDeviceInfoListCrit(); 01118 } 01119 return pDeviceInfo; 01120 } 01121 01122 /* 01123 * Initialize in case read fails 01124 */ 01125 pDeviceInfo->iosb.Status = STATUS_UNSUCCESSFUL; // catch concurrent writes? 01126 pDeviceInfo->iosb.Information = 0; 01127 01128 pDevTpl = &aDeviceTemplate[pDeviceInfo->type]; 01129 01130 UserAssert(pDeviceInfo->OpenerProcess == PsGetCurrentThread()->Cid.UniqueProcess); 01131 LOGTIME(pDeviceInfo->timeStartRead); 01132 #ifdef DIAGNOSE_IO 01133 pDeviceInfo->nReadsOutstanding++; 01134 #endif 01135 pDeviceInfo->ReadStatus = ZwReadFile( 01136 pDeviceInfo->handle, 01137 NULL, // hReadEvent 01138 InputApc, // InputApc() 01139 pDeviceInfo, // ApcContext 01140 &pDeviceInfo->iosb, 01141 (PVOID)((PBYTE)pDeviceInfo + pDevTpl->offData), 01142 pDevTpl->cbData, 01143 PZERO(LARGE_INTEGER), NULL); 01144 LOGTIME(pDeviceInfo->timeEndRead); 01145 01146 #if DBG 01147 if (pDeviceInfo->bFlags & GDIF_DBGREAD) { 01148 TAGMSG2(DBGTAG_PNP, "ZwReadFile of Device handle %lx returned status %lx", 01149 pDeviceInfo->handle, pDeviceInfo->ReadStatus); 01150 } 01151 #endif 01152 01153 if (!NT_SUCCESS(pDeviceInfo->ReadStatus)) { 01154 BOOL fPreviouslyAcquired = ExIsResourceAcquiredExclusiveLite(gpresDeviceInfoList); 01155 if (!fPreviouslyAcquired) { 01156 EnterDeviceInfoListCrit(); 01157 } 01158 01159 /* 01160 * If insufficient resources, retry the read the next time the RIT 01161 * wakes up for the ID_TIMER event by incrementing gnRetryReadInput 01162 * (Cheaper than setting our own timer), 01163 * Else just abandon reading. 01164 */ 01165 if (pDeviceInfo->ReadStatus == STATUS_INSUFFICIENT_RESOURCES) { 01166 if (pDeviceInfo->nRetryRead++ < MAXIMUM_READ_RETRIES) { 01167 pDeviceInfo->usActions |= GDIAF_RETRYREAD; 01168 gnRetryReadInput++; 01169 } 01170 } else { 01171 pDeviceInfo->bFlags &= ~GDIF_READING; 01172 } 01173 01174 #ifdef DIAGNOSE_IO 01175 pDeviceInfo->nReadsOutstanding--; 01176 #endif 01177 if (!fPreviouslyAcquired) { 01178 LeaveDeviceInfoListCrit(); 01179 } 01180 } else { 01181 pDeviceInfo->nRetryRead = 0; 01182 } 01183 01184 if (!ISTS() && !NT_SUCCESS(pDeviceInfo->ReadStatus)) 01185 RIPMSG2(RIP_WARNING, "StartDeviceRead %#p failed Status %#x", 01186 pDeviceInfo, pDeviceInfo->ReadStatus); 01187 01188 return NULL; 01189 } 01190 01191 VOID ProcessDeviceChanges(DWORD DeviceType) 01192 { 01193 PDEVICEINFO pDeviceInfo; 01194 USHORT usOriginalActions; 01195 #if DBG 01196 int nChanges = 0; 01197 ULONG timeStartReadPrev; 01198 #endif 01199 01200 /* 01201 * Reset summary information for all Mice and Keyboards 01202 */ 01203 DWORD nMice = 0; 01204 DWORD nWheels = 0; 01205 DWORD nMaxButtons = 0; 01206 int nKeyboards = 0; 01207 01208 CheckCritIn(); 01209 BEGINATOMICCHECK(); 01210 UserAssert((PtiCurrentShared() == gptiRit) || (PtiCurrentShared() == gTermIO.ptiDesktop)); 01211 01212 EnterDeviceInfoListCrit(); 01213 BEGINATOMICDEVICEINFOLISTCHECK(); 01214 01215 /* 01216 * Look for devices to Create (those which have newly arrived) 01217 * and for devices to Terminate (these which have just departed) 01218 * and for device change notifications. 01219 * Make sure the actions are processed in the right order in case we 01220 * are being asked for more than one action per device: for example, 01221 * we sometimes get QueryRemove followed quickly by RemoveCancelled 01222 * and both actions arrive here together: we should do them in the 01223 * correct order. 01224 */ 01225 pDeviceInfo = gpDeviceInfoList; 01226 while (pDeviceInfo) { 01227 if (pDeviceInfo->type != DeviceType) { 01228 pDeviceInfo = pDeviceInfo->pNext; 01229 continue; 01230 } 01231 01232 usOriginalActions = pDeviceInfo->usActions; 01233 UserAssert((usOriginalActions == 0) || (usOriginalActions & ~GDIAF_PNPWAITING)); 01234 01235 /* 01236 * Refresh Mouse: 01237 * We read a MOUSE_ATTRIBUTES_CHANGED flag when a PS/2 mouse 01238 * is plugged back in. Find out the attributes of the device. 01239 */ 01240 if (pDeviceInfo->usActions & GDIAF_REFRESH_MOUSE) { 01241 pDeviceInfo->usActions &= ~GDIAF_REFRESH_MOUSE; 01242 01243 UserAssert(pDeviceInfo->type == DEVICE_TYPE_MOUSE); 01244 #if DBG 01245 nChanges++; 01246 #endif 01247 TAGMSG1(DBGTAG_PNP, "QueryDeviceInfo: %lx", pDeviceInfo); 01248 QueryDeviceInfo(pDeviceInfo); 01249 } 01250 01251 /* 01252 * QueryRemove: 01253 * Close the file object, but retain the DEVICEINFO struct and the 01254 * registration in case we later get a RemoveCancelled. 01255 */ 01256 if (pDeviceInfo->usActions & GDIAF_QUERYREMOVE) { 01257 pDeviceInfo->usActions &= ~GDIAF_QUERYREMOVE; 01258 #if DBG 01259 nChanges++; 01260 #endif 01261 TAGMSG1(DBGTAG_PNP, "QueryRemove: %lx", pDeviceInfo); 01262 CloseDevice(pDeviceInfo); 01263 } 01264 01265 /* 01266 * New device arrived or RemoveCancelled: 01267 * If new device, Open it, register for notifications and start reading 01268 * If RemoveCancelled, unregister the old notfications first 01269 */ 01270 if (pDeviceInfo->usActions & (GDIAF_ARRIVED | GDIAF_REMOVECANCELLED)) { 01271 // Reopen the file object, (this is a new file object, of course), 01272 // Unregister for the old file, register with this new one. 01273 if (pDeviceInfo->usActions & GDIAF_REMOVECANCELLED) { 01274 pDeviceInfo->usActions &= ~GDIAF_REMOVECANCELLED; 01275 #if DBG 01276 nChanges++; 01277 #endif 01278 TAGMSG1(DBGTAG_PNP, "RemoveCancelled: %lx", pDeviceInfo); 01279 UnregisterForDeviceChangeNotifications(pDeviceInfo); 01280 } 01281 01282 #if DBG 01283 if (pDeviceInfo->usActions & GDIAF_ARRIVED) { 01284 nChanges++; 01285 } 01286 #endif 01287 01288 pDeviceInfo->usActions &= ~GDIAF_ARRIVED; 01289 if (OpenDevice(pDeviceInfo)) { 01290 PDEVICEINFO pDeviceInfoNext; 01291 RegisterForDeviceChangeNotifications(pDeviceInfo); 01292 01293 if (!(gbRemoteSession && (pDeviceInfo->usActions & GDIAF_RECONNECT))) { 01294 01295 pDeviceInfoNext = StartDeviceRead(pDeviceInfo); 01296 if (pDeviceInfoNext) { 01297 /* 01298 * pDeviceInfo wasa freed, move onto the next 01299 */ 01300 pDeviceInfo = pDeviceInfoNext; 01301 continue; 01302 } 01303 } 01304 pDeviceInfo->usActions &= ~GDIAF_RECONNECT; 01305 01306 } else { 01307 /* 01308 * If the Open failed, we free the device here, and move on to 01309 * the next device. 01310 * Assert to catch re-open failure upon RemoveCancelled. 01311 */ 01312 #if DBG 01313 if ((usOriginalActions & GDIAF_ARRIVED) == 0) { 01314 RIPMSG2(RIP_WARNING, "Re-Open %#p failed status %x during RemoveCancelled", 01315 pDeviceInfo, pDeviceInfo->OpenStatus); 01316 } 01317 #endif 01318 pDeviceInfo = FreeDeviceInfo(pDeviceInfo); 01319 continue; 01320 } 01321 } 01322 01323 /* 01324 * RemoveComplete: 01325 * Close the file object, if you have not already done so, Unregister. 01326 * FreeDeviceInfo here (which will actually request a free from the 01327 * reader or the PnP requestor thread), and move on to the next device. 01328 */ 01329 if (pDeviceInfo->usActions & GDIAF_DEPARTED) { 01330 pDeviceInfo->usActions &= ~GDIAF_DEPARTED; 01331 #if DBG 01332 nChanges++; 01333 #endif 01334 TAGMSG1(DBGTAG_PNP, "RemoveComplete: %lx (process %#x)", pDeviceInfo); 01335 CloseDevice(pDeviceInfo); 01336 UnregisterForDeviceChangeNotifications(pDeviceInfo); 01337 pDeviceInfo = FreeDeviceInfo(pDeviceInfo); 01338 continue; 01339 } 01340 01341 if (pDeviceInfo->usActions & GDIAF_IME_STATUS) { 01342 pDeviceInfo->usActions &= ~GDIAF_IME_STATUS; 01343 #if DBG 01344 nChanges++; 01345 #endif 01346 if ((pDeviceInfo->type == DEVICE_TYPE_KEYBOARD) && (pDeviceInfo->handle)) { 01347 if (FUJITSU_KBD_CONSOLE(pDeviceInfo->keyboard.Attr.KeyboardIdentifier) || 01348 (gbRemoteSession && 01349 FUJITSU_KBD_REMOTE(gRemoteClientKeyboardType)) 01350 ) { 01351 /* 01352 * Fill up the KEYBOARD_IME_STATUS structure. 01353 */ 01354 ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 01355 &giosbKbdControl, IOCTL_KEYBOARD_SET_IME_STATUS, 01356 (PVOID)&gKbdImeStatus, sizeof(gKbdImeStatus), NULL, 0); 01357 } 01358 } 01359 } 01360 01361 if (pDeviceInfo->usActions & GDIAF_RETRYREAD) { 01362 PDEVICEINFO pDeviceInfoNext; 01363 pDeviceInfo->usActions &= ~GDIAF_RETRYREAD; 01364 UserAssert(pDeviceInfo->ReadStatus == STATUS_INSUFFICIENT_RESOURCES); 01365 #if DBG 01366 timeStartReadPrev = pDeviceInfo->timeStartRead; 01367 #endif 01368 TAGMSG2(DBGTAG_PNP, "Retry Read %#p after %lx ticks", 01369 pDeviceInfo, pDeviceInfo->timeStartRead - timeStartReadPrev); 01370 pDeviceInfoNext = StartDeviceRead(pDeviceInfo); 01371 if (pDeviceInfoNext) { 01372 /* 01373 * pDeviceInfo wasa freed, move onto the next 01374 */ 01375 pDeviceInfo = pDeviceInfoNext; 01376 continue; 01377 } 01378 } 01379 01380 /* 01381 * Gather summary information on open devices 01382 */ 01383 if (pDeviceInfo->handle) { 01384 switch (pDeviceInfo->type) { 01385 case DEVICE_TYPE_MOUSE: 01386 UserAssert(PtiCurrentShared() == gTermIO.ptiDesktop); 01387 if (pDeviceInfo->usActions & GDIAF_REFRESH_MOUSE) { 01388 pDeviceInfo->usActions &= ~GDIAF_REFRESH_MOUSE; 01389 #if DBG 01390 nChanges++; 01391 #endif 01392 } 01393 nMice++; 01394 nMaxButtons = max(nMaxButtons, pDeviceInfo->mouse.Attr.NumberOfButtons); 01395 switch(pDeviceInfo->mouse.Attr.MouseIdentifier) { 01396 case WHEELMOUSE_I8042_HARDWARE: 01397 case WHEELMOUSE_SERIAL_HARDWARE: 01398 case WHEELMOUSE_HID_HARDWARE: 01399 nWheels++; 01400 } 01401 break; 01402 01403 case DEVICE_TYPE_KEYBOARD: 01404 UserAssert(PtiCurrentShared() == gptiRit); 01405 { 01406 NTSTATUS Status; 01407 // BUG BUG: why query each keyboard for indicators? They should all 01408 // be the same. 01409 #ifdef DIAGNOSE_IO 01410 gKbdIoctlLEDSStatus = 01411 #endif 01412 Status = ZwDeviceIoControlFile(pDeviceInfo->handle, NULL, NULL, NULL, 01413 &giosbKbdControl, IOCTL_KEYBOARD_QUERY_INDICATORS, 01414 NULL, 0, 01415 (PVOID)&gklpBootTime, sizeof(gklpBootTime)); 01416 UserAssertMsg2(NT_SUCCESS(Status), 01417 "IOCTL_KEYBOARD_QUERY_INDICATORS failed: DeviceInfo %#x, Status %#x", 01418 pDeviceInfo, Status); 01419 // BUG BUG, Don't handle multiple keyboards properly: the last 01420 // keyboard on the list is the one whose attributes we report! 01421 gKeyboardInfo = pDeviceInfo->keyboard.Attr; 01422 } 01423 nKeyboards++; 01424 break; 01425 01426 default: 01427 // Add code for a new type of input device here 01428 RIPMSG2(RIP_ERROR, "pDeviceInfo %#p has strange type %d", 01429 pDeviceInfo, pDeviceInfo->type); 01430 break; 01431 } 01432 } 01433 01434 /* 01435 * Notify the PnP thread that a change has been completed 01436 */ 01437 if (usOriginalActions & GDIAF_PNPWAITING) { 01438 KeSetEvent(pDeviceInfo->pkeHidChangeCompleted, EVENT_INCREMENT, FALSE); 01439 } 01440 01441 pDeviceInfo = pDeviceInfo->pNext; 01442 } 01443 01444 ENDATOMICDEVICEINFOLISTCHECK(); 01445 LeaveDeviceInfoListCrit(); 01446 01447 01448 switch (DeviceType) { 01449 case DEVICE_TYPE_MOUSE: 01450 /* 01451 * Apply summary information for Mice 01452 */ 01453 if (nMice) { 01454 if (gnMice == 0) { 01455 /* 01456 * We had no mouse before but we have one now: add a cursor 01457 */ 01458 SET_GTERMF(GTERMF_MOUSE); 01459 SYSMET(MOUSEPRESENT) = TRUE; 01460 SetGlobalCursorLevel(0); 01461 UserAssert(PpiFromProcess(gpepCSRSS)->ptiList->iCursorLevel == 0); 01462 UserAssert(PpiFromProcess(gpepCSRSS)->ptiList->pq->iCursorLevel == 0); 01463 GreMovePointer(gpDispInfo->hDev, gpsi->ptCursor.x, gpsi->ptCursor.y); 01464 } 01465 } else { 01466 if (gnMice != 0) { 01467 /* 01468 * We had a mouse before but we don't now: remove the cursor 01469 */ 01470 CLEAR_GTERMF(GTERMF_MOUSE); 01471 SYSMET(MOUSEPRESENT) = FALSE; 01472 SetGlobalCursorLevel(-1); 01473 /* 01474 * Don't leave mouse buttons stuck down, clear the global button 01475 * state here, otherwise weird stuff might happen. 01476 * Also do this in Alt-Tab processing and zzzCancelJournalling. 01477 */ 01478 #if DBG 01479 if (gwMouseOwnerButton) 01480 RIPMSG1(RIP_WARNING, 01481 "gwMouseOwnerButton=%x, being cleared forcibly\n", 01482 gwMouseOwnerButton); 01483 #endif 01484 gwMouseOwnerButton = 0; 01485 } 01486 } 01487 /* 01488 * Mouse button count represents the number of buttons on the mouse with 01489 * the most buttons. 01490 */ 01491 SYSMET(CMOUSEBUTTONS) = nMaxButtons; 01492 SYSMET(MOUSEWHEELPRESENT) = (nWheels > 0); 01493 gnMice = nMice; 01494 break; 01495 01496 case DEVICE_TYPE_KEYBOARD: 01497 /* 01498 * Apply summary information for Keyboards 01499 */ 01500 01501 if (nKeyboards > gnKeyboards) { 01502 /* 01503 * We have more keyboards, let set their LEDs properly 01504 */ 01505 UpdateKeyLights(FALSE); 01506 } 01507 01508 if ((nKeyboards != 0) && (gnKeyboards == 0)) { 01509 /* 01510 * We had no keyboard but we have one now: set the system hotkeys. 01511 */ 01512 SetDebugHotKeys(); 01513 } 01514 gnKeyboards = nKeyboards; 01515 break; 01516 01517 default: 01518 break; 01519 } 01520 01521 ENDATOMICCHECK(); 01522 } 01523 01524 /***************************************************************************\ 01525 * RequestDeviceChange() 01526 * 01527 * Flag the Device for the specified actions, then set its pkeHidChange to 01528 * trigger the RIT to perform the actions. 01529 * The current thread may not be able to do this if it is a PnP notification 01530 * from another process. 01531 * 01532 * History: 01533 * 01-20-99 IanJa Created. 01534 \***************************************************************************/ 01535 VOID RequestDeviceChange( 01536 PDEVICEINFO pDeviceInfo, 01537 USHORT usAction, 01538 BOOL fInDeviceInfoListCrit) 01539 { 01540 PDEVICE_TEMPLATE pDevTpl = &aDeviceTemplate[pDeviceInfo->type]; 01541 UserAssert(pDevTpl->pkeHidChange != NULL); 01542 UserAssert((usAction & GDIAF_FREEME) == 0); 01543 UserAssert((pDeviceInfo->usActions & GDIAF_PNPWAITING) == 0); 01544 01545 #if DBG 01546 if (pDeviceInfo->usActions != 0) { 01547 TAGMSG3(DBGTAG_PNP, "RequestDeviceChange(%#p, %x), but action %x pending", 01548 pDeviceInfo, usAction, pDeviceInfo->usActions); 01549 } 01550 01551 /* 01552 * We can't ask for synchronized actions to be performed on the Device List 01553 * if we are holding the Device List lock or the User Critical Section: 01554 * ProcessDeviceChanges() requires both of these itself. 01555 */ 01556 if (usAction & GDIAF_PNPWAITING) { 01557 CheckDeviceInfoListCritOut(); 01558 CheckCritOut(); 01559 } 01560 #endif 01561 01562 TAGMSG2(DBGTAG_PNP, "RequestDeviceChange(%p, %x)", pDeviceInfo, usAction); 01563 01564 /* 01565 * Grab the DeviceInfoList critical section if we don't already have it 01566 */ 01567 UserAssert(!fInDeviceInfoListCrit == !ExIsResourceAcquiredExclusiveLite(gpresDeviceInfoList)); 01568 if (fInDeviceInfoListCrit) { 01569 CheckDeviceInfoListCritIn(); 01570 pDeviceInfo->usActions |= usAction; 01571 } else { 01572 EnterDeviceInfoListCrit(); 01573 pDeviceInfo->usActions |= usAction; 01574 LeaveDeviceInfoListCrit(); 01575 } 01576 01577 if (usAction & GDIAF_PNPWAITING) { 01578 CheckDeviceInfoListCritOut(); 01579 KeSetEvent(pDevTpl->pkeHidChange, EVENT_INCREMENT, FALSE); 01580 KeWaitForSingleObject(pDeviceInfo->pkeHidChangeCompleted, WrUserRequest, KernelMode, FALSE, NULL); 01581 01582 EnterDeviceInfoListCrit(); 01583 /* 01584 * Assert that nothing else cleared GDIAF_PNPWAITING - only do it here. 01585 * Check that the action we were waiting for actually occurred. 01586 */ 01587 UserAssert(pDeviceInfo->usActions & GDIAF_PNPWAITING); 01588 pDeviceInfo->usActions &= ~GDIAF_PNPWAITING; 01589 UserAssert((pDeviceInfo->usActions & usAction) == 0); 01590 if (pDeviceInfo->usActions & GDIAF_FREEME) { 01591 FreeDeviceInfo(pDeviceInfo); 01592 } 01593 LeaveDeviceInfoListCrit(); 01594 } else { 01595 KeSetEvent(pDevTpl->pkeHidChange, EVENT_INCREMENT, FALSE); 01596 } 01597 }

Generated on Sat May 15 19:41:15 2004 for test by doxygen 1.3.7