diff --git a/include/libcamera/internal/v4l2_subdevice.h b/include/libcamera/internal/v4l2_subdevice.h
index c37a82af..f0818d6d 100644
--- a/include/libcamera/internal/v4l2_subdevice.h
+++ b/include/libcamera/internal/v4l2_subdevice.h
@@ -96,62 +96,63 @@ public:
 		unsigned int pad;
 		unsigned int stream;
 	};
 
 	struct Route {
 		Route()
 			: flags(0)
 		{
 		}
 
 		Route(const Stream &snk, const Stream &src, uint32_t f)
 			: sink(snk), source(src), flags(f)
 		{
 		}
 
 		Stream sink;
 		Stream source;
 		uint32_t flags;
 	};
 
 	using Routing = std::vector<Route>;
 
 	explicit V4L2Subdevice(const MediaEntity *entity);
 	~V4L2Subdevice();
 
 	int open();
 
 	const MediaEntity *entity() const { return entity_; }
 
 	int getSelection(const Stream &stream, unsigned int target,
-			 Rectangle *rect);
-	int getSelection(unsigned int pad, unsigned int target, Rectangle *rect)
+			 std::optional<Rectangle> *rect);
+	int getSelection(unsigned int pad, unsigned int target,
+			 std::optional<Rectangle> *rect)
 	{
 		return getSelection({ pad, 0 }, target, rect);
 	}
 	int setSelection(const Stream &stream, unsigned int target,
 			 Rectangle *rect);
 	int setSelection(unsigned int pad, unsigned int target, Rectangle *rect)
 	{
 		return setSelection({ pad, 0 }, target, rect);
 	}
 
 	Formats formats(const Stream &stream);
 	Formats formats(unsigned int pad)
 	{
 		return formats({ pad, 0 });
 	}
 
 	int getFormat(const Stream &stream, V4L2SubdeviceFormat *format,
 		      Whence whence = ActiveFormat);
 	int getFormat(unsigned int pad, V4L2SubdeviceFormat *format,
 		      Whence whence = ActiveFormat)
 	{
 		return getFormat({ pad, 0 }, format, whence);
 	}
 	int setFormat(const Stream &stream, V4L2SubdeviceFormat *format,
 		      Whence whence = ActiveFormat);
 	int setFormat(unsigned int pad, V4L2SubdeviceFormat *format,
 		      Whence whence = ActiveFormat)
 	{
 		return setFormat({ pad, 0 }, format, whence);
 	}
diff --git a/src/libcamera/sensor/camera_sensor_legacy.cpp b/src/libcamera/sensor/camera_sensor_legacy.cpp
index 792e4b09..570372a3 100644
--- a/src/libcamera/sensor/camera_sensor_legacy.cpp
+++ b/src/libcamera/sensor/camera_sensor_legacy.cpp
@@ -1,44 +1,45 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 /*
  * Copyright (C) 2019, Google Inc.
  *
  * A V4L2-backed camera sensor
  */
 
 #include <algorithm>
 #include <cmath>
 #include <float.h>
 #include <iomanip>
 #include <limits.h>
 #include <map>
 #include <memory>
