OS/2 Device Driver Frequently Asked Questions: Difference between revisions
No edit summary |
|||
Line 66: | Line 66: | ||
==Application Issues== | ==Application Issues== | ||
===Accessing IO ports at application level=== | |||
'''Question''': I have a requirement to access I/O ports from a 32 bit application. I know all about IOPL privilege BUT the only way to create a ring 2 IOPL segment seems to be to use a 16 bit DLL, is this right ? | |||
'''Answer''': Unfortunately yes, there is a more complete explanation of IOPL and accessing I/O ports in the Is a driver necessary section, so I will not repeat it here. | |||
Basically though ring 2 IOPL segments can only be 16 bit, there are however several approaches to solving your problem. | |||
* Use another driver, one that already exists. The TESTCFG driver contains code that allows you to access I/O port addresses higher than hex 100. | |||
* Package up your 16 bit IOPL segment into a DLL and call that from your 32 bit code segment. | |||
* Write a driver from scratch and get the driver to perform the I/O on behalf of the application. | |||
* Write a driver from scratch and get the driver to set the IOPL bits in the EFLAGS register to 3. This will allow the calling thread to perform I/O at ring 3. | |||
The last (rather neat) suggestion was supplied by Holger Veit. It should be noted that patching the EFLAGS register will only allow the calling thread to access I/O ports. | |||
===Read buffers greater than 64K=== | |||
'''Question''': When performing Read/Write operations can I use data buffers larger than 64K. | |||
'''Answer''': No you cannot. The Read/Write device driver commands have a length field which is a 16 bit word, this implies that the largest I/O operation is 64K. | |||
If you really want to perform I/O on regions greater than 64K, then you should use an IOCTL command to pass in the address of a 32 bit memory item. | |||
==compiling and building your OS/2 device driver== | ==compiling and building your OS/2 device driver== | ||
==Initialising the driver for the first time== | ==Initialising the driver for the first time== |
Revision as of 16:46, 17 June 2012
By Tim Snape
This article contains a selection of frequently asked questions and is intended to be used by anyone who is writing or planning to write OS/2 device drivers.
Support Categories
Situations when it is (un)necessary to write an OS/2 device driver
Is a driver necessary to use IRQs
Question: I have a requirement to intercept hardware interrupts from an adapter. Do I need to write a device driver.
Answer: Yes, a device driver is absolutely the only way to interact with hardware generated interrupts.
Is a driver necessary to access I/O ports
Question: I have a requirement to read and write to I/O ports. Is it necessary for me to write an OS/2 driver.
Answer: No, it is not.
Under OS/2 there are four levels of privilege (referred to as rings)
- Ring 3 - Least privilege, this is where applications normally reside
- Ring 2 - Next highest privilege. Code which is running at Ring 2 may access I/O ports under OS/2. For this reason this privilege is often referred to as I/O privilege level or IOPL.
- Ring 1 - Is not used under OS/2
- Ring 0 - Is the highest privilege level and is used by device drivers & the operating system.
In order to access an I/O port (and also to disable/enable the interrupt flag) a program MUST be running at ring 2. The way this is done is to specify in the programs definition file that a particular segment will have IOPL (IO privilege).
Next comes the clever bit. The compiler/ling will generate an executable that contains a special (IOPL) code segment. When the program is loaded, the loader will see that there is an IOPL segment & it will create a special mechanism that will allow that segment to run at ring 2.
For the technically knowledgable the loader creates a ring 2 call gate.
When the IOPL segment (containing the I/O access code) is called, privilege is changed to ring 2, and I/O access can be performed.
N.B. There is an overhead in this transition so if you plan to implement a polling loop on an I/O port (or something equally horrible) then be warned.
For some example code that accesses I/O ports go to the file download area.
Is a driver necessary to access memory on an adapter card
Question: I have a requirement to read and write to specific areas in memory in the range D000:0 to D800:0. This is to interface with a special function option card.
There is no time criticality or interrupts to deal with, so writing an OS/2 device driver does seem rather over-the-top.
In DOS, no problem. With MS-Windows, there are Global Selectors pre-defined ( _D000 etc. ).
How can this be done using OS/2.
Answer: At some point you will HAVE to use a driver to access the RAM directly. However it is not necessary to write a driver from scratch. Instead use one of OS/2's drivers to do the job for you.
Failing that, there are a number of drivers written by third parties that will provide you with this function.
I have placed some code in the anonymous ftp area that can be used to access memory directly. Download the Technical Developers Toolkit. The interesting file in the .zip is parallel.c, this contains code that reads the Bios data area used to hold the parallel port addresses.
Accessing Video Ram
Question: I need to access the memory mapped video ram do I need a driver
Answer: There is already support for obtaining addressability in the way you require. I suspect you don't need a device driver. You can access the frame buffer directly, use memory-mapped and port IO from the app level.
A note on the physical memory address space. Your graphics adapter memory can live anywhere above the end of physical memory (RAM) up to the 4Gb limit (0FFFFFFFFh). To see the memory, try as Tim suggested, using the KDB to dump physical memory, %%address.
There is an IOCTl supported by the SCREEN$ device driver for this purpose. You'll need to know the physical address and the aperture size, ie. how much memory the adapter has. See the include file bsedev.h and the definitions for SCREENDD_GETLINEARACCESS. The IOCTl will create and return a linear address which maps to the physical for you to use.
The flags field in the call is critical and one reason I asked what you're writing. They allow you to choose where in OS/2s linear address space the mapping occurs 1) in the current process address space 2) in the shared arena 3) in global space. BTW the flags map directly to those for VMAlloc except the ATTACH bit which causes a DevHlp_ProcessToGlobal.
Application Issues
Accessing IO ports at application level
Question: I have a requirement to access I/O ports from a 32 bit application. I know all about IOPL privilege BUT the only way to create a ring 2 IOPL segment seems to be to use a 16 bit DLL, is this right ?
Answer: Unfortunately yes, there is a more complete explanation of IOPL and accessing I/O ports in the Is a driver necessary section, so I will not repeat it here.
Basically though ring 2 IOPL segments can only be 16 bit, there are however several approaches to solving your problem.
- Use another driver, one that already exists. The TESTCFG driver contains code that allows you to access I/O port addresses higher than hex 100.
- Package up your 16 bit IOPL segment into a DLL and call that from your 32 bit code segment.
- Write a driver from scratch and get the driver to perform the I/O on behalf of the application.
- Write a driver from scratch and get the driver to set the IOPL bits in the EFLAGS register to 3. This will allow the calling thread to perform I/O at ring 3.
The last (rather neat) suggestion was supplied by Holger Veit. It should be noted that patching the EFLAGS register will only allow the calling thread to access I/O ports.
Read buffers greater than 64K
Question: When performing Read/Write operations can I use data buffers larger than 64K.
Answer: No you cannot. The Read/Write device driver commands have a length field which is a 16 bit word, this implies that the largest I/O operation is 64K.
If you really want to perform I/O on regions greater than 64K, then you should use an IOCTL command to pass in the address of a 32 bit memory item.