|
|
1.1 root 1: // Generic Port I/O driver for NT VERSION 1.0
2: //
3: // Adapted from NT DDK ADLIB driver
4: //
5: // Robert R. Howell January 8, 1993
6: //
7: // Robert B. Nelson (Microsoft) January 12, 1993
8: // Cleaned up comments
9: // Enabled and tested resource reporting
10: // Added code to retrieve I/O address and port count from the Registry.
11: //
12: // Robert B. Nelson (Microsoft) March 1, 1993
13: // Added support for byte, word, and long I/O.
14: // Added support for MIPS.
15: // Fixed resource reporting.
16: //
17: // Robert B. Nelson (Microsoft) May 1, 1993
18: // Fixed port number validation.
19: //
20: // Robert B. Nelson (Microsoft) Oct 25, 1993
21: // Fixed MIPS support.
22: //
23:
24: #include "genport.h"
25: #include "stdlib.h"
26:
27:
28: NTSTATUS
29: DriverEntry(
30: IN PDRIVER_OBJECT DriverObject,
31: IN PUNICODE_STRING RegistryPath
32: )
33:
34: /*++
35:
36: Routine Description:
37: This routine is the entry point for the driver. It is responsible
38: for setting the dispatch entry points in the driver object and creating
39: the device object. Any resources such as ports, interrupts and DMA
40: channels used must be reported. A symbolic link must be created between
41: the device name and an entry in \DosDevices in order to allow Win32
42: applications to open the device.
43:
44: Arguments:
45:
46: DriverObject - Pointer to driver object created by the system.
47:
48: Return Value:
49:
50: STATUS_SUCCESS if the driver initialized correctly, otherwise an error
51: indicating the reason for failure.
52:
53: --*/
54:
55: {
56: ULONG PortBase; // Port location, in NT's address form.
57: ULONG PortCount; // Count of contiguous I/O ports
58: PHYSICAL_ADDRESS PortAddress;
59:
60: PLOCAL_DEVICE_INFO pLocalInfo; // Device extension:
61: // local information for each device.
62: NTSTATUS Status;
63: PDEVICE_OBJECT DeviceObject;
64:
65: CM_RESOURCE_LIST ResourceList; // Resource usage list to report to system
66: BOOLEAN ResourceConflict; // This is set true if our I/O ports
67: // conflict with another driver
68:
69: // Try to retrieve base I/O port and range from the Parameters key of our
70: // entry in the Registry.
71: // If there isn't anything specified then use the values compiled into
72: // this driver.
73: {
74: static WCHAR SubKeyString[] = L"\\Parameters";
75: UNICODE_STRING paramPath;
76: RTL_QUERY_REGISTRY_TABLE paramTable[3];
77: ULONG DefaultBase = BASE_PORT;
78: ULONG DefaultCount = NUMBER_PORTS;
79:
80: //
81: // Since the registry path parameter is a "counted" UNICODE string, it
82: // might not be zero terminated. For a very short time allocate memory
83: // to hold the registry path as well as the Parameters key name zero
84: // terminated so that we can use it to delve into the registry.
85: //
86:
87: paramPath.MaximumLength = RegistryPath->Length + sizeof(SubKeyString);
88: paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
89:
90: if (paramPath.Buffer != NULL)
91: {
92: RtlMoveMemory(
93: paramPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
94:
95: RtlMoveMemory(
96: ¶mPath.Buffer[RegistryPath->Length / 2], SubKeyString,
97: sizeof(SubKeyString));
98:
99: paramPath.Length = paramPath.MaximumLength - 2;
100:
101: RtlZeroMemory(¶mTable[0], sizeof(paramTable));
102:
103: paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
104: paramTable[0].Name = L"IoPortAddress";
105: paramTable[0].EntryContext = &PortBase;
106: paramTable[0].DefaultType = REG_DWORD;
107: paramTable[0].DefaultData = &DefaultBase;
108: paramTable[0].DefaultLength = sizeof(ULONG);
109:
110: paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
111: paramTable[1].Name = L"IoPortCount";
112: paramTable[1].EntryContext = &PortCount;
113: paramTable[1].DefaultType = REG_DWORD;
114: paramTable[1].DefaultData = &DefaultCount;
115: paramTable[1].DefaultLength = sizeof(ULONG);
116:
117: if (!NT_SUCCESS(RtlQueryRegistryValues(
118: RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
119: paramPath.Buffer, ¶mTable[0], NULL, NULL)))
120: {
121: PortBase = DefaultBase;
122: PortCount = DefaultCount;
123: }
124: ExFreePool(paramPath.Buffer);
125: }
126: }
127:
128: // Register resource usage (ports)
129: //
130: // This ensures that there isn't a conflict between this driver and
131: // a previously loaded one or a future loaded one.
132:
133: RtlZeroMemory((PVOID)&ResourceList, sizeof(ResourceList));
134:
135: ResourceList.Count = 1;
136: ResourceList.List[0].InterfaceType = Isa;
137: // ResourceList.List[0].Busnumber = 0; Already 0
138: ResourceList.List[0].PartialResourceList.Count = 1;
139: ResourceList.List[0].PartialResourceList.PartialDescriptors[0].Type =
140: CmResourceTypePort;
141: ResourceList.List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
142: CmResourceShareDriverExclusive;
143: ResourceList.List[0].PartialResourceList.PartialDescriptors[0].Flags =
144: CM_RESOURCE_PORT_IO;
145: ResourceList.List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start =
146: PortAddress;
147: ResourceList.List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
148: PortCount;
149:
150: // Report our resource usage and detect conflicts
151: Status = IoReportResourceUsage(
152: NULL,
153: DriverObject,
154: &ResourceList,
155: sizeof(ResourceList),
156: NULL,
157: NULL,
158: 0,
159: FALSE,
160: &ResourceConflict);
161:
162: if (ResourceConflict)
163: Status = STATUS_DEVICE_CONFIGURATION_ERROR;
164:
165: if (!NT_SUCCESS(Status))
166: {
167: KdPrint( ("Resource reporting problem %8X", Status) );
168:
169: return Status;
170: }
171:
172: // Initialize the driver object dispatch table.
173: // NT sends requests to these routines.
174:
175: DriverObject->MajorFunction[IRP_MJ_CREATE] = GpdDispatch;
176: DriverObject->MajorFunction[IRP_MJ_CLOSE] = GpdDispatch;
177: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GpdDispatch;
178: DriverObject->DriverUnload = GpdUnload;
179:
180: // Create our device.
181: Status = GpdCreateDevice(
182: GPD_DEVICE_NAME,
183: GPD_TYPE,
184: DriverObject,
185: &DeviceObject
186: );
187:
188: if ( NT_SUCCESS(Status) )
189: {
190: PHYSICAL_ADDRESS MappedAddress;
191: ULONG MemType;
192:
193: // Convert the IO port address into a form NT likes.
194: MemType = 1; // located in IO space
195: PortAddress.LowPart = PortBase;
196: PortAddress.HighPart = 0;
197: HalTranslateBusAddress( Isa,
198: 0,
199: PortAddress,
200: &MemType,
201: &MappedAddress );
202:
203:
204: // Initialize the local driver info for each device object.
205: pLocalInfo = (PLOCAL_DEVICE_INFO)DeviceObject->DeviceExtension;
206:
207: if (MemType == 0)
208: {
209: // Port is accessed through memory space - so get a virtual address
210:
211: pLocalInfo->PortWasMapped = TRUE;
212:
213: // BUGBUG
214: // MmMapIoSpace can fail if we run out of PTEs, we should be
215: // checking the return value here
216:
217: pLocalInfo->PortBase = MmMapIoSpace(MappedAddress, PortCount, FALSE);
218: }
219: else
220: {
221: pLocalInfo->PortWasMapped = FALSE;
222: pLocalInfo->PortBase = (PVOID)MappedAddress.LowPart;
223: }
224:
225: pLocalInfo->DeviceObject = DeviceObject;
226: pLocalInfo->DeviceType = GPD_TYPE;
227: pLocalInfo->PortCount = PortCount;
228: pLocalInfo->PortMemoryType = MemType;
229: }
230: else
231: {
232: //
233: // Error creating device - release resources
234: //
235:
236: RtlZeroMemory((PVOID)&ResourceList, sizeof(ResourceList));
237:
238: // Unreport our resource usage
239: Status = IoReportResourceUsage(
240: NULL,
241: DriverObject,
242: &ResourceList,
243: sizeof(ResourceList),
244: NULL,
245: NULL,
246: 0,
247: FALSE,
248: &ResourceConflict);
249: }
250:
251: return Status;
252: }
253:
254: NTSTATUS
255: GpdCreateDevice(
256: IN PWSTR PrototypeName,
257: IN DEVICE_TYPE DeviceType,
258: IN PDRIVER_OBJECT DriverObject,
259: OUT PDEVICE_OBJECT *ppDevObj
260: )
261:
262: /*++
263:
264: Routine Description:
265: This routine creates the device object and the symbolic link in
266: \DosDevices.
267:
268: Ideally a name derived from a "Prototype", with a number appended at
269: the end should be used. For simplicity, just use the fixed name defined
270: in the include file. This means that only one device can be created.
271:
272: A symbolic link must be created between the device name and an entry
273: in \DosDevices in order to allow Win32 applications to open the device.
274:
275: Arguments:
276:
277: PrototypeName - Name base, # WOULD be appended to this.
278:
279: DeviceType - Type of device to create
280:
281: DriverObject - Pointer to driver object created by the system.
282:
283: ppDevObj - Pointer to place to store pointer to created device object
284:
285: Return Value:
286:
287: STATUS_SUCCESS if the device and link are created correctly, otherwise
288: an error indicating the reason for failure.
289:
290: --*/
291:
292:
293: {
294: NTSTATUS Status; // Status of utility calls
295: UNICODE_STRING NtDeviceName;
296: UNICODE_STRING Win32DeviceName;
297:
298:
299: // Get UNICODE name for device.
300:
301: RtlInitUnicodeString(&NtDeviceName, PrototypeName);
302:
303: Status = IoCreateDevice( // Create it.
304: DriverObject,
305: sizeof(LOCAL_DEVICE_INFO),
306: &NtDeviceName,
307: DeviceType,
308: 0,
309: FALSE, // Not Exclusive
310: ppDevObj
311: );
312:
313: if (!NT_SUCCESS(Status))
314: return Status; // Give up if create failed.
315:
316: // Clear local device info memory
317: RtlZeroMemory((*ppDevObj)->DeviceExtension, sizeof(LOCAL_DEVICE_INFO));
318:
319: //
320: // Set up the rest of the device info
321: // These are used for IRP_MJ_READ and IRP_MJ_WRITE which we don't use
322: //
323: // (*ppDevObj)->Flags |= DO_BUFFERED_IO;
324: // (*ppDevObj)->AlignmentRequirement = FILE_BYTE_ALIGNMENT;
325: //
326:
327: RtlInitUnicodeString(&Win32DeviceName, DOS_DEVICE_NAME);
328:
329: Status = IoCreateSymbolicLink( &Win32DeviceName, &NtDeviceName );
330:
331: if (!NT_SUCCESS(Status)) // If we we couldn't create the link then
332: { // abort installation.
333: IoDeleteDevice(*ppDevObj);
334: }
335:
336: return Status;
337: }
338:
339:
340: NTSTATUS
341: GpdDispatch(
342: IN PDEVICE_OBJECT pDO,
343: IN PIRP pIrp
344: )
345:
346: /*++
347:
348: Routine Description:
349: This routine is the dispatch handler for the driver. It is responsible
350: for processing the IRPs.
351:
352: Arguments:
353:
354: pDO - Pointer to device object.
355:
356: pIrp - Pointer to the current IRP.
357:
358: Return Value:
359:
360: STATUS_SUCCESS if the IRP was processed successfully, otherwise an error
361: indicating the reason for failure.
362:
363: --*/
364:
365: {
366: PLOCAL_DEVICE_INFO pLDI;
367: PIO_STACK_LOCATION pIrpStack;
368: NTSTATUS Status;
369:
370: // Initialize the irp info field.
371: // This is used to return the number of bytes transfered.
372:
373: pIrp->IoStatus.Information = 0;
374: pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension; // Get local info struct
375:
376: pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
377:
378: // Set default return status
379: Status = STATUS_NOT_IMPLEMENTED;
380:
381: // Dispatch based on major fcn code.
382:
383: switch (pIrpStack->MajorFunction)
384: {
385: case IRP_MJ_CREATE:
386: case IRP_MJ_CLOSE:
387: // We don't need any special processing on open/close so we'll
388: // just return success.
389: Status = STATUS_SUCCESS;
390: break;
391:
392: case IRP_MJ_DEVICE_CONTROL:
393: // Dispatch on IOCTL
394: switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
395: {
396: case IOCTL_GPD_READ_PORT_UCHAR:
397: case IOCTL_GPD_READ_PORT_USHORT:
398: case IOCTL_GPD_READ_PORT_ULONG:
399: Status = GpdIoctlReadPort(
400: pLDI,
401: pIrp,
402: pIrpStack,
403: pIrpStack->Parameters.DeviceIoControl.IoControlCode
404: );
405: break;
406:
407: case IOCTL_GPD_WRITE_PORT_UCHAR:
408: case IOCTL_GPD_WRITE_PORT_USHORT:
409: case IOCTL_GPD_WRITE_PORT_ULONG:
410: Status = GpdIoctlWritePort(
411: pLDI,
412: pIrp,
413: pIrpStack,
414: pIrpStack->Parameters.DeviceIoControl.IoControlCode
415: );
416: break;
417: }
418: break;
419: }
420:
421: // We're done with I/O request. Record the status of the I/O action.
422: pIrp->IoStatus.Status = Status;
423:
424: // Don't boost priority when returning since this took little time.
425: IoCompleteRequest(pIrp, IO_NO_INCREMENT );
426:
427: return Status;
428: }
429:
430:
431: NTSTATUS
432: GpdIoctlReadPort(
433: IN PLOCAL_DEVICE_INFO pLDI,
434: IN PIRP pIrp,
435: IN PIO_STACK_LOCATION IrpStack,
436: IN ULONG IoctlCode )
437:
438:
439: /*++
440:
441: Routine Description:
442: This routine processes the IOCTLs which read from the ports.
443:
444: Arguments:
445:
446: pLDI - our local device data
447: pIrp - IO request packet
448: IrpStack - The current stack location
449: IoctlCode - The ioctl code from the IRP
450:
451: Return Value:
452: STATUS_SUCCESS -- OK
453:
454: STATUS_INVALID_PARAMETER -- The buffer sent to the driver
455: was too small to contain the
456: port, or the buffer which
457: would be sent back to the driver
458: was not a multiple of the data size.
459:
460: STATUS_ACCESS_VIOLATION -- An illegal port number was given.
461:
462: --*/
463:
464: {
465: // NOTE: Use METHOD_BUFFERED ioctls.
466: PULONG pIOBuffer; // Pointer to transfer buffer
467: // (treated as an array of longs).
468: ULONG InBufferSize; // Amount of data avail. from caller.
469: ULONG OutBufferSize; // Max data that caller can accept.
470: ULONG nPort; // Port number to read
471: ULONG DataBufferSize;
472:
473: // Size of buffer containing data from application
474: InBufferSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
475:
476: // Size of buffer for data to be sent to application
477: OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
478:
479: // NT copies inbuf here before entry and copies this to outbuf after
480: // return, for METHOD_BUFFERED IOCTL's.
481: pIOBuffer = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
482:
483: // Check to ensure input buffer is big enough to hold a port number and
484: // the output buffer is at least as big as the port data width.
485: //
486: switch (IoctlCode)
487: {
488: case IOCTL_GPD_READ_PORT_UCHAR:
489: DataBufferSize = sizeof(UCHAR);
490: break;
491: case IOCTL_GPD_READ_PORT_USHORT:
492: DataBufferSize = sizeof(USHORT);
493: break;
494: case IOCTL_GPD_READ_PORT_ULONG:
495: DataBufferSize = sizeof(ULONG);
496: break;
497: }
498:
499: if ( InBufferSize != sizeof(ULONG) || OutBufferSize < DataBufferSize )
500: {
501: return STATUS_INVALID_PARAMETER;
502: }
503:
504: // Buffers are big enough.
505:
506: nPort = *pIOBuffer; // Get the I/O port number from the buffer.
507:
508: if (nPort >= pLDI->PortCount ||
509: (nPort + DataBufferSize) > pLDI->PortCount ||
510: (((ULONG)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
511: {
512: return STATUS_ACCESS_VIOLATION; // It was not legal.
513: }
514:
515: if (pLDI->PortMemoryType == 1)
516: {
517: // Address is in I/O space
518:
519: switch (IoctlCode)
520: {
521: case IOCTL_GPD_READ_PORT_UCHAR:
522: *(PUCHAR)pIOBuffer = READ_PORT_UCHAR(
523: (PUCHAR)((ULONG)pLDI->PortBase + nPort) );
524: break;
525: case IOCTL_GPD_READ_PORT_USHORT:
526: *(PUSHORT)pIOBuffer = READ_PORT_USHORT(
527: (PUSHORT)((ULONG)pLDI->PortBase + nPort) );
528: break;
529: case IOCTL_GPD_READ_PORT_ULONG:
530: *(PULONG)pIOBuffer = READ_PORT_ULONG(
531: (PULONG)((ULONG)pLDI->PortBase + nPort) );
532: break;
533: }
534: } else {
535: // Address is in Memory space
536:
537: switch (IoctlCode)
538: {
539: case IOCTL_GPD_READ_PORT_UCHAR:
540: *(PUCHAR)pIOBuffer = READ_REGISTER_UCHAR(
541: (PUCHAR)((ULONG)pLDI->PortBase + nPort) );
542: break;
543: case IOCTL_GPD_READ_PORT_USHORT:
544: *(PUSHORT)pIOBuffer = READ_REGISTER_USHORT(
545: (PUSHORT)((ULONG)pLDI->PortBase + nPort) );
546: break;
547: case IOCTL_GPD_READ_PORT_ULONG:
548: *(PULONG)pIOBuffer = READ_REGISTER_ULONG(
549: (PULONG)((ULONG)pLDI->PortBase + nPort) );
550: break;
551: }
552: }
553:
554: // Indicate # of bytes read
555: //
556:
557: pIrp->IoStatus.Information = DataBufferSize;
558:
559: return STATUS_SUCCESS;
560: }
561:
562:
563: NTSTATUS
564: GpdIoctlWritePort(
565: IN PLOCAL_DEVICE_INFO pLDI,
566: IN PIRP pIrp,
567: IN PIO_STACK_LOCATION IrpStack,
568: IN ULONG IoctlCode
569: )
570:
571: /*++
572:
573: Routine Description:
574: This routine processes the IOCTLs which write to the ports.
575:
576: Arguments:
577:
578: pLDI - our local device data
579: pIrp - IO request packet
580: IrpStack - The current stack location
581: IoctlCode - The ioctl code from the IRP
582:
583: Return Value:
584: STATUS_SUCCESS -- OK
585:
586: STATUS_INVALID_PARAMETER -- The buffer sent to the driver
587: was too small to contain the
588: port, or the buffer which
589: would be sent back to the driver
590: was not a multiple of the data size.
591:
592: STATUS_ACCESS_VIOLATION -- An illegal port number was given.
593:
594: --*/
595:
596: {
597: // NOTE: Use METHOD_BUFFERED ioctls.
598: PULONG pIOBuffer; // Pointer to transfer buffer
599: // (treated as array of longs).
600: ULONG InBufferSize ; // Amount of data avail. from caller.
601: ULONG OutBufferSize ; // Max data that caller can accept.
602: ULONG nPort; // Port number to read or write.
603: ULONG DataBufferSize;
604:
605: // Size of buffer containing data from application
606: InBufferSize = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
607:
608: // Size of buffer for data to be sent to application
609: OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
610:
611: // NT copies inbuf here before entry and copies this to outbuf after return,
612: // for METHOD_BUFFERED IOCTL's.
613: pIOBuffer = (PULONG) pIrp->AssociatedIrp.SystemBuffer;
614:
615: // We don't return any data on a write port.
616: pIrp->IoStatus.Information = 0;
617:
618: // Check to ensure input buffer is big enough to hold a port number as well
619: // as the data to write.
620: //
621: // The relative port # is a ULONG, and the data is the type appropriate to
622: // the IOCTL.
623: //
624:
625: switch (IoctlCode)
626: {
627: case IOCTL_GPD_WRITE_PORT_UCHAR:
628: DataBufferSize = sizeof(UCHAR);
629: break;
630: case IOCTL_GPD_WRITE_PORT_USHORT:
631: DataBufferSize = sizeof(USHORT);
632: break;
633: case IOCTL_GPD_WRITE_PORT_ULONG:
634: DataBufferSize = sizeof(ULONG);
635: break;
636: }
637:
638: if ( InBufferSize < (sizeof(ULONG) + DataBufferSize) )
639: {
640: return STATUS_INVALID_PARAMETER;
641: }
642:
643: nPort = *pIOBuffer++;
644:
645: if (nPort >= pLDI->PortCount ||
646: (nPort + DataBufferSize) > pLDI->PortCount ||
647: (((ULONG)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
648: {
649: return STATUS_ACCESS_VIOLATION; // Illegal port number
650: }
651:
652: if (pLDI->PortMemoryType == 1)
653: {
654: // Address is in I/O space
655:
656: switch (IoctlCode)
657: {
658: case IOCTL_GPD_WRITE_PORT_UCHAR:
659: WRITE_PORT_UCHAR(
660: (PUCHAR)((ULONG)pLDI->PortBase + nPort),
661: *(PUCHAR)pIOBuffer );
662: break;
663: case IOCTL_GPD_WRITE_PORT_USHORT:
664: WRITE_PORT_USHORT(
665: (PUSHORT)((ULONG)pLDI->PortBase + nPort),
666: *(PUSHORT)pIOBuffer );
667: break;
668: case IOCTL_GPD_WRITE_PORT_ULONG:
669: WRITE_PORT_ULONG(
670: (PULONG)((ULONG)pLDI->PortBase + nPort),
671: *(PULONG)pIOBuffer );
672: break;
673: }
674: } else {
675: // Address is in Memory space
676:
677: switch (IoctlCode)
678: {
679: case IOCTL_GPD_WRITE_PORT_UCHAR:
680: WRITE_REGISTER_UCHAR(
681: (PUCHAR)((ULONG)pLDI->PortBase + nPort),
682: *(PUCHAR)pIOBuffer );
683: break;
684: case IOCTL_GPD_WRITE_PORT_USHORT:
685: WRITE_REGISTER_USHORT(
686: (PUSHORT)((ULONG)pLDI->PortBase + nPort),
687: *(PUSHORT)pIOBuffer );
688: break;
689: case IOCTL_GPD_WRITE_PORT_ULONG:
690: WRITE_REGISTER_ULONG(
691: (PULONG)((ULONG)pLDI->PortBase + nPort),
692: *(PULONG)pIOBuffer );
693: break;
694: }
695: }
696:
697: return STATUS_SUCCESS;
698: }
699:
700:
701: VOID
702: GpdUnload(
703: PDRIVER_OBJECT DriverObject
704: )
705:
706: /*++
707:
708: Routine Description:
709: This routine prepares our driver to be unloaded. It is responsible
710: for freeing all resources allocated by DriverEntry as well as any
711: allocated while the driver was running. The symbolic link must be
712: deleted as well.
713:
714: Arguments:
715:
716: DriverObject - Pointer to driver object created by the system.
717:
718: Return Value:
719:
720: None
721:
722: --*/
723:
724: {
725: PLOCAL_DEVICE_INFO pLDI;
726: CM_RESOURCE_LIST NullResourceList;
727: BOOLEAN ResourceConflict;
728: UNICODE_STRING Win32DeviceName;
729:
730: // Find our global data
731: pLDI = (PLOCAL_DEVICE_INFO)DriverObject->DeviceObject->DeviceExtension;
732:
733: // Unmap the ports
734:
735: if (pLDI->PortWasMapped)
736: {
737: MmUnmapIoSpace(pLDI->PortBase, pLDI->PortCount);
738: }
739:
740: // Report we're not using any hardware. If we don't do this
741: // then we'll conflict with ourselves (!) on the next load
742:
743: RtlZeroMemory((PVOID)&NullResourceList, sizeof(NullResourceList));
744:
745: IoReportResourceUsage(
746: NULL,
747: DriverObject,
748: &NullResourceList,
749: sizeof(ULONG),
750: NULL,
751: NULL,
752: 0,
753: FALSE,
754: &ResourceConflict );
755:
756: // Assume all handles are closed down.
757: // Delete the things we allocated - devices, symbolic links
758:
759: RtlInitUnicodeString(&Win32DeviceName, DOS_DEVICE_NAME);
760:
761: IoDeleteSymbolicLink(&Win32DeviceName);
762:
763: IoDeleteDevice(pLDI->DeviceObject);
764: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.