+#include <optional>
 #include <string.h>
 #include <string>
 #include <vector>
 
 #include <libcamera/base/class.h>
 #include <libcamera/base/log.h>
 #include <libcamera/base/utils.h>
 
 #include <libcamera/camera.h>
 #include <libcamera/control_ids.h>
 #include <libcamera/controls.h>
 #include <libcamera/geometry.h>
 #include <libcamera/orientation.h>
 #include <libcamera/property_ids.h>
 #include <libcamera/transform.h>
 
 #include <libcamera/ipa/core_ipa_interface.h>
 
 #include "libcamera/internal/bayer_format.h"
 #include "libcamera/internal/camera_lens.h"
 #include "libcamera/internal/camera_sensor.h"
 #include "libcamera/internal/camera_sensor_properties.h"
 #include "libcamera/internal/formats.h"
 #include "libcamera/internal/media_device.h"
 #include "libcamera/internal/sysfs.h"
 #include "libcamera/internal/v4l2_subdevice.h"
 
 namespace libcamera {
 
 class BayerFormat;
@@ -363,103 +364,117 @@ int CameraSensorLegacy::validateSensorDriver()
 	}
 
 	/* Verify if sensor supports horizontal/vertical flips. */
 	auto queryFlip = [&](uint32_t id, const char *name) -> std::pair<bool, bool> {
 		const struct v4l2_query_ext_ctrl *flipInfo = subdev_->controlInfo(id);
 		if (!flipInfo || flipInfo->flags & V4L2_CTRL_FLAG_READ_ONLY) {
 			LOG(CameraSensor, Debug)
 				<< "Camera sensor does not support " << name << " flip";
 			return { false, false };
 		}
 
 		return { true, flipInfo->flags & V4L2_CTRL_FLAG_MODIFY_LAYOUT };
 	};
 
 	auto hflip = queryFlip(V4L2_CID_HFLIP, "horizontal");
 	auto vflip = queryFlip(V4L2_CID_VFLIP, "vertical");
 
 	if (hflip.first && vflip.first && (hflip.second != vflip.second)) {
 		LOG(CameraSensor, Error)
 			<< "Flips with differing alter bayer order properties"
 			<< " are unsupported. Disabling flipping.";
 	} else {
 		supportHFlips_ = hflip.first;
 		supportVFlips_ = vflip.first;
 		flipsAlterBayerOrder_ = hflip.second || vflip.second;
 	}
 
 	/*
 	 * Make sure the required selection targets are supported.
 	 *
-	 * Failures in reading any of the targets are not deemed to be fatal,
+	 * Unavailable selection targets are not deemed to be fatal,
 	 * but some properties and features, like constructing a
 	 * IPACameraSensorInfo for the IPA module, won't be supported.
 	 *
 	 * \todo Make support for selection targets mandatory as soon as all
 	 * test platforms have been updated.
 	 */
-	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_NATIVE_SIZE, &pixelArrayArea_);
-	if (ret) {
+	std::optional<Rectangle> rect;
+	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_NATIVE_SIZE, &rect);
+	if (ret)
+		return ret;
+	if (!rect) {
 		/*
 		 * Default the pixel array size to the largest size supported
 		 * by the sensor. The sizes_ vector is sorted in ascending
 		 * order, the largest size is thus the last element.
 		 */
 		pixelArrayArea_ = Rectangle(sizes_.back());
 
 		LOG(CameraSensor, Warning)
 			<< "The PixelArrayArea property has been defaulted to "
 			<< pixelArrayArea_;
 		err = -EINVAL;
+	} else {
+		pixelArrayArea_ = *rect;
 	}
 
-	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_BOUNDS, &readableArea_);
-	if (ret) {
+	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_BOUNDS, &rect);
+	if (ret)
+		return ret;
+	if (!rect) {
 		readableArea_ = pixelArrayArea_;
 		LOG(CameraSensor, Warning)
 			<< "The PixelArrayReadableArea property has been defaulted to "
 			<< readableArea_;
 		err = -EINVAL;
+	} else {
+		readableArea_ = *rect;
 	}
 
-	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_DEFAULT, &activeArea_);
-	if (ret) {
+	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP_DEFAULT, &rect);
+	if (ret)
+		return ret;
+	if (!rect) {
 		activeArea_ = readableArea_;
 		LOG(CameraSensor, Warning)
 			<< "The PixelArrayActiveAreas property has been defaulted to "
 			<< activeArea_;
 		err = -EINVAL;
+	} else {
+		activeArea_ = *rect;
 	}
 
-	Rectangle rect;
 	ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &rect);
