Parallel Port Card with Address Greater Than 3ff

I’m supporting hardware that currently has two interfaces, one uses a parallel port and the other is 8 bit ISA. Up until 2010 they were still using legacy 16 bit aps with PortTalk as a driver. This worked through XP, but wouldn’t work on newer OSs.

I created 32 bit drivers for the parallel and ISA cards and they have worked OK for the last three years. In the last year, finding parallel port cards that support the old address range has been getting more and more difficult. They found one that will, but I’ve been asked to modify the existing driver to support the wider I/O address range of the newer parallel cards.

I’ve been searching for information about this, but I’ve turned up very little. Most of the information that is available was written when I/O addresses above 0x3FF were not commonly used.

For the parallel driver I adapted some code I found for a freeware driver called inpout32 and it worked fine. It’s been three years but I recall stripping down the driver somewhat because our hardware interface is pretty simple. Is there an obvious reason why this won’t work for higher I/O addresses?

Thanks,
Bill

I guess the first question to ask is: Does the new card have its addresses in Port I/O Space or in Memory space?

Remember… they’re two separate address spaces on Windows (regardless of the processor architecture, I hope we don’t have to devolve to this discussion) and they are thus different resource types that are accessed by different HAL functions.

Let’s start there. And maybe you can explain more about your situation, specifically.

Peter
OSR

xxxxx@toc-cs.com wrote:

I’ve been searching for information about this, but I’ve turned up very little. Most of the information that is available was written when I/O addresses above 0x3FF were not commonly used.

For the parallel driver I adapted some code I found for a freeware driver called inpout32 and it worked fine. It’s been three years but I recall stripping down the driver somewhat because our hardware interface is pretty simple. Is there an obvious reason why this won’t work for higher I/O addresses?

If “inpout32” works by having you send individual ioctls for each
request, then it will work just fine (ignoring the rather important fact
that you are stepping on an I/O port that has likely been claimed by
another driver).

However, some of the generic I/O drivers worked by modifying the I/O
permission map for the process. That, I think, is going to have big
problems on the newer systems.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

As Tim said if inpout32 is likely to have the problem of using registers
that the systems parallel port driver have taken. You may want to consider
creating a small driver that uses IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE,
IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO and
IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO. I did this for a client a while back
as a KMDF driver, with a user mode DLL that either called the driver or
called WinUSB to use the open source USB to parallel hardware.

Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.com
Blog: http://msmvps.com/blogs/WinDrvr

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of Tim Roberts
Sent: Tuesday, December 17, 2013 12:43 PM
To: Windows System Software Devs Interest List
Subject: Re: [ntdev] Parallel Port Card with Address Greater Than 3ff

xxxxx@toc-cs.com wrote:

I’ve been searching for information about this, but I’ve turned up very
little. Most of the information that is available was written when I/O
addresses above 0x3FF were not commonly used.

For the parallel driver I adapted some code I found for a freeware driver
called inpout32 and it worked fine. It’s been three years but I recall
stripping down the driver somewhat because our hardware interface is pretty
simple. Is there an obvious reason why this won’t work for higher I/O
addresses?

If “inpout32” works by having you send individual ioctls for each request,
then it will work just fine (ignoring the rather important fact that you are
stepping on an I/O port that has likely been claimed by another driver).

However, some of the generic I/O drivers worked by modifying the I/O
permission map for the process. That, I think, is going to have big
problems on the newer systems.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Hopefully I can answer all of your questions.

Peter:

The card uses the Port I/O space. The system has an INI file the applications use and in there you tell the applications which hardware interface you are using and the port address.

The hardware design is 1980s vintage. They first released it in 1989 and it’s still in production. They are slowly updating the hardware designs, but it has been slow. It’s a small company and they drop all development work when they have a new system to build, which the last few years has been almost constant.

The parallel interface was first designed when the 80386 was the hottest thing on the market and the software was designed for Windows 1.0. Most of my job has been rewriting the Windows code, but I support the drivers too. (My original background was in embedded firmware development, so this isn’t alien territory for me.)

Tim:

