diff --git a/conformance.tex b/conformance.tex
index 94d7a06..4bdaac4 100644
--- a/conformance.tex
+++ b/conformance.tex
@@ -30,8 +30,9 @@ \section{Conformance Targets}\label{sec:Conformance / Conformance Targets}
 \ref{sec:Conformance / Driver Conformance / IOMMU Driver Conformance},
 \ref{sec:Conformance / Driver Conformance / Sound Driver Conformance},
 \ref{sec:Conformance / Driver Conformance / Memory Driver Conformance},
-\ref{sec:Conformance / Driver Conformance / I2C Adapter Driver Conformance} or
-\ref{sec:Conformance / Driver Conformance / SCMI Driver Conformance}.
+\ref{sec:Conformance / Driver Conformance / I2C Adapter Driver Conformance},
+\ref{sec:Conformance / Driver Conformance / SCMI Driver Conformance} or
+\ref{sec:Conformance / Driver Conformance / General Purpose IO Driver Conformance}.
 
     \item Clause \ref{sec:Conformance / Legacy Interface: Transitional Device and Transitional Driver Conformance}.
   \end{itemize}
@@ -54,8 +55,9 @@ \section{Conformance Targets}\label{sec:Conformance / Conformance Targets}
 \ref{sec:Conformance / Device Conformance / IOMMU Device Conformance},
 \ref{sec:Conformance / Device Conformance / Sound Device Conformance},
 \ref{sec:Conformance / Device Conformance / Memory Device Conformance},
-\ref{sec:Conformance / Device Conformance / I2C Adapter Device Conformance} or
-\ref{sec:Conformance / Device Conformance / SCMI Device Conformance}.
+\ref{sec:Conformance / Device Conformance / I2C Adapter Device Conformance},
+\ref{sec:Conformance / Device Conformance / SCMI Device Conformance} or
+\ref{sec:Conformance / Device Conformance / General Purpose IO Device Conformance}.
 
     \item Clause \ref{sec:Conformance / Legacy Interface: Transitional Device and Transitional Driver Conformance}.
   \end{itemize}
@@ -301,6 +303,15 @@ \section{Conformance Targets}\label{sec:Conformance / Conformance Targets}
 \item \ref{drivernormative:Device Types / SCMI Device / Device Operation / Setting Up eventq Buffers}
 \end{itemize}
 
+\conformance{\subsection}{General Purpose IO Driver Conformance}\label{sec:Conformance / Driver Conformance / General Purpose IO Driver Conformance}
+
+An General Purpose IO driver MUST conform to the following normative statements:
+
+\begin{itemize}
+\item \ref{devicenormative:Device Types / General Purpose IO / Virtqueues}
+\item \ref{devicenormative:Device Types / General Purpose IO / Data flow}
+\end{itemize}
+
 \conformance{\section}{Device Conformance}\label{sec:Conformance / Device Conformance}
 
 A device MUST conform to the following normative statements:
@@ -550,6 +561,15 @@ \section{Conformance Targets}\label{sec:Conformance / Conformance Targets}
 \item \ref{devicenormative:Device Types / SCMI Device / Device Operation / Shared Memory Operation}
 \end{itemize}
 
