# <iohw.h> <iohw.h> # `` [added with TR18015 and TR18037] * * * **`ioindex_t· ioreg`** **`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 **``** 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);Copy to clipboard The header `` 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 **`ioreg`** describes 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 name `dev` can also be used to construct the name of a function to call. - The type **`ioindex_t`** describes an integer type that can be used to index into a **hardware buffer**, an array of I/O addresses. - An argument named **`group`** describes 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 name `dev` can 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: - **`iord`** reads a port and returns as the value of the function. - **`iowr`** writes `val` to a port. - **`ioor`** ORs `val` into a port (bitwise inclusive OR). - **`ioand`** ANDs `val` into a port (bitwise AND). - **`ioxor`** XORs `val` into a port (bitwise exclusive OR). Moreover: - The suffix **`buf`** performs the operation with the element `idx` of a buffer. - The suffix **`l`** (lowercase **`L`**) takes the type of the port as `unsigned long` instead of `unsigned int`. Similarly, functions whose name begins with **`iogroup_`** operate on hardware groups: - The suffix **`acquire`** establishes `group` as the active hardware group. - The suffix **`release`** disestablished `group` as the active hardware group. - The suffix **`map`** maps the dynamic `group` into the actual hardware group `direct`. In this [implementation](https://docs.qualcomm.com/doc/80-N3040-23/topic/c_index.html#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)Copy to clipboard 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 */ }Copy to clipboard All actual driver calls will be to the function (or macro) `kbd_brd`. * * * See also the **[Table of Contents](https://docs.qualcomm.com/doc/80-N3040-23/topic/c_index.html#Table%20of%20Contents)** and the **[Index](https://docs.qualcomm.com/doc/80-N3040-23/topic/_c_index.html)**. *[Copyright](https://docs.qualcomm.com/doc/80-N3040-23/topic/c_crit_pjp.html) © 1992-2006by P.J. Plauger. All rights reserved.* Last Published: Oct 06, 2026 Previous Topic Next Topic