mirror of
https://github.com/86Box/docs.git
synced 2026-02-22 09:35:33 -07:00
Initial review commit of API documentation
This commit is contained in:
1
conf.py
1
conf.py
@@ -31,6 +31,7 @@ author = '86Box Project'
|
||||
extensions = [
|
||||
'sphinx_rtd_theme',
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'linuxdoc.rstFlatTable'
|
||||
]
|
||||
autosectionlabel_prefix_document = True
|
||||
master_doc = 'index'
|
||||
|
||||
314
dev/api/device.rst
Normal file
314
dev/api/device.rst
Normal file
@@ -0,0 +1,314 @@
|
||||
.. include:: /include.rst
|
||||
|
||||
Devices
|
||||
=======
|
||||
|
||||
The **device** is the main unit of emulated components in 86Box. Each device has one or more ``device_t`` structures, which contain metadata about the device itself, several callbacks and an array of user-facing configuration options. Unless otherwise stated, all structures and functions in this page are provided by ``86box/device.h``.
|
||||
|
||||
.. flat-table:: device_t
|
||||
:header-rows: 1
|
||||
:widths: 1 1 999
|
||||
|
||||
* - :cspan:`1` Member
|
||||
- Description
|
||||
|
||||
* - :cspan:`1` name
|
||||
- The device's name, displayed in the user interface. ``"Foo-1234"`` for example. Suffixes like ``"(PCI)"`` are removed at run-time.
|
||||
|
||||
* - :cspan:`1` internal_name
|
||||
- The device's internal name, used to identify the device in the emulated machine's configuration file. ``"foo1234"`` for example.
|
||||
|
||||
* - :cspan:`1` flags
|
||||
- One or more bitwise flags to indicate the expansion bus(es) supported by the device, for determining device eligibility on the selected machine:
|
||||
|
||||
* ``DEVICE_ISA``: 8-bit ISA;
|
||||
* ``DEVICE_AT``: 16-bit ISA;
|
||||
* ``DEVICE_EISA``: EISA (reserved for future use);
|
||||
* ``DEVICE_VLB``: VESA Local Bus;
|
||||
* ``DEVICE_PCI``: 32-bit PCI;
|
||||
* ``DEVICE_AGP``: AGP 3.3V;
|
||||
* ``DEVICE_AC97``: AMR or CNR;
|
||||
* ``DEVICE_PCJR``: IBM PCjr;
|
||||
* ``DEVICE_PS2``: IBM PS/1 or PS/2;
|
||||
* ``DEVICE_MCA``: IBM Micro Channel Architecture;
|
||||
* ``DEVICE_CBUS``: PC-98 C-BUS (reserved for future use);
|
||||
* ``DEVICE_COM``: serial (reserved for future use);
|
||||
* ``DEVICE_LPT``: parallel (reserved for future use).
|
||||
|
||||
* - :cspan:`1` local
|
||||
- 32-bit value which can be read from this structure by the ``init`` callback.
|
||||
Use this value to tell different subtypes of the same device, for example.
|
||||
|
||||
* - :cspan:`1` init
|
||||
- Function called whenever this device is initialized, either from starting 86Box or from a hard reset. Can be ``NULL``. Takes the form of:
|
||||
|
||||
``void *init(const struct device_t *info)``
|
||||
|
||||
where ``info`` is a pointer to this ``device_t`` structure, and
|
||||
the return value is an opaque pointer passed to the other callbacks below, usually a :ref:`state structure <dev/api/device:State structure>`.
|
||||
The opaque pointer will be invalid if this function is ``NULL``.
|
||||
|
||||
* - :cspan:`1` close
|
||||
- Function called whenever this device is de-initialized, either from closing 86Box or from a hard reset. Can be ``NULL``. Takes the form of:
|
||||
|
||||
``void close(void *priv)``
|
||||
|
||||
where ``priv`` is the opaque pointer that was returned by ``init``.
|
||||
|
||||
* - :cspan:`1` reset
|
||||
- Function called whenever this device undergoes a soft reset. Can be ``NULL``. Takes the form of:
|
||||
|
||||
``void reset(void *priv)``
|
||||
|
||||
where ``priv`` is the opaque pointer that was returned by ``init``.
|
||||
|
||||
* - :rspan:`2`
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<div class="vertical-text">union</div>
|
||||
- available
|
||||
- Function called whenever this device's availability is being checked. Can be ``NULL``. Takes the form of:
|
||||
|
||||
``int available()``
|
||||
|
||||
where the return value must be ``1`` if the device is available for selection, or ``0`` if it is unavailable (due to missing ROMs, for example).
|
||||
The device will always be available if this function is ``NULL``.
|
||||
|
||||
* - poll
|
||||
- Function called whenever the mouse position is updated. Valid for mouse devices only. Takes the form of:
|
||||
|
||||
``int poll(int x, int y, int z, int b, void *priv)``
|
||||
|
||||
where ``x`` and ``y`` are the relative movement coordinates,
|
||||
``z`` is the relative wheel coordinate,
|
||||
``b`` is the button state (bit 0 / 0x01 set for left button, bit 1 / 0x02 set for right button, bit 3 / 0x04 set for middle button),
|
||||
``priv`` is the opaque pointer that was returned by ``init``, and
|
||||
the return value must be ``0`` if the change was processed or any other value otherwise.
|
||||
|
||||
* - register_pci_slot
|
||||
- Reserved for future use.
|
||||
|
||||
* - :cspan:`1` speed_changed
|
||||
- Function called whenever the emulated CPU clock speed is changed. Can be ``NULL``. Timer intervals and anything else sensitive to the CPU clock speed should be updated in this callback. Takes the form of:
|
||||
|
||||
``void speed_changed(void *priv)``
|
||||
|
||||
where ``priv`` is the opaque pointer that was returned by ``init``.
|
||||
|
||||
* - :cspan:`1` force_redraw
|
||||
- Function called whenever the emulated screen has to be fully redrawn. Can be ``NULL``. Only useful for video cards. Takes the form of:
|
||||
|
||||
``void force_redraw(void *priv)``
|
||||
|
||||
where ``priv`` is the opaque pointer that was returned by ``init``.
|
||||
|
||||
* - :cspan:`1` config
|
||||
- Array of device configuration options, or ``NULL`` if no options are available. See :ref:`dev/api/device:Configuration`.
|
||||
|
||||
State structure
|
||||
---------------
|
||||
|
||||
Most devices need a place to store their internal state. We discourage the use of global structures, and instead recommend allocating state structures dynamically in the ``init`` callback and freeing them in the ``close`` callback::
|
||||
|
||||
typedef struct {
|
||||
uint32_t type; /* example: copied from device_t.local */
|
||||
uint8_t regs[256]; /* example: 256*8-bit registers */
|
||||
} foo_t;
|
||||
|
||||
static void *
|
||||
foo_init(const device_t *info)
|
||||
{
|
||||
/* Allocate a blank state structure. */
|
||||
foo_t *dev = (foo_t *) malloc(sizeof(foo_t));
|
||||
memset(dev, 0, sizeof(foo_t));
|
||||
|
||||
/* Do whatever you want. */
|
||||
dev->type = info->local; /* copy device_t.local value */
|
||||
|
||||
/* Return a pointer to the state structure. */
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void
|
||||
foo_close(void *priv)
|
||||
{
|
||||
/* Get the state structure. */
|
||||
foo_t *dev = (foo_t *) priv;
|
||||
|
||||
/* Do whatever you want, then deallocate the state structure. */
|
||||
free(dev);
|
||||
}
|
||||
|
||||
const device_t foo1234_device = {
|
||||
.name = "Foo-1234",
|
||||
.internal_name = "foo1234",
|
||||
.flags = DEVICE_AT, /* 16-bit ISA */
|
||||
.local = 1234,
|
||||
.init = foo_init,
|
||||
.close = foo_close,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
const device_t foo4321_device = {
|
||||
.name = "Foo-4321",
|
||||
.internal_name = "foo4321",
|
||||
.flags = DEVICE_PCI, /* 32-bit PCI */
|
||||
.local = 4321, /* different device subtype */
|
||||
.init = foo_init,
|
||||
.close = foo_close,
|
||||
/* ... */
|
||||
};
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Devices can have any number of user-facing configuration options, usually accessed through the **Configure** button next to the selection box for the device's class. Examples for all option types currently configurable through the user interface are shown in the image below.
|
||||
|
||||
.. image:: images/deviceconfig.png
|
||||
:align: center
|
||||
|
||||
These options are stored in the emulated machine's configuration file, in a section identified by the device's ``name``:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
[Foo-1234]
|
||||
selection = 0
|
||||
hex16 = 0220
|
||||
hex20 = D8000
|
||||
fname = D:/VMs/86Box/86Box.exe
|
||||
binary = 1
|
||||
spinner = 1234
|
||||
midi_out = 0
|
||||
midi_in = 0
|
||||
|
||||
|
||||
Configuration options can be specified in the ``config`` member of ``device_t``, as a pointer to a ``const`` array of ``device_config_t`` objects terminated by an object of ``type`` ``-1``.
|
||||
|
||||
.. flat-table:: device_config_t
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Member
|
||||
- Description
|
||||
|
||||
* - name
|
||||
- Internal name for this option, used in the emulated machine's configuration file.
|
||||
|
||||
* - description
|
||||
- Description for this option, displayed in the user interface.
|
||||
|
||||
* - type
|
||||
- One of the following option types:
|
||||
|
||||
* ``CONFIG_SELECTION``: combobox containing a list of values specified by the ``selection`` member;
|
||||
* ``CONFIG_HEX16``: combobox containing a list of 16-bit hexadecimal values (useful for ISA I/O ports) specified by the ``selection`` member;
|
||||
* ``CONFIG_HEX20``: combobox containing a list of 20-bit hexadecimal values (useful for ISA memory addresses) specified by the ``selection`` member;
|
||||
* ``CONFIG_STRING``: arbitrary text string entered by the user, currently **not visible nor configurable** in the user interface;
|
||||
* ``CONFIG_FNAME``: arbitrary file path entered by the user directly or through a file selector button;
|
||||
* ``CONFIG_BINARY``: checkbox;
|
||||
* ``CONFIG_INT``: arbitrary integer number, currently **not visible nor configurable** in the user interface;
|
||||
* ``CONFIG_SPINNER``: arbitrary integer number entered by the user directly or through up/down arrows, within a range specified by the ``spinner`` member;
|
||||
* ``CONFIG_MAC``: last 3 octets of a MAC address, currently **not visible nor configurable** in the user interface;
|
||||
* ``CONFIG_MIDI_OUT``: combobox containing a list of system MIDI output devices;
|
||||
* ``CONFIG_MIDI_IN``: combobox containing a list of system MIDI input devices;
|
||||
* ``-1``: **mandatory** terminator to indicate the end of the option list.
|
||||
|
||||
* - default_string
|
||||
- Default string value for a ``CONFIG_STRING`` option. Can be ``""`` if not applicable.
|
||||
|
||||
* - default_int
|
||||
- Default integer value for a ``CONFIG_HEX16``, ``CONFIG_HEX20``, ``CONFIG_INT`` or ``CONFIG_SPINNER`` option. Can be 0 if not applicable.
|
||||
|
||||
* - file_filter
|
||||
- File type filter for a ``CONFIG_FNAME`` option. Can be ``""`` if not applicable. Must be specified in Windows ``description|mask|description|mask...`` format, for example:
|
||||
|
||||
``"Raw image (*.img)|*.img|Virtual Hard Disk (*.vhd)|*.vhd"``
|
||||
|
||||
* - spinner
|
||||
- ``device_config_spinner_t`` sub-structure containing the minimum/maximum/step values for a ``CONFIG_SPINNER`` option. Can be ``{ 0 }`` if not applicable.
|
||||
|
||||
.. flat-table::
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Member
|
||||
- Description
|
||||
|
||||
* - min
|
||||
- Minimum selectable value.
|
||||
|
||||
* - max
|
||||
- Maximum selectable value.
|
||||
|
||||
* - step
|
||||
- Units to be incremented/decremented with the arrow buttons. Note that the user can still type in arbitrary numbers that are within ``min`` and ``max`` but not aligned to ``step``.
|
||||
|
||||
* - selection
|
||||
- Array of ``device_config_selection_t`` sub-structures containing the choices for a ``CONFIG_SELECTION``, ``CONFIG_HEX16`` or ``CONFIG_HEX20`` option. Can be ``{ 0 }`` if not applicable. Must be terminated with an object with a ``description`` of ``""``.
|
||||
|
||||
.. flat-table::
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Member
|
||||
- Description
|
||||
|
||||
* - description
|
||||
- Description for this choice, displayed in the user interface.
|
||||
|
||||
* - value
|
||||
- Integer value corresponding to this choice, used in the emulated machine's configuration file.
|
||||
|
||||
Configured option values can be accessed using ``device_get_config_*`` functions from within the device's ``init`` callback.
|
||||
|
||||
.. note:: ``device_get_config_*`` functions should **never** be called outside of a device's ``init`` callback. You are responsible for reading the options' configured values in the ``init`` callback and storing them in your device's :ref:`state structure <dev/api/device:State structure>` if necessary.
|
||||
|
||||
.. flat-table:: device_get_config_string
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - name
|
||||
- The option's ``name``. Accepted option types are ``CONFIG_STRING`` and ``CONFIG_FNAME``.
|
||||
|
||||
* - **Return value**
|
||||
- The option's configured string value, or its ``default_string`` if no value is present. Note that a ``const char *`` is returned.
|
||||
|
||||
.. flat-table:: device_get_config_int / device_get_config_hex16 / device_get_config_hex20
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - name
|
||||
- The option's ``name``. Accepted option types are:
|
||||
|
||||
* ``device_get_config_int``: ``CONFIG_SELECTION``, ``CONFIG_BINARY``, ``CONFIG_INT``, ``CONFIG_SPINNER``, ``CONFIG_MIDI_OUT``, ``CONFIG_MIDI_IN``
|
||||
* ``device_get_config_hex16``: ``CONFIG_HEX16``
|
||||
* ``device_get_config_hex20``: ``CONFIG_HEX20``
|
||||
|
||||
* - **Return value**
|
||||
- The option's configured integer value (``CONFIG_BINARY`` returns 1 if checked or 0 otherwise), or its ``default_int`` if no value is present.
|
||||
|
||||
.. flat-table:: device_get_config_int_ex / device_get_config_mac
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - name
|
||||
- The option's ``name``. Accepted option types are:
|
||||
|
||||
* ``device_get_config_int_ex``: ``CONFIG_SELECTION``, ``CONFIG_BINARY``, ``CONFIG_INT``, ``CONFIG_SPINNER``, ``CONFIG_MIDI_OUT``, ``CONFIG_MIDI_IN``
|
||||
* ``device_get_config_mac``: ``CONFIG_MAC``
|
||||
|
||||
* - dflt_int
|
||||
- The default value to return if no configured value is present.
|
||||
|
||||
* - **Return value**
|
||||
- The option's configured integer value (``CONFIG_BINARY`` returns 1 if checked or 0 otherwise), or ``dflt_int`` if no value is present.
|
||||
76
dev/api/dma.rst
Normal file
76
dev/api/dma.rst
Normal file
@@ -0,0 +1,76 @@
|
||||
.. include:: /include.rst
|
||||
|
||||
DMA
|
||||
===
|
||||
|
||||
86Box offers two mechanisms for **Direct Memory Access**: 8237 DMA for ISA devices and direct memory read/write for PCI devices.
|
||||
|
||||
8237 DMA
|
||||
--------
|
||||
|
||||
``86box/dma.h`` provides the ``dma_channel_read`` and ``dma_channel_write`` functions to read or write (respectively) a value from or to an 8237 DMA channel.
|
||||
|
||||
.. flat-table:: dma_channel_read
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - channel
|
||||
- DMA channel number: ``0``-``3`` for 8-bit channels or ``5``-``7`` for 16-bit channels.
|
||||
|
||||
* - **Return value**
|
||||
- 8- (channels ``0``-``3``) or 16-bit (channels ``5``-``7``) value read from the given DMA channel, or ``DMA_NODATA`` if no data was read.
|
||||
|
||||
May include a ``DMA_OVER`` flag (located above the most significant data bit so as to not affect the data) indicating that this was the last byte or word transferred, after which the channel is auto-initialized or masked depending on its configuration.
|
||||
|
||||
.. flat-table:: dma_channel_write
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - channel
|
||||
- DMA channel number: ``0``-``3`` for 8-bit channels or ``5``-``7`` for 16-bit channels.
|
||||
|
||||
* - val
|
||||
- 8- (channels ``0``-``3``) or 16-bit (channels ``5``-``7``) value to write to the given DMA channel.
|
||||
|
||||
* - **Return value**
|
||||
- * ``0`` on success;
|
||||
* ``DMA_NODATA`` if no data was actually written;
|
||||
* ``DMA_OVER`` if this was the last byte or word transferred, after which the channel is auto-initialized or masked depending on its configuration.
|
||||
|
||||
Direct memory read/write
|
||||
------------------------
|
||||
|
||||
``86box/mem.h`` provides the ``mem_read*_phys`` and ``mem_write*_phys`` functions, which directly read or write physical memory. These are useful for PCI devices, which have to perform DMA on their own.
|
||||
|
||||
.. flat-table:: mem_readb_phys / mem_readw_phys / mem_readl_phys
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - addr
|
||||
- 32-bit memory address to read.
|
||||
|
||||
* - **Return value**
|
||||
- 8- (``mem_readb_phys``), 16- (``mem_readw_phys``) or 32-bit (``mem_readl_phys``) value read from the given memory address.
|
||||
|
||||
|
||||
.. flat-table:: mem_writeb_phys / mem_writew_phys / mem_writel_phys
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - addr
|
||||
- 32-bit memory address to write.
|
||||
|
||||
* - val
|
||||
- 8- (``mem_readb_phys``), 16- (``mem_readw_phys``) or 32-bit (``mem_readl_phys``) value to write to the given memory address.
|
||||
BIN
dev/api/images/deviceconfig.png
Normal file
BIN
dev/api/images/deviceconfig.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
11
dev/api/index.rst
Normal file
11
dev/api/index.rst
Normal file
@@ -0,0 +1,11 @@
|
||||
API
|
||||
===
|
||||
|
||||
This section documents the internal **Application Programming Interface** for implementing devices on 86Box.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
device
|
||||
io
|
||||
dma
|
||||
133
dev/api/io.rst
Normal file
133
dev/api/io.rst
Normal file
@@ -0,0 +1,133 @@
|
||||
.. include:: /include.rst
|
||||
|
||||
Port I/O
|
||||
========
|
||||
|
||||
86Box handles the x86 port I/O space through **I/O handlers**. These handlers can be added with the ``io_sethandler`` function and removed with the ``io_removehandler`` function, both provided by ``86box/io.h``.
|
||||
|
||||
.. flat-table:: io_sethandler / io_removehandler
|
||||
:header-rows: 1
|
||||
:widths: 1 999
|
||||
|
||||
* - Parameter
|
||||
- Description
|
||||
|
||||
* - base
|
||||
- The first I/O port (0x0000-0xFFFF) to be covered by this handler.
|
||||
|
||||
* - size
|
||||
- The amount of I/O ports (1-65536) starting at ``base`` to be covered by this handler.
|
||||
|
||||
* - inb
|
||||
- :rspan:`2` I/O read operation callback functions. Can be ``NULL``. Each callback takes the form of:
|
||||
|
||||
``TYPE callback(uint16_t addr, void *priv)``
|
||||
|
||||
where ``TYPE`` corresponds to the operation's width (``uint8_t`` for ``inb``, ``uint16_t`` for ``inw`` or ``uint32_t`` for ``inl``),
|
||||
``addr`` is the exact I/O port being read,
|
||||
``priv`` is the opaque pointer (see ``priv`` below), and
|
||||
the return value is the value to be read.
|
||||
|
||||
* - inw
|
||||
|
||||
* - inl
|
||||
|
||||
* - outb
|
||||
- :rspan:`2` I/O write operation callback functions. Can be ``NULL``. Each callback takes the form of:
|
||||
|
||||
``void callback(uint16_t addr, TYPE val, void *priv)``
|
||||
|
||||
where ``TYPE`` corresponds to the operation's width (``uint8_t`` for ``outb``, ``uint16_t`` for ``outw`` or ``uint32_t`` for ``outl``),
|
||||
``addr`` is the exact I/O port being written,
|
||||
``val`` is the value being written, and
|
||||
``priv`` is the opaque pointer (see ``priv`` below).
|
||||
|
||||
* - outw
|
||||
|
||||
* - outl
|
||||
|
||||
* - priv
|
||||
- Opaque pointer, passed to this handler's read/write operation callbacks.
|
||||
Usually a pointer to the device's :ref:`state structure <dev/api/device:State structure>`.
|
||||
|
||||
I/O handlers can be added or removed at any time, although ``io_removehandler`` must be called with the **exact same** parameters that ``io_sethandler`` was originally called with. For non-Plug and Play devices, you might want to add handlers in the ``init`` callback; for ISA Plug and Play devices, you'd add and/or remove handlers on the ``config_changed`` callback; for PCI devices, you'd do the same whenever the Command register or Base Address (BAR) registers are written to; and so on.
|
||||
|
||||
.. note:: There is no need to call ``io_removehandler`` on the device's ``close`` callback, since a hard reset already removes all I/O handlers.
|
||||
|
||||
Callback fallbacks
|
||||
------------------
|
||||
|
||||
When an I/O handler receives an operation with a width for which it has no callback, the operation will automatically **fall back** to a lower width for which there is a callback. For example, if an ``inl`` operation falls on a handler which has no ``inl`` callback, 86Box will break the operation down to ``inw`` or ``inb`` callbacks on successive port numbers, then combine their return values:
|
||||
|
||||
* ``inl`` callback present::
|
||||
|
||||
uint32_t val = inl(port);
|
||||
|
||||
* ``inl`` callback not present, but ``inw`` callback present::
|
||||
|
||||
uint32_t val = inw(port);
|
||||
val |= (inw(port + 1) << 16);
|
||||
|
||||
* ``inl`` and ``inw`` callbacks not present, but ``inb`` callback present::
|
||||
|
||||
uint32_t val = inb(port);
|
||||
val |= (inb(port + 1) << 8);
|
||||
val |= (inb(port + 2) << 16);
|
||||
val |= (inb(port + 3) << 24);
|
||||
|
||||
* ``inl``, ``inw`` and ``inb`` callbacks not present::
|
||||
|
||||
uint32_t val = 0xffffffff;
|
||||
|
||||
The same applies to write callbacks:
|
||||
|
||||
* ``outl`` callback present::
|
||||
|
||||
uint32_t val = /* ... */;
|
||||
outl(port, val);
|
||||
|
||||
* ``outl`` callback not present, but ``outw`` callback present::
|
||||
|
||||
uint32_t val = /* ... */;
|
||||
outw(port, val & 0xffff);
|
||||
outw(port + 1, (val >> 16) & 0xffff);
|
||||
|
||||
* ``outl`` and ``outw`` callbacks not present, but ``outb`` callback present::
|
||||
|
||||
uint32_t val = /* ... */;
|
||||
outb(port, val & 0xff);
|
||||
outb(port + 1, (val >> 8) & 0xff);
|
||||
outb(port + 2, (val >> 16) & 0xff);
|
||||
outb(port + 3, (val >> 24) & 0xff);
|
||||
|
||||
* ``outl``, ``outw`` and ``outb`` callbacks not present:
|
||||
|
||||
No operation performed.
|
||||
|
||||
This feature's main use cases are devices which store registers that are 8-bit wide but may be accessed with 16- or 32-bit operations::
|
||||
|
||||
typedef struct {
|
||||
uint8_t regs[256];
|
||||
} foo_t;
|
||||
|
||||
uint8_t
|
||||
foo_inb(uint16_t addr, void *priv)
|
||||
{
|
||||
foo_t *dev = (foo_t *) priv;
|
||||
return dev->regs[addr & 0xff]; /* example: register index = I/O port's least significant byte */
|
||||
}
|
||||
|
||||
/* No foo_inw, so a 16-bit operation will read two 8-bit registers in succession.
|
||||
No foo_inl, so a 32-bit operation will read four 8-bit registers in succession. */
|
||||
|
||||
Multiple I/O handlers
|
||||
---------------------
|
||||
|
||||
Any given I/O port can have an **unlimited** amount of I/O handlers, such that:
|
||||
|
||||
* when a **read** operation occurs, all read callbacks will be called, and their return values will be logically **AND**\ ed together;
|
||||
* when a **write** operation occurs, all write callbacks will be called with the same written value.
|
||||
|
||||
Read callbacks can effectively return "don't care" (without interfering with other handlers) by returning a value with all bits set: ``0xff`` with ``inb``, ``0xffff`` with ``inw`` or ``0xffffffff`` with ``inl``.
|
||||
|
||||
.. note:: The same callback fallback rules specified above also apply with multiple handlers.
|
||||
26
include.rst
26
include.rst
@@ -67,4 +67,30 @@
|
||||
div.admonition > p:nth-child(2) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.wy-table-responsive table td {
|
||||
white-space: normal;
|
||||
}
|
||||
.rst-content table.docutils caption {
|
||||
padding-top: 0;
|
||||
font-family: monospace;
|
||||
font-style: normal;
|
||||
}
|
||||
table.docutils > tbody > tr > td > ul {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
table.docutils > tbody > tr > td > ul > li > p {
|
||||
font-size: inherit;
|
||||
}
|
||||
table.docutils > tbody > tr > td > div.wy-table-responsive {
|
||||
margin-top: 0.5em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
tr.row-odd > td {
|
||||
background-color: #fcfcfc !important;
|
||||
}
|
||||
.vertical-text {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
</style>
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
@@ -46,4 +46,5 @@ Contents
|
||||
|
||||
dev/buildguide
|
||||
dev/builds
|
||||
dev/api/index
|
||||
dev/formats/index
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
Sphinx==4.3.0
|
||||
sphinx-rtd-theme==1.0.0
|
||||
linuxdoc==20211220
|
||||
|
||||
Reference in New Issue
Block a user