+\conformance{\subsection}{General Purpose IO Device Conformance}\label{sec:Conformance / Device Conformance / General Purpose IO Device Conformance}
+
+An General Purpose IO device MUST conform to the following normative statements:
+
+\begin{itemize}
+\item \ref{devicenormative:Device Types / General Purpose IO / Virtqueues}
+\item \ref{devicenormative:Device Types / General Purpose IO / Data flow}
+\end{itemize}
+
 \conformance{\section}{Legacy Interface: Transitional Device and Transitional Driver Conformance}\label{sec:Conformance / Legacy Interface: Transitional Device and Transitional Driver Conformance}
 A conformant implementation MUST be either transitional or
 non-transitional, see \ref{intro:Legacy
diff --git a/content.tex b/content.tex
index ceb2562..a5e1ec4 100644
--- a/content.tex
+++ b/content.tex
@@ -2876,7 +2876,7 @@ \chapter{Device Types}\label{sec:Device Types}
 \hline
 40         &   Bluetooth device \\
 \hline
-41         &   GPIO device \\
+41         &   General Purpose IO device \\
 \hline
 \end{tabular}
 
@@ -6583,6 +6583,7 @@ \subsubsection{Legacy Interface: Framing Requirements}\label{sec:Device
 \input{virtio-mem.tex}
 \input{virtio-i2c.tex}
 \input{virtio-scmi.tex}
+\input{devices/virtio-gpio.tex}
 
 \chapter{Reserved Feature Bits}\label{sec:Reserved Feature Bits}
 
diff --git a/devices/virtio-gpio.tex b/devices/virtio-gpio.tex
new file mode 100644
index 0000000..8417acb
--- /dev/null
+++ b/devices/virtio-gpio.tex
@@ -0,0 +1,381 @@
+\section{General Purpose IO Device}\label{sec:Device Types / General Purpose IO}
+
+The virtio gpio device is a general purpose IO device that supports a variable
+number of named IO lines that may be switched either as input or output and
+in logical level 0 or 1.
+
+\subsection{Device ID}\label{sec:Device Types / General Purpose IO / Device ID}
+  41
+
+\subsection{Version}\label{sec:Device Types / General Purpose IO / Version}
+  1
+
+\subsection{Device configuration layout}\label{sec:Device Types / General Purpose IO / Device configuration layout}
+
+General purpose IO configuration uses the following layout structure:
+
+\begin{lstlisting}
+struct virtio_gpio_config {
+    __u8    version;
+    __u8    reserved0;
+    __u16   num_gpios;
+    __u32   names_size;
+    __u8    reserved1[24];
+    __u8    name[32];
+    __u8    line_names[];
+};
+\end{lstlisting}
+
+\begin{itemize}
+    \item for \field{version} field currently only value 1 supported.
+    \item the \field{line names block} holds a stream of zero-terminated strings,
+        containing the individual line names in ASCII. line names must unique.
+    \item the \field{name} field may contain a zero terminated device name
+          or serial number in ASCII.
+    \item unspecified fields are reserved for future use and should be zero.
+    \item future versions may extend this configuration space by additional fields.
+\end{itemize}
+
+\subsection{Feature bits}\label{sec:Device Types / General Purpose IO / Feature bits}
+
+\begin{description}
+\item[VIRTIO_GPIO_F_ARBITRATION (0)] line arbitration -- REQUEST and RELEASE operations.
+\item[VIRTIO_GPIO_F_IRQ (1)] IRQ control
+\end{description}
+
+\subsection{Virtqueues}\label{sec:Device Types / General Purpose IO / Virtqueues}
+\begin{description}
+\item[0] rx (device to CPU)
+\item[1] tx (CPU to device)
+\end{description}
+
+The virtqueues transport messages of the type struct virtio_gpio_msg from device to CPU or CPU to device.
+
+\subsubsection{Virtqueues}\label{sec:Device Types / General Purpose IO / Virtqueues / Message format}
+
+The queues transport messages of the struct virtio_gpio_msg:
+
+\begin{lstlisting}
+struct virtio_gpio_msg {
+    __le16  type;
+    __le16  pin;
+    __le32  value;
+};
+\end{lstlisting}
+
+\subsubsection{Message types}\label{sec:Device Types / General Purpose IO / Virtqueues / Message types}
+
+\begin{lstlisting}
+/* messages types: driver -> device */
+#define VIRTIO_GPIO_MSG_CPU_REQUEST             0x0001
+#define VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT     0x0002
+#define VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT    0x0003
+#define VIRTIO_GPIO_MSG_CPU_GET_DIRECTION       0x0004
+#define VIRTIO_GPIO_MSG_CPU_GET_LEVEL           0x0005
+#define VIRTIO_GPIO_MSG_CPU_SET_LEVEL           0x0006
+#define VIRTIO_GPIO_MSG_CPU_RELEASE             0x0007
+#define VIRTIO_GPIO_MSG_CPU_SET_IRQ             0x0008
+
+/* message types: device -> driver */
+#define VIRTIO_GPIO_MSG_DEVICE_LEVEL            0x0011
+
+/* reply mask: device sets this bit on replies (along with request's message type)
+#define VIRTIO_GPIO_MSG_REPLY                   0x8000
+\end{lstlisting}
+
+\subsubsection{Error codes}\label{sec:Device Types / General Purpose IO / Virtqueues / Error codes}
+
+If requests result in an error, the device shall respond with an appropriate
+error code, which is encoded as \textbf{negative} value in the reply message's
+\textit{value} field.
+
+\begin{lstlisting}
+/* success, no error */
+#define VIRTIO_GPIO_ERR_OK      0x0000
+/* internal fault */
+#define VIRTIO_GPIO_ERR_FAULT   0x0001
+/* requested pin does not exist */
+#define VIRTIO_GPIO_ERR_NO_PIN  0x0002
+/* communications error */
+#define VIRTIO_GPIO_ERR_COMM    0x0003
+/* configuration not supported */
+#define VIRTIO_GPIO_ERR_INVAL   0x0004
+\end{lstlisting}
+
+\devicenormative{\subsubsection}{Virtqueues}{Device Types / General Purpose IO / Virtqueues}
+
+The device MUST read from the tx queue and write to rx queue.
+
+The device MUST NOT write to the tx queue.
+
+\drivernormative{\subsubsection}{Virtqueues}{Device Types / General Purpose IO / Virtqueues}
+
+The device MUST read from the rx queue and write to tx queue.
+
+The device MUST NOT write to the rx queue.
+
+\subsection{Data flow}\label{sec:Device Types / General Purpose IO / Data flow}
+
+\begin{itemize}
+    \item all operations, except \field{VIRTIO_GPIO_MSG_DEVICE_LEVEL}, are initiated by CPU (tx queue)
+    \item device replies with the orinal \field{type} value OR'ed with \field{VIRTIO_GPIO_MSG_REPLY} (rx queue)
+    \item requests are processed and replied in the they had been sent
+    \item the number of concurrent requests is limited by the device's queue size
+    \item async notifications by the device may be interleaved with request responses
+    \item VIRTIO_GPIO_MSG_DEVICE_LEVEL is only sent asynchronously from device to CPU
+    \item in replies, a negative \field{value} field denotes an error code
+    \item in level or direction values, only bit 0 shall be used
+    \item valid direction values are: bit 0: 0 = output, 1 = input
+    \item valid line level values are: bit 0: 0 = inactive, 1 = active
+    \item CPU should not send messages with unspecified \field{type} value
+    \item CPU should ignore ignore messages with unspecified \field{type} value
+\end{itemize}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_REQUEST}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-REQUEST}
+
+Notify the device that given line number is going to be used.
+
+Only available if feature bit VIRTIO_GPIO_F_ARBITRATION is set.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & error code (0 = success) \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_RELEASE}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-RELEASE}
+
+Notify the device that given line number is not used anymore.
+
+Only available if feature bit VIRTIO_GPIO_F_ARBITRATION is set.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & error code (0 = success) \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_DIRECTION_INPUT}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-DIRECTION-INPUT}
+
+Set line line direction to input.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & error code (0 = success) \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_DIRECTION_OUTPUT}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-DIRECTION-OUTPUT}
+
+Set line direction to output and given line level.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & bit 0: output level (0=inactive, 1=active) \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & error code (0 = success) \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_GET_DIRECTION}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-GET-DIRECTION}
+
+Retrieve line direction.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & bit 0: direction (0=output, 1=input) or errno code \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_GET_LEVEL}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-GET-LEVEL}
+
+Retrieve line level.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & bit 0: line level (0=inactive, 1=active) or errno code \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_SET_LEVEL}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-SET-LEVEL}
+
+Set line level (output only)
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & bit 0: line level (0=inactive, 1=active) \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & bit 0: new line level or (negative) errno code \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_CPU_SET_IRQ}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-CPU-SET-IRQ}
+
+Set the IRQ mask. See \ref{sec:Device Types / General Purpose IO / IRQ handling}.
+
+Only available if feature bit VIRTIO_GPIO_F_IRQ has been negotiated.
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & IRQ mask \\
+    \hline
+    \textbf{reply:} & \\
+    \hline
+    \field{value} field: & (negative) errno code \\
+    \hline
+\end{tabular}
+
+\subsubsection{VIRTIO_GPIO_MSG_DEVICE_LEVEL}\label{sec:Device Types / General Purpose IO / Data flow / VIRTIO-GPIO-MSG-DEVICE-LEVEL}
+
+Async notification from device to CPU: line level changed
+
+\begin{tabular}{ll}
+    \hline
+    \textbf{request:} & \\
+    \hline
+    \field{line}  field: & logical line number \\
+    \field{value} field: & unused (should be zero) \\
+    \hline
+    \textbf{reply:} & \\
+    \field{value} field: & bit 0: line level (0=inactive, 1=active) \\
+    \hline
+\end{tabular}
+
+\devicenormative{\subsubsection}{Data flow}{Device Types / General Purpose IO / Data flow}
+
+The device MUST reply to all driver requests in they had been sent.
+
+The device MUST copy the \field{line} field from the request to its reply.
+
+Except for async notification, the device MUST reply the orignal message type, but with the highest bit set
+(or'ed with VIRTIO_GPIO_MSG_REPLY)
+
+In case of error the device MUST fill an \textbf{negative} value into the \field{value} field.
+
+On switching to output, the device SHOULD set internal output level before switching the line to output.
+
+The device SHOULD send VIRTIO_GPIO_MSG_DEVICE_LEVEL message for a particular line when it is in input
+direction and line level changes.
+
+\drivernormative{\subsubsection}{Data flow}{Device Types / General Purpose IO / Data flow}
+
+The driver MUST NOT send VIRTIO_GPIO_MSG_DEVICE_LEVEL and MUST NOT set the highest bit in the message type.
+
+The driver MUST NOT send messages with types not defined in this specification.
+
+The driver MUST treat all negative values of the \field{value} field as errors, regardless whether
+the actual codes are explicitly defined in this specification.
+
+\subsection{IRQ handling}\label{sec:Device Types / General Purpose IO / IRQ handling}
+
+IRQ handling is only enabled if feature VIRTIO_GPIO_F_IRQ had been negotiated -- in
+this case only explicitly configured events are sent via VIRTIO_GPIO_MSG_DEVICE_LEVEL
+message. Otherwise level state changes are sent unconditionally.
+
+IRQ masking is configured via VIRTIO_GPIO_MSG_CPU_IRQ message, using the following
+(or'ed) mask bits:
+
+\begin{lstlisting}
+/* fire on levels */
+#define VIRTIO_GPIO_IRQ_HI      0x0001
+#define VIRTIO_GPIO_IRQ_LOW     0x0002
+
+/* fire on edge */
+#define VIRTIO_GPIO_IRQ_RAISING 0x0004
+#define VIRTIO_GPIO_IRQ_FALLING 0x0008
+
+/* enabled */
+#define VIRTIO_GPIO_IRQ_ARMED   0x0016
+#define VIRTIO_GPIO_IRQ_ALWAYS  0x0032
+\end{lstlisting}
+
+The actual kind of IRQ fired is determined on whether / how the line state changed
+from the previous message.
+
+IRQs are fired only, if either \textbf{ARMED} or \textbf{ALWAYS} are set. The
+\textbf{ARMED} flag is automatically cleared on IRQ signal, thus needs explicit
+rearming / unmasking.
+
+\devicenormative{\subsubsection}{IRQ handling}{sec:Device Types / General Purpose IO / IRQ handling}
+
+The device MUST maintain the IRQ masking state independently from other states like
+line direction or line states.
+
+When VIRTIO_GPIO_F_IRQ is negotiated, all irq mask registers need to be cleared,
+so no IRQs can occour, until explicitly enabled.
+
+\subsection{Future versions}\label{sec:Device Types / General Purpose IO / Future versions}
+
+\begin{itemize}
+    \item adding new functionality should be done by adding optional feature bits, if possible --
+          new versions shall only be introduces when feature bits are not sufficient
+    \item future versions must increment the \field{version} value
+    \item the basic data structures (config space, message format) should remain
+          backwards compatible, but may increased in size or use reserved fields
+    \item device needs to support commands in older versions
+    \item CPU should not send commands of newer versions that the device doesn't support
+\end{itemize}
+
+\subsection{Design considerations}\label{sec:Device Types / General Purpose IO / Design considerations}
+
+This specification has been layed out for being easy to implement in \textbf{hardware},
+silicon or FPGA, with a minimum number of required gates, in order to save chip space,
+power consumption and heat emissions, but also being easy to emulate in software, on both
+device and driver side.
+
+For that reason, data structures and signaling protocols have been designed to be very
+simple (e.g. fixed buffer layouts), and features that may not be always present or needed
+(e.g. IRQs) are explicitly negotiated by optional feature bits.
+
+Signal flow has been designed to use a simple (in-order) request-response scheme with
+separated tx/rx queues for all driver initiated transactions, that the device replies
+by just flipping a few bits and sending the packet back.
+
+The subset of virtio used here can also be easily implemented by very low level means
+like serial lines.