-	if (ret) {
+	if (ret)
+		return ret;
+	if (!rect) {
 		LOG(CameraSensor, Warning)
 			<< "Failed to retrieve the sensor crop rectangle";
 		err = -EINVAL;
 	}
 
 	if (err) {
 		LOG(CameraSensor, Warning)
 			<< "The sensor kernel driver needs to be fixed";
 		LOG(CameraSensor, Warning)
 			<< "See Documentation/sensor_driver_requirements.rst in the libcamera sources for more information";
 	}
 
 	if (!bayerFormat_)
 		return 0;
 
 	/*
 	 * For raw sensors, make sure the sensor driver supports the controls
 	 * required by the CameraSensor class.
 	 */
 	static constexpr uint32_t mandatoryControls[] = {
 		V4L2_CID_ANALOGUE_GAIN,
 		V4L2_CID_EXPOSURE,
 		V4L2_CID_HBLANK,
 		V4L2_CID_PIXEL_RATE,
 		V4L2_CID_VBLANK,
 	};
 
 	err = 0;
 	for (uint32_t ctrl : mandatoryControls) {
 		if (!controls.count(ctrl)) {
@@ -871,65 +886,70 @@ int CameraSensorLegacy::applyConfiguration(const SensorConfiguration &config,
 	/* \todo Handle AnalogCrop. Most sensors do not support set_selection */
 	/* \todo Handle scaling in the digital domain. */
 
 	return 0;
 }
 
 V4L2Subdevice::Stream CameraSensorLegacy::imageStream() const
 {
 	return { pad_, 0 };
 }
 
 int CameraSensorLegacy::sensorInfo(IPACameraSensorInfo *info) const
 {
 	if (!bayerFormat_)
 		return -EINVAL;
 
 	info->model = model();
 	info->pixelArrayArea = pixelArrayArea_;
 
 	/*
 	 * The active area is a static property, while the crop rectangle needs
 	 * to be re-read as it depends on the sensor configuration.
 	 */
 	info->activeArea = activeArea_;
 
 	/*
 	 * \todo Support for retrieving the crop rectangle is scheduled to
 	 * become mandatory. For the time being use the default value if it has
 	 * been initialized at sensor driver validation time.
 	 */
-	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &info->analogCrop);
-	if (ret) {
+	std::optional<Rectangle> crop;
+	int ret = subdev_->getSelection(pad_, V4L2_SEL_TGT_CROP, &crop);
+	if (ret)
+		return ret;
+	if (!crop) {
 		info->analogCrop = activeArea_;
 		LOG(CameraSensor, Warning)
 			<< "The analogue crop rectangle has been defaulted to the active area size";
+	} else {
+		info->analogCrop = *crop;
 	}
 
 	/* The bit depth and image size depend on the currently applied format. */
 	V4L2SubdeviceFormat format{};
 	ret = subdev_->getFormat(pad_, &format);
 	if (ret)
 		return ret;
 	info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel;
 	info->outputSize = format.size;
 
 	std::optional<int32_t> cfa = properties_.get(properties::draft::ColorFilterArrangement);
 	info->cfaPattern = cfa ? *cfa : properties::draft::ColorFilterArrangementRGB;
 
 	/*
 	 * Retrieve the pixel rate, line length and minimum/maximum frame
 	 * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE,
 	 * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory.
 	 */
 	static constexpr uint32_t cids[] = {
 		V4L2_CID_PIXEL_RATE,
 		V4L2_CID_HBLANK,
 		V4L2_CID_VBLANK,
 	};
 
 	ControlList ctrls = subdev_->getControls(cids);
 	if (ctrls.empty()) {
 		LOG(CameraSensor, Error)
 			<< "Failed to retrieve camera info controls";
 		return -EINVAL;
 	}
diff --git a/src/libcamera/sensor/camera_sensor_raw.cpp b/src/libcamera/sensor/camera_sensor_raw.cpp
index 55b386ce..641801a1 100644
--- a/src/libcamera/sensor/camera_sensor_raw.cpp
+++ b/src/libcamera/sensor/camera_sensor_raw.cpp
@@ -397,92 +397,93 @@ std::optional<int> CameraSensorRaw::init()
 		/* Drop non-raw formats (in case we have a hybrid sensor). */
 		const MediaBusFormatInfo &info = MediaBusFormatInfo::info(code);
 		if (info.colourEncoding != PixelFormatInfo::ColourEncodingRAW)
 			continue;
 
 		mbusCodes_.push_back(code);
 		std::transform(ranges.begin(), ranges.end(), std::back_inserter(sizes_),
 			       [](const SizeRange &range) { return range.max; });
 	}
 
 	if (mbusCodes_.empty()) {
 		LOG(CameraSensor, Debug) << "No raw image formats found";
 		return { 0 };
 	}
 
 	std::sort(mbusCodes_.begin(), mbusCodes_.end());
 	std::sort(sizes_.begin(), sizes_.end());
 
 	/*
 	 * Remove duplicate sizes. There are no duplicate media bus codes as
 	 * they are the keys in the formats map.
 	 */
 	auto last = std::unique(sizes_.begin(), sizes_.end());
 	sizes_.erase(last, sizes_.end());
 
 	/*
 	 * 3. Query selection rectangles. Retrieve properties, and verify that
 	 * all the expected selection rectangles are supported.
 	 */
 
-	Rectangle rect;
+	std::optional<Rectangle> rect;
 	ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP_BOUNDS,
 				    &rect);
-	if (ret) {
+	if (ret || !rect) {
 		LOG(CameraSensor, Error) << "No pixel array crop bounds";
-		return { ret };
+		return { ret ? ret : -EINVAL };
 	}
 
 	/*
 	 * \todo Implement querying the physical sensor size based on pad 1,
 	 * stream 0. See
 	 * https://lore.kernel.org/linux-media/20260409201501.975242-23-sakari.ailus@linux.intel.com/
 	 */
 	LOG(CameraSensor, Warning) << "PixelArrayArea might be incorrect";
 	pixelArrayArea_ = Rectangle(0, 0,
-				    rect.x + rect.width,
-				    rect.y + rect.height);
+				    rect->x + rect->width,
+				    rect->y + rect->height);
 
-	readableArea_ = rect;
+	readableArea_ = *rect;
 
 	ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP_DEFAULT,
-				    &activeArea_);
-	if (ret) {
+				    &rect);
+	if (ret || !rect) {
 		LOG(CameraSensor, Error) << "No pixel array crop default";
-		return { ret };
+		return { ret ? ret : -EINVAL };
 	}
+	activeArea_ = *rect;
 
 	ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP,
 				    &rect);
