Coming Back to Driver Development

I assume that’s what I should be looking for?

For what? If you don’t support IRP_MJ_PNP and IRP_MJ_POWER, then it isn’t WDM. It’s a legacy driver. For ISA, that’s not surprising. ISA is not a PnP bus (there’s no way for a board to identify itself), so you have to use INF magic to assign the driver. Given the magic, you CAN participate in the PnP world.

Yes, non-PnP hardware is supported. There’s lots of it, even in a modern computer. Much of it gets exposed through the BIOS ACPI DSDT.

OK, I misunderstood the information. IRP_MJ_PNP and IRP_MJ_POWER are not used in this driver, so this is a legacy driver after all. It looks like a rewrite is necessary.

Since it is necessary should I be looking at converting this to a KMDF driver instead?

I thought I remembered some PnP ISA hardware back in the day. I could be wrong. They say memory is the second thing to go… Can’t remember the first.

Yes. Rewrite it in KMDF.

It was a bad decision to write this driver as an NT V4 style driver back in 2010. This was already deprecated, and by 2000 it was not architecturally correct to just use whatever resources you want within toting through the PnP manager.

Peter

1 Like

I don’t know what I was thinking back then.

It looks like most of the online documentation for legacy drivers (pre-WDM) have fallen in the bit bucket. The old driver is pretty simple, it’s essentially 4 functions: DriverEntry, DrvUnload, DrvCreateDispatch, and DrvDeviceControl. There are two macros for __drv_dispatchType that define the DrvCreateDispatch and DrvDeviceControl functions.

I can’t find much on __drv_dispatchType anywhere. I assume DrvUnload, DrvCreateDispatch, and DrvDeviceControl fit into the architecture in some other way under KMDF?

I’ve never seen the macro __drv_dispatchType… so that’s a new one on me.

So, yes… you can handle create (if you need to, usually you don’t) and dispatching IOCTLs by control code in KMDF. You just need to learn a bit about how to write a WDF driver.

My best hint for leaning WDF is to forget everything you know, or don’t know, about WDM. Approach learning KMDF like you’re learning how to write a driver for a new OS. Of course, standard Windows architectural concepts (threads, IRQLs, etc) all still,apply. But the details of Request handling are very different… and trying to mentally map one driver type to another will lead to constant sorrow.

Peter

_drv_dispatchType is one of the standard prefast macros and is used for
classifying 'irp handler functions - as in the standard WDM driver dispatch
section of a driver object.

Mark Roddy

What Peter said … take the basic ideas (threads, synchronization, userspace and kernel space, etc.) but treat it as an entirely new OS and programming model Start with one of the simply KMDF samples out there, build it and step through it, then go from there …

I’ve spent the week digesting a few of the driver samples. Specifically the AMCC5933 driver, which I had to go back a couple of versions to dig out. That’s an ISA driver. I also looked at the non-PnP driver sample (ioctl). I think I’m getting the gist of how the KMDF driver architecture works.

I see the steps to initiate a non-PnP driver are a bit different since you have to tell the driver what the actual resources are rather than have it figure it out for itself. It appears the sample doesn’t actually access any hardware though. It appears to just do file I/O.

The hardware I’m working with is pretty simple. It defines 3 I/O ports numbered sequentially from a base address, usually 0x300. So it read and writes to 0x300, 0x301, and 0x302. The board can be set to different I/O port base addresses, though 0x300 is the most common. For a non-PnP driver I believe these addresses need to be in the inf file? And I assume all three need to be enumerated separately?

How do I go about assigning the port addresses in the DeviceAdd function? In the AMCC5933 sample the EvtDevicePrepareHardware function has a loop that parses the resource list and then call MmMapIoSpace to assign the hardware space within the driver. I assume I will call MmMapIoSpace directly once I know what the ports are? And I will call this three times, one for each port used?

Does the driver need to reread the inf file every time the computer boots to get the I/O port addresses when initializing the driver?

A WDF driver for an ISA bus device is identical to a WDF driver for any other hardware device. It gets its resources in PrepareHardware, and it accesses them via the HAL’s READ_REGISTER_xxx and READ_PORT_xxx methods.

