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.

664 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 - 2001 Microsoft Corporation
  3. Module Name:
  4. ### ## # ## ## # ## ## ##### ### ## ## #### ##### #####
  5. ## # ## ### ## ### # ## ## ## ## ### ### ### ## # ## ## ## ##
  6. ### ## ### ## #### # ## ## ## ## ## ## ######## ## ## ## ## ##
  7. ### ## # # ## # #### #### ##### ## ## # ### ## ## ## ## ## ##
  8. ### ### ### # ### #### #### ####### # # ## ## ##### #####
  9. # ## ### ### # ## ## ## ## ## ## # ## ## ## # ## ##
  10. ### ## ## # # ## ## ## ## ## # ## ## #### ## ##
  11. Abstract:
  12. This module contains the entire implementation of
  13. the NVRAM miniport for the ServerWorks
  14. CSB5 server chip set.
  15. Author:
  16. Wesley Witt (wesw) 1-Oct-2001
  17. Environment:
  18. Kernel mode only.
  19. Notes:
  20. --*/
  21. #include "swnvram.h"
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(INIT,DriverEntry)
  24. #endif
  25. #define CLEARBITS(_val,_mask) ((_val) &= ~(_mask))
  26. #define SETBITS(_val,_mask) ((_val) |= (_mask))
  27. BOOLEAN
  28. SaNvramStartNextIo(
  29. IN PDEVICE_EXTENSION DeviceExtension
  30. )
  31. /*++
  32. Routine Description:
  33. This function is called by the ISR and the StartIo functions.
  34. The purpose is to modify the device's hardware registers
  35. such that the next I/O is started on the device.
  36. Arguments:
  37. DeviceExtension - A pointer to the mini-port's device extension
  38. Context:
  39. IRQL: DISPATCH_LEVEL or DIRQL, arbitrary thread context
  40. Return Value:
  41. A value of TRUE is returned if the I/O is started successfully.
  42. Otherwise a value of FALSE is returned.
  43. --*/
  44. {
  45. USHORT Control;
  46. //
  47. // This function executes at DIRQL and it synchronized
  48. // with the ISR.
  49. //
  50. //
  51. // Read the current value of the NVRAM address register
  52. //
  53. Control = READ_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase );
  54. if (Control & NVRAM_CONTROL_BUSY) {
  55. //
  56. // This should never happen, but the device us telling
  57. // us that it is busy.
  58. //
  59. return FALSE;
  60. }
  61. //
  62. // Setup the device for the I/O
  63. //
  64. //
  65. // Clear the Function code
  66. //
  67. CLEARBITS( Control, NVRAM_CONTROL_FUNCTION_CODE );
  68. switch (DeviceExtension->IoFunction) {
  69. case IRP_MJ_WRITE:
  70. //
  71. // Stuff the next dword into the data register
  72. //
  73. WRITE_REGISTER_ULONG(
  74. (PULONG)(DeviceExtension->NvramMemBase+4),
  75. DeviceExtension->IoBuffer[DeviceExtension->IoIndex]
  76. );
  77. //
  78. // Set the bit to indicate a write
  79. //
  80. SETBITS( Control, NVRAM_CONTROL_FUNCTION_WRITE );
  81. break;
  82. case IRP_MJ_READ:
  83. //
  84. // Set the bit to indicate a read
  85. //
  86. SETBITS( Control, NVRAM_CONTROL_FUNCTION_READ );
  87. break;
  88. default:
  89. return FALSE;
  90. }
  91. //
  92. // Clear the I/O address
  93. //
  94. CLEARBITS( Control, NVRAM_CONTROL_ADDRESS );
  95. //
  96. // Set the requested I/O address
  97. //
  98. Control = Control | (USHORT) (DeviceExtension->IoOffset + DeviceExtension->IoIndex);
  99. //
  100. // Write the new control value to the address register
  101. //
  102. WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, Control );
  103. return TRUE;
  104. }
  105. BOOLEAN
  106. SaNvramInterruptService(
  107. IN PKINTERRUPT InterruptObject,
  108. IN PVOID ServiceContext
  109. )
  110. /*++
  111. Routine Description:
  112. This function is the device's interrupt service routine and
  113. is called by the OS to service the interrupt. The interrupt
  114. spin lock is held so work here is kept to a minimum.
  115. Arguments:
  116. InterruptObject - Pointer to an interrupt object.
  117. DeviceExtension - Pointer to the mini-port's device extension
  118. Context:
  119. IRQL: DIRQL, arbitrary thread context
  120. Return Value:
  121. A value of TRUE is returned if the interrupt is serviced by
  122. this function. Otherwise a value of FALSE is returned.
  123. --*/
  124. {
  125. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) ServiceContext;
  126. USHORT Control;
  127. //
  128. // First thing is to check the DONE bit in the NVRAM address register.
  129. // This bit indicates that the device has completed a previous
  130. // command request. This tells the ISR that the interrupt was
  131. // likely generated by the NVRAM device.
  132. //
  133. Control = READ_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase );
  134. if ((Control & NVRAM_CONTROL_DONE) == 0) {
  135. return FALSE;
  136. }
  137. //
  138. // Now the interrupt must be stopped.
  139. // This is accomplished by setting the done
  140. // bit and clearing the function code.
  141. //
  142. CLEARBITS( Control, NVRAM_CONTROL_FUNCTION_CODE );
  143. SETBITS( Control, NVRAM_CONTROL_DONE );
  144. WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, Control );
  145. //
  146. // Check to see if this is a bogus interrupt
  147. //
  148. if (DeviceExtension->IoIndex >= DeviceExtension->IoLength) {
  149. return FALSE;
  150. }
  151. //
  152. // Process the I/O
  153. //
  154. if (DeviceExtension->IoFunction == IRP_MJ_READ) {
  155. //
  156. // Fetch the double word value from the NVRAM data register
  157. //
  158. DeviceExtension->IoBuffer[DeviceExtension->IoIndex] = READ_REGISTER_ULONG( (PULONG)(DeviceExtension->NvramMemBase+4) );
  159. }
  160. DeviceExtension->IoIndex += 1;
  161. DeviceExtension->CompletedIoSize += sizeof(ULONG);
  162. if (DeviceExtension->IoIndex >= DeviceExtension->IoLength) {
  163. //
  164. // We're done so we need to have the DPC start the next I/O
  165. //
  166. SaPortRequestDpc( DeviceExtension, NULL );
  167. } else {
  168. //
  169. // More I/O necessary so request the device start the next I/O
  170. //
  171. if (!SaNvramStartNextIo( DeviceExtension )) {
  172. //
  173. // Something failed so be sure that the next I/O is started
  174. //
  175. SaPortRequestDpc( DeviceExtension, NULL );
  176. }
  177. }
  178. return TRUE;
  179. }
  180. NTSTATUS
  181. SaNvramRead(
  182. IN PVOID DeviceExtensionIn,
  183. IN PIRP Irp,
  184. IN PVOID FsContext,
  185. IN LONGLONG StartingOffset,
  186. IN PVOID DataBuffer,
  187. IN ULONG DataBufferLength
  188. )
  189. /*++
  190. Routine Description:
  191. This routine processes the read requests for the local display miniport.
  192. Arguments:
  193. DeviceExtensionIn - Miniport's device extension
  194. StartingOffset - Starting offset for the I/O
  195. DataBuffer - Pointer to the data buffer
  196. DataBufferLength - Length of the data buffer in bytes
  197. Return Value:
  198. NT status code.
  199. --*/
  200. {
  201. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
  202. //
  203. // Validate the I/O parameters
  204. //
  205. if (((StartingOffset + DataBufferLength) / sizeof(ULONG)) > MAX_NVRAM_SIZE) {
  206. REPORT_ERROR( SA_DEVICE_NVRAM, "Starting offset is too large\n", STATUS_INVALID_PARAMETER_1 );
  207. return STATUS_INVALID_PARAMETER_1;
  208. }
  209. //
  210. // Save the I/O parameters
  211. //
  212. DeviceExtension->IoBuffer = (PULONG)DataBuffer;
  213. DeviceExtension->IoLength = DataBufferLength / sizeof(ULONG);
  214. DeviceExtension->IoFunction = IRP_MJ_READ;
  215. DeviceExtension->IoOffset = (ULONG) (StartingOffset / sizeof(ULONG));
  216. DeviceExtension->IoIndex = 0;
  217. DeviceExtension->CompletedIoSize = 0;
  218. //
  219. // Start the I/O
  220. if (!SaNvramStartNextIo( DeviceExtension )) {
  221. REPORT_ERROR( SA_DEVICE_NVRAM, "SaNvramStartNextIo failed\n", STATUS_UNSUCCESSFUL );
  222. return STATUS_UNSUCCESSFUL;
  223. }
  224. return STATUS_PENDING;
  225. }
  226. NTSTATUS
  227. SaNvramWrite(
  228. IN PVOID DeviceExtensionIn,
  229. IN PIRP Irp,
  230. IN PVOID FsContext,
  231. IN LONGLONG StartingOffset,
  232. IN PVOID DataBuffer,
  233. IN ULONG DataBufferLength
  234. )
  235. /*++
  236. Routine Description:
  237. This routine processes the write requests for the local display miniport.
  238. Arguments:
  239. DeviceExtensionIn - Miniport's device extension
  240. StartingOffset - Starting offset for the I/O
  241. DataBuffer - Pointer to the data buffer
  242. DataBufferLength - Length of the data buffer in bytes
  243. Return Value:
  244. NT status code.
  245. --*/
  246. {
  247. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
  248. //
  249. // Validate the I/O parameters
  250. //
  251. if (((StartingOffset + DataBufferLength) / sizeof(ULONG)) > MAX_NVRAM_SIZE) {
  252. REPORT_ERROR( SA_DEVICE_NVRAM, "Starting offset is too large\n", STATUS_INVALID_PARAMETER_1 );
  253. return STATUS_INVALID_PARAMETER_1;
  254. }
  255. //
  256. // Save the I/O parameters
  257. //
  258. DeviceExtension->IoBuffer = (PULONG)DataBuffer;
  259. DeviceExtension->IoLength = DataBufferLength / sizeof(ULONG);
  260. DeviceExtension->IoFunction = IRP_MJ_WRITE;
  261. DeviceExtension->IoOffset = (ULONG) (StartingOffset / sizeof(ULONG));
  262. DeviceExtension->IoIndex = 0;
  263. DeviceExtension->CompletedIoSize = 0;
  264. //
  265. // Start the I/O
  266. if (!SaNvramStartNextIo( DeviceExtension )) {
  267. REPORT_ERROR( SA_DEVICE_NVRAM, "SaNvramStartNextIo failed\n", STATUS_UNSUCCESSFUL );
  268. return STATUS_UNSUCCESSFUL;
  269. }
  270. return STATUS_PENDING;
  271. }
  272. VOID
  273. SaNvramDpcRoutine(
  274. IN PKDPC Dpc,
  275. IN PDEVICE_OBJECT DeviceObject,
  276. IN PIRP Irp,
  277. IN PVOID Context
  278. )
  279. /*++
  280. Routine Description:
  281. This function is the device's DPC-for-ISR function. It is called
  282. only by the ISR function and it's only function is to start the
  283. next I/O.
  284. Arguments:
  285. DeviceObject - Pointer to the target device object.
  286. DeviceExtension - Pointer to the mini-port's device extension.
  287. Context - Mini-port supplied context pointer.
  288. Context:
  289. IRQL: DISPATCH_LEVEL, DPC context
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) Irp;
  295. NTSTATUS Status;
  296. //
  297. // Set the status based on the data
  298. // that was transfered.
  299. //
  300. if (DeviceExtension->CompletedIoSize == (DeviceExtension->IoIndex * sizeof(ULONG))) {
  301. Status = STATUS_SUCCESS;
  302. } else {
  303. Status = STATUS_UNEXPECTED_IO_ERROR;
  304. }
  305. //
  306. // Reset the current I/O paramaters to
  307. // prevent the ISR from reacting to a
  308. // bogus interrupt.
  309. //
  310. DeviceExtension->IoBuffer = NULL;
  311. DeviceExtension->IoLength = 0;
  312. DeviceExtension->IoFunction = 0;
  313. DeviceExtension->IoOffset = 0;
  314. DeviceExtension->IoIndex = 0;
  315. //
  316. // Complete this IRP and start the next
  317. // IRP is there is one in the queue
  318. //
  319. SaPortCompleteRequest(
  320. DeviceExtension,
  321. NULL,
  322. DeviceExtension->CompletedIoSize,
  323. Status,
  324. FALSE
  325. );
  326. }
  327. NTSTATUS
  328. SaNvramDeviceIoctl(
  329. IN PVOID DeviceExtension,
  330. IN PIRP Irp,
  331. IN PVOID FsContext,
  332. IN ULONG FunctionCode,
  333. IN PVOID InputBuffer,
  334. IN ULONG InputBufferLength,
  335. IN PVOID OutputBuffer,
  336. IN ULONG OutputBufferLength
  337. )
  338. /*++
  339. Routine Description:
  340. This function is called by the SAPORT driver so that
  341. the mini-port driver can service an IOCTL call.
  342. Arguments:
  343. DeviceExtension - A pointer to the mini-port's device extension
  344. FunctionCode - The IOCTL function code
  345. InputBuffer - Pointer to the input buffer, contains the data sent down by the I/O
  346. InputBufferLength - Length in bytes of the InputBuffer
  347. OutputBuffer - Pointer to the output buffer, contains the data generated by this call
  348. OutputBufferLength - Length in bytes of the OutputBuffer
  349. Context:
  350. IRQL: IRQL PASSIVE_LEVEL, arbitrary thread context
  351. Return Value:
  352. If the function succeeds, it must return STATUS_SUCCESS.
  353. Otherwise, it must return one of the error status values defined in ntstatus.h.
  354. --*/
  355. {
  356. NTSTATUS Status = STATUS_SUCCESS;
  357. PSA_NVRAM_CAPS NvramCaps = NULL;
  358. switch (FunctionCode) {
  359. case FUNC_SA_GET_VERSION:
  360. *((PULONG)OutputBuffer) = SA_INTERFACE_VERSION;
  361. break;
  362. case FUNC_SA_GET_CAPABILITIES:
  363. NvramCaps = (PSA_NVRAM_CAPS)OutputBuffer;
  364. NvramCaps->SizeOfStruct = sizeof(SA_NVRAM_CAPS);
  365. NvramCaps->NvramSize = MAX_NVRAM_SIZE;
  366. break;
  367. default:
  368. Status = STATUS_NOT_SUPPORTED;
  369. REPORT_ERROR( SA_DEVICE_NVRAM, "Unsupported device control", Status );
  370. break;
  371. }
  372. return Status;
  373. }
  374. NTSTATUS
  375. SaNvramHwInitialize(
  376. IN PDEVICE_OBJECT DeviceObject,
  377. IN PIRP Irp,
  378. IN PVOID DeviceExtensionIn,
  379. IN PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResources,
  380. IN ULONG PartialResourceCount
  381. )
  382. /*++
  383. Routine Description:
  384. This function is called by the SAPORT driver so that
  385. the mini-port driver can initialize it's hardware
  386. resources.
  387. Arguments:
  388. DeviceObject - Pointer to the target device object.
  389. Irp - Pointer to an IRP structure that describes the requested I/O operation.
  390. DeviceExtension - A pointer to the mini-port's device extension.
  391. PartialResources - Pointer to the translated resources alloacted by the system.
  392. PartialResourceCount - The number of resources in the PartialResources array.
  393. Context:
  394. IRQL: IRQL PASSIVE_LEVEL, system thread context
  395. Return Value:
  396. If the function succeeds, it must return STATUS_SUCCESS.
  397. Otherwise, it must return one of the error status values defined in ntstatus.h.
  398. --*/
  399. {
  400. PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceExtensionIn;
  401. PCM_PARTIAL_RESOURCE_DESCRIPTOR ResourceMemory = NULL;
  402. ULONG i;
  403. for (i=0; i<PartialResourceCount; i++) {
  404. if (PartialResources[i].Type == CmResourceTypeMemory) {
  405. ResourceMemory = &PartialResources[i];
  406. }
  407. }
  408. if (ResourceMemory == NULL) {
  409. REPORT_ERROR( SA_DEVICE_NVRAM, "Missing memory resource", STATUS_UNSUCCESSFUL );
  410. return STATUS_UNSUCCESSFUL;
  411. }
  412. //
  413. // Setup the memory base address
  414. //
  415. DeviceExtension->NvramMemBase = (PUCHAR) SaPortGetVirtualAddress(
  416. DeviceExtension,
  417. ResourceMemory->u.Memory.Start,
  418. ResourceMemory->u.Memory.Length
  419. );
  420. if (DeviceExtension->NvramMemBase == NULL) {
  421. REPORT_ERROR( SA_DEVICE_NVRAM, "SaPortGetVirtualAddress failed", STATUS_NO_MEMORY );
  422. return STATUS_NO_MEMORY;
  423. }
  424. //
  425. // Enable interrupts on the hardware
  426. //
  427. WRITE_REGISTER_USHORT( (PUSHORT)DeviceExtension->NvramMemBase, NVRAM_CONTROL_INTERRUPT_ENABLE );
  428. return STATUS_SUCCESS;
  429. }
  430. NTSTATUS
  431. DriverEntry(
  432. IN PDRIVER_OBJECT DriverObject,
  433. IN PUNICODE_STRING RegistryPath
  434. )
  435. /*++
  436. Routine Description:
  437. This routine is the driver's entry point, called by the I/O system
  438. to load the driver. The driver's entry points are initialized and
  439. a mutex to control paging is initialized.
  440. In DBG mode, this routine also examines the registry for special
  441. debug parameters.
  442. Arguments:
  443. DriverObject - a pointer to the object that represents this device driver.
  444. RegistryPath - a pointer to this driver's key in the Services tree.
  445. Return Value:
  446. STATUS_SUCCESS
  447. --*/
  448. {
  449. NTSTATUS Status;
  450. SAPORT_INITIALIZATION_DATA SaPortInitData;
  451. RtlZeroMemory( &SaPortInitData, sizeof(SAPORT_INITIALIZATION_DATA) );
  452. SaPortInitData.StructSize = sizeof(SAPORT_INITIALIZATION_DATA);
  453. SaPortInitData.DeviceType = SA_DEVICE_NVRAM;
  454. SaPortInitData.HwInitialize = SaNvramHwInitialize;
  455. SaPortInitData.DeviceIoctl = SaNvramDeviceIoctl;
  456. SaPortInitData.Read = SaNvramRead;
  457. SaPortInitData.Write = SaNvramWrite;
  458. SaPortInitData.InterruptServiceRoutine = SaNvramInterruptService;
  459. SaPortInitData.IsrForDpcRoutine = SaNvramDpcRoutine;
  460. SaPortInitData.DeviceExtensionSize = sizeof(DEVICE_EXTENSION);
  461. Status = SaPortInitialize( DriverObject, RegistryPath, &SaPortInitData );
  462. if (!NT_SUCCESS(Status)) {
  463. REPORT_ERROR( SA_DEVICE_NVRAM, "SaPortInitialize failed\n", Status );
  464. return Status;
  465. }
  466. return STATUS_SUCCESS;
  467. }