The system has worked in the past with the I/O addresses under 0x400 (almost always using the typical addresses for LPT1 or LPT2). When the company builds a new system, they get a legacy PCI to parallel card that supports the old port addresses.

This problem cropped up when a user had a PC failure and replaced it with a new computer with some PCI to parallel card they picked up. The new card appears to only support port addresses like 0x3000. For some reason they can’t get communication between any of the software programs and the external hardware and they think it is the driver. The troubleshooter has worked with these systems since the mid-90s so he knows them well and he said it looks like the driver was where the problem was.

I’m flying a little blind here because the guy from the company troubleshooting the problem is in California, I’m in Washington State, and the system he was troubleshooting was in Singapore. Due to a hardware failure with the development hardware that I had, I currently have no hardware to test anything on (which isn’t a huge problem for the user mode parts of the project, but does make it more difficult for the hardware part).

I don’t think the driver is modifying the permission map. The driver writes with an IOCTL_WRITE_PORT_UCHAR and reads with IOCTL_READ_PORT_UCHAR. From the ap this is done with a call to DeviceIoControl. The driver’s hwinterfaceDeviceControl function parses the call and calls READ_PORT_UCHAR(address) or WRITE_PORT_UCHAR(address, data). The macros

#define IOCTL_READ_PORT_UCHAR CTL_CODE(40000, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_WRITE_PORT_UCHAR CTL_CODE(40000, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

In any case, would the system be claiming ports in the 0x3000 range, but not in the 0x378 or 0x278 blocks? It works fine when the ports are in that range.

Don:
This is a PCI to parallel. USB to parallel won’t work. I have a beta USB driver for this system (direct USB communication, no parallel), but they haven’t finished the hardware.

The total data load is very low, but the 125us sub-frame timing killed the system with only one byte per 125us. I had to restructure how the program sent data down the hardware pipe to get acceptable transfer timing. But that’s a completely different issue.

Bill

For me, this is absolutely obvious that the wire protocol of the thing should be re-evaluated, and considered to be supported using MS’s standard parallel port driver and its IOCTLs.

After this, the app should be rewritten using these IOCTLs.

This is THE solution once and forever. All PCI-to-parallel and USB-to-parallel plugs will be supported automatically. And no more driver writing and PortIO. No more INI files.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

wrote in message news:xxxxx@ntdev…
> Hopefully I can answer all of your questions.
>
> Peter:
>
> The card uses the Port I/O space. The system has an INI file the applications use and in there you tell the applications which hardware interface you are using and the port address.
>
> The hardware design is 1980s vintage. They first released it in 1989 and it’s still in production. They are slowly updating the hardware designs, but it has been slow. It’s a small company and they drop all development work when they have a new system to build, which the last few years has been almost constant.
>
> The parallel interface was first designed when the 80386 was the hottest thing on the market and the software was designed for Windows 1.0. Most of my job has been rewriting the Windows code, but I support the drivers too. (My original background was in embedded firmware development, so this isn’t alien territory for me.)
>
> Tim:
>
> The system has worked in the past with the I/O addresses under 0x400 (almost always using the typical addresses for LPT1 or LPT2). When the company builds a new system, they get a legacy PCI to parallel card that supports the old port addresses.
>
> This problem cropped up when a user had a PC failure and replaced it with a new computer with some PCI to parallel card they picked up. The new card appears to only support port addresses like 0x3000. For some reason they can’t get communication between any of the software programs and the external hardware and they think it is the driver. The troubleshooter has worked with these systems since the mid-90s so he knows them well and he said it looks like the driver was where the problem was.
>
> I’m flying a little blind here because the guy from the company troubleshooting the problem is in California, I’m in Washington State, and the system he was troubleshooting was in Singapore. Due to a hardware failure with the development hardware that I had, I currently have no hardware to test anything on (which isn’t a huge problem for the user mode parts of the project, but does make it more difficult for the hardware part).
>
> I don’t think the driver is modifying the permission map. The driver writes with an IOCTL_WRITE_PORT_UCHAR and reads with IOCTL_READ_PORT_UCHAR. From the ap this is done with a call to DeviceIoControl. The driver’s hwinterfaceDeviceControl function parses the call and calls READ_PORT_UCHAR(address) or WRITE_PORT_UCHAR(address, data). The macros
>
> #define IOCTL_READ_PORT_UCHAR CTL_CODE(40000, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
> #define IOCTL_WRITE_PORT_UCHAR CTL_CODE(40000, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
>
> In any case, would the system be claiming ports in the 0x3000 range, but not in the 0x378 or 0x278 blocks? It works fine when the ports are in that range.
>
> Don:
> This is a PCI to parallel. USB to parallel won’t work. I have a beta USB driver for this system (direct USB communication, no parallel), but they haven’t finished the hardware.
>
> The total data load is very low, but the 125us sub-frame timing killed the system with only one byte per 125us. I had to restructure how the program sent data down the hardware pipe to get acceptable transfer timing. But that’s a completely different issue.
>
> Bill
>