You specify the non-PnP resources via LogConfig directives in your INF file.

Peter

The non-PnP sample has no PrepareHardware section, but it doesn’t access hardware. This hardware has nothing for the OS to detect. I should put the information in the LogConfig section of the INF file in a PrepareHardware function? Where to put the information was not clear from the samples.

1 you add the LogConfig to the inf 2 this will force assign the hardware resources to the “pnp” device 3 your pnp driver will receive these resources in PrepareHardware

Don’t read a non-PnP sample. You’re writing a PnP WDF driver, even though that driver receives non-PnP resources. That you specify.

I don’t how to be more clear than I have been: Put the resources in a LogConfig section in your INF. You will get called with these resources in PrepareHardware… they’ll come in the TranslatedResources structure. Just try it. It works. I promise.

Peter

Once I knew what the key words were, I see there is a LogConfig section in the AMCC5933 sample. Just for clarification, the OS parses both the hardware and the LogConfig section and provides a combined structure with the resources found by both methods? Anyway, I see how to parse it now.

I have another question. The old driver only has two functions that are ever called, a write port and read port. The function that handles this is:

`NTSTATUS IsaDrvDeviceControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP pIrp)
{
PIO_STACK_LOCATION irpSp;
NTSTATUS ntStatus = STATUS_SUCCESS;

ULONG               inBufLength;   /* Input buffer length */
ULONG               outBufLength;  /* Output buffer length */

PUCHAR              CharBuffer; 
PUSHORT             ShortBuffer;
PULONG              LongBuffer;
PVOID               ioBuffer;

USHORT Offset;
UCHAR Value;

DeviceObject;

irpSp = IoGetCurrentIrpStackLocation( pIrp );
inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;

ioBuffer    = pIrp->AssociatedIrp.SystemBuffer;

CharBuffer  = (PUCHAR) ioBuffer;
ShortBuffer = (PUSHORT) ioBuffer;
LongBuffer  = (PULONG) ioBuffer;

switch(irpSp->Parameters.DeviceIoControl.IoControlCode)
{
	case IOCTL_READ_PORT_UCHAR:
		if ((inBufLength >= 2) && (outBufLength >= 1)) 
		{
			DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: IOCTL_READ_PORT_UCHAR 0x%X\n",ShortBuffer[0]);
			(UCHAR)Value = READ_PORT_UCHAR((PUCHAR)ShortBuffer[0]);
			DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: Value Read %X\n",Value);
			CharBuffer[0] = Value;
		} 
		else 
		{
			DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: IOCTL_READ_PORT_UCHAR Error inBufLength=%u, outBufLength=%u\n",inBufLength,outBufLength);
			ntStatus = STATUS_BUFFER_TOO_SMALL;
		}
		pIrp->IoStatus.Information = 1; /* Output Buffer Size */
		ntStatus = STATUS_SUCCESS;
		break;

	case IOCTL_WRITE_PORT_UCHAR:
		if (inBufLength >= 3) 
		{
			DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: IOCTL_WRITE_PORT_UCHAR(0x%X,0x%X)\n",ShortBuffer[0], CharBuffer[2]);
			WRITE_PORT_UCHAR((PUCHAR)ShortBuffer[0], CharBuffer[2]);
		} 
		else 
		{
			DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: IOCTL_WRITE_PORT_UCHAR STATUS_BUFFER_TOO_SMALL inBufLength=%u\n",inBufLength);
			ntStatus = STATUS_BUFFER_TOO_SMALL;
		}
		pIrp->IoStatus.Information = 0; /* Output Buffer Size */
		ntStatus = STATUS_SUCCESS;
		break;

	default:
		DbgPrintEx(DPFLTR_IHVDRIVER_ID,DPFLTR_TRACE_LEVEL,"MTIsaDrv: Unsupported IOCTL Call code=0x%X\n",irpSp->Parameters.DeviceIoControl.IoControlCode);
		ntStatus = STATUS_UNSUCCESSFUL;
		pIrp->IoStatus.Information = 0;
		break;
}
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return ntStatus;

}
`

