]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
comedi: add comedi_check_request_region()
authorIan Abbott <abbotti@mev.co.uk>
Fri, 30 Jan 2026 16:47:26 +0000 (16:47 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Apr 2026 13:49:36 +0000 (15:49 +0200)
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@mev.co.uk>
Link: https://patch.msgid.link/20260130170416.49994-2-abbotti@mev.co.uk
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/comedi/drivers.c
include/linux/comedi/comedidev.h

index db225a3bf0128c29ed113e29dfd0ca6cfc81b41a..5b02107bb6bfe651105d4320052bedbb53dd6311 100644 (file)
@@ -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
index 35fdc41845ceee5b8c8a8eace0fc5fae056a373e..577a08f37aeebab3967260ec4d3a0a71fec5c237 100644 (file)
@@ -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,