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

pnp.c File Reference

#include "precomp.h"

Go to the source code of this file.

Classes

struct  _CDROM_NOTIFY

Defines

#define EVENT_CDROM_MEDIA_ARRIVAL   1
#define EVENT_CDROM_MEDIA_REMOVAL   2

Typedefs

typedef _CDROM_NOTIFY CDROM_NOTIFY
typedef _CDROM_NOTIFYPCDROM_NOTIFY

Functions

NTSTATUS Win32kPnPDriverEntry (IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING pustrRegistryPath)
VOID InitializeMediaChange (HANDLE hMediaRequestEvent)
__inline VOID EnterMediaCrit ()
__inline VOID LeaveMediaCrit ()
ULONG GetDeviceChangeInfo ()
NTSTATUS DeviceCDROMNotify (IN PTARGET_DEVICE_CUSTOM_NOTIFICATION Notification, IN PCDROM_NOTIFY pContext)
NTSTATUS DeviceClassCDROMNotify (IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION classChange, IN PVOID Unused)
PDEVICEINFO CreateDeviceInfo (DWORD DeviceType, PUNICODE_STRING pustrName, BYTE bFlags)
NTSTATUS DeviceClassNotify (IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION classChange, IN PVOID DeviceType)
BOOL OpenMultiplePortDevice (DWORD DeviceType)
NTSTATUS xxxRegisterForDeviceClassNotifications ()
NTSTATUS QueryDeviceInfo (PDEVICEINFO pDeviceInfo)
BOOL OpenDevice (PDEVICEINFO pDeviceInfo)
VOID CloseDevice (PDEVICEINFO pDeviceInfo)
BOOL RegisterForDeviceChangeNotifications (PDEVICEINFO pDeviceInfo)
BOOL UnregisterForDeviceChangeNotifications (PDEVICEINFO pDeviceInfo)
NTSTATUS DeviceNotify (IN PPLUGPLAY_NOTIFY_HDR pNotification, IN PDEVICEINFO pDeviceInfo)
PDEVICEINFO StartDeviceRead (PDEVICEINFO pDeviceInfo)
VOID ProcessDeviceChanges (DWORD DeviceType)
VOID RequestDeviceChange (PDEVICEINFO pDeviceInfo, USHORT usAction, BOOL fInDeviceInfoListCrit)

Variables

DEVICE_TEMPLATE aDeviceTemplate [DEVICE_TYPE_MAX+1]
NTSTATUS gKbdIoctlLEDSStatus = -1
LIST_ENTRY gMediaChangeList
PFAST_MUTEX gMediaChangeMutex
HANDLE gpEventMediaChange = NULL
UCHAR DriveLetterChange [26]


Define Documentation

#define EVENT_CDROM_MEDIA_ARRIVAL   1
 

Definition at line 70 of file w32/ntuser/kernel/pnp.c.

Referenced by DeviceCDROMNotify(), and GetDeviceChangeInfo().

#define EVENT_CDROM_MEDIA_REMOVAL   2
 

Definition at line 71 of file w32/ntuser/kernel/pnp.c.

Referenced by DeviceCDROMNotify().


Typedef Documentation

typedef struct _CDROM_NOTIFY CDROM_NOTIFY
 

typedef struct _CDROM_NOTIFY * PCDROM_NOTIFY
 

Referenced by DeviceCDROMNotify(), DeviceClassCDROMNotify(), and GetDeviceChangeInfo().


Function Documentation

VOID CloseDevice PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 885 of file w32/ntuser/kernel/pnp.c.

References CheckCritIn, NT_SUCCESS, NTSTATUS(), PsGetCurrentThread, Status, and VOID().

Referenced by ProcessDeviceChanges().

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 }

PDEVICEINFO CreateDeviceInfo DWORD  DeviceType,
PUNICODE_STRING  pustrName,
BYTE  bFlags
 

Definition at line 406 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, BEGINATOMICCHECK, BYTE, CheckCritIn, CreateKernelEvent(), DEVICE_TYPE_MAX, ENDATOMICCHECK, EnterDeviceInfoListCrit(), EXITATOMICCHECK, FALSE, GDIAF_ARRIVED, gpDeviceInfoList, LeaveDeviceInfoListCrit(), NULL, RequestDeviceChange(), RtlCopyUnicodeString(), and TRUE.

Referenced by DeviceClassNotify(), OpenMultiplePortDevice(), and RawInputThread().

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 }

NTSTATUS DeviceCDROMNotify IN PTARGET_DEVICE_CUSTOM_NOTIFICATION  Notification,
IN PCDROM_NOTIFY  pContext
 

Definition at line 248 of file w32/ntuser/kernel/pnp.c.

