<iohw.h>
[added with TR18015 and TR18037]
ioand
· ioandbuf
· ioandbufl
· ioandl
· iogroup_acquire
· iogroup_map
· iogroup_release
· ioor
· ioorbuf
· ioorbufl
· ioorl
· iord
· iordbuf
· iordbufl
· iordl
· iowr
· iowrbuf
· iowrbufl
· iowrl
· ioxor
· ioxorbuf
· ioxorbufl
· ioxorl
Include the added header <iohw.h>
so that you can write low-level I/O hardware drivers in C that
are easier to port to different architectures.
Note that the use of this header does not require the additions to the C language mandated by TR18037, which include fixed-point arithmetic and named address spaces.
/* TYPES */ typedef i-type ioindex_t; typedef i-type ioreg; /* FUNCTIONS (all masked by macros) */ unsigned int iord(ioreg dev); unsigned long iordl(ioreg dev); unsigned int iordbuf(ioreg dev, ioindex_t idx); unsigned long iordbufl(ioreg dev, ioindex_t idx); void iowr(ioreg dev, unsigned int val); void iowrl(ioreg dev, unsigned int val); void iowrbuf(ioreg dev, ioindex_t idx, unsigned int val); void iowrbufl(ioreg dev, ioindex_t idx, unsigned int val); void ioor(ioreg dev, unsigned int val); void ioorl(ioreg dev, unsigned int val); void ioorbuf(ioreg dev, ioindex_t idx, unsigned int val); void ioorbufl(ioreg dev, ioindex_t idx, unsigned int val); void ioand(ioreg dev, unsigned int val); void ioandl(ioreg dev, unsigned int val); void ioandbuf(ioreg dev, ioindex_t idx, unsigned int val); void ioandbufl(ioreg dev, ioindex_t idx, unsigned int val); void ioxor(ioreg dev, unsigned int val); void ioxorl(ioreg dev, unsigned int val); void ioxorbuf(ioreg dev, ioindex_t idx, unsigned int val); void ioxorbufl(ioreg dev, ioindex_t idx, unsigned int val); void iogroup_acquire(int group); void iogroup_release(int group); void iogroup_map(int group, int direct);
The header <iohw.h> defines two types and a number
of functions, all of which are typically masked as macros. You should view
this header as a prototype for defining the atomic operations needed to
express a low-level I/O hardware driver (thus the root name iohw)
that is intended to be reasonably portable C.
The facilities in this header are structured around a few basic concepts:
- The type
ioregdescribes the space of all I/O addresses. These can be port addresses, for processors with port I/O instructions, or memory addresses, for processors with memory-mapped I/O hardware. In a simpler implementation, the actual argument corresponding to the parameter namedevcan also be used to construct the name of a function to call. - The type
ioindex_tdescribes an integer type that can be used to index into a hardware buffer, an array of I/O addresses. - An argument named
groupdescribes the space of all hardware groups, which might be meaningful on an architecture that supports switching among groups of similar I/O addresses by changing a base address dynamically. In a simpler implementation, the actual argument corresponding to the parameter namedevcan also be used to construct the name of a function to call.
The function names are thus suggestive of specific I/O operations, though they have no required semantics:
iordreads a port and returns as the value of the function.iowrwritesvalto a port.ioorORsvalinto a port (bitwise inclusive OR).ioandANDsvalinto a port (bitwise AND).ioxorXORsvalinto a port (bitwise exclusive OR).
Moreover:
- The suffix
bufperforms the operation with the elementidxof a buffer. - The suffix
l(lowercaseL) takes the type of the port asunsigned longinstead ofunsigned int.
Similarly, functions whose name begins with iogroup_
operate on hardware groups:
- The suffix
acquireestablishesgroupas the active hardware group. - The suffix
releasedisestablishedgroupas the active hardware group. - The suffix
mapmaps the dynamicgroupinto the actual hardware groupdirect.
In this implementation, all functions are masked by macros that follow the pattern:
#define _IOHW_CAT(x, y) x##_##y /* expand arguments and paste */ #define iordbuf(dev, idx) _IOHW_CAT(dev, brd)(idx)
Thus, the first argument (after macro expansion) is pasted onto a suitable suffix to produce the name of the actual function to call. So you can write code such as:
#define KBD kbd /* root name of keyboard functions */
#define KBD_STATUS 0 /* first of two adjacent ports */
#define KBD_DATA 1 /* second of two adjacent ports */
#define KBD_DONE 0x80 /* DONE status bit */
extern unsigned int kbd_brd(ioindex_t idx); /* actual driver */
unsigned int getkbd()
{ /* read keyboard when ready */
while ((iordbuf(KBD, KBD_STATUS) & KBD_DONE) == 0)
; /* wait until character is present */
return (iordbuf(KBD, KBD_DATA)); /* read character and clear DONE */
}
All actual driver calls will be to the function
(or macro) kbd_brd.
See also the Table of Contents and the Index.
Copyright © 1992-2006 by P.J. Plauger. All rights reserved.