pIrp on input has the port to use, and data to write for a write function as well as the buffer to return data. It looks like this should be done in the EvtIoDeviceControl function. The buffer sizes are included in the arguments, but I’m unclear where the port number, data, and return buffer are.

The device context you get from
‘devExt = DeviceGetContext(WdfIoQueueGetDevice(Queue));’

can include a handle to the request, but I haven’t found anything using this handle. Some of the samples have port I/O, but none of those do the I/O in direct response to calls from an application.

The WDF equivalent of getting IRP->AssociatedIrp.SystemBuffer for an INPUT argument is calling WdfRequestRetrieveInputBuffer. For an output argument (for you to return a result) call WdfRequestRetireveOutputBuffer.

It seems you could do some reading in the WDK and figure this out…

Peter

The device context you get from … can include a handle to the request …

No, only if you put it there. The device context is simply a structure that YOU define that includes whatever information YOU need to track. In a case like this, where you immediately handle and complete requests, there’s no need for any state information.

Remember that, for METHOD_BUFFERED ioctls, as these surely are, the input and output buffer are the same. The code above makes that clear. KMDF hides that a little bit, since there are separate calls, but WdfRequestRetrieveInputBuffer and …OutputBuffer will return the same pointer. That just means you have to be careful not to overwrite anything you might need.

I’m sorry. I was an idiot. I had been looking for a couple of days and it just didn’t occur to me to look at WdfRequest function definitions. In hindsight it was blind of me.

I did find the functions that got me the pointers I needed.

I got it compiled, but there is a problem with the INF file. I get warnings about the LogConfig statement. I found some documentation on LogConfigOverride, but that appears to not apply here.

I read the description here:
https://docs.microsoft.com/en-us/windows-hardware/drivers/install/inf-logconfig-directive

And followed the example at the bottom. This is the code in the INF
`[MTIsaDrv_Device.NT]
CopyFiles=Drivers_Dir
LogConfig=MTIsa_LogConfig

[MTIsa_LogConfig]
ConfigPriority=NORMAL
IoConfig=3@300-302%ff00(3ff::slight_smile:
`

I get the following warnings when I compile this
`
1>\MTIsaDrv\MTIsaDrv.inf(52-52): warning 2009: Legacy directive ‘LogConfig’ will be ignored.

1>\MTIsaDrv.inf(52-52): warning 1300: Found legacy LogConfig operation.

1>\MTIsaDrv\MTIsaDrv.inf(54-54): warning 2083: Section [mtisa_logconfig] not referenced or used.
`
(I edited the paths for readability)

1300: You will see this error if you use deprecated sections or directives such as LogConfig or DDInstall.CoInstallers.
2083: It doesn’t seem to think it’s referenced.
2009: I can’t find any reference to this, but Warning 2222 has the same wording. It says:

"This warning indicates that the INF specifies a deprecated directive. When the driver is installed, the directive referencing the section is not evaluated. For example, the INF LogConfig Directive directive is no longer supported, so the following section results in this warning.

[InstallSection.LogConfigOverride]
LogConfig=LogConfigSection

For information about which INF directives are deprecated, see INF Directives."

In the warnings and errors page here:
https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/inf-validation-errors-and-warnings

I was getting some other errors until I changed from Universal Driver to Desktop in the Properties
Driver Settings->General->Target Platform

Changing the Target OS in the same section to Windows 8.1 or 7 doesn’t change anything when compiling. If the above warning explanation is true, it looks like the Win 10 WDK no longer supports LogConfig, which makes this a dead end. I guess I should try the Win 8 WDK?

Setting the driver to be “Desktop” and not “Universal” was going to be MY suggestion.

Regardless of whatever warnings you get… does the INF/Driver install and work?

Peter

It took some effort to get the debug environment set up. windbg kept failing installing on my development machine and I had to move some equipment around to co-locate the test machine with my development machine. The test machine is normally with the test equipment, which weighs about 70 lbs. and is elsewhere.