-	if (ret) {
+	if (ret || !rect) {
 		LOG(CameraSensor, Error) << "No pixel array crop rectangle";
-		return { ret };
+		return { ret ? ret : -EINVAL };
 	}
 
 	/*
 	 * 4. Verify that all required controls are present.
 	 */
 
 	const ControlIdMap &controls = subdev_->controls().idmap();
 
 	static constexpr uint32_t mandatoryControls[] = {
 		V4L2_CID_ANALOGUE_GAIN,
 		V4L2_CID_CAMERA_ORIENTATION,
 		V4L2_CID_EXPOSURE,
 		V4L2_CID_HBLANK,
 		V4L2_CID_PIXEL_RATE,
 		V4L2_CID_VBLANK,
 	};
 
 	ret = 0;
 
 	for (uint32_t ctrl : mandatoryControls) {
 		if (!controls.count(ctrl)) {
 			LOG(CameraSensor, Error)
 				<< "Mandatory V4L2 control " << utils::hex(ctrl)
 				<< " not available";
 			ret = -EINVAL;
 		}
 	}
 
 	if (ret) {
 		LOG(CameraSensor, Error)
@@ -987,64 +988,70 @@ int CameraSensorRaw::setEmbeddedDataEnabled(bool enable)
 	 * source stream, as there would be something seriously wrong
 	 * otherwise.
 	 */
 	bool enabled = false;
 
 	for (const V4L2Subdevice::Route &route : routing) {
 		if (route.source != streams_.edata->source)
 			continue;
 
 		enabled = route.flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE;
 		break;
 	}
 
 	if (enabled != enable)
 		return enabled ? -EISCONN : -ENOSTR;
 
 	return 0;
 }
 
 int CameraSensorRaw::sensorInfo(IPACameraSensorInfo *info) const
 {
 	info->model = model();
 	info->pixelArrayArea = pixelArrayArea_;
 
 	/*
 	 * The active area is a static property, while the crop rectangle needs
 	 * to be re-read as it depends on the sensor configuration.
 	 */
 	info->activeArea = activeArea_;
 
+	std::optional<Rectangle> crop;
 	int ret = subdev_->getSelection(streams_.image.sink, V4L2_SEL_TGT_CROP,
-					&info->analogCrop);
+					&crop);
 	if (ret)
 		return ret;
+	if (!crop) {
+		LOG(CameraSensor, Error) << "No pixel array crop rectangle";
+		return -EINVAL;
+	}
+	info->analogCrop = *crop;
 
 	/* The bit depth and image size depend on the currently applied format. */
 	V4L2SubdeviceFormat format{};
 	ret = subdev_->getFormat(streams_.image.source, &format);
 	if (ret)
 		return ret;
 	info->bitsPerPixel = MediaBusFormatInfo::info(format.code).bitsPerPixel;
 	info->outputSize = format.size;
 
 	std::optional<int32_t> cfa = properties_.get(properties::draft::ColorFilterArrangement);
 	info->cfaPattern = cfa ? *cfa : properties::draft::ColorFilterArrangementRGB;
 
 	/*
 	 * Retrieve the pixel rate, line length and minimum/maximum frame
 	 * duration through V4L2 controls. Support for the V4L2_CID_PIXEL_RATE,
 	 * V4L2_CID_HBLANK and V4L2_CID_VBLANK controls is mandatory.
 	 */
 	static constexpr uint32_t cids[] = {
 		V4L2_CID_PIXEL_RATE,
 		V4L2_CID_HBLANK,
 		V4L2_CID_VBLANK,
 	};
 
 	ControlList ctrls = subdev_->getControls(cids);
 	if (ctrls.empty()) {
 		LOG(CameraSensor, Error)
 			<< "Failed to retrieve camera info controls";
 		return -EINVAL;
 	}
 
diff --git a/src/libcamera/v4l2_subdevice.cpp b/src/libcamera/v4l2_subdevice.cpp
index a69de154..0ab9d9ff 100644
--- a/src/libcamera/v4l2_subdevice.cpp
+++ b/src/libcamera/v4l2_subdevice.cpp
@@ -1082,163 +1082,181 @@ std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Route &route)
 /**
  * \typedef V4L2Subdevice::Routing
  * \brief V4L2 subdevice routing table
  *
  * This class stores a subdevice routing table as a vector of routes.
  */
 
 /**
  * \brief Insert a text representation of a V4L2Subdevice::Routing into an
  * output stream
  * \param[in] out The output stream
  * \param[in] routing The V4L2Subdevice::Routing
  * \return The output stream \a out
  */
 std::ostream &operator<<(std::ostream &out, const V4L2Subdevice::Routing &routing)
 {
 	for (const auto &[i, route] : utils::enumerate(routing)) {
 		out << "[" << i << "] " << route;
 		if (i != routing.size() - 1)
 			out << ", ";
 	}
 
 	return out;
 }
 
 /**
  * \brief Create a V4L2 subdevice from a MediaEntity using its device node
  * path
  */
 V4L2Subdevice::V4L2Subdevice(const MediaEntity *entity)
