Source code of Windows XP (NT5)
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.

634 lines
16 KiB

  1. /*++
  2. Copyright (c) 1997-1998 Microsoft Corporation
  3. Module Name:
  4. SERENUM.C
  5. Abstract:
  6. This module contains contains the entry points for a standard bus
  7. PNP / WDM driver.
  8. @@BEGIN_DDKSPLIT
  9. Author:
  10. Jay Senior
  11. @@END_DDKSPLIT
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. @@BEGIN_DDKSPLIT
  16. Revision History:
  17. Louis J. Giliberto, Jr. Cleanup 7-May-98
  18. @@END_DDKSPLIT
  19. --*/
  20. #include "pch.h"
  21. //
  22. // Declare some entry functions as pageable, and make DriverEntry
  23. // discardable
  24. //
  25. NTSTATUS DriverEntry(PDRIVER_OBJECT, PUNICODE_STRING);
  26. #ifdef ALLOC_PRAGMA
  27. #pragma alloc_text(INIT, DriverEntry)
  28. #pragma alloc_text(PAGE, Serenum_DriverUnload)
  29. #endif
  30. NTSTATUS
  31. DriverEntry (
  32. IN PDRIVER_OBJECT DriverObject,
  33. IN PUNICODE_STRING UniRegistryPath
  34. )
  35. /*++
  36. Routine Description:
  37. Initialize the entry points of the driver.
  38. --*/
  39. {
  40. ULONG i;
  41. UNREFERENCED_PARAMETER (UniRegistryPath);
  42. Serenum_KdPrint_Def (SER_DBG_SS_TRACE, ("Driver Entry\n"));
  43. Serenum_KdPrint_Def (SER_DBG_SS_TRACE, ("RegPath: %x\n", UniRegistryPath));
  44. //
  45. // Set ever slot to initially pass the request through to the lower
  46. // device object
  47. //
  48. for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
  49. DriverObject->MajorFunction[i] = Serenum_DispatchPassThrough;
  50. }
  51. //
  52. // Fill in the Dispatch slots intercepted by the filter driver.
  53. //
  54. DriverObject->MajorFunction [IRP_MJ_CREATE] =
  55. DriverObject->MajorFunction [IRP_MJ_CLOSE] = Serenum_CreateClose;
  56. DriverObject->MajorFunction [IRP_MJ_PNP] = Serenum_PnP;
  57. DriverObject->MajorFunction [IRP_MJ_POWER] = Serenum_Power;
  58. DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = Serenum_IoCtl;
  59. DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
  60. = Serenum_InternIoCtl;
  61. DriverObject->DriverUnload = Serenum_DriverUnload;
  62. DriverObject->DriverExtension->AddDevice = Serenum_AddDevice;
  63. #if DBG
  64. SerenumLogInit();
  65. #endif
  66. return STATUS_SUCCESS;
  67. }
  68. NTSTATUS
  69. SerenumSyncCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp,
  70. IN PKEVENT SerenumSyncEvent)
  71. {
  72. UNREFERENCED_PARAMETER(DeviceObject);
  73. UNREFERENCED_PARAMETER(Irp);
  74. KeSetEvent(SerenumSyncEvent, IO_NO_INCREMENT, FALSE);
  75. return STATUS_MORE_PROCESSING_REQUIRED;
  76. }
  77. NTSTATUS
  78. Serenum_CreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  79. /*++
  80. Routine Description:
  81. Some outside source is trying to create a file against us.
  82. If this is for the FDO (the bus itself) then the caller is trying to
  83. open the propriatary conection to tell us which serial port to enumerate.
  84. If this is for the PDO (an object on the bus) then this is a client that
  85. wishes to use the serial port.
  86. --*/
  87. {
  88. PIO_STACK_LOCATION irpStack;
  89. NTSTATUS status;
  90. PFDO_DEVICE_DATA fdoData;
  91. KEVENT completionEvent;
  92. PDEVICE_OBJECT pNextDevice;
  93. UNREFERENCED_PARAMETER(DeviceObject);
  94. irpStack = IoGetCurrentIrpStackLocation(Irp);
  95. if (((PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension)->IsFDO) {
  96. fdoData = (PFDO_DEVICE_DATA)DeviceObject->DeviceExtension;
  97. pNextDevice = ((PFDO_DEVICE_DATA)DeviceObject->DeviceExtension)
  98. ->TopOfStack;
  99. } else {
  100. fdoData = ((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension)->
  101. ParentFdo->DeviceExtension;
  102. pNextDevice = ((PFDO_DEVICE_DATA)((PPDO_DEVICE_DATA)DeviceObject->
  103. DeviceExtension)->ParentFdo->
  104. DeviceExtension)->TopOfStack;
  105. }
  106. switch (irpStack->MajorFunction) {
  107. case IRP_MJ_CREATE:
  108. Serenum_KdPrint_Def(SER_DBG_SS_TRACE, ("Create"));
  109. //
  110. // Pass on the create and the close
  111. //
  112. status = Serenum_DispatchPassThrough(DeviceObject, Irp);
  113. break;
  114. case IRP_MJ_CLOSE:
  115. Serenum_KdPrint_Def (SER_DBG_SS_TRACE, ("Close \n"));
  116. //
  117. // Send the close down; after it finishes we can open and take
  118. // over the port
  119. //
  120. IoCopyCurrentIrpStackLocationToNext(Irp);
  121. KeInitializeEvent(&completionEvent, SynchronizationEvent, FALSE);
  122. IoSetCompletionRoutine(Irp, SerenumSyncCompletion, &completionEvent,
  123. TRUE, TRUE, TRUE);
  124. status = IoCallDriver(pNextDevice, Irp);
  125. if (status == STATUS_PENDING) {
  126. KeWaitForSingleObject(&completionEvent, Executive, KernelMode, FALSE,
  127. NULL);
  128. }
  129. status = Irp->IoStatus.Status;
  130. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  131. break;
  132. }
  133. return status;
  134. }
  135. NTSTATUS
  136. Serenum_IoCtl (
  137. IN PDEVICE_OBJECT DeviceObject,
  138. IN PIRP Irp
  139. )
  140. /*++
  141. Routine Description:
  142. --*/
  143. {
  144. PIO_STACK_LOCATION irpStack;
  145. NTSTATUS status;
  146. ULONG inlen;
  147. ULONG outlen;
  148. PCOMMON_DEVICE_DATA commonData;
  149. PFDO_DEVICE_DATA fdoData;
  150. PVOID buffer;
  151. HANDLE keyHandle;
  152. ULONG actualLength;
  153. status = STATUS_SUCCESS;
  154. irpStack = IoGetCurrentIrpStackLocation (Irp);
  155. ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
  156. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  157. fdoData = (PFDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  158. buffer = Irp->AssociatedIrp.SystemBuffer;
  159. //
  160. // We only take Device Control requests for the FDO.
  161. // That is the bus itself.
  162. //
  163. // The request is one of the propriatary Ioctls for
  164. //
  165. // NB We ARE a filter driver, so we DO pass on the irp if we don't handle it
  166. //
  167. inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  168. outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  169. if (!commonData->IsFDO) {
  170. //
  171. // These commands are only allowed to go to the FDO. Since they came
  172. // into the PDO, we need to fire them down to the serenum Fdo.
  173. //
  174. IoSkipCurrentIrpStackLocation (Irp);
  175. return IoCallDriver(
  176. ((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension)->ParentFdo,
  177. Irp );
  178. }
  179. status = Serenum_IncIoCount (fdoData);
  180. if (!NT_SUCCESS (status)) {
  181. //
  182. // This bus has received the PlugPlay remove IRP. It will no longer
  183. // respond to external requests.
  184. //
  185. Irp->IoStatus.Status = status;
  186. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  187. return status;
  188. }
  189. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  190. case IOCTL_SERENUM_GET_PORT_NAME:
  191. //
  192. // Get the port name from the registry.
  193. // This IOCTL is used by the modem cpl.
  194. //
  195. status = IoOpenDeviceRegistryKey(fdoData->UnderlyingPDO,
  196. PLUGPLAY_REGKEY_DEVICE,
  197. STANDARD_RIGHTS_READ,
  198. &keyHandle);
  199. if (!NT_SUCCESS(status)) {
  200. //
  201. // This is a fatal error. If we can't get to our registry key,
  202. // we are sunk.
  203. //
  204. Serenum_KdPrint_Def (SER_DBG_PNP_ERROR,
  205. ("IoOpenDeviceRegistryKey failed - %x \n", status));
  206. } else {
  207. status = Serenum_GetRegistryKeyValue(
  208. keyHandle,
  209. L"PortName",
  210. sizeof(L"PortName"),
  211. Irp->AssociatedIrp.SystemBuffer,
  212. irpStack->Parameters.DeviceIoControl.OutputBufferLength,
  213. &actualLength);
  214. if ( STATUS_OBJECT_NAME_NOT_FOUND == status ||
  215. STATUS_INVALID_PARAMETER == status ) {
  216. status = Serenum_GetRegistryKeyValue(
  217. keyHandle,
  218. L"Identifier",
  219. sizeof(L"Identifier"),
  220. Irp->AssociatedIrp.SystemBuffer,
  221. irpStack->Parameters.DeviceIoControl.OutputBufferLength,
  222. &actualLength);
  223. }
  224. Irp->IoStatus.Information = actualLength;
  225. ZwClose (keyHandle);
  226. }
  227. break;
  228. default:
  229. //
  230. // This is not intended for us - fire and forget!
  231. //
  232. Serenum_DecIoCount (fdoData);
  233. return Serenum_DispatchPassThrough(
  234. DeviceObject,
  235. Irp);
  236. }
  237. Serenum_DecIoCount (fdoData);
  238. Irp->IoStatus.Status = status;
  239. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  240. return status;
  241. }
  242. NTSTATUS
  243. Serenum_InternIoCtl (
  244. PDEVICE_OBJECT DeviceObject,
  245. IN PIRP Irp
  246. )
  247. /*++
  248. Routine Description:
  249. --*/
  250. {
  251. PIO_STACK_LOCATION irpStack;
  252. NTSTATUS status;
  253. PCOMMON_DEVICE_DATA commonData;
  254. PPDO_DEVICE_DATA pdoData;
  255. PVOID buffer;
  256. // PAGED_CODE();
  257. status = STATUS_SUCCESS;
  258. irpStack = IoGetCurrentIrpStackLocation (Irp);
  259. ASSERT (IRP_MJ_INTERNAL_DEVICE_CONTROL == irpStack->MajorFunction);
  260. commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension;
  261. pdoData = (PPDO_DEVICE_DATA) DeviceObject->DeviceExtension;
  262. //
  263. // We only take Internal Device Control requests for the PDO.
  264. // That is the objects on the bus (representing the serial ports)
  265. //
  266. // We do pass on the irp if this comes into the fdo, but not if it comes
  267. // into the pdo.
  268. //
  269. if (commonData->IsFDO) {
  270. return Serenum_DispatchPassThrough(
  271. DeviceObject,
  272. Irp);
  273. } else if (pdoData->Removed) {
  274. //
  275. // This bus has received the PlugPlay remove IRP. It will no longer
  276. // respond to external requests.
  277. //
  278. status = STATUS_DELETE_PENDING;
  279. } else {
  280. buffer = Irp->UserBuffer;
  281. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  282. case IOCTL_INTERNAL_SERENUM_REMOVE_SELF:
  283. Serenum_KdPrint(pdoData, SER_DBG_SS_TRACE, ("Remove self\n"));
  284. ((PFDO_DEVICE_DATA) pdoData->ParentFdo->DeviceExtension)->
  285. PDOForcedRemove = TRUE;
  286. Serenum_PDO_EnumMarkMissing(pdoData->ParentFdo->DeviceExtension, DeviceObject->DeviceExtension);
  287. IoInvalidateDeviceRelations(
  288. ((PFDO_DEVICE_DATA) pdoData->ParentFdo->DeviceExtension)->
  289. UnderlyingPDO,
  290. BusRelations );
  291. status = STATUS_SUCCESS;
  292. break;
  293. default:
  294. //
  295. // Pass it through
  296. //
  297. return Serenum_DispatchPassThrough(DeviceObject, Irp);
  298. }
  299. }
  300. Irp->IoStatus.Status = status;
  301. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  302. return status;
  303. }
  304. VOID
  305. Serenum_DriverUnload (
  306. IN PDRIVER_OBJECT Driver
  307. )
  308. /*++
  309. Routine Description:
  310. Clean up everything we did in driver entry.
  311. --*/
  312. {
  313. UNREFERENCED_PARAMETER (Driver);
  314. PAGED_CODE();
  315. //
  316. // All the device objects should be gone.
  317. //
  318. ASSERT (NULL == Driver->DeviceObject);
  319. //
  320. // Here we free any resources allocated in DriverEntry
  321. //
  322. #if DBG
  323. SerenumLogFree();
  324. #endif
  325. return;
  326. }
  327. NTSTATUS
  328. Serenum_IncIoCount (
  329. PFDO_DEVICE_DATA Data
  330. )
  331. {
  332. InterlockedIncrement (&Data->OutstandingIO);
  333. if (Data->Removed) {
  334. if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
  335. KeSetEvent (&Data->RemoveEvent, 0, FALSE);
  336. }
  337. return STATUS_DELETE_PENDING;
  338. }
  339. return STATUS_SUCCESS;
  340. }
  341. VOID
  342. Serenum_DecIoCount (
  343. PFDO_DEVICE_DATA Data
  344. )
  345. {
  346. if (0 == InterlockedDecrement (&Data->OutstandingIO)) {
  347. KeSetEvent (&Data->RemoveEvent, 0, FALSE);
  348. }
  349. }
  350. NTSTATUS
  351. Serenum_DispatchPassThrough(
  352. IN PDEVICE_OBJECT DeviceObject,
  353. IN PIRP Irp
  354. )
  355. /*++
  356. Routine Description:
  357. Passes a request on to the lower driver.
  358. --*/
  359. {
  360. PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
  361. BOOLEAN waitForEnum = FALSE;
  362. NTSTATUS rval;
  363. PFDO_DEVICE_DATA pFdoData;
  364. BOOLEAN isFdo;
  365. isFdo = ((PCOMMON_DEVICE_DATA)DeviceObject->DeviceExtension)->IsFDO;
  366. if (isFdo) {
  367. pFdoData = (PFDO_DEVICE_DATA)DeviceObject->DeviceExtension;
  368. #if DBG
  369. switch (IrpStack->MajorFunction) {
  370. case IRP_MJ_READ:
  371. LOGENTRY(LOG_PASSTHROUGH, 'SFRD', DeviceObject, Irp, 0);
  372. break;
  373. case IRP_MJ_WRITE:
  374. LOGENTRY(LOG_PASSTHROUGH, 'SFWR', DeviceObject, Irp, 0);
  375. break;
  376. case IRP_MJ_DEVICE_CONTROL:
  377. LOGENTRY(LOG_PASSTHROUGH, 'SFDC', DeviceObject, Irp, 0);
  378. break;
  379. case IRP_MJ_CREATE:
  380. LOGENTRY(LOG_PASSTHROUGH, 'SFCR', DeviceObject, Irp, 0);
  381. break;
  382. case IRP_MJ_CLOSE:
  383. LOGENTRY(LOG_PASSTHROUGH, 'SFCL', DeviceObject, Irp, 0);
  384. break;
  385. default:
  386. break;
  387. }
  388. #endif // DBG
  389. } else {
  390. pFdoData = ((PPDO_DEVICE_DATA) DeviceObject->DeviceExtension)->
  391. ParentFdo->DeviceExtension;
  392. #if DBG
  393. switch (IrpStack->MajorFunction) {
  394. case IRP_MJ_READ:
  395. LOGENTRY(LOG_PASSTHROUGH, 'SPRD', DeviceObject, Irp, 0);
  396. break;
  397. case IRP_MJ_WRITE:
  398. LOGENTRY(LOG_PASSTHROUGH, 'SPWR', DeviceObject, Irp, 0);
  399. break;
  400. case IRP_MJ_DEVICE_CONTROL:
  401. LOGENTRY(LOG_PASSTHROUGH, 'SPDC', DeviceObject, Irp, 0);
  402. break;
  403. case IRP_MJ_CREATE:
  404. LOGENTRY(LOG_PASSTHROUGH, 'SPCR', DeviceObject, Irp, 0);
  405. break;
  406. case IRP_MJ_CLOSE:
  407. LOGENTRY(LOG_PASSTHROUGH, 'SPCL', DeviceObject, Irp, 0);
  408. break;
  409. default:
  410. break;
  411. }
  412. #endif // DBG
  413. }
  414. if (IrpStack->MajorFunction == IRP_MJ_CREATE) {
  415. //
  416. // If we're doing an enumeration, we must wait here
  417. //
  418. waitForEnum = TRUE;
  419. LOGENTRY(LOG_PASSTHROUGH, 'SPCW', DeviceObject, Irp, 0);
  420. rval = KeWaitForSingleObject(&pFdoData->CreateSemaphore, Executive,
  421. KernelMode, FALSE, NULL);
  422. if (!NT_SUCCESS(rval)) {
  423. LOGENTRY(LOG_PASSTHROUGH, 'SPCF', DeviceObject, Irp, rval);
  424. Irp->IoStatus.Status = rval;
  425. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  426. return rval;
  427. }
  428. }
  429. //
  430. // Pass the IRP to the target
  431. //
  432. IoSkipCurrentIrpStackLocation (Irp);
  433. rval = IoCallDriver(pFdoData->TopOfStack, Irp);
  434. if (waitForEnum) {
  435. KeReleaseSemaphore(&pFdoData->CreateSemaphore, IO_NO_INCREMENT, 1, FALSE);
  436. }
  437. return rval;
  438. }
  439. void
  440. Serenum_InitPDO (
  441. PDEVICE_OBJECT Pdo,
  442. PFDO_DEVICE_DATA FdoData
  443. )
  444. /*
  445. Description:
  446. Common code to initialize a newly created serenum pdo.
  447. Called either when the control panel exposes a device or when Serenum senses
  448. a new device was attached.
  449. Parameters:
  450. Pdo - The pdo
  451. FdoData - The fdo's device extension
  452. */
  453. {
  454. ULONG FdoFlags = FdoData->Self->Flags;
  455. PPDO_DEVICE_DATA pdoData = Pdo->DeviceExtension;
  456. KIRQL oldIrql;
  457. //
  458. // Check the IO style
  459. //
  460. if (FdoFlags & DO_BUFFERED_IO) {
  461. Pdo->Flags |= DO_BUFFERED_IO;
  462. } else if (FdoFlags & DO_DIRECT_IO) {
  463. Pdo->Flags |= DO_DIRECT_IO;
  464. }
  465. //
  466. // Increment the pdo's stacksize so that it can pass irps through
  467. //
  468. Pdo->StackSize += FdoData->Self->StackSize;
  469. //
  470. // Initialize the rest of the device extension
  471. //
  472. pdoData->IsFDO = FALSE;
  473. pdoData->Self = Pdo;
  474. pdoData->ParentFdo = FdoData->Self;
  475. pdoData->Started = FALSE; // irp_mn_start has yet to be received
  476. pdoData->Attached = TRUE; // attached to the bus
  477. pdoData->Removed = FALSE; // no irp_mn_remove as of yet
  478. pdoData->DebugLevel = FdoData->DebugLevel; // Copy the debug level
  479. pdoData->DeviceState = PowerDeviceD0;
  480. pdoData->SystemState = PowerSystemWorking;
  481. //
  482. // Add the pdo to serenum's list
  483. //
  484. ASSERT(FdoData->NewPDO == NULL);
  485. ASSERT(FdoData->NewPdoData == NULL);
  486. ASSERT(FdoData->NewNumPDOs == 0);
  487. KeAcquireSpinLock(&FdoData->EnumerationLock, &oldIrql);
  488. FdoData->NewPDO = Pdo;
  489. FdoData->NewPdoData = pdoData;
  490. FdoData->NewNumPDOs = 1;
  491. FdoData->EnumFlags |= SERENUM_ENUMFLAG_DIRTY;
  492. KeReleaseSpinLock(&FdoData->EnumerationLock, oldIrql);
  493. Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  494. Pdo->Flags |= DO_POWER_PAGABLE;
  495. }