References CheckCritOut, EnterMediaCrit(), _CDROM_NOTIFY::Entry, EVENT_CDROM_MEDIA_ARRIVAL, EVENT_CDROM_MEDIA_REMOVAL, EVENT_INCREMENT, FALSE, gbRemoteSession, gMediaChangeList, gpEventMediaChange, IoUnregisterPlugPlayNotification(), KeSetEvent(), LeaveMediaCrit(), NTSTATUS(), PCDROM_NOTIFY, PTARGET_DEVICE_CUSTOM_NOTIFICATION, and _CDROM_NOTIFY::Size.

Referenced by DeviceClassCDROMNotify().

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 }

NTSTATUS DeviceClassCDROMNotify IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION  classChange,
IN PVOID  Unused
 

Definition at line 310 of file w32/ntuser/kernel/pnp.c.

References CheckCritOut, DeviceCDROMNotify(), _CDROM_NOTIFY::DeviceName, EventCategoryTargetDeviceChange, gpWin32kDriverObject, IoGetDeviceObjectPointer(), IoRegisterPlugPlayNotification(), NT_SUCCESS, NTSTATUS(), ObDereferenceObject, PCDROM_NOTIFY, PDEVICE_INTERFACE_CHANGE_NOTIFICATION, _CDROM_NOTIFY::RegistrationHandle, _CDROM_NOTIFY::Size, Size, and Status.

Referenced by xxxRegisterForDeviceClassNotifications().

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 }

NTSTATUS DeviceClassNotify IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION  classChange,
IN PVOID  DeviceType
 

Definition at line 503 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, CheckCritOut, CreateDeviceInfo(), DEVICE_TYPE_KEYBOARD, DEVICE_TYPE_MOUSE, DWORD, EnterCrit, LeaveCrit, and tagDEVICE_TEMPLATE::pClassGUID.

Referenced by xxxRegisterForDeviceClassNotifications().

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 }

NTSTATUS DeviceNotify IN PPLUGPLAY_NOTIFY_HDR  pNotification,
IN PDEVICEINFO  pDeviceInfo
 

Definition at line 1025 of file w32/ntuser/kernel/pnp.c.

References CheckCritOut, CheckDeviceInfoListCritOut, FALSE, gbRemoteSession, GDIAF_DEPARTED, GDIAF_PNPWAITING, GDIAF_QUERYREMOVE, GDIAF_REMOVECANCELLED, gpDeviceInfoList, NTSTATUS(), NULL, PsGetCurrentThread, RequestDeviceChange(), and USHORT.

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 }

__inline VOID EnterMediaCrit  ) 
 

Definition at line 142 of file w32/ntuser/kernel/pnp.c.

References ExAcquireFastMutexUnsafe(), gMediaChangeMutex, KeEnterCriticalRegion, and VOID().

Referenced by DeviceCDROMNotify(), and GetDeviceChangeInfo().

00142 { 00143 KeEnterCriticalRegion(); 00144 ExAcquireFastMutexUnsafe(gMediaChangeMutex); 00145 }

ULONG GetDeviceChangeInfo  ) 
 

Definition at line 162 of file w32/ntuser/kernel/pnp.c.

References _CDROM_NOTIFY::DeviceName, EnterMediaCrit(), _CDROM_NOTIFY::Event, EVENT_CDROM_MEDIA_ARRIVAL, Executive, FALSE, gMediaChangeList, IoBuildDeviceIoControlRequest(), IoCallDriver, IoGetDeviceObjectPointer(), ISCSRSS, KeInitializeEvent, KernelMode, KeWaitForSingleObject(), LeaveMediaCrit(), NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, PCDROM_NOTIFY, and RtlInitUnicodeString().

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 }

VOID InitializeMediaChange HANDLE  hMediaRequestEvent  ) 
 

Definition at line 119 of file w32/ntuser/kernel/pnp.c.

References ExEventObjectType, ExInitializeFastMutex, gbRemoteSession, gMediaChangeList, gMediaChangeMutex, gpEventMediaChange, KernelMode, NULL, and ObReferenceObjectByHandle().

Referenced by NtUserInitialize().

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 }

__inline VOID LeaveMediaCrit  ) 
 

Definition at line 147 of file w32/ntuser/kernel/pnp.c.

References ExReleaseFastMutexUnsafe(), gMediaChangeMutex, KeLeaveCriticalRegion, and VOID().

Referenced by DeviceCDROMNotify(), and GetDeviceChangeInfo().

00147 { 00148 ExReleaseFastMutexUnsafe(gMediaChangeMutex); 00149 KeLeaveCriticalRegion(); 00150 }

BOOL OpenDevice PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 807 of file w32/ntuser/kernel/pnp.c.