-	: V4L2Device(entity->deviceNode()), entity_(entity)
+	: V4L2Device(entity->deviceNode()), entity_(entity), caps_{}
 {
 }
 
 V4L2Subdevice::~V4L2Subdevice()
 {
 	close();
 }
 
 /**
  * \brief Open a V4L2 subdevice
  * \return 0 on success or a negative error code otherwise
  */
 int V4L2Subdevice::open()
 {
 	int ret = V4L2Device::open(O_RDWR);
 	if (ret)
 		return ret;
 
 	/*
 	 * Try to query the subdev capabilities. The VIDIOC_SUBDEV_QUERYCAP API
 	 * was introduced in kernel v5.8, ENOTTY errors must be ignored to
 	 * support older kernels.
 	 */
 	caps_ = {};
 	ret = ioctl(VIDIOC_SUBDEV_QUERYCAP, &caps_);
 	if (ret < 0 && errno != ENOTTY) {
 		ret = -errno;
 		LOG(V4L2, Error)
 			<< "Unable to query capabilities: " << strerror(-ret);
 		return ret;
 	}
 
 	/* If the subdev supports streams, enable the streams API. */
 	if (caps_.hasStreams()) {
 		struct v4l2_subdev_client_capability clientCaps{};
 		clientCaps.capabilities = V4L2_SUBDEV_CLIENT_CAP_STREAMS;
 
 		ret = ioctl(VIDIOC_SUBDEV_S_CLIENT_CAP, &clientCaps);
 		if (ret < 0) {
 			ret = -errno;
 			LOG(V4L2, Error)
 				<< "Unable to set client capabilities: "
 				<< strerror(-ret);
 			return ret;
 		}
 	}
 
 	return 0;
 }
 
 /**
  * \fn V4L2Subdevice::entity()
  * \brief Retrieve the media entity associated with the subdevice
  * \return The subdevice's associated media entity.
  */
 
 /**
  * \brief Get selection rectangle \a rect for \a target
  * \param[in] stream The stream the rectangle is retrieved from
  * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags
- * \param[out] rect The retrieved selection rectangle
+ * \param[out] rect The retrieved selection rectangle, if available
+ *
+ * If the ioctl returns EINVAL or ENOTTY, no rectangle is reported and \a rect
+ * is empty. EINVAL can indicate an unsupported target or unavailable stream
+ * state; an empty result does not distinguish these cases.
+ *
+ * Invalid pad indices and nonzero streams on devices without streams support
+ * are rejected with -EINVAL before issuing the ioctl. All other ioctl errors
+ * are returned unchanged. The output \a rect is cleared on entry.
  *
  * \todo Define a V4L2SelectionTarget enum for the selection target
  *
- * \return 0 on success or a negative error code otherwise
+ * \return 0 if the rectangle was retrieved or is unavailable, or a negative
+ * error code otherwise
  */
 int V4L2Subdevice::getSelection(const Stream &stream, unsigned int target,
-				Rectangle *rect)
+				std::optional<Rectangle> *rect)
 {
+	rect->reset();
+
+	if (stream.pad >= entity_->pads().size() ||
+	    (stream.stream && !caps_.hasStreams())) {
+		LOG(V4L2, Error) << "Invalid selection stream " << stream;
+		return -EINVAL;
+	}
+
 	struct v4l2_subdev_selection sel = {};
 
 	sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	sel.pad = stream.pad;
 	sel.stream = stream.stream;
 	sel.target = target;
 	sel.flags = 0;
 
 	int ret = ioctl(VIDIOC_SUBDEV_G_SELECTION, &sel);
 	if (ret < 0) {
+		if (ret == -EINVAL || ret == -ENOTTY)
+			return 0;
+
 		LOG(V4L2, Error)
 			<< "Unable to get rectangle " << target << " on pad "
 			<< stream << ": " << strerror(-ret);
 		return ret;
 	}
 
-	rect->x = sel.r.left;
-	rect->y = sel.r.top;
-	rect->width = sel.r.width;
-	rect->height = sel.r.height;
+	*rect = Rectangle(sel.r.left, sel.r.top, sel.r.width, sel.r.height);
 
 	return 0;
 }
 
 /**
  * \fn V4L2Subdevice::getSelection(unsigned int pad, unsigned int target,
- * Rectangle *rect)
+ * std::optional<Rectangle> *rect)
  * \brief Get selection rectangle \a rect for \a target
  * \param[in] pad The 0-indexed pad number the rectangle is retrieved from
  * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags
- * \param[out] rect The retrieved selection rectangle
+ * \param[out] rect The retrieved selection rectangle, if available
  *
- * \return 0 on success or a negative error code otherwise
+ * \return 0 if the rectangle was retrieved or is unavailable, or a negative
+ * error code otherwise
  */
 
 /**
  * \brief Set selection rectangle \a rect for \a target
  * \param[in] stream The stream the rectangle is to be applied to
  * \param[in] target The selection target defined by the V4L2_SEL_TGT_* flags
  * \param[inout] rect The selection rectangle to be applied
  *
  * \todo Define a V4L2SelectionTarget enum for the selection target
  *
  * \return 0 on success or a negative error code otherwise
  */
 int V4L2Subdevice::setSelection(const Stream &stream, unsigned int target,
 				Rectangle *rect)
 {
 	struct v4l2_subdev_selection sel = {};
 
 	sel.which = V4L2_SUBDEV_FORMAT_ACTIVE;
 	sel.pad = stream.pad;
 	sel.stream = stream.stream;
 	sel.target = target;
 	sel.flags = 0;
 
 	sel.r.left = rect->x;
 	sel.r.top = rect->y;
 	sel.r.width = rect->width;
 	sel.r.height = rect->height;
 
 	int ret = ioctl(VIDIOC_SUBDEV_S_SELECTION, &sel);
 	if (ret < 0) {