Anyway, got it set up and tried installing the driver. I didn’t see any of the DbgPrint messages in windbg (I changed the TraceEvents to DbgPrint in the driver code), but I did look at the install log. I think it tells me everything I need to know about LogConfig and Win 10:

     sto: {Stage Driver Package: C:\Users\test\AppData\Local\Temp\{3564404b-bdcc-2a41-b9c0-28f1a7aca49f}\mtisadrv.inf} 00:24:59.580
     inf:      {Query Configurability: C:\Users\test\AppData\Local\Temp\{3564404b-bdcc-2a41-b9c0-28f1a7aca49f}\mtisadrv.inf} 00:24:59.596
!    inf:           Legacy directive 'LogConfig' will be ignored. Code = 2009, Line = 51
!    inf:           Found legacy LogConfig operation. Code = 1300
!    inf:           Driver package 'mtisadrv.inf' is NOT configurable.
     inf:      {Query Configurability: exit(0x00000000)} 00:24:59.596
     flq:      {FILE_QUEUE_COMMIT} 00:24:59.596
     flq:           Copying 'C:\Users\test\AppData\Local\Temp\{3564404b-bdcc-2a41-b9c0-28f1a7aca49f}\MTIsaDrv.cat' to 'C:\WINDOWS\System32\DriverStore\Temp\{11957266-6ca9-bf41-9f75-29c5ee7d722f}\MTIsaDrv.cat'.
     flq:           Copying 'C:\Users\test\AppData\Local\Temp\{3564404b-bdcc-2a41-b9c0-28f1a7aca49f}\mtisadrv.inf' to 'C:\WINDOWS\System32\DriverStore\Temp\{11957266-6ca9-bf41-9f75-29c5ee7d722f}\mtisadrv.inf'.
     flq:           Copying 'C:\Users\test\AppData\Local\Temp\{3564404b-bdcc-2a41-b9c0-28f1a7aca49f}\MTIsaDrv.sys' to 'C:\WINDOWS\System32\DriverStore\Temp\{11957266-6ca9-bf41-9f75-29c5ee7d722f}\MTIsaDrv.sys'.
     flq:      {FILE_QUEUE_COMMIT - exit(0x00000000)} 00:24:59.612
     sto:      {DRIVERSTORE IMPORT VALIDATE} 00:24:59.612
     sig:           Driver package catalog is valid.
!!!  sig:           Driver package INF file hash is not present in catalog file. Filename = mtisadrv.inf, Error = 0xE000024B
!    sig:           Driver package appears to be tampered, but user wants to install it anyway.
     sto:      {DRIVERSTORE IMPORT VALIDATE: exit(0x00000000)} 00:25:01.596
     sig:      Signer Score  = 0x80000000 (Unsigned)
     sto:      {Core Driver Package Import: mtisadrv.inf_x86_cecc67334ca843ca} 00:25:01.596
     sto:           {DRIVERSTORE IMPORT BEGIN} 00:25:01.596
     bak:                Create system restore point:
     bak:                     Description = Device Driver Package Install: Robson Technologies Inc. Multitrace Driver
     bak:                     Time        = 6094ms
     bak:                     Status      = 0x00000000 (SUCCESS)
     sto:           {DRIVERSTORE IMPORT BEGIN: exit(0x00000000)} 00:25:07.697
     cpy:           {Copy Directory: C:\WINDOWS\System32\DriverStore\Temp\{11957266-6ca9-bf41-9f75-29c5ee7d722f}} 00:25:07.697
     cpy:                Target Path = C:\WINDOWS\System32\DriverStore\FileRepository\mtisadrv.inf_x86_cecc67334ca843ca
     cpy:           {Copy Directory: exit(0x00000000)} 00:25:07.697
     idb:           {Register Driver Package: C:\WINDOWS\System32\DriverStore\FileRepository\mtisadrv.inf_x86_cecc67334ca843ca\mtisadrv.inf} 00:25:07.712
     idb:                Created driver package object 'mtisadrv.inf_x86_cecc67334ca843ca' in DRIVERS database node.
     idb:                Created driver INF file object 'oem7.inf' in DRIVERS database node.
     idb:                Registered driver package 'mtisadrv.inf_x86_cecc67334ca843ca' with 'oem7.inf'.
     idb:           {Register Driver Package: exit(0x00000000)} 00:25:07.712
     idb:           {Publish Driver Package: C:\WINDOWS\System32\DriverStore\FileRepository\mtisadrv.inf_x86_cecc67334ca843ca\mtisadrv.inf} 00:25:07.712
     idb:                Activating driver package 'mtisadrv.inf_x86_cecc67334ca843ca'.
     cpy:                Published 'mtisadrv.inf_x86_cecc67334ca843ca\mtisadrv.inf' to 'oem7.inf'.