References BOOL, CheckCritIn, DEVICE_TYPE_KEYBOARD, DEVICE_TYPE_MOUSE, FALSE, gbRemoteSession, GDIF_NOTPNP, ghRemoteKeyboardChannel, ghRemoteMouseChannel, gptiRit, gTermIO, NT_SUCCESS, NTSTATUS(), NULL, ObjectAttributes, PsGetCurrentThread, PtiCurrentShared, tagTERMINAL::ptiDesktop, QueryDeviceInfo(), Status, and ZwCreateFile().

Referenced by ProcessDeviceChanges().

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 }

BOOL OpenMultiplePortDevice DWORD  DeviceType  ) 
 

Definition at line 565 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, CheckCritIn, CreateDeviceInfo(), DEVICE_TYPE_MAX, FALSE, FastGetProfileDwordW(), FastGetProfileStringW(), GDIF_NOTPNP, gpWin32kDriverObject, L, MAX_PATH, NULL, PMAP_INPUT, tagDEVICE_TEMPLATE::pwszClassName, tagDEVICE_TEMPLATE::pwszDefDevName, tagDEVICE_TEMPLATE::pwszLegacyDevName, RtlAppendUnicodeToString(), RtlInitUnicodeString(), TRUE, UINT, and tagDEVICE_TEMPLATE::uiRegistrySection.

Referenced by xxxRegisterForDeviceClassNotifications().

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 }

VOID ProcessDeviceChanges DWORD  DeviceType  ) 
 

Definition at line 1191 of file w32/ntuser/kernel/pnp.c.

References tagKEYBOARD_DEVICE_INFO::Attr, tagMOUSE_DEVICE_INFO::Attr, BEGINATOMICCHECK, BEGINATOMICDEVICEINFOLISTCHECK, CheckCritIn, CLEAR_GTERMF, CloseDevice(), DEVICE_TYPE_KEYBOARD, DEVICE_TYPE_MOUSE, DWORD, ENDATOMICCHECK, ENDATOMICDEVICEINFOLISTCHECK, EnterDeviceInfoListCrit(), EVENT_INCREMENT, FALSE, FreeDeviceInfo(), gbRemoteSession, GDIAF_ARRIVED, GDIAF_DEPARTED, GDIAF_IME_STATUS, GDIAF_PNPWAITING, GDIAF_QUERYREMOVE, GDIAF_RECONNECT, GDIAF_REFRESH_MOUSE, GDIAF_REMOVECANCELLED, GDIAF_RETRYREAD, giosbKbdControl, gKbdImeStatus, gKbdIoctlLEDSStatus, gKeyboardInfo, gklpBootTime, gnKeyboards, gnMice, gpDeviceInfoList, gpDispInfo, gpepCSRSS, gpsi, gptiRit, gRemoteClientKeyboardType, GTERMF_MOUSE, gTermIO, gwMouseOwnerButton, tagDISPLAYINFO::hDev, KeSetEvent(), tagDEVICEINFO::keyboard, LeaveDeviceInfoListCrit(), max, tagDEVICEINFO::mouse, NT_SUCCESS, NTSTATUS(), NULL, OpenDevice(), PpiFromProcess, PtiCurrentShared, tagTERMINAL::ptiDesktop, QueryDeviceInfo(), RegisterForDeviceChangeNotifications(), SET_GTERMF, SetDebugHotKeys(), SetGlobalCursorLevel(), StartDeviceRead(), Status, SYSMET, TRUE, UnregisterForDeviceChangeNotifications(), UpdateKeyLights(), USHORT, and VOID().

Referenced by RawInputThread(), and xxxDesktopThread().

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 }

NTSTATUS QueryDeviceInfo PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 761 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, tagDEVICE_TEMPLATE::cbAttr, tagDEVICE_TEMPLATE::IOCTL_Attr, NT_SUCCESS, NTSTATUS(), NULL, tagDEVICE_TEMPLATE::offAttr, PBYTE, and Status.

Referenced by OpenDevice(), and ProcessDeviceChanges().

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 }

BOOL RegisterForDeviceChangeNotifications PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 929 of file w32/ntuser/kernel/pnp.c.

References BOOL, CheckCritIn, DeviceNotify(), EventCategoryTargetDeviceChange, GDIF_NOTPNP, gptiRit, gpWin32kDriverObject, gTermIO, IoRegisterPlugPlayNotification(), KernelMode, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), PsGetCurrentThread, PtiCurrentShared, tagTERMINAL::ptiDesktop, Status, and TRUE.

Referenced by ProcessDeviceChanges().

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 }

VOID RequestDeviceChange PDEVICEINFO  pDeviceInfo,
USHORT  usAction,
BOOL  fInDeviceInfoListCrit
 

