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.

428 lines
9.7 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbcpnp.c
  5. Abstract:
  6. SMBus Class Driver Plug and Play support
  7. Author:
  8. Bob Moore (Intel)
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "smbc.h"
  14. #include "oprghdlr.h"
  15. #define SMBHC_DEVICE_NAME L"\\Device\\SmbHc"
  16. extern ULONG SMBCDebug;
  17. //
  18. // Prototypes
  19. //
  20. NTSTATUS
  21. SmbCPnpDispatch(
  22. IN PDEVICE_OBJECT DeviceObject,
  23. IN PIRP Irp
  24. );
  25. NTSTATUS
  26. SmbCStartDevice (
  27. IN PDEVICE_OBJECT FDO,
  28. IN PIRP Irp
  29. );
  30. NTSTATUS
  31. SmbCStopDevice (
  32. IN PDEVICE_OBJECT FDO,
  33. IN PIRP Irp
  34. );
  35. NTSTATUS
  36. SmbClassCreateFdo (
  37. IN PDRIVER_OBJECT DriverObject,
  38. IN PDEVICE_OBJECT PDO,
  39. IN ULONG MiniportExtensionSize,
  40. IN PSMB_INITIALIZE_MINIPORT MiniportInitialize,
  41. IN PVOID MiniportContext,
  42. OUT PDEVICE_OBJECT *FDO
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(PAGE,SmbCPnpDispatch)
  46. #pragma alloc_text(PAGE,SmbCStartDevice)
  47. #pragma alloc_text(PAGE,SmbClassCreateFdo)
  48. #endif
  49. NTSTATUS
  50. SmbCPnpDispatch(
  51. IN PDEVICE_OBJECT DeviceObject,
  52. IN PIRP Irp
  53. )
  54. /*++
  55. Routine Description:
  56. This routine is the dispatcher for plug and play requests.
  57. Arguments:
  58. DeviceObject - Pointer to class device object.
  59. Irp - Pointer to the request packet.
  60. Return Value:
  61. Status is returned.
  62. --*/
  63. {
  64. PIO_STACK_LOCATION irpStack;
  65. PSMBDATA SmbData;
  66. KEVENT syncEvent;
  67. NTSTATUS status = STATUS_NOT_SUPPORTED;
  68. PAGED_CODE();
  69. //
  70. // Get a pointer to the current parameters for this request. The
  71. // information is contained in the current stack location.
  72. //
  73. irpStack = IoGetCurrentIrpStackLocation(Irp);
  74. SmbData = (PSMBDATA) DeviceObject->DeviceExtension;
  75. SmbPrint (SMB_NOTE, ("SmbCPnpDispatch: PnP dispatch, minor = %d\n",
  76. irpStack->MinorFunction));
  77. //
  78. // Dispatch minor function
  79. //
  80. switch (irpStack->MinorFunction) {
  81. case IRP_MN_START_DEVICE:
  82. IoCopyCurrentIrpStackLocationToNext (Irp);
  83. KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
  84. IoSetCompletionRoutine(Irp, SmbCSynchronousRequest, &syncEvent, TRUE, TRUE, TRUE);
  85. status = IoCallDriver(SmbData->Class.LowerDeviceObject, Irp);
  86. if (status == STATUS_PENDING) {
  87. KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
  88. status = Irp->IoStatus.Status;
  89. }
  90. status = SmbCStartDevice (DeviceObject, Irp);
  91. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  92. return status;
  93. case IRP_MN_STOP_DEVICE:
  94. status = SmbCStopDevice(DeviceObject, Irp);
  95. break;
  96. case IRP_MN_QUERY_STOP_DEVICE:
  97. SmbPrint(SMB_LOW, ("SmbCPnp: IRP_MN_QUERY_STOP_DEVICE\n"));
  98. status = STATUS_SUCCESS;
  99. break;
  100. case IRP_MN_CANCEL_STOP_DEVICE:
  101. SmbPrint(SMB_LOW, ("SmbCPnp: IRP_MN_CANCEL_STOP_DEVICE\n"));
  102. status = STATUS_SUCCESS;
  103. break;
  104. default:
  105. SmbPrint(SMB_LOW, ("SmbCPnp: Unimplemented PNP minor code %d\n",
  106. irpStack->MinorFunction));
  107. }
  108. if (status != STATUS_NOT_SUPPORTED) {
  109. Irp->IoStatus.Status = status;
  110. }
  111. if (NT_SUCCESS(status) || (status == STATUS_NOT_SUPPORTED)) {
  112. IoSkipCurrentIrpStackLocation (Irp);
  113. status = IoCallDriver(SmbData->Class.LowerDeviceObject, Irp) ;
  114. } else {
  115. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  116. }
  117. return status;
  118. }
  119. NTSTATUS
  120. SmbClassCreateFdo (
  121. IN PDRIVER_OBJECT DriverObject,
  122. IN PDEVICE_OBJECT PDO,
  123. IN ULONG MiniportExtensionSize,
  124. IN PSMB_INITIALIZE_MINIPORT MiniportInitialize,
  125. IN PVOID MiniportContext,
  126. OUT PDEVICE_OBJECT *OutFDO
  127. )
  128. /*++
  129. Routine Description:
  130. This routine will create and initialize a functional device object to
  131. be attached to a SMBus Host controller PDO. It is called from the miniport
  132. AddDevice routine.
  133. Arguments:
  134. DriverObject - a pointer to the driver object this is created under
  135. PDO - a pointer to the SMBus HC PDO
  136. MiniportExtensionSize - Extension size required by the miniport
  137. MiniportInitialize - a pointer to the miniport init routine
  138. MiniportContext - Miniport-defined context info
  139. OutFDO - a location to store the pointer to the new device object
  140. Return Value:
  141. STATUS_SUCCESS if everything was successful
  142. reason for failure otherwise
  143. --*/
  144. {
  145. NTSTATUS Status;
  146. UNICODE_STRING UnicodeString;
  147. PDEVICE_OBJECT FDO;
  148. PDEVICE_OBJECT lowerDevice = NULL;
  149. PSMBDATA SmbData;
  150. //
  151. // Allocate a device object for this miniport
  152. //
  153. RtlInitUnicodeString(&UnicodeString, SMBHC_DEVICE_NAME);
  154. Status = IoCreateDevice(
  155. DriverObject,
  156. sizeof (SMBDATA) + MiniportExtensionSize,
  157. &UnicodeString,
  158. FILE_DEVICE_UNKNOWN, // DeviceType
  159. 0,
  160. FALSE,
  161. &FDO
  162. );
  163. if (Status != STATUS_SUCCESS) {
  164. SmbPrint(SMB_LOW, ("SmbC: unable to create device object: %X\n", Status ));
  165. return(Status);
  166. }
  167. //
  168. // Initialize class data
  169. //
  170. FDO->Flags |= DO_BUFFERED_IO;
  171. //
  172. // Layer our FDO on top of the PDO
  173. //
  174. lowerDevice = IoAttachDeviceToDeviceStack(FDO,PDO);
  175. //
  176. // No status. Do the best we can.
  177. //
  178. ASSERT(lowerDevice);
  179. //
  180. // Fill out class data
  181. //
  182. SmbData = (PSMBDATA) FDO->DeviceExtension;
  183. SmbData->Class.MajorVersion = SMB_CLASS_MAJOR_VERSION;
  184. SmbData->Class.MinorVersion = SMB_CLASS_MINOR_VERSION;
  185. SmbData->Class.Miniport = SmbData + 1;
  186. SmbData->Class.DeviceObject = FDO;
  187. SmbData->Class.LowerDeviceObject = lowerDevice;
  188. SmbData->Class.PDO = PDO;
  189. SmbData->Class.CurrentIrp = NULL;
  190. SmbData->Class.CurrentSmb = NULL;
  191. KeInitializeEvent (&SmbData->AlarmEvent, NotificationEvent, FALSE);
  192. KeInitializeSpinLock (&SmbData->SpinLock);
  193. InitializeListHead (&SmbData->WorkQueue);
  194. InitializeListHead (&SmbData->Alarms);
  195. KeInitializeTimer (&SmbData->RetryTimer);
  196. KeInitializeDpc (&SmbData->RetryDpc, SmbCRetry, SmbData);
  197. //
  198. // Miniport initialization
  199. //
  200. Status = MiniportInitialize (&SmbData->Class, SmbData->Class.Miniport, MiniportContext);
  201. FDO->Flags |= DO_POWER_PAGABLE;
  202. FDO->Flags &= ~DO_DEVICE_INITIALIZING;
  203. if (!NT_SUCCESS(Status)) {
  204. IoDeleteDevice (FDO);
  205. return Status;
  206. }
  207. *OutFDO = FDO;
  208. return Status;
  209. }
  210. NTSTATUS
  211. SmbCStartDevice (
  212. IN PDEVICE_OBJECT FDO,
  213. IN PIRP Irp
  214. )
  215. {
  216. NTSTATUS Status;
  217. PSMBDATA SmbData;
  218. SmbPrint(SMB_LOW, ("SmbCStartDevice Entered with fdo %x\n", FDO));
  219. SmbData = (PSMBDATA) FDO->DeviceExtension;
  220. //
  221. // Initialize the Miniclass driver.
  222. //
  223. SmbData->Class.CurrentIrp = Irp;
  224. Status = SmbData->Class.ResetDevice (
  225. &SmbData->Class,
  226. SmbData->Class.Miniport
  227. );
  228. SmbData->Class.CurrentIrp = NULL;
  229. if (!NT_SUCCESS(Status)) {
  230. SmbPrint(SMB_ERROR,
  231. ("SmbCStartDevice: Class.ResetDevice failed. = %Lx\n",
  232. Status));
  233. return Status;
  234. }
  235. //
  236. // Install the Operation Region handlers
  237. //
  238. Status = RegisterOpRegionHandler (SmbData->Class.LowerDeviceObject,
  239. ACPI_OPREGION_ACCESS_AS_RAW,
  240. ACPI_OPREGION_REGION_SPACE_SMB,
  241. (PACPI_OP_REGION_HANDLER)SmbCRawOpRegionHandler,
  242. SmbData,
  243. 0,
  244. &SmbData->RawOperationRegionObject);
  245. if (!NT_SUCCESS(Status)) {
  246. SmbPrint(SMB_ERROR,
  247. ("SmbCStartDevice: Could not install raw Op region handler, status = %Lx\n",
  248. Status));
  249. //
  250. // Failure to register opregion handler is not critical. It just reduces functionality
  251. //
  252. SmbData->RawOperationRegionObject = NULL;
  253. Status = STATUS_SUCCESS;
  254. }
  255. return Status;
  256. }
  257. NTSTATUS
  258. SmbCStopDevice (
  259. IN PDEVICE_OBJECT FDO,
  260. IN PIRP Irp
  261. )
  262. {
  263. NTSTATUS Status;
  264. PSMBDATA SmbData;
  265. SmbPrint(SMB_LOW, ("SmbCStopDevice Entered with fdo %x\n", FDO));
  266. SmbData = (PSMBDATA) FDO->DeviceExtension;
  267. //
  268. // Stop handling operation regions before turning off driver.
  269. //
  270. if (SmbData->RawOperationRegionObject) {
  271. DeRegisterOpRegionHandler (SmbData->Class.LowerDeviceObject,
  272. SmbData->RawOperationRegionObject);
  273. }
  274. //
  275. // Stop the device
  276. //
  277. SmbData->Class.CurrentIrp = Irp;
  278. Status = SmbData->Class.StopDevice (
  279. &SmbData->Class,
  280. SmbData->Class.Miniport
  281. );
  282. SmbData->Class.CurrentIrp = NULL;
  283. return Status;
  284. }
  285. NTSTATUS
  286. SmbCSynchronousRequest (
  287. IN PDEVICE_OBJECT DeviceObject,
  288. IN PIRP Irp,
  289. IN PKEVENT IoCompletionEvent
  290. )
  291. /*++
  292. Routine Description:
  293. Completion function for synchronous IRPs sent to this driver.
  294. No event.
  295. --*/
  296. {
  297. KeSetEvent(IoCompletionEvent, IO_NO_INCREMENT, FALSE);
  298. return STATUS_MORE_PROCESSING_REQUIRED;
  299. }