ioctl/streamon: add dedicated error types
diff --git a/src/device/queue.rs b/src/device/queue.rs
index e3b7bc8..8c3beb3 100644
--- a/src/device/queue.rs
+++ b/src/device/queue.rs
@@ -9,7 +9,9 @@
 use crate::{Format, PixelFormat, QueueType};
 use direction::*;
 use dqbuf::*;
-use ioctl::{DQBufError, GFmtError, QueryBuffer, SFmtError, TryFmtError};
+use ioctl::{
+    DQBufError, GFmtError, QueryBuffer, SFmtError, StreamOffError, StreamOnError, TryFmtError,
+};
 use qbuf::*;
 use states::BufferState;
 use states::*;
@@ -316,7 +318,7 @@
         self.state.num_queued_buffers.get()
     }
 
-    pub fn streamon(&self) -> crate::Result<()> {
+    pub fn streamon(&self) -> Result<(), StreamOnError> {
         let type_ = self.inner.type_;
         ioctl::streamon(&self.inner, type_)
     }
@@ -326,7 +328,7 @@
     /// If successful, then all the buffers that are queued but have not been
     /// dequeued yet return to the `Free` state. Buffer references obtained via
     /// `dequeue()` remain valid.
-    pub fn streamoff(&self) -> crate::Result<Vec<CanceledBuffer<M>>> {
+    pub fn streamoff(&self) -> Result<Vec<CanceledBuffer<M>>, StreamOffError> {
         let type_ = self.inner.type_;
         ioctl::streamoff(&self.inner, type_)?;
 
diff --git a/src/ioctl/streamon.rs b/src/ioctl/streamon.rs
index d1276cc..562c777 100644
--- a/src/ioctl/streamon.rs
+++ b/src/ioctl/streamon.rs
@@ -1,7 +1,9 @@
 //! Safe wrapper for the `VIDIOC_STREAM(ON|OFF)` ioctls.
 use crate::QueueType;
-use crate::Result;
+use nix::errno::Errno;
+use nix::Error;
 use std::os::unix::io::AsRawFd;
+use thiserror::Error;
 
 #[doc(hidden)]
 mod ioctl {
@@ -9,16 +11,42 @@
     nix::ioctl_write_ptr!(vidioc_streamoff, b'V', 19, u32);
 }
 
-/// Safe wrapper around the `VIDIOC_STREAMON` ioctl.
-pub fn streamon(fd: &impl AsRawFd, queue: QueueType) -> Result<()> {
-    unsafe { ioctl::vidioc_streamon(fd.as_raw_fd(), &(queue as u32)) }?;
+#[derive(Debug, Error)]
+pub enum StreamOnError {
+    #[error("Queue type not supported, or no buffers allocated or enqueued")]
+    InvalidQueue,
+    #[error("Invalid pad configuration")]
+    InvalidPadConfig,
+    #[error("Invalid pipeline link configuration")]
+    InvalidPipelineConfig,
+    #[error("Unexpected ioctl error: {0}")]
+    IoctlError(nix::Error),
+}
 
-    Ok(())
+/// Safe wrapper around the `VIDIOC_STREAMON` ioctl.
+pub fn streamon(fd: &impl AsRawFd, queue: QueueType) -> Result<(), StreamOnError> {
+    match unsafe { ioctl::vidioc_streamon(fd.as_raw_fd(), &(queue as u32)) } {
+        Ok(_) => Ok(()),
+        Err(Error::Sys(Errno::EINVAL)) => Err(StreamOnError::InvalidQueue),
+        Err(Error::Sys(Errno::EPIPE)) => Err(StreamOnError::InvalidPadConfig),
+        Err(Error::Sys(Errno::ENOLINK)) => Err(StreamOnError::InvalidPipelineConfig),
+        Err(e) => Err(StreamOnError::IoctlError(e)),
+    }
+}
+
+#[derive(Debug, Error)]
+pub enum StreamOffError {
+    #[error("Queue type not supported")]
+    InvalidQueue,
+    #[error("Unexpected ioctl error: {0}")]
+    IoctlError(nix::Error),
 }
 
 /// Safe wrapper around the `VIDIOC_STREAMOFF` ioctl.
-pub fn streamoff(fd: &impl AsRawFd, queue: QueueType) -> Result<()> {
-    unsafe { ioctl::vidioc_streamoff(fd.as_raw_fd(), &(queue as u32)) }?;
-
-    Ok(())
+pub fn streamoff(fd: &impl AsRawFd, queue: QueueType) -> Result<(), StreamOffError> {
+    match unsafe { ioctl::vidioc_streamoff(fd.as_raw_fd(), &(queue as u32)) } {
+        Ok(_) => Ok(()),
+        Err(Error::Sys(Errno::EINVAL)) => Err(StreamOffError::InvalidQueue),
+        Err(e) => Err(StreamOffError::IoctlError(e)),
+    }
 }