Definition at line 1535 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, CheckCritOut, CheckDeviceInfoListCritIn, CheckDeviceInfoListCritOut, EnterDeviceInfoListCrit(), EVENT_INCREMENT, ExIsResourceAcquiredExclusiveLite(), FALSE, FreeDeviceInfo(), GDIAF_FREEME, GDIAF_PNPWAITING, gpresDeviceInfoList, KernelMode, KeSetEvent(), KeWaitForSingleObject(), LeaveDeviceInfoListCrit(), NULL, tagDEVICE_TEMPLATE::pkeHidChange, VOID(), and WrUserRequest.

Referenced by CreateDeviceInfo(), DeviceNotify(), NlsKbdSendIMENotification(), ProcessMouseInput(), and UpdateMouseInfo().

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 }

PDEVICEINFO StartDeviceRead PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 1099 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, BOOL, tagDEVICE_TEMPLATE::cbData, EnterDeviceInfoListCrit(), ExIsResourceAcquiredExclusiveLite(), FreeDeviceInfo(), GDIAF_FREEME, GDIAF_RETRYREAD, GDIF_DBGREAD, GDIF_READING, gnRetryReadInput, gpresDeviceInfoList, InputApc(), ISTS, LeaveDeviceInfoListCrit(), LOGTIME, MAXIMUM_READ_RETRIES, NT_SUCCESS, NULL, tagDEVICE_TEMPLATE::offData, PBYTE, PsGetCurrentThread, and PZERO.

Referenced by InputApc(), and ProcessDeviceChanges().

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 }

BOOL UnregisterForDeviceChangeNotifications PDEVICEINFO  pDeviceInfo  ) 
 

Definition at line 981 of file w32/ntuser/kernel/pnp.c.

References BOOL, CheckCritIn, FALSE, GDIF_NOTPNP, gptiRit, gTermIO, IoUnregisterPlugPlayNotification(), NT_SUCCESS, NTSTATUS(), NULL, PsGetCurrentThread, PtiCurrentShared, tagTERMINAL::ptiDesktop, Status, and TRUE.

Referenced by ProcessDeviceChanges().

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 }

NTSTATUS Win32kPnPDriverEntry IN PDRIVER_OBJECT  DriverObject,
IN PUNICODE_STRING  pustrRegistryPath
 

Definition at line 90 of file w32/ntuser/kernel/pnp.c.

References gpWin32kDriverObject.

Referenced by xxxRegisterForDeviceClassNotifications().

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 }

NTSTATUS xxxRegisterForDeviceClassNotifications  ) 
 

Definition at line 639 of file w32/ntuser/kernel/pnp.c.

References aDeviceTemplate, CheckCritIn, DEVICE_TYPE_MAX, DeviceClassCDROMNotify(), DeviceClassNotify(), DWORD, EnterCrit, EventCategoryDeviceInterfaceChange, gbRemoteSession, gpWin32kDriverObject, IO_NOTIFICATION_EVENT_CATEGORY, IoCreateDriver(), IoRegisterPlugPlayNotification(), L, LeaveCrit, NT_SUCCESS, NTSTATUS(), NULL, OpenMultiplePortDevice(), PDRIVER_NOTIFICATION_CALLBACK_ROUTINE, PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, RtlInitUnicodeString(), Status, and Win32kPnPDriverEntry().

Referenced by RawInputThread().

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 }


Variable Documentation

DEVICE_TEMPLATE aDeviceTemplate[DEVICE_TYPE_MAX+1]
 

Definition at line 17 of file w32/ntuser/kernel/pnp.c.

Referenced by CreateDeviceInfo(), DeviceClassNotify(), InputApc(), OpenMultiplePortDevice(), QueryDeviceInfo(), RawInputThread(), RequestDeviceChange(), StartDeviceRead(), Win32kNtUserCleanup(), xxxDesktopThread(), and xxxRegisterForDeviceClassNotifications().

UCHAR DriveLetterChange[26]
 

Definition at line 69 of file w32/ntuser/kernel/pnp.c.

NTSTATUS gKbdIoctlLEDSStatus = -1
 

Definition at line 54 of file w32/ntuser/kernel/pnp.c.

Referenced by ProcessDeviceChanges().

LIST_ENTRY gMediaChangeList
 

Definition at line 66 of file w32/ntuser/kernel/pnp.c.

Referenced by DeviceCDROMNotify(), GetDeviceChangeInfo(), and InitializeMediaChange().

PFAST_MUTEX gMediaChangeMutex
 

Definition at line 67 of file w32/ntuser/kernel/pnp.c.

Referenced by EnterMediaCrit(), InitializeMediaChange(), and LeaveMediaCrit().

HANDLE gpEventMediaChange = NULL
 

Definition at line 68 of file w32/ntuser/kernel/pnp.c.

Referenced by DeviceCDROMNotify(), and InitializeMediaChange().


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