It’s been three years since I wrote the driver and I’ve forgotten why I did it this way. Isn’t the standard parallel driver intended for driving a printer only? The way the protocol works is different from the printer protocol and we already have an installed user base. I doubt there would be much enthusiasm for replacing all the parallel hardware worldwide. It would require replacing hardware in the external chassis, the largest of which weighs about 500 pounds. replacing the hardware would require either sending in the systems for upgrade or sending someone to the systems.

Maybe I’m misunderstanding you?

The INI file is used for other software settings too. I would prefer some other mechanism, but that’s what’s been there for over 20 years now.

Before I started they tried several USB to ISA and USB to parallel solutions and all of them were painfully slow. The software I/O architecture is about the worst possible for USB timing. The 125us sub-frame timing kills us.

The external hardware can only handle one byte at a time. The data bus in the chassis is essentially an 8 bit ISA bus with a few minor modifications. The ISA interface mostly just buffers the ISA lines and puts them on the external hardware’s bus.

Everything is written one byte at a time. ISA is a demand bus, so you get things through pretty much at bus speed. USB 2 has the 125us sub frames as the smallest time slice possible. The overall data load is really quite small, but when you can only do one byte per sub frame, it gets ultra slow.

I would love to redo the entire I/O architecture, but that would be a massive change to the entire system. The software is written in layers like a network stack which is good most of the time, but there are places where many levels would have to be completely rewritten from scratch for a new I/O scheme and it would take extensive testing to ensure it works correctly. The software is so ancient that some things that would take me 15 minutes in a modern C++ design have literally taken me more than a week to do.

Maybe I’m misunderstanding what you’re saying, but any solution that requires hardware redesign is probably a non-starter. I can make a case for moderate software changes, but rewriting the I/O system from the ground up is out of scope too.

Bill

>parallel driver intended for driving a printer only? The way the protocol works is different from the

printer protocol and we already have an installed user base

Just be 100% sure of this, double-check this. Probably you can still reuse the printer protocol for this. Are you using control wires of LPT cable to transfer data? or do some other seriously non-standard things?

OS-provided drivers are always better, but yes, they only support the printer protocol.

Otherwise, you will have all issues you’re having now. You should make a decision - either you do hacks in the driver (up to hardcoding the addresses to the driver) and/or app for each new PCI-to parallel card, or you use the printer protocol and the set of standard IOCTLs by the OS-provided parallel driver.

Also, if you still use hacks, you will need to properly disable the OS-provided driver, and then deal with ACPI and power management, so that the rest of the OS will not power-down your PCI-to-parallel card during the transaction.

Also note that the device-side has firmware, which can be remade the same way as the driver side with nearly the same complexity. Switching to a standard printer protocol (and firmware updates to do this) is probably easier in man*hours then providing a personal hack for each new PCI-to-parallel card on the market.


Maxim S. Shatskih
Microsoft MVP on File System And Storage
xxxxx@storagecraft.com
http://www.storagecraft.com

See if the I/O range is enabled, by reading the config space in the debugger. It may not be enabled if the card doesn’t have a PNP driver installed for it.

xxxxx@toc-cs.com wrote:

