[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260130170416.49994-2-abbotti@mev.co.uk>
Date: Fri, 30 Jan 2026 16:47:26 +0000
From: Ian Abbott <abbotti@....co.uk>
To: linux-kernel@...r.kernel.org
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
Ian Abbott <abbotti@....co.uk>,
H Hartley Sweeten <hsweeten@...ionengravers.com>
Subject: [PATCH 01/46] comedi: add comedi_check_request_region()
There is an existing comedi_request_region(dev, start, len) function
used by COMEDI drivers for legacy devices to request an I/O port region
starting at a specified base address (which must be non-zero) and with a
specified length. It uses request_region(). On success, it sets
dev->iobase and dev->iolen and returns 0. There is a alternative
function __comedi_request_region(dev, start, len) which does the same
thing without setting dev->iobase and dev->iolen.
Most hardware devices have restrictions on the allowed I/O port base
address and alignment, so add new functions
comedi_check_request_region(dev, start, len, minstart, maxend, minalign)
and __comedi_check_request_region(dev, start, len, minstart, maxend,
minalign) to perform these additional checks. Turn the original
functions into static inline wrapper functions that call the new
functions.
Signed-off-by: Ian Abbott <abbotti@....co.uk>
---
drivers/comedi/drivers.c | 46 ++++++++++++++++++++-------
include/linux/comedi/comedidev.h | 53 +++++++++++++++++++++++++++++---
2 files changed, 84 insertions(+), 15 deletions(-)
diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c
index 69cd2a253c66..316cb510b89b 100644
--- a/drivers/comedi/drivers.c
+++ b/drivers/comedi/drivers.c
@@ -933,19 +933,24 @@ int comedi_load_firmware(struct comedi_device *dev,
EXPORT_SYMBOL_GPL(comedi_load_firmware);
/**
- * __comedi_request_region() - Request an I/O region for a legacy driver
+ * __comedi_check_request_region() - Request an I/O region for a legacy driver
* @dev: COMEDI device.
* @start: Base address of the I/O region.
* @len: Length of the I/O region.
+ * @minstart: Minimum allowed start address of region.
+ * @maxend: Maximum allowed region end address of region.
+ * @minalign: Required alignment for base address.
*
* Requests the specified I/O port region which must start at a non-zero
- * address.
+ * address, must fall within specified bounds, and must be correctly aligned.
*
* Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request
* fails.
*/
-int __comedi_request_region(struct comedi_device *dev,
- unsigned long start, unsigned long len)
+int __comedi_check_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len,
+ unsigned long minstart, unsigned long maxend,
+ unsigned long minalign)
{
if (!start) {
dev_warn(dev->class_dev,
@@ -954,6 +959,19 @@ int __comedi_request_region(struct comedi_device *dev,
return -EINVAL;
}
+ if (start < minstart || start > maxend || maxend - start < len - 1) {
+ dev_warn(dev->class_dev,
+ "%s: I/O base address or length out of range\n",
+ dev->board_name);
+ return -EINVAL;
+ }
+ if (!IS_ALIGNED(start, minalign)) {
+ dev_warn(dev->class_dev,
+ "%s: I/O base address not correctly aligned\n",
+ dev->board_name);
+ return -EINVAL;
+ }
+
if (!request_region(start, len, dev->board_name)) {
dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n",
dev->board_name, start, len);
@@ -962,16 +980,19 @@ int __comedi_request_region(struct comedi_device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(__comedi_request_region);
+EXPORT_SYMBOL_GPL(__comedi_check_request_region);
/**
- * comedi_request_region() - Request an I/O region for a legacy driver
+ * comedi_check_request_region() - Request an I/O region for a legacy driver
* @dev: COMEDI device.
* @start: Base address of the I/O region.
* @len: Length of the I/O region.
+ * @minstart: Minimum allowed start address of region.
+ * @maxend: Maximum allowed region end address of region.
+ * @minalign: Required alignment for base address.
*
* Requests the specified I/O port region which must start at a non-zero
- * address.
+ * address, must fall within specified bounds, and must be correctly aligned.
*
* On success, @dev->iobase is set to the base address of the region and
* @dev->iolen is set to its length.
@@ -979,12 +1000,15 @@ EXPORT_SYMBOL_GPL(__comedi_request_region);
* Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request
* fails.
*/
-int comedi_request_region(struct comedi_device *dev,
- unsigned long start, unsigned long len)
+int comedi_check_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len,
+ unsigned long minstart, unsigned long maxend,
+ unsigned long minalign)
{
int ret;
- ret = __comedi_request_region(dev, start, len);
+ ret = __comedi_check_request_region(dev, start, len, minstart, maxend,
+ minalign);
if (ret == 0) {
dev->iobase = start;
dev->iolen = len;
@@ -992,7 +1016,7 @@ int comedi_request_region(struct comedi_device *dev,
return ret;
}
-EXPORT_SYMBOL_GPL(comedi_request_region);
+EXPORT_SYMBOL_GPL(comedi_check_request_region);
/**
* comedi_legacy_detach() - A generic (*detach) function for legacy drivers
diff --git a/include/linux/comedi/comedidev.h b/include/linux/comedi/comedidev.h
index 35fdc41845ce..577a08f37aee 100644
--- a/include/linux/comedi/comedidev.h
+++ b/include/linux/comedi/comedidev.h
@@ -1026,10 +1026,55 @@ int comedi_load_firmware(struct comedi_device *dev, struct device *hw_dev,
unsigned long context),
unsigned long context);
-int __comedi_request_region(struct comedi_device *dev,
- unsigned long start, unsigned long len);
-int comedi_request_region(struct comedi_device *dev,
- unsigned long start, unsigned long len);
+int __comedi_check_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len,
+ unsigned long minstart, unsigned long maxend,
+ unsigned long minalign);
+int comedi_check_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len,
+ unsigned long minstart, unsigned long maxend,
+ unsigned long minalign);
+
+/**
+ * __comedi_request_region() - Request an I/O region for a legacy driver
+ * @dev: COMEDI device.
+ * @start: Base address of the I/O region.
+ * @len: Length of the I/O region.
+ *
+ * Requests the specified I/O port region which must start at a non-zero
+ * address.
+ *
+ * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request
+ * fails.
+ */
+static inline int __comedi_request_region(struct comedi_device *dev,
+ unsigned long start,
+ unsigned long len)
+{
+ return __comedi_check_request_region(dev, start, len, 0, ~0ul, 1);
+}
+
+/**
+ * comedi_request_region() - Request an I/O region for a legacy driver
+ * @dev: COMEDI device.
+ * @start: Base address of the I/O region.
+ * @len: Length of the I/O region.
+ *
+ * Requests the specified I/O port region which must start at a non-zero
+ * address.
+ *
+ * On success, @dev->iobase is set to the base address of the region and
+ * @dev->iolen is set to its length.
+ *
+ * Returns 0 on success, -EINVAL if @start is 0, or -EIO if the request
+ * fails.
+ */
+static inline int comedi_request_region(struct comedi_device *dev,
+ unsigned long start, unsigned long len)
+{
+ return comedi_check_request_region(dev, start, len, 0, ~0ul, 1);
+}
+
void comedi_legacy_detach(struct comedi_device *dev);
int comedi_auto_config(struct device *hardware_device,
--
2.51.0
Powered by blists - more mailing lists