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.

2077 lines
73 KiB

  1. #include "precomp.h" // Precompiled header
  2. /****************************************************************************************
  3. * *
  4. * Module: SPX_PNP.C *
  5. * *
  6. * Creation: 27th September 1998 *
  7. * *
  8. * Author: Paul Smith *
  9. * *
  10. * Version: 1.0.0 *
  11. * *
  12. * Description: Generic Plug and Play Functions to handle PnP IRPS. *
  13. * *
  14. ****************************************************************************************/
  15. /* History...
  16. 1.0.0 27/09/98 PBS Creation.
  17. */
  18. #define FILE_ID SPX_PNP_C // File ID for Event Logging see SPX_DEFS.H for values.
  19. /*****************************************************************************
  20. ******************************* *******************************
  21. ******************************* Prototypes *******************************
  22. ******************************* *******************************
  23. *****************************************************************************/
  24. NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp);
  25. NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp);
  26. NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard);
  27. NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject);
  28. NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp);
  29. NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp);
  30. NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject);
  31. NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort);
  32. NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject);
  33. NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject);
  34. NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject);
  35. NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject);
  36. NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject);
  37. // Paging...
  38. #ifdef ALLOC_PRAGMA
  39. #pragma alloc_text (PAGE, Spx_AddDevice)
  40. #pragma alloc_text (PAGE, Spx_DispatchPnp)
  41. #pragma alloc_text (PAGE, Spx_Card_FDO_DispatchPnp)
  42. #pragma alloc_text (PAGE, Spx_Card_StartDevice)
  43. #pragma alloc_text (PAGE, Spx_Card_StopDevice)
  44. #pragma alloc_text (PAGE, Spx_Card_RemoveDevice)
  45. #pragma alloc_text (PAGE, Spx_CallDriverBelow)
  46. #pragma alloc_text (PAGE, Spx_Port_PDO_DispatchPnp)
  47. #pragma alloc_text (PAGE, Spx_Port_StartDevice)
  48. #pragma alloc_text (PAGE, Spx_Port_StopDevice)
  49. #pragma alloc_text (PAGE, Spx_Port_RemoveDevice)
  50. #pragma alloc_text (PAGE, Spx_EnumPorts)
  51. #pragma alloc_text (PAGE, Spx_DoExternalNaming)
  52. #pragma alloc_text (PAGE, Spx_GetExternalName)
  53. #pragma alloc_text (PAGE, Spx_RemoveExternalNaming)
  54. #pragma alloc_text (PAGE, Spx_CreatePortInstanceID)
  55. #endif
  56. #include <initguid.h>
  57. #include <ntddser.h>
  58. /*****************************************************************************
  59. ***************************** ******************************
  60. ***************************** Spx_AddDevice ******************************
  61. ***************************** ******************************
  62. ******************************************************************************
  63. prototype: NTSTATUS Spx_AddDevice(IN PDRIVER_OBJECT pDriverObject,IN PDEVICE_OBJECT pPDO)
  64. description: Create a functional device object (FDO) for the specified card physical device object.
  65. parameters: pDriver point to the driver object
  66. pPDO points to a card physical device object (PDO)
  67. returns: STATUS_SUCCESS
  68. STATUS_NO_MORE_ENTRIES
  69. */
  70. NTSTATUS Spx_AddDevice(IN PDRIVER_OBJECT pDriverObject,IN PDEVICE_OBJECT pPDO)
  71. {
  72. NTSTATUS status = STATUS_SUCCESS;
  73. PDEVICE_OBJECT pDevObject = NULL;
  74. PCARD_DEVICE_EXTENSION pCard = NULL;
  75. PDEVICE_OBJECT pLowerDevObject = NULL;
  76. static ULONG CardNumber = 0;
  77. ULONG i = 0;
  78. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  79. SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering Spx_AddDevice.\n", PRODUCT_NAME));
  80. if(pPDO == NULL)
  81. {
  82. SpxDbgMsg(SPX_MISC_DBG, ("%s: In Spx_AddDevice - No more entries.\n", PRODUCT_NAME));
  83. return(STATUS_NO_MORE_ENTRIES);
  84. }
  85. /* Create the device object... */
  86. status = IoCreateDevice(pDriverObject,
  87. sizeof(CARD_DEVICE_EXTENSION),
  88. NULL, // Doesn't need a name.
  89. FILE_DEVICE_CONTROLLER,
  90. FILE_DEVICE_SECURE_OPEN,
  91. TRUE,
  92. &pDevObject);
  93. if(!SPX_SUCCESS(status))
  94. {
  95. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  96. SpxDbgMsg(SPX_ERRORS,("%s: Create Device failed for card %d. CardExt at 0x%X.\n",
  97. PRODUCT_NAME,CardNumber++,&pDevObject));
  98. sprintf(szErrorMsg, "Card %d: Failed IoCreateDevice.", CardNumber++);
  99. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  100. pDriverObject, // Driver Object
  101. NULL, // Device Object (Optional)
  102. PhysicalZero, // Physical Address 1
  103. PhysicalZero, // Physical Address 2
  104. 0, // SequenceNumber
  105. 0, // Major Function Code
  106. 0, // RetryCount
  107. FILE_ID | __LINE__, // UniqueErrorValue
  108. STATUS_SUCCESS, // FinalStatus
  109. szErrorMsg); // Error Message
  110. if(pDevObject) // Clean up Device Object
  111. IoDeleteDevice(pDevObject);
  112. SpxDbgMsg(SPX_ERRORS, ("%s: Leaving Spx_AddDevice - FAILURE.\n", PRODUCT_NAME));
  113. return(status);
  114. }
  115. ASSERT(pDevObject != NULL);
  116. /* Initialise the device extension... */
  117. pCard = pDevObject->DeviceExtension; /* Point to card extension */
  118. RtlZeroMemory(pCard,sizeof(CARD_DEVICE_EXTENSION)); /* Zero extension structure */
  119. pDevObject->Flags |= DO_POWER_PAGABLE; // Get power IRPs at IRQL PASSIVE_LEVEL
  120. pDevObject->Flags &= ~DO_DEVICE_INITIALIZING;
  121. pLowerDevObject = IoAttachDeviceToDeviceStack(pDevObject,pPDO); /* Attach to device stack */
  122. ASSERT(pLowerDevObject != NULL);
  123. KeInitializeSpinLock(&pCard->PnpPowerFlagsLock); /* Initialise the PNP flags lock */
  124. ClearPnpPowerFlags(pCard,PPF_STARTED); /* Not started yet */
  125. ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); /* Not pending a stop */
  126. ClearPnpPowerFlags(pCard,PPF_REMOVE_PENDING); /* Not pending a remove */
  127. pCard->IsFDO = TRUE; /* Card Object is a Functional Device Object (FDO) */
  128. pCard->CardNumber = CardNumber++; /* Enumerate card devices */
  129. pCard->DeviceObject = pDevObject; /* Back pointer to device object */
  130. pCard->LowerDeviceObject= pLowerDevObject; /* Pointer to device below in device stack */
  131. pCard->DriverObject = pDriverObject; /* Pointer to driver object */
  132. pCard->PDO = pPDO; /* Pointer to card physical device object (PDO) */
  133. pCard->DeviceState = PowerDeviceD0; /* Initial power state */
  134. pCard->SystemState = PowerSystemWorking; /* System in full power State */
  135. pCard->NumPDOs = 0; /* Initialise attached port PDO pointers */
  136. for(i=0; i<PRODUCT_MAX_PORTS; i++)
  137. pCard->AttachedPDO[i] = NULL;
  138. SetPnpPowerFlags(pCard,PPF_POWERED); /* Initially assumed we are powered */
  139. XXX_CardInit(pCard); /* Initialise non-hardware extension fields */
  140. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Leaving Spx_AddDevice - SUCCESS.\n",PRODUCT_NAME));
  141. return(status);
  142. } /* Spx_AddDevice */
  143. /*****************************************************************************
  144. **************************** *****************************
  145. **************************** Spx_DispatchPnp *****************************
  146. **************************** *****************************
  147. ******************************************************************************
  148. prototype: NTSTATUS Spx_DispatchPnp(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
  149. description: The plug and play dispatch routine.
  150. Determines whether IRP is for a card or a port and calls other functions to handle it.
  151. parameters: pDevObject points to a device object for this driver
  152. pIrp points to the Plug and Play I/O Request (IRP) to be processed
  153. returns: NT Status Code
  154. */
  155. NTSTATUS Spx_DispatchPnp(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
  156. {
  157. PCOMMON_OBJECT_DATA CommonData = (PCOMMON_OBJECT_DATA) pDevObject->DeviceExtension;
  158. NTSTATUS status = STATUS_SUCCESS;
  159. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  160. if(CommonData->IsFDO) /* Functional Device Object ? */
  161. status = Spx_Card_FDO_DispatchPnp(pDevObject,pIrp); /* Yes, must be card device */
  162. else
  163. status = Spx_Port_PDO_DispatchPnp(pDevObject,pIrp); /* No, must be port device */
  164. return(status);
  165. } /* Spx_DispatchPnp */
  166. /*****************************************************************************
  167. ************************ ************************
  168. ************************ Spx_Card_FDO_DispatchPnp ************************
  169. ************************ ************************
  170. ******************************************************************************
  171. prototype: NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp)
  172. description: The plug and play dispatch routine to handle IRPs for card devices.
  173. parameters: pDevObject points to a card device object for this driver
  174. pIrp points to the Plug and Play I/O Request (IRP) to be processed
  175. returns: NT Status Code
  176. */
  177. NTSTATUS Spx_Card_FDO_DispatchPnp(IN PDEVICE_OBJECT pFDO,IN PIRP pIrp)
  178. {
  179. PCARD_DEVICE_EXTENSION pCard = pFDO->DeviceExtension;
  180. PDEVICE_OBJECT pLowerDevObj = pCard->LowerDeviceObject;
  181. NTSTATUS status;
  182. PDEVICE_CAPABILITIES pDevCaps = NULL;
  183. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  184. PDEVICE_RELATIONS pRelations = NULL;
  185. ULONG length = 0;
  186. ULONG i = 0;
  187. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  188. switch(pIrpStack->MinorFunction)
  189. {
  190. /*****************************************************************************
  191. *************************** IRP_MN_START_DEVICE **************************
  192. *****************************************************************************/
  193. case IRP_MN_START_DEVICE:
  194. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_START_DEVICE Irp for Card %d.\n",
  195. PRODUCT_NAME,pCard->CardNumber));
  196. /* Call driver below first... */
  197. status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
  198. /* If successful, then start the card... */
  199. if(NT_SUCCESS(status)) // Must use NT_SUCCESS() here!!
  200. status = Spx_Card_StartDevice(pFDO,pIrp); /* Start the card */
  201. pIrp->IoStatus.Status = status;
  202. pIrp->IoStatus.Information = 0;
  203. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  204. break;
  205. /*****************************************************************************
  206. ********************** IRP_MN_QUERY_DEVICE_RELATIONS *********************
  207. *****************************************************************************/
  208. case IRP_MN_QUERY_DEVICE_RELATIONS:
  209. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_RELATIONS Irp for Card %d.\n",
  210. PRODUCT_NAME,pCard->CardNumber));
  211. if(pIrpStack->Parameters.QueryDeviceRelations.Type != BusRelations) /* Only handle BusRelations */
  212. {
  213. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: IRP_MN_QUERY_DEVICE_RELATIONS for Card - Non bus.\n",PRODUCT_NAME));
  214. IoSkipCurrentIrpStackLocation(pIrp);
  215. status = IoCallDriver(pLowerDevObj,pIrp);
  216. break;
  217. }
  218. /* Enumerate devices on the card... */
  219. Spx_EnumPorts(pFDO); /* Enumerate and create port device objects */
  220. /* Tell the Plug and Play Manager any found ports... */
  221. i = 0;
  222. if(pIrp->IoStatus.Information) /* Get current device object count */
  223. i = ((PDEVICE_RELATIONS)pIrp->IoStatus.Information)->Count;
  224. length = sizeof(DEVICE_RELATIONS)+((pCard->NumPDOs+i)*sizeof(PDEVICE_OBJECT));
  225. if(pRelations = SpxAllocateMem(NonPagedPool, length))/* Allocate new structure */
  226. {
  227. /* Copy in the device objects so far... */
  228. if(i)
  229. RtlCopyMemory
  230. (
  231. pRelations->Objects,
  232. ((PDEVICE_RELATIONS)pIrp->IoStatus.Information)->Objects,
  233. i * sizeof (PDEVICE_OBJECT)
  234. );
  235. pRelations->Count = i; /* Update device count */
  236. /* Add specialix ports to the device relations... */
  237. if(pCard->NumPDOs)
  238. {
  239. for(i=0; i<PRODUCT_MAX_PORTS; i++)
  240. {
  241. if(pCard->AttachedPDO[i]) /* If object exists */
  242. { /* add to table */
  243. pRelations->Objects[pRelations->Count++] = pCard->AttachedPDO[i];
  244. ObReferenceObject(pCard->AttachedPDO[i]);
  245. }
  246. }
  247. }
  248. if(pIrp->IoStatus.Information != 0) /* If previous structure */
  249. SpxFreeMem((PVOID)pIrp->IoStatus.Information); /* then free */
  250. pIrp->IoStatus.Information = (ULONG_PTR)pRelations; /* Set new structure */
  251. }
  252. else
  253. {
  254. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  255. sprintf(szErrorMsg, "Card at %08X%08X: Insufficient resources.", pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  256. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  257. pCard->DriverObject, // Driver Object
  258. pCard->DeviceObject, // Device Object (Optional)
  259. PhysicalZero, // Physical Address 1
  260. PhysicalZero, // Physical Address 2
  261. 0, // SequenceNumber
  262. pIrpStack->MajorFunction, // Major Function Code
  263. 0, // RetryCount
  264. FILE_ID | __LINE__, // UniqueErrorValue
  265. STATUS_SUCCESS, // FinalStatus
  266. szErrorMsg); // Error Message
  267. }
  268. pIrp->IoStatus.Status = STATUS_SUCCESS;
  269. IoSkipCurrentIrpStackLocation(pIrp); /* Copy parameters to next stack */
  270. status = IoCallDriver(pLowerDevObj,pIrp); /* Call driver below */
  271. break;
  272. /*****************************************************************************
  273. ********************** IRP_MN_QUERY_PNP_DEVICE_STATE *********************
  274. *****************************************************************************/
  275. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  276. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_PNP_DEVICE_STATE Irp for Card %d.\n",
  277. PRODUCT_NAME,pCard->CardNumber));
  278. IoSkipCurrentIrpStackLocation(pIrp);
  279. status = IoCallDriver(pLowerDevObj,pIrp);
  280. break;
  281. /*****************************************************************************
  282. ************************ IRP_MN_QUERY_CAPABILITIES ***********************
  283. *****************************************************************************/
  284. case IRP_MN_QUERY_CAPABILITIES:
  285. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_CAPABILITIES Irp for Card %d.\n",
  286. PRODUCT_NAME,pCard->CardNumber));
  287. IoSkipCurrentIrpStackLocation(pIrp);
  288. status = IoCallDriver(pLowerDevObj,pIrp);
  289. break;
  290. /*****************************************************************************
  291. ************************ IRP_MN_QUERY_STOP_DEVICE ************************
  292. *****************************************************************************/
  293. case IRP_MN_QUERY_STOP_DEVICE:
  294. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_STOP_DEVICE Irp for Card %d.\n",
  295. PRODUCT_NAME,pCard->CardNumber));
  296. status = STATUS_SUCCESS;
  297. SetPnpPowerFlags(pCard,PPF_STOP_PENDING); // We must now expect a STOP IRP
  298. if(SPX_SUCCESS(status)) // If we can stop, pass IRP on down
  299. {
  300. pIrp->IoStatus.Status = status;
  301. IoSkipCurrentIrpStackLocation(pIrp);
  302. status = IoCallDriver(pLowerDevObj,pIrp);
  303. }
  304. else // If we can't then complete
  305. {
  306. pIrp->IoStatus.Status = status;
  307. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  308. }
  309. break;
  310. /*****************************************************************************
  311. ************************ IRP_MN_CANCEL_STOP_DEVICE ***********************
  312. *****************************************************************************/
  313. case IRP_MN_CANCEL_STOP_DEVICE:
  314. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_CANCEL_STOP_DEVICE Irp for Card %d.\n",
  315. PRODUCT_NAME,pCard->CardNumber));
  316. /* Call driver below first... */
  317. status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
  318. if(NT_SUCCESS(status))
  319. {
  320. // we return the device to its working state here.
  321. ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); // We are no longer expecting a STOP IRP.
  322. status = STATUS_SUCCESS;
  323. }
  324. pIrp->IoStatus.Status = status;
  325. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  326. break;
  327. /*****************************************************************************
  328. **************************** IRP_MN_STOP_DEVICE **************************
  329. *****************************************************************************/
  330. case IRP_MN_STOP_DEVICE:
  331. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_STOP_DEVICE Irp for Card %d.\n",
  332. PRODUCT_NAME, pCard->CardNumber));
  333. Spx_Card_StopDevice(pCard); /* Stop the card hardware */
  334. pIrp->IoStatus.Status = STATUS_SUCCESS; /* Cannot fail this request */
  335. IoSkipCurrentIrpStackLocation(pIrp);
  336. status = IoCallDriver(pLowerDevObj,pIrp);
  337. break;
  338. /*****************************************************************************
  339. ************************ IRP_MN_QUERY_REMOVE_DEVICE **********************
  340. *****************************************************************************/
  341. case IRP_MN_QUERY_REMOVE_DEVICE:
  342. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_QUERY_REMOVE_DEVICE Irp for Card %d.\n",
  343. PRODUCT_NAME, pCard->CardNumber));
  344. status = STATUS_SUCCESS;
  345. if(SPX_SUCCESS(status)) // If we can stop, pass IRP on down
  346. {
  347. SetPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are now ready to remove the card
  348. pIrp->IoStatus.Status = status;
  349. IoSkipCurrentIrpStackLocation(pIrp);
  350. status = IoCallDriver(pLowerDevObj,pIrp);
  351. }
  352. else // If we can't then complete
  353. {
  354. pIrp->IoStatus.Status = status;
  355. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  356. }
  357. break;
  358. /*****************************************************************************
  359. *********************** IRP_MN_CANCEL_REMOVE_DEVICE **********************
  360. *****************************************************************************/
  361. case IRP_MN_CANCEL_REMOVE_DEVICE:
  362. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_REMOVE_DEVICE Irp for Card %d.\n",
  363. PRODUCT_NAME, pCard->CardNumber));
  364. /* Call driver below first... */
  365. status = Spx_CallDriverBelow(pLowerDevObj,pIrp);
  366. if(NT_SUCCESS(status))
  367. {
  368. ClearPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are no longer expecting to remove the device.
  369. }
  370. pIrp->IoStatus.Status = status;
  371. IoCompleteRequest(pIrp,IO_NO_INCREMENT);
  372. break;
  373. /*****************************************************************************
  374. ************************* IRP_MN_SURPRISE_REMOVAL ************************
  375. *****************************************************************************/
  376. case IRP_MN_SURPRISE_REMOVAL:
  377. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_SURPRISE_REMOVAL Irp for Card %d.\n",
  378. PRODUCT_NAME, pCard->CardNumber));
  379. status = Spx_Card_StopDevice(pCard); // Lets stop the port ready for the REMOVE IRP if we are not already.
  380. SetPnpPowerFlags(pCard,PPF_REMOVE_PENDING); // We are now ready to remove the card
  381. pIrp->IoStatus.Status = status;
  382. IoSkipCurrentIrpStackLocation(pIrp);
  383. status = IoCallDriver(pLowerDevObj,pIrp);
  384. break;
  385. /*****************************************************************************
  386. ************************** IRP_MN_REMOVE_DEVICE **************************
  387. *****************************************************************************/
  388. case IRP_MN_REMOVE_DEVICE:
  389. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_REMOVE_DEVICE Irp for Card %d.\n",
  390. PRODUCT_NAME, pCard->CardNumber));
  391. status = Spx_Card_RemoveDevice(pFDO);
  392. pIrp->IoStatus.Status = status;
  393. IoSkipCurrentIrpStackLocation(pIrp);
  394. status = IoCallDriver(pLowerDevObj,pIrp);
  395. break;
  396. default:
  397. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got PnP Irp - MinorFunction=0x%02X for Card %d.\n",
  398. PRODUCT_NAME,pIrpStack->MinorFunction,pCard->CardNumber));
  399. IoSkipCurrentIrpStackLocation(pIrp);
  400. status = IoCallDriver(pLowerDevObj,pIrp);
  401. break;
  402. }
  403. return(status);
  404. } /* Spx_Card_FDO_DispatchPnp */
  405. /*****************************************************************************
  406. ************************** ***************************
  407. ************************** Spx_CallDriverBelow ***************************
  408. ************************** ***************************
  409. ******************************************************************************
  410. prototype: NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp)
  411. description: Pass the IRP to the driver below this first and wait for it to complete.
  412. parameters: pLowerDevObj points to a device object for the device below
  413. pIrp points to the Plug and Play I/O Request (IRP) to be processed
  414. returns: NT Status Code
  415. */
  416. NTSTATUS Spx_CallDriverBelow(IN PDEVICE_OBJECT pLowerDevObj,IN PIRP pIrp)
  417. {
  418. KEVENT eventWaitLowerDrivers;
  419. NTSTATUS status;
  420. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  421. IoCopyCurrentIrpStackLocationToNext(pIrp); /* Copy parameters to the stack below */
  422. KeInitializeEvent(&eventWaitLowerDrivers,SynchronizationEvent,FALSE); /* Initialise event if need to wait */
  423. IoSetCompletionRoutine(pIrp,Spx_DispatchPnpPowerComplete,&eventWaitLowerDrivers,TRUE,TRUE,TRUE);
  424. if((status = IoCallDriver(pLowerDevObj,pIrp)) == STATUS_PENDING)
  425. {
  426. KeWaitForSingleObject(&eventWaitLowerDrivers,Executive,KernelMode,FALSE,NULL);
  427. status = pIrp->IoStatus.Status;
  428. }
  429. return(status);
  430. } /* Spx_CallDriverBelow */
  431. /************************************************************************************
  432. ************************ *************************
  433. ************************ Spx_DispatchPnpPowerComplete *************************
  434. ************************ *************************
  435. *************************************************************************************
  436. prototype: NTSTATUS Spx_DispatchPnpPowerComplete(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp,IN PVOID Context)
  437. description: The PnP IRP was completed by the lower-level drivers.
  438. Signal this to whoever registered us.
  439. parameters: pDevObject point to the device completing the IRP
  440. pIrp points to the Plug and Play I/O Request (IRP) to be completed
  441. Context was set when the lower driver was called (actually event)
  442. returns: NT Status Code
  443. */
  444. NTSTATUS Spx_DispatchPnpPowerComplete(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp,IN PVOID Context)
  445. {
  446. PIO_STACK_LOCATION stack = NULL;
  447. PKEVENT event = (PKEVENT) Context;
  448. NTSTATUS status;
  449. UNREFERENCED_PARAMETER(pDevObject);
  450. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering DispatchPnpComplete.\n",PRODUCT_NAME));
  451. status = STATUS_SUCCESS;
  452. stack = IoGetCurrentIrpStackLocation(pIrp);
  453. switch(stack->MajorFunction)
  454. {
  455. case IRP_MJ_PNP:
  456. switch(stack->MinorFunction)
  457. {
  458. case IRP_MN_START_DEVICE: // Codes which need processing after lower drivers
  459. case IRP_MN_QUERY_CAPABILITIES:
  460. case IRP_MN_CANCEL_STOP_DEVICE:
  461. case IRP_MN_CANCEL_REMOVE_DEVICE:
  462. KeSetEvent(event,0,FALSE); // Wake up waiting process //
  463. return(STATUS_MORE_PROCESSING_REQUIRED);
  464. default:
  465. break;
  466. }
  467. break;
  468. case IRP_MJ_POWER:
  469. KeSetEvent(event, 0, FALSE); // Wake up waiting process
  470. return(STATUS_MORE_PROCESSING_REQUIRED);
  471. default:
  472. break;
  473. }
  474. return(status);
  475. } /* Spx_DispatchPnpPowerComplete */
  476. /*****************************************************************************
  477. ************************** **************************
  478. ************************** Spx_Card_StartDevice **************************
  479. ************************** **************************
  480. ******************************************************************************
  481. prototype: NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
  482. description: Start the card device:
  483. Process resources (interrupt, I/O, memory)
  484. Initialise and start the hardware
  485. parameters: pDevObject point to the card device to start
  486. pIrp points to the start I/O Request (IRP)
  487. returns: NT Status Code
  488. */
  489. NTSTATUS Spx_Card_StartDevice(IN PDEVICE_OBJECT pDevObject,IN PIRP pIrp)
  490. {
  491. PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
  492. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  493. NTSTATUS status = STATUS_SUCCESS;
  494. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  495. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Card_StartDevice for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
  496. /* Translate the card resources... */
  497. status = XXX_CardGetResources( pDevObject,
  498. pIrpStack->Parameters.StartDevice.AllocatedResources,
  499. pIrpStack->Parameters.StartDevice.AllocatedResourcesTranslated);
  500. if(!SPX_SUCCESS(status))
  501. return(status);
  502. /* Start the hardware... */
  503. if(!SPX_SUCCESS(status = XXX_CardStart(pCard)))
  504. return(status);
  505. SetPnpPowerFlags(pCard,PPF_STARTED); /* Card has been started */
  506. return(status);
  507. } /* Spx_Card_StartDevice */
  508. /*****************************************************************************
  509. ***************************** ******************************
  510. ***************************** Spx_EnumPorts ******************************
  511. ***************************** ******************************
  512. ******************************************************************************
  513. prototype: NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject)
  514. description: Enumerate port devices found on the card device:
  515. parameters: pDevObject point to the card device to enumerate
  516. returns: NT Status Code
  517. */
  518. NTSTATUS Spx_EnumPorts(IN PDEVICE_OBJECT pDevObject)
  519. {
  520. PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
  521. PPORT_DEVICE_EXTENSION pPort = NULL;
  522. NTSTATUS status = STATUS_SUCCESS;
  523. PDEVICE_OBJECT PortPDO = NULL;
  524. UNICODE_STRING PortPDOName;
  525. static ULONG CurrentInstance = 0;
  526. UNICODE_STRING InstanceStr;
  527. WCHAR InstanceNumberBuffer[10];
  528. POWER_STATE PowerState;
  529. USHORT PortNumber = 0;
  530. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  531. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_EnumPorts for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
  532. // Name and create device objects for each port on the card...
  533. for(PortNumber=0;PortNumber<pCard->NumberOfPorts;PortNumber++)
  534. {
  535. if(pCard->AttachedPDO[PortNumber] == NULL) // Only create if not already present
  536. {
  537. // Create the base port name ("XxPort")...
  538. RtlZeroMemory(&PortPDOName, sizeof(UNICODE_STRING));
  539. PortPDOName.MaximumLength = DEVICE_OBJECT_NAME_LENGTH * sizeof(WCHAR);
  540. PortPDOName.Buffer = SpxAllocateMem(PagedPool, PortPDOName.MaximumLength+sizeof(WCHAR));
  541. if(PortPDOName.Buffer == NULL) continue;
  542. RtlZeroMemory(PortPDOName.Buffer, PortPDOName.MaximumLength+sizeof(WCHAR));
  543. RtlAppendUnicodeToString(&PortPDOName, PORT_PDO_NAME_BASE);
  544. // Create the instance ("0")...
  545. RtlInitUnicodeString(&InstanceStr,NULL);
  546. InstanceStr.MaximumLength = sizeof(InstanceNumberBuffer);
  547. InstanceStr.Buffer = InstanceNumberBuffer;
  548. RtlIntegerToUnicodeString(CurrentInstance++, 10, &InstanceStr);
  549. // Append instance to the device name ("XxPort0")...
  550. RtlAppendUnicodeStringToString(&PortPDOName, &InstanceStr);
  551. // Create the port device object with this name...
  552. status = IoCreateDevice(pDevObject->DriverObject,
  553. sizeof(PORT_DEVICE_EXTENSION),
  554. &PortPDOName, // Object Name
  555. FILE_DEVICE_SERIAL_PORT,
  556. FILE_DEVICE_SECURE_OPEN,
  557. TRUE,
  558. &PortPDO);
  559. if(!SPX_SUCCESS(status))
  560. {
  561. SpxDbgMsg(SPX_ERRORS,("%s: Create Device failed = %wZ\n",PRODUCT_NAME,&PortPDOName));
  562. SpxFreeMem(PortPDOName.Buffer);
  563. continue;
  564. }
  565. ASSERT(PortPDO != NULL);
  566. // Increment the pdo's stacksize so that it can pass irps through...
  567. PortPDO->StackSize += pDevObject->StackSize;
  568. // Keep a pointer to the device in the card structure...
  569. pCard->NumPDOs++;
  570. pCard->AttachedPDO[PortNumber] = PortPDO;
  571. ObReferenceObject(PortPDO);
  572. // Initialise port device object and extension...
  573. pPort = PortPDO->DeviceExtension;
  574. RtlZeroMemory(pPort,sizeof(PORT_DEVICE_EXTENSION)); // Clear the device extension
  575. pPort->DeviceName = PortPDOName;
  576. KeInitializeSpinLock(&pPort->PnpPowerFlagsLock); // Initialise the PNP flags lock
  577. ClearPnpPowerFlags(pPort,PPF_STARTED); // Not started yet
  578. ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Not pending a stop
  579. ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Not pending a remove
  580. ClearPnpPowerFlags(pPort,PPF_REMOVED); // Not removed
  581. SetPnpPowerFlags(pPort,PPF_POWERED); // Initially powered up
  582. InitializeListHead(&pPort->StalledIrpQueue); // Initialise the stalled IRP list
  583. KeInitializeSpinLock(&pPort->StalledIrpLock); // Initialise the StalledIrpLock flags lock
  584. pPort->UnstallingFlag = FALSE; // Initialise UnstallingIrps Flag.
  585. pPort->IsFDO = FALSE;
  586. pPort->PortNumber = PortNumber; // system port number
  587. pPort->UniqueInstanceID = FALSE; // Instance ID not unique by default.
  588. pPort->DeviceIsOpen = FALSE; // Port is closed to start with
  589. pPort->DeviceObject = PortPDO; // Backpointer to device object
  590. pPort->DeviceState = PowerDeviceD0; // Port device in full power state
  591. pPort->SystemState = PowerSystemWorking; // System in full power State
  592. pPort->pParentCardExt = pCard; // Point to the parent card extension
  593. ExInitializeFastMutex(&pPort->OpenMutex);
  594. if(!SPX_SUCCESS(status = XXX_PortInit(pPort))) // Initialise hardware
  595. continue;
  596. // Inform Power Manager the of the new power state.
  597. PowerState.DeviceState = pPort->DeviceState;
  598. PoSetPowerState(pPort->DeviceObject, DevicePowerState, PowerState);
  599. PortPDO->Flags &= ~DO_DEVICE_INITIALIZING; // Finished Initialising
  600. PortPDO->Flags |= DO_BUFFERED_IO; // Do Buffered IO
  601. PortPDO->Flags |= DO_BUS_ENUMERATED_DEVICE; // Bus enumerated
  602. PortPDO->Flags |= DO_POWER_PAGABLE; // Get power IRPs at IRQL PASSIVE_LEVEL
  603. }
  604. else
  605. {
  606. PortPDO = pCard->AttachedPDO[PortNumber];
  607. pPort = PortPDO->DeviceExtension;
  608. if(pPort->PnpPowerFlags & PPF_REMOVED)
  609. ClearPnpPowerFlags(pPort,PPF_REMOVED);
  610. }
  611. }
  612. return(status);
  613. } // End Spx_EnumPorts
  614. /*****************************************************************************
  615. ************************** ***************************
  616. ************************** Spx_Card_StopDevice ***************************
  617. ************************** ***************************
  618. ******************************************************************************
  619. prototype: NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard)
  620. description: Stop the card device:
  621. Stop the hardware
  622. Deinitialise card resources (interrupt, I/O, memory)
  623. parameters: pCard points to the card device to stop
  624. returns: NT Status Code
  625. */
  626. NTSTATUS Spx_Card_StopDevice(IN PCARD_DEVICE_EXTENSION pCard)
  627. {
  628. NTSTATUS status = STATUS_SUCCESS;
  629. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  630. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Card_StopDevice for Card %d.\n",PRODUCT_NAME,pCard->CardNumber));
  631. if(pCard->PnpPowerFlags & PPF_STARTED) /* If card is running */
  632. {
  633. XXX_CardStop(pCard); /* Stop the card */
  634. }
  635. ClearPnpPowerFlags(pCard,PPF_STARTED); /* Indicate card is stopped */
  636. ClearPnpPowerFlags(pCard,PPF_STOP_PENDING); /* Clear stop pending flag */
  637. return(status);
  638. } /* Spx_Card_StopDevice */
  639. /*****************************************************************************
  640. ************************* **************************
  641. ************************* Spx_Card_RemoveDevice **************************
  642. ************************* **************************
  643. ******************************************************************************
  644. prototype: NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
  645. description: Remove the card device:
  646. Deallocate any resources
  647. Delete device object
  648. parameters: pDevObject points to the card device object to remove
  649. returns: NT Status Code
  650. */
  651. NTSTATUS Spx_Card_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
  652. {
  653. PCARD_DEVICE_EXTENSION pCard = pDevObject->DeviceExtension;
  654. PDEVICE_OBJECT pPortPdo;
  655. PPORT_DEVICE_EXTENSION pPort;
  656. NTSTATUS status = STATUS_SUCCESS;
  657. int loop;
  658. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  659. SpxDbgMsg(SPX_TRACE_CALLS, ("%s: Entering Spx_Card_RemoveDevice for Card %d.\n",
  660. PRODUCT_NAME, pCard->CardNumber));
  661. /* First remove all "removed" port device objects... */
  662. for(loop=0; loop<PRODUCT_MAX_PORTS; loop++)
  663. {
  664. if(pPortPdo = pCard->AttachedPDO[loop]) /* Enumerated port PDO ? */
  665. {
  666. pPort = pPortPdo->DeviceExtension; /* Get the device extension */
  667. XXX_PortDeInit(pPort); /* Deinitialise port structure */
  668. if(pPort->DeviceName.Buffer)
  669. {
  670. SpxFreeMem(pPort->DeviceName.Buffer); /* Free device name buffer */
  671. pPort->DeviceName.Buffer = NULL;
  672. }
  673. pCard->AttachedPDO[loop] = NULL; /* Remove the port PDO pointer */
  674. pCard->NumPDOs--; /* One less port attached */
  675. IoDeleteDevice(pPortPdo); /* Delete the port device object */
  676. ObDereferenceObject(pPortPdo); /* Dereference the object */
  677. }
  678. }
  679. /* Now, remove the card device object... */
  680. Spx_Card_StopDevice(pCard); /* Stop the card and release resources */
  681. XXX_CardDeInit(pCard); /* Deinitialise non-hardware fields */
  682. IoDetachDevice(pCard->LowerDeviceObject); /* Detach card device from the device stack. */
  683. IoDeleteDevice(pDevObject); /* Delete Card FDO from system. */
  684. return(status);
  685. } /* Spx_Card_RemoveDevice */
  686. /*****************************************************************************
  687. ************************ ************************
  688. ************************ Spx_Port_PDO_DispatchPnp ************************
  689. ************************ ************************
  690. ******************************************************************************
  691. prototype: NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp)
  692. description: The plug and play dispatch routine to handle IRPs for port devices.
  693. parameters: pDevObject points to a port device object for this driver
  694. pIrp points to the Plug and Play I/O Request (IRP) to be processed
  695. returns: NT Status Code
  696. */
  697. NTSTATUS Spx_Port_PDO_DispatchPnp(IN PDEVICE_OBJECT pPDO,IN PIRP pIrp)
  698. {
  699. PPORT_DEVICE_EXTENSION pPort = pPDO->DeviceExtension;
  700. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  701. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  702. NTSTATUS status;
  703. PWCHAR ReturnBuffer = NULL;
  704. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  705. status = pIrp->IoStatus.Status;
  706. switch (pIrpStack->MinorFunction)
  707. {
  708. /*****************************************************************************
  709. *************************** IRP_MN_START_DEVICE **************************
  710. *****************************************************************************/
  711. case IRP_MN_START_DEVICE:
  712. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_START_DEVICE Irp for Port %d.\n",
  713. PRODUCT_NAME,pPort->PortNumber));
  714. status = STATUS_UNSUCCESSFUL;
  715. if(SPX_SUCCESS(status = Spx_Port_StartDevice(pPDO)))
  716. Spx_UnstallIrps(pPort); // Restart any queued IRPs (from a previous start)
  717. break;
  718. /*****************************************************************************
  719. ***************************** IRP_MN_QUERY_ID ****************************
  720. *****************************************************************************/
  721. case IRP_MN_QUERY_ID:
  722. {
  723. PUNICODE_STRING pId = NULL;
  724. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  725. switch(pIrpStack->Parameters.QueryId.IdType)
  726. {
  727. case BusQueryCompatibleIDs:
  728. case BusQueryDeviceID:
  729. case BusQueryInstanceID:
  730. case BusQueryHardwareIDs:
  731. {
  732. status = STATUS_SUCCESS;
  733. switch(pIrpStack->Parameters.QueryId.IdType)
  734. {
  735. case BusQueryDeviceID:
  736. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryDeviceID Irp for Port %d.\n",
  737. PRODUCT_NAME,pPort->PortNumber));
  738. SpxDbgMsg(SPX_MISC_DBG,("%s: Device ID %wZ.\n", PRODUCT_NAME,&pPort->DeviceID));
  739. pId = &pPort->DeviceID;
  740. break;
  741. case BusQueryInstanceID:
  742. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryInstanceID Irp for Port %d.\n",
  743. PRODUCT_NAME, pPort->PortNumber));
  744. SpxDbgMsg(SPX_MISC_DBG,("%s: Instance ID %wZ.\n",PRODUCT_NAME,&pPort->InstanceID));
  745. pId = &pPort->InstanceID;
  746. break;
  747. case BusQueryCompatibleIDs:
  748. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryCompatibleIDs Irp for Port %d.\n",
  749. PRODUCT_NAME, pPort->PortNumber));
  750. pId = &pPort->CompatibleIDs;
  751. break;
  752. case BusQueryHardwareIDs:
  753. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_ID - BusQueryHardwareIDs Irp for Port %d.\n",
  754. PRODUCT_NAME, pPort->PortNumber));
  755. pId = &pPort->HardwareIDs;
  756. break;
  757. default:
  758. break;
  759. }
  760. if(pId)
  761. {
  762. if(pId->Buffer)
  763. {
  764. if(ReturnBuffer = SpxAllocateMem(PagedPool, pId->Length + sizeof(WCHAR)))
  765. RtlCopyMemory(ReturnBuffer, pId->Buffer, pId->Length + sizeof(WCHAR));
  766. else
  767. {
  768. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
  769. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  770. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  771. pPort->DriverObject, // Driver Object
  772. pPort->DeviceObject, // Device Object (Optional)
  773. PhysicalZero, // Physical Address 1
  774. PhysicalZero, // Physical Address 2
  775. 0, // SequenceNumber
  776. pIrpStack->MajorFunction, // Major Function Code
  777. 0, // RetryCount
  778. FILE_ID | __LINE__, // UniqueErrorValue
  779. STATUS_SUCCESS, // FinalStatus
  780. szErrorMsg); // Error Message
  781. status = STATUS_INSUFFICIENT_RESOURCES;
  782. }
  783. }
  784. pIrp->IoStatus.Information = (ULONG_PTR)ReturnBuffer;
  785. }
  786. break;
  787. }
  788. default:
  789. break;
  790. }
  791. break;
  792. }
  793. /*****************************************************************************
  794. ************************* IRP_MN_QUERY_DEVICE_TEXT ***********************
  795. *****************************************************************************/
  796. case IRP_MN_QUERY_DEVICE_TEXT:
  797. {
  798. PUNICODE_STRING pText = NULL;
  799. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  800. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_TEXT Irp for Port %d.\n",
  801. PRODUCT_NAME,pPort->PortNumber));
  802. if(pIrpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
  803. pText = &pPort->DevDesc;
  804. if(pIrpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation)
  805. pText = &pPort->DevLocation;
  806. if((pText == NULL)||(pText->Buffer == NULL))
  807. break;
  808. if(!(ReturnBuffer = SpxAllocateMem(PagedPool, pText->Length + sizeof(WCHAR))))
  809. {
  810. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
  811. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  812. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  813. pPort->DriverObject, // Driver Object
  814. pPort->DeviceObject, // Device Object (Optional)
  815. PhysicalZero, // Physical Address 1
  816. PhysicalZero, // Physical Address 2
  817. 0, // SequenceNumber
  818. pIrpStack->MajorFunction, // Major Function Code
  819. 0, // RetryCount
  820. FILE_ID | __LINE__, // UniqueErrorValue
  821. STATUS_SUCCESS, // FinalStatus
  822. szErrorMsg); // Error Message
  823. status = STATUS_INSUFFICIENT_RESOURCES;
  824. break;
  825. }
  826. status = STATUS_SUCCESS;
  827. RtlCopyMemory(ReturnBuffer, pText->Buffer, pText->Length + sizeof(WCHAR));
  828. pIrp->IoStatus.Information = (ULONG_PTR)ReturnBuffer;
  829. break;
  830. }
  831. /*****************************************************************************
  832. ************************ IRP_MN_QUERY_CAPABILITIES ***********************
  833. *****************************************************************************/
  834. case IRP_MN_QUERY_CAPABILITIES:
  835. {
  836. PDEVICE_CAPABILITIES pDevCaps = NULL;
  837. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_CAPABILITIES Irp for Port %d.\n",
  838. PRODUCT_NAME,pPort->PortNumber));
  839. // Get the packet
  840. pDevCaps = pIrpStack->Parameters.DeviceCapabilities.Capabilities;
  841. // Set the capabilities.
  842. pDevCaps->Version = 1;
  843. pDevCaps->Size = sizeof(DEVICE_CAPABILITIES);
  844. // We cannot wake the system.
  845. pDevCaps->SystemWake = PowerSystemUnspecified;
  846. pDevCaps->DeviceWake = PowerSystemUnspecified;
  847. // Set device state mapping...
  848. pDevCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0;
  849. pDevCaps->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
  850. pDevCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
  851. pDevCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
  852. pDevCaps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  853. pDevCaps->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
  854. // We have no latencies.
  855. pDevCaps->D1Latency = 0;
  856. pDevCaps->D2Latency = 0;
  857. pDevCaps->D3Latency = 0;
  858. // No locking or ejection.
  859. pDevCaps->LockSupported = FALSE;
  860. pDevCaps->EjectSupported = FALSE;
  861. // Removable
  862. pDevCaps->Removable = FALSE;
  863. // Not a Docking device.
  864. pDevCaps->DockDevice = FALSE;
  865. // System wide unique ID.
  866. pDevCaps->UniqueID = pPort->UniqueInstanceID;
  867. //UINumber
  868. pDevCaps->UINumber = pPort->PortNumber+1;
  869. // Raw capable
  870. pDevCaps->RawDeviceOK = TRUE;
  871. // Silent Install
  872. pDevCaps->SilentInstall = FALSE;
  873. // Surprise Removal
  874. pDevCaps->SurpriseRemovalOK = FALSE;
  875. status = STATUS_SUCCESS;
  876. break;
  877. }
  878. /*****************************************************************************
  879. ************************ IRP_MN_QUERY_STOP_DEVICE ************************
  880. *****************************************************************************/
  881. case IRP_MN_QUERY_STOP_DEVICE:
  882. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_STOP_DEVICE Irp for Port %d.\n",
  883. PRODUCT_NAME,pPort->PortNumber));
  884. status = STATUS_UNSUCCESSFUL;
  885. if(pPort->PnpPowerFlags & PPF_STARTED)
  886. {
  887. ExAcquireFastMutex(&pPort->OpenMutex);
  888. if(pPort->DeviceIsOpen)
  889. {
  890. ExReleaseFastMutex(&pPort->OpenMutex);
  891. status = STATUS_DEVICE_BUSY;
  892. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: ------- failing; Port %d open\n",
  893. PRODUCT_NAME, pPort->PortNumber));
  894. }
  895. else
  896. {
  897. SetPnpPowerFlags(pPort,PPF_STOP_PENDING);
  898. status = STATUS_SUCCESS;
  899. ExReleaseFastMutex(&pPort->OpenMutex);
  900. }
  901. }
  902. break;
  903. /*****************************************************************************
  904. ************************ IRP_MN_CANCEL_STOP_DEVICE ***********************
  905. *****************************************************************************/
  906. case IRP_MN_CANCEL_STOP_DEVICE:
  907. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_STOP_DEVICE Irp for Port %d.\n",
  908. PRODUCT_NAME,pPort->PortNumber));
  909. status = STATUS_SUCCESS;
  910. ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear the stop pending flag
  911. Spx_UnstallIrps(pPort); // Restart any queued IRPs
  912. break;
  913. /*****************************************************************************
  914. *************************** IRP_MN_STOP_DEVICE ***************************
  915. *****************************************************************************/
  916. case IRP_MN_STOP_DEVICE:
  917. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_STOP_DEVICE Irp for Port %d\n",
  918. PRODUCT_NAME,pPort->PortNumber));
  919. status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
  920. status = Spx_Port_StopDevice(pPort);
  921. ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear the stop pending flag
  922. break;
  923. /*****************************************************************************
  924. *********************** IRP_MN_QUERY_REMOVE_DEVICE ***********************
  925. *****************************************************************************/
  926. case IRP_MN_QUERY_REMOVE_DEVICE:
  927. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_REMOVE_DEVICE Irp for Port %d.\n",
  928. PRODUCT_NAME,pPort->PortNumber));
  929. ExAcquireFastMutex(&pPort->OpenMutex);
  930. if(pPort->DeviceIsOpen)
  931. {
  932. ExReleaseFastMutex(&pPort->OpenMutex);
  933. status = STATUS_DEVICE_BUSY;
  934. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: ------- failing; Port %d open\n",
  935. PRODUCT_NAME, pPort->PortNumber));
  936. }
  937. else
  938. {
  939. SetPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are now ready to remove the port
  940. status = STATUS_SUCCESS;
  941. ExReleaseFastMutex(&pPort->OpenMutex);
  942. }
  943. break;
  944. /*****************************************************************************
  945. *********************** IRP_MN_CANCEL_REMOVE_DEVICE **********************
  946. *****************************************************************************/
  947. case IRP_MN_CANCEL_REMOVE_DEVICE:
  948. SpxDbgMsg(SPX_TRACE_PNP_IRPS, ("%s: Got IRP_MN_CANCEL_REMOVE_DEVICE Irp for Port %d.\n",
  949. PRODUCT_NAME, pPort->PortNumber));
  950. status = STATUS_SUCCESS;
  951. ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are no longer expecting to remove the device.
  952. break;
  953. /*****************************************************************************
  954. ************************* IRP_MN_SURPRISE_REMOVAL ************************
  955. *****************************************************************************/
  956. case IRP_MN_SURPRISE_REMOVAL:
  957. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_SURPRISE_REMOVAL Irp for Port %d\n",
  958. PRODUCT_NAME,pPort->PortNumber));
  959. status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
  960. status = Spx_Port_StopDevice(pPort);
  961. SetPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // We are now ready to remove the port
  962. break;
  963. /*****************************************************************************
  964. ************************** IRP_MN_REMOVE_DEVICE **************************
  965. *****************************************************************************/
  966. case IRP_MN_REMOVE_DEVICE:
  967. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_REMOVE_DEVICE Irp for Port %d\n",
  968. PRODUCT_NAME,pPort->PortNumber));
  969. status = STATUS_SUCCESS; // we must never fail this IRP (if we do we will probably unload).
  970. Spx_KillStalledIRPs(pPDO); // Kill off any waiting IRPS on the stalled list
  971. status = Spx_Port_RemoveDevice(pPDO);
  972. ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Clear the pending flag
  973. break;
  974. /*****************************************************************************
  975. ********************** IRP_MN_QUERY_DEVICE_RELATIONS *********************
  976. *****************************************************************************/
  977. case IRP_MN_QUERY_DEVICE_RELATIONS:
  978. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got IRP_MN_QUERY_DEVICE_RELATIONS Irp for Port %d.\n",
  979. PRODUCT_NAME, pPort->PortNumber));
  980. switch(pIrpStack->Parameters.QueryDeviceRelations.Type)
  981. {
  982. case TargetDeviceRelation:
  983. {
  984. PDEVICE_RELATIONS pDevRel = NULL;
  985. if(pIrp->IoStatus.Information != 0)
  986. break;
  987. if(!(pDevRel = SpxAllocateMem(PagedPool, sizeof(DEVICE_RELATIONS))))
  988. {
  989. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  990. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
  991. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  992. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  993. pPort->DriverObject, // Driver Object
  994. pPort->DeviceObject, // Device Object (Optional)
  995. PhysicalZero, // Physical Address 1
  996. PhysicalZero, // Physical Address 2
  997. 0, // SequenceNumber
  998. pIrpStack->MajorFunction, // Major Function Code
  999. 0, // RetryCount
  1000. FILE_ID | __LINE__, // UniqueErrorValue
  1001. STATUS_SUCCESS, // FinalStatus
  1002. szErrorMsg); // Error Message
  1003. status = STATUS_INSUFFICIENT_RESOURCES;
  1004. break;
  1005. }
  1006. pDevRel->Count = 1;
  1007. pDevRel->Objects[0] = pPDO;
  1008. ObReferenceObject(pPDO);
  1009. status = STATUS_SUCCESS;
  1010. pIrp->IoStatus.Information = (ULONG_PTR)pDevRel;
  1011. break;
  1012. }
  1013. case BusRelations:
  1014. {
  1015. PDEVICE_RELATIONS pDevRel = NULL;
  1016. if(pIrp->IoStatus.Information != 0)
  1017. break;
  1018. if(!(pDevRel = SpxAllocateMem(PagedPool, sizeof(DEVICE_RELATIONS))))
  1019. {
  1020. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  1021. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
  1022. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1023. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1024. pPort->DriverObject, // Driver Object
  1025. pPort->DeviceObject, // Device Object (Optional)
  1026. PhysicalZero, // Physical Address 1
  1027. PhysicalZero, // Physical Address 2
  1028. 0, // SequenceNumber
  1029. pIrpStack->MajorFunction, // Major Function Code
  1030. 0, // RetryCount
  1031. FILE_ID | __LINE__, // UniqueErrorValue
  1032. STATUS_SUCCESS, // FinalStatus
  1033. szErrorMsg); // Error Message
  1034. status = STATUS_INSUFFICIENT_RESOURCES;
  1035. break;
  1036. }
  1037. pDevRel->Count = 0;
  1038. status = STATUS_SUCCESS;
  1039. pIrp->IoStatus.Information = (ULONG_PTR)pDevRel;
  1040. break;
  1041. }
  1042. default:
  1043. break;
  1044. }
  1045. break;
  1046. default:
  1047. SpxDbgMsg(SPX_TRACE_PNP_IRPS,("%s: Got PnP Irp - MinorFunction=0x%02X for Port %d.\n",
  1048. PRODUCT_NAME,pIrpStack->MinorFunction, pPort->PortNumber));
  1049. break;
  1050. }
  1051. pIrp->IoStatus.Status = status;
  1052. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1053. return(status);
  1054. } /* Spx_Port_PDO_DispatchPnp */
  1055. /*****************************************************************************
  1056. ************************** **************************
  1057. ************************** Spx_Port_StartDevice **************************
  1058. ************************** **************************
  1059. ******************************************************************************
  1060. prototype: NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject)
  1061. description: Start the port device:
  1062. Setup external naming
  1063. Initialise and start the hardware
  1064. parameters: pDevObject point to the card device to start
  1065. pIrp points to the start I/O Request (IRP)
  1066. returns: NT Status Code
  1067. */
  1068. NTSTATUS Spx_Port_StartDevice(IN PDEVICE_OBJECT pDevObject)
  1069. {
  1070. PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
  1071. NTSTATUS status = STATUS_SUCCESS;
  1072. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1073. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_StartDevice for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
  1074. if(!pPort->CreatedSymbolicLink)
  1075. {
  1076. if(!SPX_SUCCESS(status = Spx_DoExternalNaming(pDevObject))) // Set up external name for device
  1077. return(status);
  1078. }
  1079. if(!SPX_SUCCESS(status = XXX_PortStart(pPort))) // Start hardware.
  1080. {
  1081. Spx_RemoveExternalNaming(pDevObject); // Remove external naming.
  1082. return(status);
  1083. }
  1084. SetPnpPowerFlags(pPort,PPF_STARTED); // Port has been started.
  1085. ClearPnpPowerFlags(pPort,PPF_REMOVED); // Port is not removed...yet.
  1086. ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Not pending a stop.
  1087. ClearPnpPowerFlags(pPort,PPF_REMOVE_PENDING); // Not pending a remove.
  1088. return(status);
  1089. } // Spx_Port_StartDevice
  1090. /*****************************************************************************
  1091. ************************** **************************
  1092. ************************** Spx_GetExternalName **************************
  1093. ************************** **************************
  1094. ******************************************************************************
  1095. prototype: NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject)
  1096. description: Setup external naming for a port:
  1097. get Dos Name for port
  1098. form symbolic link name
  1099. parameters: pDevObject points to the device object for the port to be named
  1100. returns: NT Status Code
  1101. */
  1102. NTSTATUS Spx_GetExternalName(IN PDEVICE_OBJECT pDevObject)
  1103. {
  1104. PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
  1105. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  1106. NTSTATUS status = STATUS_SUCCESS;
  1107. HANDLE PnPKeyHandle;
  1108. UNICODE_STRING TmpLinkName;
  1109. WCHAR *pRegName = NULL;
  1110. ULONG BuffLen = 0;
  1111. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  1112. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1113. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_GetExternalName for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
  1114. status = IoOpenDeviceRegistryKey(pDevObject, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &PnPKeyHandle);
  1115. if(!SPX_SUCCESS(status))
  1116. return(status);
  1117. // Get the device name allocated by the PNP manager from the registry...
  1118. if(pRegName = SpxAllocateMem(PagedPool,SYMBOLIC_NAME_LENGTH * sizeof(WCHAR) + sizeof(WCHAR)))
  1119. {
  1120. status = Spx_GetRegistryKeyValue( PnPKeyHandle,
  1121. L"PortName",
  1122. wcslen(L"PortName") * sizeof(WCHAR),
  1123. pRegName,
  1124. SYMBOLIC_NAME_LENGTH * sizeof(WCHAR));
  1125. }
  1126. else
  1127. {
  1128. status = STATUS_INSUFFICIENT_RESOURCES;
  1129. }
  1130. ZwClose(PnPKeyHandle);
  1131. if(!SPX_SUCCESS(status))
  1132. {
  1133. if(pRegName != NULL)
  1134. SpxFreeMem(pRegName);
  1135. return(STATUS_SUCCESS); // Port has not been given a name yet but we must not fail.
  1136. }
  1137. RtlZeroMemory(&TmpLinkName, sizeof(UNICODE_STRING));
  1138. if(!SPX_SUCCESS(status))
  1139. goto NamingError;
  1140. TmpLinkName.MaximumLength = SYMBOLIC_NAME_LENGTH * sizeof(WCHAR);
  1141. TmpLinkName.Buffer = SpxAllocateMem(PagedPool, TmpLinkName.MaximumLength + sizeof(WCHAR));
  1142. if(!TmpLinkName.Buffer)
  1143. {
  1144. sprintf(szErrorMsg, "Port %d on card at %08X%08X Insufficient resources",
  1145. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1146. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1147. pPort->DriverObject, // Driver Object
  1148. pPort->DeviceObject, // Device Object (Optional)
  1149. PhysicalZero, // Physical Address 1
  1150. PhysicalZero, // Physical Address 2
  1151. 0, // SequenceNumber
  1152. 0, // Major Function Code
  1153. 0, // RetryCount
  1154. FILE_ID | __LINE__, // UniqueErrorValue
  1155. STATUS_SUCCESS, // FinalStatus
  1156. szErrorMsg); // Error Message
  1157. status = STATUS_INSUFFICIENT_RESOURCES;
  1158. goto NamingError;
  1159. }
  1160. RtlZeroMemory(TmpLinkName.Buffer, TmpLinkName.MaximumLength + sizeof(WCHAR));
  1161. // Create the "\\DosDevices\\<SymbolicName>" string.
  1162. RtlAppendUnicodeToString(&TmpLinkName, L"\\");
  1163. RtlAppendUnicodeToString(&TmpLinkName, DEFAULT_DIRECTORY);
  1164. RtlAppendUnicodeToString(&TmpLinkName, L"\\");
  1165. RtlAppendUnicodeToString(&TmpLinkName, pRegName);
  1166. pPort->SymbolicLinkName.Length = 0;
  1167. pPort->SymbolicLinkName.MaximumLength = TmpLinkName.Length + sizeof(WCHAR);
  1168. pPort->SymbolicLinkName.Buffer = SpxAllocateMem(PagedPool, pPort->SymbolicLinkName.MaximumLength);
  1169. if(!pPort->SymbolicLinkName.Buffer)
  1170. {
  1171. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Insufficient resources",
  1172. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1173. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1174. pPort->DriverObject, // Driver Object
  1175. pPort->DeviceObject, // Device Object (Optional)
  1176. PhysicalZero, // Physical Address 1
  1177. PhysicalZero, // Physical Address 2
  1178. 0, // SequenceNumber
  1179. 0, // Major Function Code
  1180. 0, // RetryCount
  1181. FILE_ID | __LINE__, // UniqueErrorValue
  1182. STATUS_SUCCESS, // FinalStatus
  1183. szErrorMsg); // Error Message
  1184. status = STATUS_INSUFFICIENT_RESOURCES;
  1185. goto NamingError;
  1186. }
  1187. RtlZeroMemory(pPort->SymbolicLinkName.Buffer, pPort->SymbolicLinkName.MaximumLength);
  1188. RtlAppendUnicodeStringToString(&pPort->SymbolicLinkName, &TmpLinkName);
  1189. pPort->DosName.Buffer = SpxAllocateMem(PagedPool, 64 + sizeof(WCHAR));
  1190. if(!pPort->DosName.Buffer)
  1191. {
  1192. sprintf(szErrorMsg, "Port %d on card at %08X%08X:: Insufficient resources",
  1193. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1194. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1195. pPort->DriverObject, // Driver Object
  1196. pPort->DeviceObject, // Device Object (Optional)
  1197. PhysicalZero, // Physical Address 1
  1198. PhysicalZero, // Physical Address 2
  1199. 0, // SequenceNumber
  1200. 0, // Major Function Code
  1201. 0, // RetryCount
  1202. FILE_ID | __LINE__, // UniqueErrorValue
  1203. STATUS_SUCCESS, // FinalStatus
  1204. szErrorMsg); // Error Message
  1205. status = STATUS_INSUFFICIENT_RESOURCES;
  1206. goto NamingError;
  1207. }
  1208. pPort->DosName.MaximumLength = 64 + sizeof(WCHAR);
  1209. pPort->DosName.Length = 0;
  1210. RtlZeroMemory(pPort->DosName.Buffer, pPort->DosName.MaximumLength);
  1211. RtlAppendUnicodeToString(&pPort->DosName, pRegName);
  1212. RtlZeroMemory(((PUCHAR) (&pPort->DosName.Buffer[0])) + pPort->DosName.Length, sizeof(WCHAR));
  1213. SpxDbgMsg(SPX_MISC_DBG, ("%s: DeviceName is %wZ\n", PRODUCT_NAME, &pPort->DeviceName));
  1214. SpxDbgMsg(SPX_MISC_DBG, ("%s: DosName is %wZ\n", PRODUCT_NAME, &pPort->DosName));
  1215. SpxDbgMsg(SPX_MISC_DBG, ("%s: SymbolicName is %wZ\n", PRODUCT_NAME, &pPort->SymbolicLinkName));
  1216. if(pRegName != NULL)
  1217. SpxFreeMem(pRegName); // Free pRegName
  1218. if(TmpLinkName.Buffer != NULL)
  1219. SpxFreeMem(TmpLinkName.Buffer); // Free TmpLinkName
  1220. return(status);
  1221. NamingError:;
  1222. if(TmpLinkName.Buffer != NULL)
  1223. SpxFreeMem(TmpLinkName.Buffer);
  1224. if(pRegName != NULL)
  1225. SpxFreeMem(pRegName);
  1226. return(status);
  1227. }
  1228. /*****************************************************************************
  1229. ************************** **************************
  1230. ************************** Spx_DoExternalNaming **************************
  1231. ************************** **************************
  1232. ******************************************************************************
  1233. prototype: NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject)
  1234. description: Setup external naming for a port:
  1235. create symbolic link
  1236. add to registry
  1237. register and enable interface
  1238. parameters: pDevObject points to the device object for the port to be named
  1239. returns: NT Status Code
  1240. */
  1241. NTSTATUS Spx_DoExternalNaming(IN PDEVICE_OBJECT pDevObject)
  1242. {
  1243. PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
  1244. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  1245. NTSTATUS status = STATUS_SUCCESS;
  1246. CHAR szErrorMsg[MAX_ERROR_LOG_INSERT]; // Limited to 51 characters + 1 null
  1247. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1248. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_DoExternalNaming for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
  1249. // Get external name...
  1250. if( !SPX_SUCCESS(status = Spx_GetExternalName(pDevObject)) || (pPort->DosName.Buffer == NULL))
  1251. return(status);
  1252. status = IoCreateSymbolicLink(&pPort->SymbolicLinkName, &pPort->DeviceName); // Create the symbolic link...
  1253. if(!SPX_SUCCESS(status))
  1254. {
  1255. sprintf(szErrorMsg, "Port %d on card at %08X%08X:: Insufficient resources",
  1256. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1257. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1258. pPort->DriverObject, // Driver Object
  1259. pPort->DeviceObject, // Device Object (Optional)
  1260. PhysicalZero, // Physical Address 1
  1261. PhysicalZero, // Physical Address 2
  1262. 0, // SequenceNumber
  1263. 0, // Major Function Code
  1264. 0, // RetryCount
  1265. FILE_ID | __LINE__, // UniqueErrorValue
  1266. STATUS_SUCCESS, // FinalStatus
  1267. szErrorMsg); // Error Message
  1268. goto ExternalNamingError;
  1269. }
  1270. // Add mapping to "SERIALCOMM" section of registry...
  1271. pPort->CreatedSymbolicLink = TRUE;
  1272. status = RtlWriteRegistryValue( RTL_REGISTRY_DEVICEMAP,
  1273. L"SERIALCOMM",
  1274. pPort->DeviceName.Buffer,
  1275. REG_SZ,
  1276. pPort->DosName.Buffer,
  1277. pPort->DosName.Length + sizeof(WCHAR));
  1278. if(!SPX_SUCCESS(status))
  1279. {
  1280. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Registry error.",
  1281. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1282. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1283. pPort->DriverObject, // Driver Object
  1284. pPort->DeviceObject, // Device Object (Optional)
  1285. PhysicalZero, // Physical Address 1
  1286. PhysicalZero, // Physical Address 2
  1287. 0, // SequenceNumber
  1288. 0, // Major Function Code
  1289. 0, // RetryCount
  1290. FILE_ID | __LINE__, // UniqueErrorValue
  1291. STATUS_SUCCESS, // FinalStatus
  1292. szErrorMsg); // Error Message
  1293. goto ExternalNamingError;
  1294. }
  1295. status = IoRegisterDeviceInterface( pDevObject, (LPGUID)&GUID_CLASS_COMPORT,
  1296. NULL, &pPort->DeviceClassSymbolicName);
  1297. if(!NT_SUCCESS(status)) // Could return good values of STATUS_SUCCESS or STATUS_OBJECT_NAME_EXISTS
  1298. {
  1299. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Interface error.",
  1300. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1301. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1302. pPort->DriverObject, // Driver Object
  1303. pPort->DeviceObject, // Device Object (Optional)
  1304. PhysicalZero, // Physical Address 1
  1305. PhysicalZero, // Physical Address 2
  1306. 0, // SequenceNumber
  1307. 0, // Major Function Code
  1308. 0, // RetryCount
  1309. FILE_ID | __LINE__, // UniqueErrorValue
  1310. STATUS_SUCCESS, // FinalStatus
  1311. szErrorMsg); // Error Message
  1312. pPort->DeviceClassSymbolicName.Buffer = NULL;
  1313. goto ExternalNamingError;
  1314. }
  1315. // Enable the device interface.
  1316. status = IoSetDeviceInterfaceState(&pPort->DeviceClassSymbolicName, TRUE);
  1317. if(!NT_SUCCESS(status)) // Could return good values of STATUS_SUCCESS or STATUS_OBJECT_NAME_EXISTS
  1318. {
  1319. sprintf(szErrorMsg, "Port %d on card at %08X%08X: Interface error.",
  1320. pPort->PortNumber+1, pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1321. Spx_LogMessage( STATUS_SEVERITY_ERROR,
  1322. pPort->DriverObject, // Driver Object
  1323. pPort->DeviceObject, // Device Object (Optional)
  1324. PhysicalZero, // Physical Address 1
  1325. PhysicalZero, // Physical Address 2
  1326. 0, // SequenceNumber
  1327. 0, // Major Function Code
  1328. 0, // RetryCount
  1329. FILE_ID | __LINE__, // UniqueErrorValue
  1330. STATUS_SUCCESS, // FinalStatus
  1331. szErrorMsg); // Error Message
  1332. goto ExternalNamingError;
  1333. }
  1334. pPort->CreatedSerialCommEntry = TRUE; // Set flag.
  1335. return(status);
  1336. ExternalNamingError:;
  1337. if(!SPX_SUCCESS(status))
  1338. Spx_RemoveExternalNaming(pDevObject); // Remove and tidy up any allocations
  1339. return(status);
  1340. } // End Spx_DoExternalNaming
  1341. /*****************************************************************************
  1342. ************************ ************************
  1343. ************************ Spx_RemoveExternalNaming ************************
  1344. ************************ ************************
  1345. ******************************************************************************
  1346. prototype: NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject)
  1347. description: Remove external naming:
  1348. remove symbolic link
  1349. remove from registry
  1350. stop interface
  1351. parameters: pDevObject points to the device object for the port to be named.
  1352. returns: NT Status Code
  1353. */
  1354. NTSTATUS Spx_RemoveExternalNaming(IN PDEVICE_OBJECT pDevObject)
  1355. {
  1356. PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
  1357. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  1358. NTSTATUS status = STATUS_UNSUCCESSFUL;
  1359. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1360. if(pPort->CreatedSymbolicLink)
  1361. {
  1362. if(pPort->DosName.Buffer)
  1363. {
  1364. SpxFreeMem(pPort->DosName.Buffer); // Free DOS name buffer.
  1365. pPort->DosName.Buffer = NULL;
  1366. }
  1367. if(pPort->SymbolicLinkName.Buffer)
  1368. {
  1369. SpxFreeMem(pPort->SymbolicLinkName.Buffer); // Free symbolic link name buffer.
  1370. pPort->SymbolicLinkName.Buffer = NULL;
  1371. }
  1372. Spx_GetExternalName(pDevObject); // Get external name..
  1373. if(pPort->SymbolicLinkName.Buffer)
  1374. status = IoDeleteSymbolicLink(&pPort->SymbolicLinkName); // Delete Symbolic Link.
  1375. if(pPort->DeviceClassSymbolicName.Buffer) // Device Interface name
  1376. IoSetDeviceInterfaceState(&pPort->DeviceClassSymbolicName, FALSE); // Disable Device Interface.
  1377. pPort->CreatedSymbolicLink = FALSE; // Reset created flag.
  1378. }
  1379. if(pPort->DosName.Buffer)
  1380. {
  1381. SpxFreeMem(pPort->DosName.Buffer); // Free DOS name buffer.
  1382. pPort->DosName.Buffer = NULL;
  1383. }
  1384. if(pPort->SymbolicLinkName.Buffer)
  1385. {
  1386. SpxFreeMem(pPort->SymbolicLinkName.Buffer); // Free symbolic link name buffer.
  1387. pPort->SymbolicLinkName.Buffer = NULL;
  1388. }
  1389. if(pPort->CreatedSerialCommEntry && pPort->DeviceName.Buffer)
  1390. {
  1391. RtlDeleteRegistryValue( RTL_REGISTRY_DEVICEMAP, // Delete SERIALCOMM registry entry.
  1392. SERIAL_DEVICE_MAP,
  1393. pPort->DeviceName.Buffer);
  1394. pPort->CreatedSerialCommEntry = FALSE; // Reset created flag.
  1395. }
  1396. if(pPort->DeviceClassSymbolicName.Buffer) // Device Interface name
  1397. {
  1398. SpxFreeMem(pPort->DeviceClassSymbolicName.Buffer); // Free Device Interface Name.
  1399. pPort->DeviceClassSymbolicName.Buffer = NULL;
  1400. }
  1401. return(STATUS_SUCCESS);
  1402. } // End Spx_RemoveExternalNaming
  1403. /*****************************************************************************
  1404. ************************** ***************************
  1405. ************************** Spx_Port_StopDevice ***************************
  1406. ************************** ***************************
  1407. ******************************************************************************
  1408. prototype: NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort)
  1409. description: Stop the port device:
  1410. Stop the hardware
  1411. Remove external naming
  1412. parameters: pPort points to the port device extension to be stopped
  1413. returns: NT Status Code
  1414. */
  1415. NTSTATUS Spx_Port_StopDevice(IN PPORT_DEVICE_EXTENSION pPort)
  1416. {
  1417. NTSTATUS status = STATUS_SUCCESS;
  1418. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1419. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_StopDevice for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
  1420. if(pPort->PnpPowerFlags & PPF_STARTED)
  1421. XXX_PortStop(pPort); // Stop the port hardware.
  1422. ClearPnpPowerFlags(pPort,PPF_STARTED); // Indicate card is stopped.
  1423. ClearPnpPowerFlags(pPort,PPF_STOP_PENDING); // Clear stop pending flag.
  1424. return(status);
  1425. } // End Spx_Port_StopDevice
  1426. /*****************************************************************************
  1427. ************************* **************************
  1428. ************************* Spx_Port_RemoveDevice **************************
  1429. ************************* **************************
  1430. ******************************************************************************
  1431. prototype: NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
  1432. description: Remove the port device object:
  1433. Remove PDO pointer from card structure
  1434. Deinitialise port hardware
  1435. Delete the device object
  1436. parameters: pDevObject points to the port device object to be stopped
  1437. returns: NT Status Code
  1438. */
  1439. NTSTATUS Spx_Port_RemoveDevice(IN PDEVICE_OBJECT pDevObject)
  1440. {
  1441. PPORT_DEVICE_EXTENSION pPort = pDevObject->DeviceExtension;
  1442. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  1443. NTSTATUS status = STATUS_SUCCESS;
  1444. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1445. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_Port_RemoveDevice for Port %d.\n",PRODUCT_NAME,pPort->PortNumber));
  1446. if(pPort->PnpPowerFlags & PPF_REMOVED) // Has device been removed already?
  1447. return(STATUS_SUCCESS);
  1448. Spx_Port_StopDevice(pPort); // Stop the hardware.
  1449. ClearPnpPowerFlags(pPort,PPF_STARTED); // Mark the PDO as stopped.
  1450. Spx_RemoveExternalNaming(pDevObject); // Remove external naming.
  1451. // Mark the port device as "removed", but don't delete the PDO until the card device is removed...
  1452. SetPnpPowerFlags(pPort,PPF_REMOVED); // Mark the PDO as "removed".
  1453. return(status);
  1454. } // End Spx_Port_RemoveDevice
  1455. /////////////////////////////////////////////////////////////////////////////////////////////
  1456. // Create an Instance ID for the port and try to make it globally unique if possible.
  1457. //
  1458. NTSTATUS
  1459. Spx_CreatePortInstanceID(IN PPORT_DEVICE_EXTENSION pPort)
  1460. {
  1461. PCARD_DEVICE_EXTENSION pCard = pPort->pParentCardExt;
  1462. NTSTATUS status = STATUS_SUCCESS;
  1463. CHAR szTemp[100]; // Space to hold string
  1464. int szTempPos = 0;
  1465. HANDLE PnPKeyHandle;
  1466. BOOLEAN UseBusWideInstanceID = FALSE; // Try to create system wide unique instance IDs
  1467. PAGED_CODE(); // Macro in checked build to assert if pagable code is run at or above dispatch IRQL
  1468. SpxDbgMsg(SPX_TRACE_CALLS,("%s: Entering Spx_CreatePortInstanceID for Port %d.\n", PRODUCT_NAME, pPort->PortNumber));
  1469. status = IoOpenDeviceRegistryKey(pCard->PDO, PLUGPLAY_REGKEY_DRIVER, STANDARD_RIGHTS_READ, &PnPKeyHandle);
  1470. if(SPX_SUCCESS(status))
  1471. {
  1472. ULONG Data = 0;
  1473. if(SPX_SUCCESS(Spx_GetRegistryKeyValue(PnPKeyHandle, L"UseBusWideInstanceID",
  1474. wcslen(L"UseBusWideInstanceID") * sizeof(WCHAR), &Data, sizeof(ULONG))))
  1475. {
  1476. if(Data > 0)
  1477. UseBusWideInstanceID = TRUE; // Installer has told us to use a bus wide instance ID
  1478. // because child devices already exist with that type of ID.
  1479. }
  1480. ZwClose(PnPKeyHandle);
  1481. }
  1482. if(UseBusWideInstanceID)
  1483. {
  1484. pPort->UniqueInstanceID = FALSE; // ID created is not unique system wide.
  1485. status = STATUS_SUCCESS;
  1486. }
  1487. else
  1488. {
  1489. switch(pCard->InterfaceType)
  1490. {
  1491. case Isa:
  1492. // Start Instance ID with ISA address
  1493. szTempPos += sprintf(szTemp,"ISA&%08X%08X&", pCard->PhysAddr.HighPart, pCard->PhysAddr.LowPart);
  1494. pPort->UniqueInstanceID = TRUE; // ID created is unique system wide.
  1495. status = STATUS_SUCCESS;
  1496. break;
  1497. case PCIBus:
  1498. {
  1499. ULONG PCI_BusNumber = 0;
  1500. ULONG PCI_DeviceFunction = 0;
  1501. ULONG ResultLength;
  1502. // Try to get DevicePropertyBusNumber
  1503. if(!SPX_SUCCESS(status = IoGetDeviceProperty(pCard->PDO, DevicePropertyBusNumber,
  1504. sizeof(PCI_BusNumber), &PCI_BusNumber, &ResultLength)))
  1505. break;
  1506. // Start Instance ID with PCI bus number
  1507. szTempPos += sprintf(szTemp,"PCI&%04X&", PCI_BusNumber);
  1508. // Try to get DevicePropertyAddress
  1509. if(!SPX_SUCCESS(status = IoGetDeviceProperty(pCard->PDO, DevicePropertyAddress,
  1510. sizeof(PCI_DeviceFunction), &PCI_DeviceFunction, &ResultLength)))
  1511. break;
  1512. // Add on PCI Device and Function IDs
  1513. szTempPos += sprintf(szTemp + szTempPos,"%08X&", PCI_DeviceFunction);
  1514. pPort->UniqueInstanceID = TRUE; // ID created is unique system wide.
  1515. status = STATUS_SUCCESS;
  1516. break;
  1517. }
  1518. default:
  1519. pPort->UniqueInstanceID = FALSE; // ID created is not unique system wide.
  1520. status = STATUS_SUCCESS;
  1521. break;
  1522. }
  1523. }
  1524. // Finish off the InstanceID with the port number on the card.
  1525. sprintf(szTemp + szTempPos,"%04X", pPort->PortNumber);
  1526. status = Spx_InitMultiString(FALSE, &pPort->InstanceID, szTemp, NULL);
  1527. return status;
  1528. }
  1529. // End of SPX_PNP.C