!    inf:                Legacy directive 'LogConfig' will be ignored. Code = 2009, Line = 51
     idb:                Indexed 2 device IDs for 'mtisadrv.inf_x86_cecc67334ca843ca'.
     sto:                Flushed driver database node 'DRIVERS'. Time = 31 ms
     sto:                Flushed driver database node 'SYSTEM'. Time = 31 ms
     idb:           {Publish Driver Package: exit(0x00000000)} 00:25:07.775
     sto:           {DRIVERSTORE IMPORT END} 00:25:07.775
     dvi:                Flushed all driver package files to disk. Time = 0 ms
     sig:                Installed catalog 'MTIsaDrv.cat' as 'oem7.cat'.
     bak:                Commit system restore point:
     bak:                     Description = Device Driver Package Install: Robson Technologies Inc. Multitrace Driver
     bak:                     Time        = 0ms
     bak:                     Status      = 0x00000000 (SUCCESS)
     sto:           {DRIVERSTORE IMPORT END: exit(0x00000000)} 00:25:07.962
     sto:      {Core Driver Package Import: exit(0x00000000)} 00:25:07.962
     sto: {Stage Driver Package: exit(0x00000000)} 00:25:07.962

It looks like LogConfig no longer works with Win 10 if I’m reading the log correctly.

When it looked like this was the situation, I did alert the guy i report to to give him a heads up. We are already talking about changing the hardware. Looks like that’s the route now.

Thanks for taking the time to post this… This is both surprising and very concerning.

So, I spent some time looking around this morning…

COULD it be that we all just “failed to get the email” that this particular directive has been deprecated, and that it’s been REPLACED by a new section called FactDef??

Could you please give this a try, and let us know how it goes? Because, while nothing at all would surprise me about Microsoft these days, I really don’t see how Windows could just eliminate support for non-PnP devices. That would be incredibly unwise, and would rule-out a lot of industrial control PCs.

Peter

The first mentions of LogConfig are related to the configurable state of the INF. A configurable INF, known as Declarative publicly (the D in DCH), failure just means the install will go down the older install path that requires a user mode process to spin up and orchestrate the install

! inf: Legacy directive ‘LogConfig’ will be ignored. Code = 2009, Line = 51
! inf: Found legacy LogConfig operation. Code = 1300
! inf: Driver package ‘mtisadrv.inf’ is NOT configurable.

msports.inf still refers to LogConfig, so I have some doubt that support has been removed, but how often do we see ISA style serial ports anymore ;).

Again, while it may mean it is unsupported, I don’t interpret this line as not supported, but rather this metadata is ignored when the driver package is copied over to the driver store

inf:                Legacy directive 'LogConfig' will be ignored. Code = 2009, Line = 51

FactDef has been around since XP, not quite a new section. Rather, I think you should experiment with LogConfigOverride too. From the LogConfig docs, https://docs.microsoft.com/en-us/windows-hardware/drivers/install/inf-logconfig-directive

As a result, the LogConfig directive under a DDInstall section is ignored for PnP devices,. To override the resources reported by the bus for a PnP device, include the LogConfig directive under a DDInstall.LogConfigOverride section. In this case, the resources specified in the log-config-section is used instead of those reported by the bus.

Finally, you should look at the Details tab in the device’s properties dialog. I am guessing a properly processed LogConfig will show up as its own property entry. Maybe there are some clues in the properties.