I don’t think the driver is modifying the permission map. The driver writes with an IOCTL_WRITE_PORT_UCHAR and reads with IOCTL_READ_PORT_UCHAR. From the ap this is done with a call to DeviceIoControl. The driver’s hwinterfaceDeviceControl function parses the call and calls READ_PORT_UCHAR(address) or WRITE_PORT_UCHAR(address, data). The macros

#define IOCTL_READ_PORT_UCHAR CTL_CODE(40000, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_WRITE_PORT_UCHAR CTL_CODE(40000, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

In any case, would the system be claiming ports in the 0x3000 range, but not in the 0x378 or 0x278 blocks? It works fine when the ports are in that range.

There is no reason why that should “just work”. Is it possible that the
driver is validating the port number and rejecting ports outside of a
certain range?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts wrote:

xxxxx@toc-cs.com wrote:
> I don’t think the driver is modifying the permission map. The driver writes with an IOCTL_WRITE_PORT_UCHAR and reads with IOCTL_READ_PORT_UCHAR. From the ap this is done with a call to DeviceIoControl. The driver’s hwinterfaceDeviceControl function parses the call and calls READ_PORT_UCHAR(address) or WRITE_PORT_UCHAR(address, data). The macros
>
> #define IOCTL_READ_PORT_UCHAR CTL_CODE(40000, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
> #define IOCTL_WRITE_PORT_UCHAR CTL_CODE(40000, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)
>
> In any case, would the system be claiming ports in the 0x3000 range, but not in the 0x378 or 0x278 blocks? It works fine when the ports are in that range.
There is no reason why that should “just work”.

Make that “SHOULDN’T”.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Maxim:
By device side, I guess you mean the firmware in the PCI card. The external hardware this is interfacing to has no firmware.

When a computer is configured at the factory, there are no drivers loaded other than our driver, but a driver conflict is a possibility on this system. The users bought this computer to replace a system our company had provided that died. I also told the troubleshooter to look at the ACPI settings for the computer. Both of those are good suggestions.

Tim:
I don’t see anyplace in the code where the address is getting filtered. I do see where it is using a port 0x402 higher than the base port. Here is the code in the ap to initialize the parallel port:

unsigned char ECP_ExtendedControlRegData;
OutPar32((unsigned short)(Pport+2),0x04);
// set ECP parallel port to EPP mode
ECP_ExtendedControlRegData = InPar32((unsigned short)(Pport+0x402));
ECP_ExtendedControlRegData &= 0x1f; // clear mode bits
ECP_ExtendedControlRegData |= 0x80; // set to EPP mode
OutPar32((unsigned short)(Pport+0x402), ECP_ExtendedControlRegData);

OutPar32((unsigned short)(Pport+2), 0x0c);
OutPar32((unsigned short)(Pport+2), 0x08);
OutPar32((unsigned short)(Pport+2), 0x0c);
OutPar32(Pport, 0x40);
OutPar32((unsigned short)(Pport+2), 0x06);
OutPar32((unsigned short)(Pport+2), 0x07);
OutPar32((unsigned short)(Pport+2), 0x04);

Pport is the base port address. It is an unsigned short. InPar32 inputs one byte, Outpar32 outputs 1 byte.

I have a book with the parallel port protocol around here somewhere. I don’t recall ofhand what the port 0x402 is there for ports which initialize in the 0x3000 range.

Alex:
Unfortunately our driver is not PnP.

We’ll see what the troubleshooter finds with other drivers and ACPI. With the holidays this time of year it may be a bit before he can get with the customer.

Bill

xxxxx@toc-cs.com wrote:

I don’t see anyplace in the code where the address is getting filtered. I do see where it is using a port 0x402 higher than the base port. Here is the code in the ap to initialize the parallel port:

Yes, that’s the way an ECP parallel port works. The standard ports for
LPT1 are at 378 to 37F, and there’s an additional range at 778 to 77F
for the ECP mode.

Are you quite sure your PCI parallel port board supports EPP mode? If
you go to Device Manager and look at “resources”, do you see two
ranges? Or, at least, a range of at least 0x410 ports?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.