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.

390 lines
11 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. Michael Hills
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "smbc.h"
  14. NTSTATUS
  15. SmbCRawOpRegionCompletion (
  16. IN PDEVICE_OBJECT DeviceObject,
  17. IN PIRP Irp,
  18. IN PVOID Context
  19. )
  20. /*++
  21. Routine Description:
  22. This routine starts or continues servicing the device's work queue
  23. Arguments:
  24. DeviceObject - EC device object
  25. Irp - Completing Irp
  26. Context - Note used
  27. Return Value:
  28. Status
  29. --*/
  30. {
  31. PACPI_OPREGION_CALLBACK completionHandler;
  32. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
  33. PVOID completionContext;
  34. PFIELDUNITOBJ FieldUnit;
  35. POBJDATA Data;
  36. PBUFFERACC_BUFFER dataBuffer;
  37. PSMB_REQUEST request;
  38. ULONG i;
  39. //
  40. // Grab the arguments from the irp
  41. //
  42. completionHandler = (PACPI_OPREGION_CALLBACK) irpSp->Parameters.Others.Argument1;
  43. completionContext = (PVOID) irpSp->Parameters.Others.Argument2;
  44. FieldUnit = (PFIELDUNITOBJ) irpSp->Parameters.Others.Argument3;
  45. Data = (POBJDATA) irpSp->Parameters.Others.Argument4;
  46. SmbPrint(
  47. SMB_HANDLER,
  48. ("SmbCRawOpRegionCompletion: Callback: %08lx Context: %08lx "
  49. "Status: %08lx\n",
  50. completionHandler, completionContext, Irp->IoStatus.Status )
  51. );
  52. //
  53. // Copy the results into the buffer for a read.
  54. //
  55. request = (PSMB_REQUEST) Data->uipDataValue;
  56. Data->uipDataValue = 0;
  57. dataBuffer = (PBUFFERACC_BUFFER) Data->pbDataBuff;
  58. dataBuffer->Status = request->Status;
  59. switch (request->Protocol) {
  60. case SMB_RECEIVE_BYTE:
  61. case SMB_READ_BYTE:
  62. case SMB_READ_WORD:
  63. case SMB_READ_BLOCK:
  64. case SMB_PROCESS_CALL:
  65. case SMB_BLOCK_PROCESS_CALL:
  66. //
  67. // There is data to return
  68. //
  69. if (request->Status != SMB_STATUS_OK) {
  70. SmbPrint(SMB_ERROR, ("SmbCRawOpRegionCompletion: SMBus error %x\n", request->Status));
  71. dataBuffer->Length = 0xff;
  72. RtlFillMemory (dataBuffer->Data, 32, 0xff);
  73. } else {
  74. if ((request->Protocol == SMB_READ_BLOCK) || (request->Protocol == SMB_BLOCK_PROCESS_CALL)) {
  75. RtlCopyMemory (dataBuffer->Data, request->Data, request->BlockLength);
  76. dataBuffer->Length = request->BlockLength;
  77. } else {
  78. *(PULONG)dataBuffer->Data = *((PULONG)(request->Data));
  79. dataBuffer->Length = 0xff;
  80. // This field is reseved for all but block accesses
  81. }
  82. }
  83. }
  84. //
  85. // Invoke the AML interpreter's callback
  86. //
  87. (completionHandler)( completionContext);
  88. //
  89. // We are done with this irp
  90. //
  91. ExFreePool (request);
  92. IoFreeIrp (Irp);
  93. //
  94. // Return this always --- we had to free the irp ourselves
  95. //
  96. return STATUS_MORE_PROCESSING_REQUIRED;
  97. }
  98. NTSTATUS EXPORT
  99. SmbCRawOpRegionHandler (
  100. ULONG AccessType,
  101. PFIELDUNITOBJ FieldUnit,
  102. POBJDATA Data,
  103. ULONG_PTR Context,
  104. PACPI_OPREGION_CALLBACK CompletionHandler,
  105. PVOID CompletionContext
  106. )
  107. /*++
  108. Routine Description:
  109. This routine handles requests to service the EC operation region
  110. Arguments:
  111. AccessType - Read or Write data
  112. FieldUnit - Opregion field info (address, command, protocol, etc.)
  113. Data - Data Buffer
  114. Context - SMBDATA
  115. CompletionHandler - AMLI handler to call when operation is complete
  116. CompletionContext - Context to pass to the AMLI handler
  117. Return Value:
  118. Status
  119. Notes:
  120. Could this be optimized by bypassing some of the IO subsystem?
  121. --*/
  122. {
  123. NTSTATUS status;
  124. PIRP irp = NULL;
  125. PIO_STACK_LOCATION irpSp;
  126. PSMBDATA smbData = (PSMBDATA) Context;
  127. PSMB_REQUEST request = NULL;
  128. PNSOBJ opRegion;
  129. PBUFFERACC_BUFFER dataBuffer;
  130. ULONG accType = FieldUnit->FieldDesc.dwFieldFlags & ACCTYPE_MASK;
  131. ULONG i;
  132. // DbgBreakPoint ();
  133. SmbPrint(
  134. SMB_HANDLER,
  135. ("SmbCRawOpRegionHandler: Entered - NSObj(%08x) ByteOfs(%08x) Start(%08x)"
  136. " Num(%08x) Flags(%08x)\n",
  137. FieldUnit->pnsFieldParent,
  138. FieldUnit->FieldDesc.dwByteOffset,
  139. FieldUnit->FieldDesc.dwStartBitPos,
  140. FieldUnit->FieldDesc.dwNumBits,
  141. FieldUnit->FieldDesc.dwFieldFlags)
  142. );
  143. //
  144. // Parameter validation
  145. //
  146. if (accType != ACCTYPE_BUFFER) {
  147. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid Access type = 0x%08x should be ACCTYPE_BUFFER\n", accType) );
  148. goto SmbCOpRegionHandlerError;
  149. }
  150. if (AccessType == ACPI_OPREGION_WRITE) {
  151. if (Data->dwDataType != OBJTYPE_BUFFDATA) {
  152. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid dwDataType = 0x%08x should be OBJTYPE_BUFFDATA\n", Data->dwDataType) );
  153. goto SmbCOpRegionHandlerError;
  154. }
  155. if (Data->dwDataLen != sizeof(BUFFERACC_BUFFER)) {
  156. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid dwDataLen = 0x%08x should be 0x%08x\n", Data->dwDataLen, sizeof(BUFFERACC_BUFFER)) );
  157. goto SmbCOpRegionHandlerError;
  158. }
  159. } else if (AccessType == ACPI_OPREGION_READ) {
  160. if ((Data->dwDataType != OBJTYPE_BUFFDATA) || (Data->pbDataBuff == NULL)) {
  161. Data->dwDataType = OBJTYPE_INTDATA;
  162. Data->dwDataValue = sizeof(BUFFERACC_BUFFER);
  163. return STATUS_BUFFER_TOO_SMALL;
  164. }
  165. if (Data->dwDataLen != sizeof(BUFFERACC_BUFFER)) {
  166. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid dwDataLen = 0x%08x should be 0x%08x\n", Data->dwDataLen, sizeof(BUFFERACC_BUFFER)) );
  167. goto SmbCOpRegionHandlerError;
  168. }
  169. } else {
  170. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid AccessType = 0x%08x\n", AccessType) );
  171. goto SmbCOpRegionHandlerError;
  172. }
  173. //
  174. // Allocate an IRP for below. Allocate one extra stack location to store
  175. // some data in.
  176. //
  177. irp = IoAllocateIrp((CCHAR)(smbData->Class.DeviceObject->StackSize + 1),
  178. FALSE
  179. );
  180. request = ExAllocatePoolWithTag (NonPagedPool, sizeof (SMB_REQUEST), 'CbmS');
  181. if (!irp || !request) {
  182. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Cannot allocate irp\n") );
  183. goto SmbCOpRegionHandlerError;
  184. }
  185. //
  186. // Fill in the top location so that we can use it ourselves
  187. //
  188. irpSp = IoGetNextIrpStackLocation( irp );
  189. irpSp->Parameters.Others.Argument1 = (PVOID) CompletionHandler;
  190. irpSp->Parameters.Others.Argument2 = (PVOID) CompletionContext;
  191. irpSp->Parameters.Others.Argument3 = (PVOID) FieldUnit;
  192. irpSp->Parameters.Others.Argument4 = (PVOID) Data;
  193. IoSetNextIrpStackLocation( irp );
  194. //
  195. // Fill out the irp with the request info
  196. //
  197. irpSp = IoGetNextIrpStackLocation( irp );
  198. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  199. irpSp->Parameters.DeviceIoControl.IoControlCode = SMB_BUS_REQUEST;
  200. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(SMB_REQUEST);
  201. irpSp->Parameters.DeviceIoControl.Type3InputBuffer = request;
  202. request->Status = 0;
  203. //
  204. // Translate between Opregion Protocols and smbus protocols
  205. // and fill copy data.
  206. //
  207. //
  208. // Copy data into data buffer for writes.
  209. //
  210. dataBuffer = (PBUFFERACC_BUFFER)Data->pbDataBuff;
  211. if (AccessType == ACPI_OPREGION_WRITE) {
  212. switch ((FieldUnit->FieldDesc.dwFieldFlags & FDF_ACCATTRIB_MASK) >> 8) {
  213. case SMB_QUICK:
  214. break;
  215. case SMB_SEND_RECEIVE:
  216. case SMB_BYTE:
  217. *((PUCHAR) (request->Data)) = *((PUCHAR) (dataBuffer->Data));
  218. break;
  219. case SMB_WORD:
  220. case SMB_PROCESS:
  221. *((PUSHORT) (request->Data)) = *((PUSHORT) (dataBuffer->Data));
  222. break;
  223. case SMB_BLOCK:
  224. case SMB_BLOCK_PROCESS:
  225. dataBuffer = (PBUFFERACC_BUFFER)Data->pbDataBuff;
  226. for (i = 0; i < dataBuffer->Length; i++) {
  227. request->Data[i] = dataBuffer->Data[i];
  228. }
  229. request->BlockLength = (UCHAR) dataBuffer->Length;
  230. break;
  231. default:
  232. SmbPrint( SMB_ERROR, ("SmbCRawOpRegionHandler: Invalid AccessAs: FieldFlags = 0x%08x\n", FieldUnit->FieldDesc.dwFieldFlags) );
  233. goto SmbCOpRegionHandlerError;
  234. }
  235. }
  236. //
  237. // Determine protocol
  238. //
  239. request->Protocol = (UCHAR) ((FieldUnit->FieldDesc.dwFieldFlags & FDF_ACCATTRIB_MASK) >> 8);
  240. if ((request->Protocol < SMB_QUICK) || (request->Protocol > SMB_BLOCK_PROCESS)) {
  241. SmbPrint (SMB_ERROR, ("SmbCRawOpRegionHandler: BIOS BUG Unknown Protocol (access attribute) 0x%02x.\n", request->Protocol));
  242. ASSERTMSG ("SmbCRawOpRegionHandler: Access type DWordAcc is not suported for SMB opregions.\n", FALSE);
  243. goto SmbCOpRegionHandlerError;
  244. }
  245. if (request->Protocol <= SMB_BLOCK) {
  246. request->Protocol -= (AccessType == ACPI_OPREGION_READ) ? 1 : 2;
  247. } else {
  248. request->Protocol -= 2;
  249. }
  250. SmbPrint(SMB_HANDLER,
  251. ("SmbCRawOpRegionHandler: request->Protocol = %08x\n", request->Protocol));
  252. //
  253. // Find the Slave address nd Command value (not used for all protocols)
  254. //
  255. request->Address = (UCHAR) ((FieldUnit->FieldDesc.dwByteOffset >> 8) & 0xff);
  256. request->Command = (UCHAR) (FieldUnit->FieldDesc.dwByteOffset & 0xff);
  257. //
  258. // Pass Pointer to request in the data structure because
  259. // there is not enough space in the irp stack.
  260. // If this is a write, the data has already been copied out.
  261. // If this is a read, we will read the value of request before
  262. // copying the result data.
  263. //
  264. Data->uipDataValue = (ULONG_PTR) request;
  265. //
  266. // Set a completion routine
  267. //
  268. IoSetCompletionRoutine(
  269. irp,
  270. SmbCRawOpRegionCompletion,
  271. NULL,
  272. TRUE,
  273. TRUE,
  274. TRUE
  275. );
  276. //
  277. // Send to the front-end of the SMB driver as a normal I/O request
  278. //
  279. status = IoCallDriver (smbData->Class.DeviceObject, irp);
  280. if (!NT_SUCCESS(status)) {
  281. SmbPrint (SMB_ERROR, ("SmbCRawOpRegionHandler: Irp failed with status %08x\n", status));
  282. goto SmbCOpRegionHandlerError;
  283. }
  284. SmbPrint(
  285. SMB_HANDLER,
  286. ("SmbCRawOpRegionHandler: Exiting - Data=%x Status=%x\n",
  287. Data->uipDataValue, status)
  288. );
  289. return status;
  290. SmbCOpRegionHandlerError:
  291. if (irp) {
  292. IoFreeIrp (irp);
  293. }
  294. if (request) {
  295. ExFreePool (request);
  296. }
  297. Data->uipDataValue = 0xffffffff;
  298. Data->dwDataLen = 0;
  299. CompletionHandler( CompletionContext );
  300. return STATUS_UNSUCCESSFUL;
  301. }