Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1041 lines
28 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name :
  4. common.c
  5. Abstract:
  6. Common code for the Windows CE
  7. USB Serial Host and Filter drivers
  8. Author:
  9. Jeff Midkiff (jeffmi) 08-24-99
  10. --*/
  11. #include <stdio.h>
  12. #include "wceusbsh.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGEWCE0, QueryRegistryParameters)
  15. #pragma alloc_text(PAGEWCE0, CreateDevObjAndSymLink)
  16. #pragma alloc_text(PAGEWCE0, DeleteDevObjAndSymLink)
  17. #pragma alloc_text(PAGEWCE0, IsWin9x)
  18. #pragma alloc_text(PAGEWCE1, LogError)
  19. #endif
  20. NTSTATUS
  21. QueryRegistryParameters(
  22. IN PUNICODE_STRING RegistryPath
  23. )
  24. /*++
  25. This routine queryies the Registry for our Parameters key.
  26. We are given the RegistryPath to our driver during DriverEntry,
  27. but don't yet have an extension, so we store the values in globals
  28. until we get our device extension.
  29. The values are setup from our INF.
  30. On WinNT this is under
  31. HKLM\SYSTEM\ControlSet\Services\wceusbsh\Parameters
  32. On Win98 this is under
  33. HKLM\System\CurrentControlSet\Services\Class\WCESUSB\000*
  34. Returns - nothing; use defaults
  35. --*/
  36. {
  37. #define NUM_REG_ENTRIES 6
  38. RTL_QUERY_REGISTRY_TABLE rtlQueryRegTbl[ NUM_REG_ENTRIES + 1 ];
  39. ULONG sizeOfUl = sizeof( ULONG );
  40. ULONG ulAlternateSetting = DEFAULT_ALTERNATE_SETTING;
  41. LONG lIntTimout = DEFAULT_INT_PIPE_TIMEOUT;
  42. ULONG ulMaxPipeErrors = DEFAULT_MAX_PIPE_DEVICE_ERRORS;
  43. ULONG ulDebugLevel = DBG_OFF;
  44. ULONG ulExposeComPort = FALSE;
  45. NTSTATUS status = STATUS_SUCCESS;
  46. PAGED_CODE();
  47. ASSERT( RegistryPath != NULL );
  48. RtlZeroMemory( rtlQueryRegTbl, sizeof(rtlQueryRegTbl) );
  49. //
  50. // Setup the query table
  51. // Note: the 1st table entry is the \Parameters subkey,
  52. // and the last table entry is NULL
  53. //
  54. rtlQueryRegTbl[0].QueryRoutine = NULL;
  55. rtlQueryRegTbl[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
  56. rtlQueryRegTbl[0].Name = L"Parameters";
  57. rtlQueryRegTbl[0].EntryContext = NULL;
  58. rtlQueryRegTbl[0].DefaultType = (ULONG_PTR)NULL;
  59. rtlQueryRegTbl[0].DefaultData = NULL;
  60. rtlQueryRegTbl[0].DefaultLength = (ULONG_PTR)NULL;
  61. rtlQueryRegTbl[1].QueryRoutine = NULL;
  62. rtlQueryRegTbl[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  63. rtlQueryRegTbl[1].Name = L"DebugLevel";
  64. rtlQueryRegTbl[1].EntryContext = &DebugLevel;
  65. rtlQueryRegTbl[1].DefaultType = REG_DWORD;
  66. rtlQueryRegTbl[1].DefaultData = &ulDebugLevel;
  67. rtlQueryRegTbl[1].DefaultLength = sizeOfUl;
  68. rtlQueryRegTbl[2].QueryRoutine = NULL;
  69. rtlQueryRegTbl[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  70. rtlQueryRegTbl[2].Name = L"AlternateSetting";
  71. rtlQueryRegTbl[2].EntryContext = &g_ulAlternateSetting;
  72. rtlQueryRegTbl[2].DefaultType = REG_DWORD;
  73. rtlQueryRegTbl[2].DefaultData = &ulAlternateSetting;
  74. rtlQueryRegTbl[2].DefaultLength = sizeOfUl;
  75. rtlQueryRegTbl[3].QueryRoutine = NULL;
  76. rtlQueryRegTbl[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  77. rtlQueryRegTbl[3].Name = L"InterruptTimeout";
  78. rtlQueryRegTbl[3].EntryContext = &g_lIntTimout;
  79. rtlQueryRegTbl[3].DefaultType = REG_DWORD;
  80. rtlQueryRegTbl[3].DefaultData = &lIntTimout;
  81. rtlQueryRegTbl[3].DefaultLength = sizeOfUl;
  82. rtlQueryRegTbl[4].QueryRoutine = NULL;
  83. rtlQueryRegTbl[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  84. rtlQueryRegTbl[4].Name = L"MaxPipeErrors";
  85. rtlQueryRegTbl[4].EntryContext = &g_ulMaxPipeErrors;
  86. rtlQueryRegTbl[4].DefaultType = REG_DWORD;
  87. rtlQueryRegTbl[4].DefaultData = &ulMaxPipeErrors;
  88. rtlQueryRegTbl[4].DefaultLength = sizeOfUl;
  89. rtlQueryRegTbl[5].QueryRoutine = NULL;
  90. rtlQueryRegTbl[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  91. rtlQueryRegTbl[5].Name = L"ExposeComPort";
  92. rtlQueryRegTbl[5].EntryContext = &g_ExposeComPort;
  93. rtlQueryRegTbl[5].DefaultType = REG_DWORD;
  94. rtlQueryRegTbl[5].DefaultData = &ulExposeComPort;
  95. rtlQueryRegTbl[5].DefaultLength = sizeOfUl;
  96. //
  97. // query the Registry
  98. //
  99. status = RtlQueryRegistryValues(
  100. RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, // RelativeTo
  101. RegistryPath->Buffer, // Path
  102. rtlQueryRegTbl, // QueryTable
  103. NULL, // Context
  104. NULL ); // Environment
  105. if ( !NT_SUCCESS( status ) ) {
  106. //
  107. // if registry query failed then use defaults
  108. //
  109. DbgDump( DBG_INIT, ("RtlQueryRegistryValues error: 0x%x\n", status) );
  110. g_ulAlternateSetting = ulAlternateSetting;
  111. g_lIntTimout = lIntTimout;
  112. g_ulMaxPipeErrors = ulMaxPipeErrors;
  113. DebugLevel = DBG_OFF;
  114. }
  115. DbgDump( DBG_INIT, ("DebugLevel = 0x%x\n", DebugLevel));
  116. DbgDump( DBG_INIT, ("AlternateSetting = %d\n", g_ulAlternateSetting));
  117. DbgDump( DBG_INIT, ("MaxPipeErrors = %d\n", g_ulMaxPipeErrors));
  118. DbgDump( DBG_INIT, ("INT Timeout = %d\n", g_lIntTimout));
  119. return status;
  120. }
  121. VOID
  122. ReleaseSlot(
  123. IN LONG Slot
  124. )
  125. {
  126. LONG lNumDevices = InterlockedDecrement(&g_NumDevices);
  127. UNREFERENCED_PARAMETER( Slot );
  128. ASSERT( lNumDevices >= 0);
  129. return;
  130. }
  131. NTSTATUS
  132. AcquireSlot(
  133. OUT PULONG PSlot
  134. )
  135. {
  136. NTSTATUS status = STATUS_SUCCESS;
  137. *PSlot = InterlockedIncrement(&g_NumDevices);
  138. if (*PSlot == (ULONG)0) {
  139. status = STATUS_INVALID_DEVICE_REQUEST;
  140. }
  141. return status;
  142. }
  143. NTSTATUS
  144. CreateDevObjAndSymLink(
  145. IN PDRIVER_OBJECT PDrvObj,
  146. IN PDEVICE_OBJECT PPDO,
  147. IN PDEVICE_OBJECT *PpDevObj,
  148. IN PCHAR PDevName
  149. )
  150. /*++
  151. Routine Description:
  152. Creates a named device object and symbolic link
  153. for the next available device instance. Saves both the \\Device\\PDevName%n
  154. and \\DosDevices\\PDevName%n in the device extension.
  155. Also registers our device interface with PnP system.
  156. Arguments:
  157. PDrvObj - Pointer to our driver object
  158. PPDO - Pointer to the PDO for the stack to which we should add ourselves
  159. PDevName - device name to use
  160. Return Value:
  161. NTSTATUS
  162. --*/
  163. {
  164. PDEVICE_EXTENSION pDevExt = NULL;
  165. NTSTATUS status;
  166. ULONG deviceInstance;
  167. ULONG bufferLen;
  168. BOOLEAN gotSlot = FALSE;
  169. ANSI_STRING asDevName;
  170. ANSI_STRING asDosDevName;
  171. UNICODE_STRING usDeviceName = {0}; // seen only in kernel-mode namespace
  172. UNICODE_STRING usDosDevName = {0}; // seen in user-mode namespace
  173. CHAR dosDeviceNameBuffer[DOS_NAME_MAX];
  174. CHAR deviceNameBuffer[DOS_NAME_MAX];
  175. DbgDump(DBG_INIT, (">CreateDevObjAndSymLink\n"));
  176. PAGED_CODE();
  177. ASSERT( PPDO );
  178. //
  179. // init the callers device obj
  180. //
  181. *PpDevObj = NULL;
  182. //
  183. // Get the next device instance number
  184. //
  185. status = AcquireSlot(&deviceInstance);
  186. if (status != STATUS_SUCCESS) {
  187. DbgDump(DBG_ERR, ("AcquireSlot error: 0x%x\n", status));
  188. goto CreateDeviceObjectError;
  189. } else {
  190. gotSlot = TRUE;
  191. }
  192. //
  193. // concat device name & instance number
  194. //
  195. ASSERT( *PDevName != (CHAR)NULL);
  196. sprintf(dosDeviceNameBuffer, "%s%s%03d", "\\DosDevices\\", PDevName,
  197. deviceInstance);
  198. sprintf(deviceNameBuffer, "%s%s%03d", "\\Device\\", PDevName,
  199. deviceInstance);
  200. // convert names to ANSI string
  201. RtlInitAnsiString(&asDevName, deviceNameBuffer);
  202. RtlInitAnsiString(&asDosDevName, dosDeviceNameBuffer);
  203. usDeviceName.Length = 0;
  204. usDeviceName.Buffer = NULL;
  205. usDosDevName.Length = 0;
  206. usDosDevName.Buffer = NULL;
  207. //
  208. // convert names to UNICODE
  209. //
  210. status = RtlAnsiStringToUnicodeString(&usDeviceName, &asDevName, TRUE);
  211. if (status != STATUS_SUCCESS) {
  212. DbgDump(DBG_ERR, ("RtlAnsiStringToUnicodeString error: 0x%x\n", status));
  213. goto CreateDeviceObjectError;
  214. }
  215. status = RtlAnsiStringToUnicodeString(&usDosDevName, &asDosDevName, TRUE);
  216. if (status != STATUS_SUCCESS) {
  217. DbgDump(DBG_ERR, ("RtlAnsiStringToUnicodeString error: 0x%x\n", status));
  218. goto CreateDeviceObjectError;
  219. }
  220. //
  221. // create the named devive object
  222. // Note: we may want to change this to a non-exclusive later
  223. // so xena to come in without the filter.
  224. //
  225. status = IoCreateDevice( PDrvObj,
  226. sizeof(DEVICE_EXTENSION),
  227. &usDeviceName,
  228. FILE_DEVICE_SERIAL_PORT,
  229. 0,
  230. TRUE, // Note: SerialPorts are exclusive
  231. PpDevObj);
  232. if (status != STATUS_SUCCESS) {
  233. DbgDump(DBG_ERR, ("IoCreateDevice error: 0x%x\n", status));
  234. TEST_TRAP();
  235. goto CreateDeviceObjectError;
  236. }
  237. //
  238. // get pointer to device extension
  239. //
  240. pDevExt = (PDEVICE_EXTENSION) (*PpDevObj)->DeviceExtension;
  241. RtlZeroMemory(pDevExt, sizeof(DEVICE_EXTENSION)); // (redundant)
  242. //
  243. // init SERIAL_PORT_INTERFACE
  244. //
  245. pDevExt->SerialPort.Type = WCE_SERIAL_PORT_TYPE;
  246. //
  247. // create symbolic link
  248. //
  249. status = IoCreateUnprotectedSymbolicLink(&usDosDevName, &usDeviceName);
  250. if (status != STATUS_SUCCESS) {
  251. DbgDump(DBG_ERR, ("IoCreateUnprotectedSymbolicLink error: 0x%x\n", status));
  252. goto CreateDeviceObjectError;
  253. }
  254. DbgDump(DBG_INIT, ("SymbolicLink: %ws\n", usDosDevName.Buffer));
  255. //
  256. // Make the device visible via a device association as well.
  257. // The reference string is the eight digit device index
  258. //
  259. status = IoRegisterDeviceInterface(
  260. PPDO,
  261. (LPGUID)&GUID_WCE_SERIAL_USB,
  262. NULL,
  263. &pDevExt->DeviceClassSymbolicName );
  264. if (status != STATUS_SUCCESS) {
  265. DbgDump(DBG_ERR, ("IoRegisterDeviceInterface error: 0x%x\n", status));
  266. pDevExt->DeviceClassSymbolicName.Buffer = NULL;
  267. goto CreateDeviceObjectError;
  268. }
  269. DbgDump(DBG_INIT, ("DeviceClassSymbolicName: %ws\n", pDevExt->DeviceClassSymbolicName.Buffer));
  270. //
  271. // save the Dos Device link name in our extension
  272. //
  273. strcpy(pDevExt->DosDeviceName, dosDeviceNameBuffer);
  274. pDevExt->SymbolicLink = TRUE;
  275. //
  276. // save (kernel) device name in extension
  277. //
  278. bufferLen = RtlAnsiStringToUnicodeSize(&asDevName);
  279. pDevExt->DeviceName.Length = 0;
  280. pDevExt->DeviceName.MaximumLength = (USHORT)bufferLen;
  281. pDevExt->DeviceName.Buffer = ExAllocatePool(PagedPool, bufferLen);
  282. if (pDevExt->DeviceName.Buffer == NULL) {
  283. //
  284. // Skip out. We have worse problems than missing
  285. // the name if we have no memory at this point.
  286. //
  287. status = STATUS_INSUFFICIENT_RESOURCES;
  288. DbgDump(DBG_ERR, ("CreateDevObjAndSymLink ERROR: 0x%x\n", status));
  289. goto CreateDeviceObjectError;
  290. }
  291. RtlAnsiStringToUnicodeString(&pDevExt->DeviceName, &asDevName, FALSE);
  292. // save 1's based device instance number
  293. pDevExt->SerialPort.Com.Instance = deviceInstance;
  294. CreateDeviceObjectError:;
  295. //
  296. // free Unicode strings
  297. //
  298. RtlFreeUnicodeString(&usDeviceName);
  299. RtlFreeUnicodeString(&usDosDevName);
  300. //
  301. // Delete the devobj if there was an error
  302. //
  303. if (status != STATUS_SUCCESS) {
  304. if ( *PpDevObj ) {
  305. DeleteDevObjAndSymLink( *PpDevObj );
  306. *PpDevObj = NULL;
  307. }
  308. if (gotSlot) {
  309. ReleaseSlot(deviceInstance);
  310. }
  311. }
  312. DbgDump(DBG_INIT, ("<CreateDevObjAndSymLink 0x%x\n", status));
  313. return status;
  314. }
  315. NTSTATUS
  316. DeleteDevObjAndSymLink(
  317. IN PDEVICE_OBJECT PDevObj
  318. )
  319. {
  320. PDEVICE_EXTENSION pDevExt;
  321. UNICODE_STRING usDevLink;
  322. ANSI_STRING asDevLink;
  323. NTSTATUS NtStatus = STATUS_SUCCESS;
  324. DbgDump(DBG_INIT, (">DeleteDevObjAndSymLink\n"));
  325. PAGED_CODE();
  326. ASSERT( PDevObj );
  327. pDevExt = (PDEVICE_EXTENSION) PDevObj->DeviceExtension;
  328. ASSERT( pDevExt );
  329. // get rid of the symbolic link
  330. if ( pDevExt->SymbolicLink ) {
  331. RtlInitAnsiString( &asDevLink, pDevExt->DosDeviceName );
  332. NtStatus = RtlAnsiStringToUnicodeString( &usDevLink,
  333. &asDevLink, TRUE);
  334. ASSERT(STATUS_SUCCESS == NtStatus);
  335. NtStatus = IoDeleteSymbolicLink(&usDevLink);
  336. }
  337. if (pDevExt->DeviceClassSymbolicName.Buffer)
  338. {
  339. NtStatus = IoSetDeviceInterfaceState(&pDevExt->DeviceClassSymbolicName, FALSE);
  340. if (NT_SUCCESS(NtStatus)) {
  341. DbgDump(DBG_WRN, ("IoSetDeviceInterfaceState.3: OFF\n"));
  342. }
  343. ExFreePool( pDevExt->DeviceClassSymbolicName.Buffer );
  344. pDevExt->DeviceClassSymbolicName.Buffer = NULL;
  345. }
  346. if (pDevExt->DeviceName.Buffer != NULL) {
  347. ExFreePool(pDevExt->DeviceName.Buffer);
  348. RtlInitUnicodeString(&pDevExt->DeviceName, NULL);
  349. }
  350. //
  351. // Wait to do this untill here as this triggers the unload routine
  352. // at which point everything better have been deallocated
  353. //
  354. IoDeleteDevice( PDevObj );
  355. DbgDump(DBG_INIT, ("<DeleteDevObjAndSymLink\n"));
  356. return NtStatus;
  357. }
  358. #if 0
  359. VOID
  360. SetBooleanLocked(
  361. IN OUT PBOOLEAN PDest,
  362. IN BOOLEAN Src,
  363. IN PKSPIN_LOCK PSpinLock
  364. )
  365. /*++
  366. Routine Description:
  367. This function is used to assign a BOOLEAN value with spinlock protection.
  368. Arguments:
  369. PDest - A pointer to Lval.
  370. Src - Rval.
  371. PSpinLock - Pointer to the spin lock we should hold.
  372. Return Value:
  373. None.
  374. --*/
  375. {
  376. KIRQL tmpIrql;
  377. KeAcquireSpinLock(PSpinLock, &tmpIrql);
  378. *PDest = Src;
  379. KeReleaseSpinLock(PSpinLock, tmpIrql);
  380. }
  381. #endif
  382. VOID
  383. SetPVoidLocked(
  384. IN OUT PVOID *PDest,
  385. IN OUT PVOID Src,
  386. IN PKSPIN_LOCK PSpinLock
  387. )
  388. {
  389. KIRQL tmpIrql;
  390. KeAcquireSpinLock(PSpinLock, &tmpIrql);
  391. *PDest = Src;
  392. KeReleaseSpinLock(PSpinLock, tmpIrql);
  393. }
  394. //
  395. // Note: had to use ExWorkItems to be binary compatible with Win98.
  396. // The WorkerRoutine must take as it's only parameter a PWCE_WORK_ITEM
  397. // and extract any parameters. When the WorkerRoutine is complete is MUST
  398. // call DequeueWorkItem to free it back to the worker pool & signal any waiters.
  399. //
  400. NTSTATUS
  401. QueueWorkItem(
  402. IN PDEVICE_OBJECT PDevObj,
  403. IN PWCE_WORKER_THREAD_ROUTINE WorkerRoutine,
  404. IN PVOID Context,
  405. IN ULONG Flags
  406. )
  407. {
  408. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  409. NTSTATUS status = STATUS_INVALID_PARAMETER;
  410. PWCE_WORK_ITEM pWorkItem;
  411. KIRQL irql;
  412. DbgDump(DBG_WORK_ITEMS, (">QueueWorkItem\n" ));
  413. //
  414. // N.B: you need to ensure your driver does not queue anything when it is stopped.
  415. //
  416. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  417. if ( !CanAcceptIoRequests(PDevObj, FALSE, TRUE) ) {
  418. status = STATUS_DELETE_PENDING;
  419. DbgDump(DBG_ERR, ("QueueWorkItem: 0x%x\n", status));
  420. } else if ( PDevObj && WorkerRoutine ) {
  421. pWorkItem = ExAllocateFromNPagedLookasideList( &pDevExt->WorkItemPool );
  422. if ( pWorkItem ) {
  423. status = AcquireRemoveLock(&pDevExt->RemoveLock, pWorkItem);
  424. if ( !NT_SUCCESS(status) ) {
  425. DbgDump(DBG_ERR, ("QueueWorkItem: 0x%x\n", status));
  426. TEST_TRAP();
  427. ExFreeToNPagedLookasideList( &pDevExt->WorkItemPool, pWorkItem );
  428. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  429. return status;
  430. }
  431. RtlZeroMemory( pWorkItem, sizeof(*pWorkItem) );
  432. // bump the pending count
  433. InterlockedIncrement(&pDevExt->PendingWorkItemsCount);
  434. DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsCount: %d\n", pDevExt->PendingWorkItemsCount));
  435. //
  436. // put the worker on our pending list
  437. //
  438. InsertTailList(&pDevExt->PendingWorkItems,
  439. &pWorkItem->ListEntry );
  440. //
  441. // store parameters
  442. //
  443. pWorkItem->DeviceObject = PDevObj;
  444. pWorkItem->Context = Context;
  445. pWorkItem->Flags = Flags;
  446. ExInitializeWorkItem( &pWorkItem->Item,
  447. (PWORKER_THREAD_ROUTINE)WorkerRoutine,
  448. (PVOID)pWorkItem // Context passed to WorkerRoutine
  449. );
  450. // finally, queue the worker
  451. ExQueueWorkItem( &pWorkItem->Item,
  452. CriticalWorkQueue );
  453. status = STATUS_SUCCESS;
  454. } else {
  455. status = STATUS_INSUFFICIENT_RESOURCES;
  456. DbgDump(DBG_ERR, ("AllocateWorkItem failed!\n"));
  457. TEST_TRAP()
  458. }
  459. }
  460. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  461. DbgDump(DBG_WORK_ITEMS, ("<QueueWorkItem 0x%x\n", status ));
  462. return status;
  463. }
  464. VOID
  465. DequeueWorkItem(
  466. IN PDEVICE_OBJECT PDevObj,
  467. IN PWCE_WORK_ITEM PWorkItem
  468. )
  469. {
  470. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  471. KIRQL irql;
  472. DbgDump(DBG_WORK_ITEMS, (">DequeueWorkItem\n" ));
  473. //
  474. // remove the worker from the pending list
  475. //
  476. KeAcquireSpinLock( &pDevExt->ControlLock, &irql );
  477. RemoveEntryList( &PWorkItem->ListEntry );
  478. KeReleaseSpinLock( &pDevExt->ControlLock, irql);
  479. //
  480. // free the worker back to pool
  481. //
  482. ExFreeToNPagedLookasideList( &pDevExt->WorkItemPool, PWorkItem );
  483. //
  484. // signal event if this is the last one
  485. //
  486. if (0 == InterlockedDecrement( &pDevExt->PendingWorkItemsCount) ) {
  487. DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsEvent signalled\n" ));
  488. KeSetEvent( &pDevExt->PendingWorkItemsEvent, IO_NO_INCREMENT, FALSE);
  489. }
  490. DbgDump(DBG_WORK_ITEMS, ("PendingWorkItemsCount: %d\n", pDevExt->PendingWorkItemsCount));
  491. ASSERT(pDevExt->PendingWorkItemsCount >= 0);
  492. ReleaseRemoveLock(&pDevExt->RemoveLock, PWorkItem);
  493. DbgDump(DBG_WORK_ITEMS, ("<DequeueWorkItem\n" ));
  494. return;
  495. }
  496. #pragma warning( push )
  497. #pragma warning( disable : 4706 ) // assignment w/i conditional expression
  498. NTSTATUS
  499. WaitForPendingItem(
  500. IN PDEVICE_OBJECT PDevObj,
  501. IN PKEVENT PPendingEvent,
  502. IN PULONG PPendingCount
  503. )
  504. {
  505. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  506. LARGE_INTEGER timeOut = {0,0};
  507. LONG itemsLeft;
  508. NTSTATUS status = STATUS_SUCCESS;
  509. DbgDump(DBG_PNP, (">WaitForPendingItem\n"));
  510. if ( !PDevObj || !PPendingEvent || !PPendingCount ) {
  511. status = STATUS_INVALID_PARAMETER;
  512. DbgDump(DBG_ERR, ("WaitForPendingItem: STATUS_INVALID_PARAMETER\n"));
  513. TEST_TRAP();
  514. } else {
  515. //
  516. // wait for pending item to signal it's complete
  517. //
  518. while ( itemsLeft = InterlockedExchange( PPendingCount, *PPendingCount) ) {
  519. DbgDump(DBG_PNP|DBG_EVENTS, ("Pending Items Remain: %d\n", itemsLeft ) );
  520. timeOut.QuadPart = MILLISEC_TO_100NANOSEC( DEFAULT_PENDING_TIMEOUT );
  521. DbgDump(DBG_PNP|DBG_EVENTS, ("Waiting for %d msec...\n", timeOut.QuadPart/10000));
  522. PAGED_CODE();
  523. KeWaitForSingleObject( PPendingEvent,
  524. Executive,
  525. KernelMode,
  526. FALSE,
  527. &timeOut );
  528. }
  529. DbgDump(DBG_PNP, ("Pending Items: %d\n", itemsLeft ) );
  530. }
  531. DbgDump(DBG_PNP, ("<WaitForPendingItem (0x%x)\n", status));
  532. return status;
  533. }
  534. #pragma warning( pop )
  535. BOOLEAN
  536. CanAcceptIoRequests(
  537. IN PDEVICE_OBJECT DeviceObject,
  538. IN BOOLEAN AcquireLock,
  539. IN BOOLEAN CheckOpened
  540. )
  541. /*++
  542. Routine Description:
  543. Check device extension status flags.
  544. Can NOT accept a new I/O request if device:
  545. 1) is removed,
  546. 2) has never been started,
  547. 3) is stopped,
  548. 4) has a remove request pending, or
  549. 5) has a stop device pending
  550. ** Called with the SpinLock held, else AcquireLock should be TRUE **
  551. Arguments:
  552. DeviceObject - pointer to the device object
  553. AcquireLock - if TRUE then we need to acquire the lock
  554. CheckOpened - normally set to TRUE during I/O.
  555. Special cases where FALSE include:
  556. IRP_MN_QUERY_PNP_DEVICE_STATE
  557. IRP_MJ_CREATE
  558. Return Value:
  559. TRUE/FALSE
  560. --*/
  561. {
  562. PDEVICE_EXTENSION pDevExt = DeviceObject->DeviceExtension;
  563. BOOLEAN bRc = FALSE;
  564. KIRQL irql;
  565. if (AcquireLock) {
  566. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  567. }
  568. if ( !InterlockedCompareExchange(&pDevExt->DeviceRemoved, FALSE, FALSE) &&
  569. InterlockedCompareExchange(&pDevExt->AcceptingRequests, TRUE, TRUE) &&
  570. InterlockedCompareExchange((PULONG)&pDevExt->PnPState, PnPStateStarted, PnPStateStarted) &&
  571. (CheckOpened ? InterlockedCompareExchange(&pDevExt->DeviceOpened, TRUE, TRUE) : TRUE)
  572. )
  573. {
  574. bRc = TRUE;
  575. }
  576. #if defined(DBG)
  577. else DbgDump(DBG_WRN|DBG_PNP, ("CanAcceptIoRequests = FALSE\n"));
  578. #endif
  579. if (AcquireLock) {
  580. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  581. }
  582. return bRc;
  583. }
  584. BOOLEAN
  585. IsWin9x(
  586. VOID
  587. )
  588. /*++
  589. Routine Description:
  590. Determine whether or not we are running on Win9x (vs. NT).
  591. Arguments:
  592. Return Value:
  593. TRUE iff we're running on Win9x.
  594. --*/
  595. {
  596. OBJECT_ATTRIBUTES objectAttributes;
  597. UNICODE_STRING keyName;
  598. HANDLE hKey;
  599. NTSTATUS status;
  600. BOOLEAN result;
  601. PAGED_CODE();
  602. /*
  603. * Try to open the COM Name Arbiter, which exists only on NT.
  604. */
  605. RtlInitUnicodeString(&keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter");
  606. InitializeObjectAttributes( &objectAttributes,
  607. &keyName,
  608. OBJ_CASE_INSENSITIVE,
  609. NULL,
  610. (PSECURITY_DESCRIPTOR)NULL);
  611. status = ZwOpenKey(&hKey, KEY_QUERY_VALUE, &objectAttributes);
  612. if (NT_SUCCESS(status)){
  613. status = ZwClose(hKey);
  614. ASSERT(NT_SUCCESS(status));
  615. result = FALSE;
  616. }
  617. else {
  618. result = TRUE;
  619. }
  620. return result;
  621. }
  622. VOID
  623. LogError(
  624. IN PDRIVER_OBJECT DriverObject,
  625. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  626. IN ULONG SequenceNumber,
  627. IN UCHAR MajorFunctionCode,
  628. IN UCHAR RetryCount,
  629. IN ULONG UniqueErrorValue,
  630. IN NTSTATUS FinalStatus,
  631. IN NTSTATUS SpecificIOStatus,
  632. IN ULONG LengthOfInsert1,
  633. IN PWCHAR Insert1,
  634. IN ULONG LengthOfInsert2,
  635. IN PWCHAR Insert2
  636. )
  637. /*++
  638. Routine Description:
  639. Stolen from serial.sys
  640. This routine allocates an error log entry, copies the supplied data
  641. to it, and requests that it be written to the error log file.
  642. Arguments:
  643. DriverObject - A pointer to the driver object for the device.
  644. DeviceObject - A pointer to the device object associated with the
  645. device that had the error, early in initialization, one may not
  646. yet exist.
  647. SequenceNumber - A ulong value that is unique to an IRP over the
  648. life of the irp in this driver - 0 generally means an error not
  649. associated with an irp.
  650. MajorFunctionCode - If there is an error associated with the irp,
  651. this is the major function code of that irp.
  652. RetryCount - The number of times a particular operation has been
  653. retried.
  654. UniqueErrorValue - A unique long word that identifies the particular
  655. call to this function.
  656. FinalStatus - The final status given to the irp that was associated
  657. with this error. If this log entry is being made during one of
  658. the retries this value will be STATUS_SUCCESS.
  659. SpecificIOStatus - The IO status for a particular error.
  660. LengthOfInsert1 - The length in bytes (including the terminating NULL)
  661. of the first insertion string.
  662. Insert1 - The first insertion string.
  663. LengthOfInsert2 - The length in bytes (including the terminating NULL)
  664. of the second insertion string. NOTE, there must
  665. be a first insertion string for their to be
  666. a second insertion string.
  667. Insert2 - The second insertion string.
  668. Return Value:
  669. None.
  670. --*/
  671. {
  672. PIO_ERROR_LOG_PACKET errorLogEntry;
  673. PVOID objectToUse = NULL;
  674. SHORT dumpToAllocate = 0;
  675. PUCHAR ptrToFirstInsert = NULL;
  676. PUCHAR ptrToSecondInsert = NULL;
  677. PAGED_CODE();
  678. DbgDump(DBG_ERR, (">LogError\n"));
  679. if (Insert1 == NULL) {
  680. LengthOfInsert1 = 0;
  681. }
  682. if (Insert2 == NULL) {
  683. LengthOfInsert2 = 0;
  684. }
  685. if (ARGUMENT_PRESENT(DeviceObject)) {
  686. objectToUse = DeviceObject;
  687. } else if (ARGUMENT_PRESENT(DriverObject)) {
  688. objectToUse = DriverObject;
  689. }
  690. errorLogEntry = IoAllocateErrorLogEntry(
  691. objectToUse,
  692. (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
  693. dumpToAllocate
  694. + LengthOfInsert1 +
  695. LengthOfInsert2)
  696. );
  697. if ( errorLogEntry != NULL ) {
  698. errorLogEntry->ErrorCode = SpecificIOStatus;
  699. errorLogEntry->SequenceNumber = SequenceNumber;
  700. errorLogEntry->MajorFunctionCode = MajorFunctionCode;
  701. errorLogEntry->RetryCount = RetryCount;
  702. errorLogEntry->UniqueErrorValue = UniqueErrorValue;
  703. errorLogEntry->FinalStatus = FinalStatus;
  704. errorLogEntry->DumpDataSize = dumpToAllocate;
  705. ptrToFirstInsert = (PUCHAR)&errorLogEntry->DumpData[0];
  706. ptrToSecondInsert = ptrToFirstInsert + LengthOfInsert1;
  707. if (LengthOfInsert1) {
  708. errorLogEntry->NumberOfStrings = 1;
  709. errorLogEntry->StringOffset = (USHORT)(ptrToFirstInsert -
  710. (PUCHAR)errorLogEntry);
  711. RtlCopyMemory(
  712. ptrToFirstInsert,
  713. Insert1,
  714. LengthOfInsert1
  715. );
  716. if (LengthOfInsert2) {
  717. errorLogEntry->NumberOfStrings = 2;
  718. RtlCopyMemory(
  719. ptrToSecondInsert,
  720. Insert2,
  721. LengthOfInsert2
  722. );
  723. }
  724. }
  725. IoWriteErrorLogEntry(errorLogEntry);
  726. }
  727. DbgDump(DBG_ERR, ("<LogError\n"));
  728. return;
  729. }
  730. #if defined(DBG)
  731. PCHAR
  732. PnPMinorFunctionString (
  733. UCHAR MinorFunction
  734. )
  735. {
  736. switch (MinorFunction) {
  737. case IRP_MN_START_DEVICE:
  738. return "IRP_MN_START_DEVICE";
  739. case IRP_MN_QUERY_REMOVE_DEVICE:
  740. return "IRP_MN_QUERY_REMOVE_DEVICE";
  741. case IRP_MN_REMOVE_DEVICE:
  742. return "IRP_MN_REMOVE_DEVICE";
  743. case IRP_MN_CANCEL_REMOVE_DEVICE:
  744. return "IRP_MN_CANCEL_REMOVE_DEVICE";
  745. case IRP_MN_STOP_DEVICE:
  746. return "IRP_MN_STOP_DEVICE";
  747. case IRP_MN_QUERY_STOP_DEVICE:
  748. return "IRP_MN_QUERY_STOP_DEVICE";
  749. case IRP_MN_CANCEL_STOP_DEVICE:
  750. return "IRP_MN_CANCEL_STOP_DEVICE";
  751. case IRP_MN_QUERY_DEVICE_RELATIONS:
  752. return "IRP_MN_QUERY_DEVICE_RELATIONS";
  753. case IRP_MN_QUERY_INTERFACE:
  754. return "IRP_MN_QUERY_INTERFACE";
  755. case IRP_MN_QUERY_CAPABILITIES:
  756. return "IRP_MN_QUERY_CAPABILITIES";
  757. case IRP_MN_QUERY_RESOURCES:
  758. return "IRP_MN_QUERY_RESOURCES";
  759. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  760. return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
  761. case IRP_MN_QUERY_DEVICE_TEXT:
  762. return "IRP_MN_QUERY_DEVICE_TEXT";
  763. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  764. return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
  765. case IRP_MN_READ_CONFIG:
  766. return "IRP_MN_READ_CONFIG";
  767. case IRP_MN_WRITE_CONFIG:
  768. return "IRP_MN_WRITE_CONFIG";
  769. case IRP_MN_EJECT:
  770. return "IRP_MN_EJECT";
  771. case IRP_MN_SET_LOCK:
  772. return "IRP_MN_SET_LOCK";
  773. case IRP_MN_QUERY_ID:
  774. return "IRP_MN_QUERY_ID";
  775. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  776. return "IRP_MN_QUERY_PNP_DEVICE_STATE";
  777. case IRP_MN_QUERY_BUS_INFORMATION:
  778. return "IRP_MN_QUERY_BUS_INFORMATION";
  779. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  780. return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
  781. case IRP_MN_SURPRISE_REMOVAL:
  782. return "IRP_MN_SURPRISE_REMOVAL";
  783. default:
  784. return ((PCHAR)("unknown IRP_MN_ 0x%x\n", MinorFunction));
  785. }
  786. }
  787. #endif
  788. // EOF