Skip to contentSkip to conversation

Implement get_multiple for ACCES and PC/104 drivers

PATCH Superseded William Breathitt Gray 3 participants 16 messages Mar 17, 2018 – Mar 21, 2018

Subsystems (9)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

v3 cover Implement get_multiple for ACCES and PC/104 drivers

Changes in v2:
- Add missing bitmap.h header includes
- Fix typographical error in symbol name for word_mask
- Remove const qualifier for ports array

This patchset implements get_multiple callbacks for the PC104 GPIO drivers as well as the PCI-IDIO-16 and PCIe-IDIO-24 GPIO drivers. These devices all acquire the multiple input lines with a single read, so utilizing the get_multiple callback can provide improvement for those users who regularly access multiple input lines.

While developing this patchset I noticed many of these devices make use of Intel 8255 compatible interfaces for their I/O. I may write a generic 8255 GPIO driver in the future to reduce some of the redundant code I see pop among the drivers for these devices.

William Breathitt Gray (8):
iio: stx104: Implement get_multiple callback
gpio: 104-idio-16: Implement get_multiple callback
gpio: pci-idio-16: Implement get_multiple callback
gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks
gpio: 104-dio-48e: Implement get_multiple callback
gpio: 104-idi-48: Implement get_multiple callback
gpio: gpio-mm: Implement get_multiple callback
gpio: ws16c48: Implement get_multiple callback

 drivers/gpio/gpio-104-dio-48e.c  |  47 ++++++++++++++++
 drivers/gpio/gpio-104-idi-48.c   |  47 ++++++++++++++++
 drivers/gpio/gpio-104-idio-16.c  |  15 +++++
 drivers/gpio/gpio-gpio-mm.c      |  47 ++++++++++++++++
 drivers/gpio/gpio-pci-idio-16.c  |  50 +++++++++++++++++
 drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++
 drivers/gpio/gpio-ws16c48.c      |  47 ++++++++++++++++
 drivers/iio/adc/stx104.c         |  11 ++++
 8 files changed, 381 insertions(+)
Signature · 1 line
2.16.2
#1 lore raw

PATCH v3 1/8 iio: stx104: Implement get_multiple callback

The Apex Embedded Systems STX104 series of devices provides 4 TTL compatible lines of inputs accessed via a single 4-bit port. Since four input lines are acquired on a single port input read, the STX104 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the stx104_gpio_get_multiple function which serves as the respective get_multiple callback.

Cc Jonathan Cameron <[email protected]>
Cc Hartmut Knaack <[email protected]>
Cc Lars-Peter Clausen <[email protected]>
Cc Peter Meerwald-Stadler <[email protected]>
---
 drivers/iio/adc/stx104.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/iio/adc/stx104.c +11 -0
index 17b021f33180..0662ca199eb0 100644
@@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(inb(stx104gpio->base) & BIT(offset));
 }
 
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	*bits = inb(stx104gpio->base);
+
+	return 0;
+}
+
 static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
 	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
 	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
 	stx104gpio->chip.get = stx104_gpio_get;
+	stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
 	stx104gpio->chip.set = stx104_gpio_set;
 	stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
 	stx104gpio->base = base[id] + 3;
Signature · 1 line
2.16.2
#5 lore raw

PATCH v3 2/8 gpio: 104-idio-16: Implement get_multiple callback

In reply to William Breathitt Gray

The ACCES I/O 104-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-104-idio-16.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
drivers/gpio/gpio-104-idio-16.c +15 -0
index 2f16638a0589..5de5819e5156 100644
@@ -90,6 +90,20 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(inb(idio16gpio->base + 5) & (mask>>8));
 }
 
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+
+	*bits = 0;
+	if (*mask & 0xFF0000)
+		*bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;
+	if (*mask & 0xFF000000)
+		*bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;
+
+	return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
@@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 	idio16gpio->chip.get = idio_16_gpio_get;
+	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
 	idio16gpio->chip.set = idio_16_gpio_set;
 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
 	idio16gpio->base = base[id];
Signature · 1 line
2.16.2
#8 lore raw

PATCH v3 3/8 gpio: pci-idio-16: Implement get_multiple callback

In reply to William Breathitt Gray

The ACCES I/O PCI-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-pci-idio-16.c | 50 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)
drivers/gpio/gpio-pci-idio-16.c +50 -0
index 57d1b7fbf07b..f273cf776cac 100644
@@ -11,6 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -103,6 +104,54 @@ static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(ioread8(&idio16gpio->reg->in8_15) & (mask >> 24));
 }
 
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+	size_t i;
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+	u8 __iomem ports[] = {
+		idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
+		idio16gpio->reg->in0_7, idio16gpio->reg->in8_15
+	};
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = ioread8(ports + i);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -299,6 +348,7 @@ static int idio_16_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
 	idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
 	idio16gpio->chip.get = idio_16_gpio_get;
+	idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
 	idio16gpio->chip.set = idio_16_gpio_set;
 	idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
 
Signature · 1 line
2.16.2
#11 lore raw

PATCH v3 4/8 gpio: pcie-idio-24: Implement get_multiple/set_multiple callbacks

In reply to William Breathitt Gray

The ACCES I/O PCIe-IDIO-24 series of devices provides 24 optically-isolated digital I/O accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read -- and similarly eight output lines are set on a single port output write -- the PCIe-IDIO-24 GPIO driver may improve multiple I/O reads/writes by utilizing a get_multiple/set_multiple callbacks. This patch implements the idio_24_gpio_get_multiple function which serves as the respective get_multiple callback, and implements the idio_24_gpio_set_multiple function which serves as the respective set_multiple callback.

---
 drivers/gpio/gpio-pcie-idio-24.c | 117 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 117 insertions(+)
drivers/gpio/gpio-pcie-idio-24.c +117 -0
index f666e2e69074..412aca253c76 100644
@@ -15,6 +15,7 @@
  * This driver supports the following ACCES devices: PCIe-IDIO-24,
  * PCIe-IDI-24, PCIe-IDO-24, and PCIe-IDIO-12.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -193,6 +194,61 @@ static int idio_24_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(ioread8(&idio24gpio->reg->ttl_in0_7) & offset_mask);
 }
 
+static int idio_24_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
+	size_t i;
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+	u8 __iomem ports[] = {
+		idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
+		idio24gpio->reg->out16_23, idio24gpio->reg->in0_7,
+		idio24gpio->reg->in8_15, idio24gpio->reg->in16_23
+	};
+	const unsigned long out_mode_mask = BIT(1);
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port (port 6 is TTL GPIO) */
+		if (i < 6)
+			port_state = ioread8(ports + i);
+		else if (ioread8(&idio24gpio->reg->ctl) & out_mode_mask)
+			port_state = ioread8(&idio24gpio->reg->ttl_out0_7);
+		else
+			port_state = ioread8(&idio24gpio->reg->ttl_in0_7);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -234,6 +290,65 @@ static void idio_24_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
 }
 
+static void idio_24_gpio_set_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct idio_24_gpio *const idio24gpio = gpiochip_get_data(chip);
+	size_t i;
+	unsigned long bits_offset;
+	unsigned long gpio_mask;
+	const unsigned int gpio_reg_size = 8;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long flags;
+	unsigned int out_state;
+	u8 __iomem ports[] = {
+		idio24gpio->reg->out0_7, idio24gpio->reg->out8_15,
+		idio24gpio->reg->out16_23
+	};
+	const unsigned long out_mode_mask = BIT(1);
+	const unsigned int ttl_offset = 48;
+	const size_t ttl_i = BIT_WORD(ttl_offset);
+	const unsigned int word_offset = ttl_offset % BITS_PER_LONG;
+	const unsigned long ttl_mask = (mask[ttl_i] >> word_offset) & port_mask;
+	const unsigned long ttl_bits = (bits[ttl_i] >> word_offset) & ttl_mask;
+
+	/* set bits are processed a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* check if any set bits for current port */
+		gpio_mask = (*mask >> bits_offset) & port_mask;
+		if (!gpio_mask) {
+			/* no set bits for this port so move on to next port */
+			continue;
+		}
+
+		raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+
+		/* process output lines */
+		out_state = ioread8(ports + i) & ~gpio_mask;
+		out_state |= (*bits >> bits_offset) & gpio_mask;
+		iowrite8(out_state, ports + i);
+
+		raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+	}
+
+	/* check if setting TTL lines and if they are in output mode */
+	if (!ttl_mask || !(ioread8(&idio24gpio->reg->ctl) & out_mode_mask))
+		return;
+
+	/* handle TTL output */
+	raw_spin_lock_irqsave(&idio24gpio->lock, flags);
+
+	/* process output lines */
+	out_state = ioread8(&idio24gpio->reg->ttl_out0_7) & ~ttl_mask;
+	out_state |= ttl_bits;
+	iowrite8(out_state, &idio24gpio->reg->ttl_out0_7);
+
+	raw_spin_unlock_irqrestore(&idio24gpio->lock, flags);
+}
+
 static void idio_24_irq_ack(struct irq_data *data)
 {
 }
@@ -397,7 +512,9 @@ static int idio_24_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	idio24gpio->chip.direction_input = idio_24_gpio_direction_input;
 	idio24gpio->chip.direction_output = idio_24_gpio_direction_output;
 	idio24gpio->chip.get = idio_24_gpio_get;
+	idio24gpio->chip.get_multiple = idio_24_gpio_get_multiple;
 	idio24gpio->chip.set = idio_24_gpio_set;
+	idio24gpio->chip.set_multiple = idio_24_gpio_set_multiple;
 
 	raw_spin_lock_init(&idio24gpio->lock);
 
Signature · 1 line
2.16.2
#12 lore raw

PATCH v3 5/8 gpio: 104-dio-48e: Implement get_multiple callback

In reply to William Breathitt Gray

The ACCES I/O 104-DIO-48E series of devices contain two Programmable Peripheral Interface (PPI) chips of type 82C55, which each feature three 8-bit ports of I/O. Since eight input lines are acquired on a single port input read, the 104-DIO-48E GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the dio48e_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-104-dio-48e.c | 47 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
drivers/gpio/gpio-104-dio-48e.c +47 -0
index bab3b94c5cbc..7d43c77364db 100644
@@ -14,6 +14,7 @@
  * This driver supports the following ACCES devices: 104-DIO-48E and
  * 104-DIO-24E.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -182,6 +183,51 @@ static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(port_state & mask);
 }
 
+static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(dio48egpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
@@ -384,6 +430,7 @@ static int dio48e_probe(struct device *dev, unsigned int id)
 	dio48egpio->chip.direction_input = dio48e_gpio_direction_input;
 	dio48egpio->chip.direction_output = dio48e_gpio_direction_output;
 	dio48egpio->chip.get = dio48e_gpio_get;
+	dio48egpio->chip.get_multiple = dio48e_gpio_get_multiple;
 	dio48egpio->chip.set = dio48e_gpio_set;
 	dio48egpio->chip.set_multiple = dio48e_gpio_set_multiple;
 	dio48egpio->base = base[id];
Signature · 1 line
2.16.2
#13 lore raw

PATCH v3 6/8 gpio: 104-idi-48: Implement get_multiple callback

In reply to William Breathitt Gray

The ACCES I/O 104-IDI-48 series of devices provides 48 optically-isolated inputs accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDI-48 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idi_48_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-104-idi-48.c | 47 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
drivers/gpio/gpio-104-idi-48.c +47 -0
index add859d59766..2c230415eeba 100644
@@ -14,6 +14,7 @@
  * This driver supports the following ACCES devices: 104-IDI-48A,
  * 104-IDI-48AC, 104-IDI-48B, and 104-IDI-48BC.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -88,6 +89,51 @@ static int idi_48_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return 0;
 }
 
+static int idi_48_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct idi_48_gpio *const idi48gpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(idi48gpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void idi_48_irq_ack(struct irq_data *data)
 {
 }
@@ -256,6 +302,7 @@ static int idi_48_probe(struct device *dev, unsigned int id)
 	idi48gpio->chip.get_direction = idi_48_gpio_get_direction;
 	idi48gpio->chip.direction_input = idi_48_gpio_direction_input;
 	idi48gpio->chip.get = idi_48_gpio_get;
+	idi48gpio->chip.get_multiple = idi_48_gpio_get_multiple;
 	idi48gpio->base = base[id];
 
 	raw_spin_lock_init(&idi48gpio->lock);
Signature · 1 line
2.16.2
#14 lore raw

PATCH v3 7/8 gpio: gpio-mm: Implement get_multiple callback

In reply to William Breathitt Gray

The Diamond Systems GPIO-MM series of devices contain two 82C55A devices, which each feature three 8-bit ports of I/O. Since eight input lines are acquired on a single port input read, the GPIO-MM GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the gpiomm_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-gpio-mm.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
drivers/gpio/gpio-gpio-mm.c +47 -0
index 11ade5b288f8..94b86fca65ba 100644
@@ -14,6 +14,7 @@
  * This driver supports the following Diamond Systems devices: GPIO-MM and
  * GPIO-MM-12.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -171,6 +172,51 @@ static int gpiomm_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(port_state & mask);
 }
 
+static int gpiomm_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct gpiomm_gpio *const gpiommgpio = gpiochip_get_data(chip);
+	size_t i;
+	const size_t ports[] = { 0, 1, 2, 4, 5, 6 };
+	const unsigned int gpio_reg_size = 8;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < ARRAY_SIZE(ports); i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(gpiommgpio->base + ports[i]);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void gpiomm_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -268,6 +314,7 @@ static int gpiomm_probe(struct device *dev, unsigned int id)
 	gpiommgpio->chip.direction_input = gpiomm_gpio_direction_input;
 	gpiommgpio->chip.direction_output = gpiomm_gpio_direction_output;
 	gpiommgpio->chip.get = gpiomm_gpio_get;
+	gpiommgpio->chip.get_multiple = gpiomm_gpio_get_multiple;
 	gpiommgpio->chip.set = gpiomm_gpio_set;
 	gpiommgpio->chip.set_multiple = gpiomm_gpio_set_multiple;
 	gpiommgpio->base = base[id];
Signature · 1 line
2.16.2
#15 lore raw

PATCH v3 8/8 gpio: ws16c48: Implement get_multiple callback

In reply to William Breathitt Gray

The WinSystems WS16C48 device provides 48 lines of digital I/O accessed via six 8-bit ports. Since eight input lines are acquired on a single port input read, the WS16C48 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the ws16c48_gpio_get_multiple function which serves as the respective get_multiple callback.

---
 drivers/gpio/gpio-ws16c48.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
drivers/gpio/gpio-ws16c48.c +47 -0
index 746648244bf3..10525367aa6f 100644
@@ -11,6 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  */
+#include <linux/bitmap.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -129,6 +130,51 @@ static int ws16c48_gpio_get(struct gpio_chip *chip, unsigned offset)
 	return !!(port_state & mask);
 }
 
+static int ws16c48_gpio_get_multiple(struct gpio_chip *chip,
+	unsigned long *mask, unsigned long *bits)
+{
+	struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
+	const unsigned int gpio_reg_size = 8;
+	size_t i;
+	const size_t num_ports = chip->ngpio / gpio_reg_size;
+	unsigned int bits_offset;
+	size_t word_index;
+	unsigned int word_offset;
+	unsigned long word_mask;
+	const unsigned long port_mask = GENMASK(gpio_reg_size, 0);
+	unsigned long port_state;
+
+	/* clear bits array to a clean slate */
+	bitmap_zero(bits, chip->ngpio);
+
+	/* get bits are evaluated a gpio port register at a time */
+	for (i = 0; i < num_ports; i++) {
+		/* gpio offset in bits array */
+		bits_offset = i * gpio_reg_size;
+
+		/* word index for bits array */
+		word_index = BIT_WORD(bits_offset);
+
+		/* gpio offset within current word of bits array */
+		word_offset = bits_offset % BITS_PER_LONG;
+
+		/* mask of get bits for current gpio within current word */
+		word_mask = mask[word_index] & (port_mask << word_offset);
+		if (!word_mask) {
+			/* no get bits in this port so skip to next one */
+			continue;
+		}
+
+		/* read bits from current gpio port */
+		port_state = inb(ws16c48gpio->base + i);
+
+		/* store acquired bits at respective bits array offset */
+		bits[word_index] |= port_state << word_offset;
+	}
+
+	return 0;
+}
+
 static void ws16c48_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct ws16c48_gpio *const ws16c48gpio = gpiochip_get_data(chip);
@@ -383,6 +429,7 @@ static int ws16c48_probe(struct device *dev, unsigned int id)
 	ws16c48gpio->chip.direction_input = ws16c48_gpio_direction_input;
 	ws16c48gpio->chip.direction_output = ws16c48_gpio_direction_output;
 	ws16c48gpio->chip.get = ws16c48_gpio_get;
+	ws16c48gpio->chip.get_multiple = ws16c48_gpio_get_multiple;
 	ws16c48gpio->chip.set = ws16c48_gpio_set;
 	ws16c48gpio->chip.set_multiple = ws16c48_gpio_set_multiple;
 	ws16c48gpio->base = base[id];
Signature · 1 line
2.16.2
maintainer
#2 lore raw

Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback

In reply to William Breathitt Gray
Quoted 7 lines · On Sat, 17 Mar 2018 11:49:56 -0400 William Breathitt Gray…

The Apex Embedded Systems STX104 series of devices provides 4 TTL compatible lines of inputs accessed via a single 4-bit port. Since four input lines are acquired on a single port input read, the STX104 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the stx104_gpio_get_multiple function which serves as the respective get_multiple callback.

Quoted 5 lines
Cc Jonathan Cameron <[email protected]>
Cc Hartmut Knaack <[email protected]>
Cc Lars-Peter Clausen <[email protected]>
Cc Peter Meerwald-Stadler <[email protected]>

This one is simple so applied to the togreg branch of iio.git and pushed out as testing for the autobuilders to play with it.

Thanks,

Jonathan

Quoted 33 lines
---
 drivers/iio/adc/stx104.c | 11 +++++++++++
 1 file changed, 11 insertions(+)
drivers/iio/adc/stx104.c +11 -0
index 17b021f33180..0662ca199eb0 100644
@@ -233,6 +233,16 @@ static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset)
 	return !!(inb(stx104gpio->base) & BIT(offset));
 }
 
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+	unsigned long *bits)
+{
+	struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
+	*bits = inb(stx104gpio->base);
+
+	return 0;
+}
+
 static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset,
 	int value)
 {
@@ -342,6 +352,7 @@ static int stx104_probe(struct device *dev, unsigned int id)
 	stx104gpio->chip.direction_input = stx104_gpio_direction_input;
 	stx104gpio->chip.direction_output = stx104_gpio_direction_output;
 	stx104gpio->chip.get = stx104_gpio_get;
+	stx104gpio->chip.get_multiple = stx104_gpio_get_multiple;
 	stx104gpio->chip.set = stx104_gpio_set;
 	stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
 	stx104gpio->base = base[id] + 3;
#3 lore raw

Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback

In reply to William Breathitt Gray
Quoted 7 lines · William Breathitt Gray

The Apex Embedded Systems STX104 series of devices provides 4 TTL compatible lines of inputs accessed via a single 4-bit port. Since four input lines are acquired on a single port input read, the STX104 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the stx104_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/iio/adc/stx104.c static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 241

Quoted 7 lines
drivers/iio/adc/stx104.c +6 -0
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+       unsigned long *bits)
+{
+       struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
 
+       *bits = inb(stx104gpio->base);

I think on LE and BE if will give you different results.

Quoted 3 lines
drivers/iio/adc/stx104.c +3 -0
+
+       return 0;
+}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#4 lore raw

Re: [PATCH v3 1/8] iio: stx104: Implement get_multiple callback

Quoted 15 lines · Andy Shevchenko
Quoted 12 lines · William Breathitt Gray

The Apex Embedded Systems STX104 series of devices provides 4 TTL compatible lines of inputs accessed via a single 4-bit port. Since four input lines are acquired on a single port input read, the STX104 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the stx104_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/iio/adc/stx104.c +5 -0
+static int stx104_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
+       unsigned long *bits)
+{
+       struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+
Quoted 3 lines
Quoted 1 line

+ *bits = inb(stx104gpio->base);

I think on LE and BE if will give you different results.

That may be true for a memcpy operation, but in this case I'm relying on the standard C evaluation rules. I expect we should be fine with the returned byte assigned to an unsigned long, since it'll be evaluated by its value rather than memory representation.

William Breathitt Gray

Quoted 10 lines
Quoted 4 lines
drivers/iio/adc/stx104.c +3 -0
+
+       return 0;
+}
Signature · 2 lines
With Best Regards,
Andy Shevchenko
#6 lore raw

Re: [PATCH v3 2/8] gpio: 104-idio-16: Implement get_multiple callback

In reply to William Breathitt Gray
Quoted 8 lines · William Breathitt Gray

The ACCES I/O 104-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/gpio/gpio-104-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) · line 99

Quoted 8 lines
drivers/gpio/gpio-104-idio-16.c +7 -0
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+       unsigned long *mask, unsigned long *bits)
+{
+       struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+
+       *bits = 0;
 
+       if (*mask & 0xFF0000)

GENMASK(23, 16) ?

Quoted 1 line

+ *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;

Do you need casting?

Quoted 1 line

+ if (*mask & 0xFF000000)

GENMASK(31, 24) ?

Alternative (and for above):

(*mask >> 24) & 0xff

(*mask >> 16) & 0xff

Quoted 1 line

+ *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;

Do you need casting?

Quoted 18 lines
drivers/gpio/gpio-104-idio-16.c +5 -1
+
+       return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
@@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
        idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
        idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
        idio16gpio->chip.get = idio_16_gpio_get;
+       idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
        idio16gpio->chip.set = idio_16_gpio_set;
        idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
        idio16gpio->base = base[id];
--

2.16.2

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#7 lore raw

Re: [PATCH v3 2/8] gpio: 104-idio-16: Implement get_multiple callback

Quoted 27 lines · Andy Shevchenko
Quoted 8 lines · William Breathitt Gray

The ACCES I/O 104-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the 104-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/gpio/gpio-104-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned offset) · line 99

Quoted 8 lines
drivers/gpio/gpio-104-idio-16.c +7 -0
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+       unsigned long *mask, unsigned long *bits)
+{
+       struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+
+       *bits = 0;
 
+       if (*mask & 0xFF0000)

GENMASK(23, 16) ?

Quoted 1 line

+ *bits |= (unsigned long)inb(idio16gpio->base + 1) << 16;

Do you need casting?

Quoted 1 line

+ if (*mask & 0xFF000000)

Quoted 7 lines

GENMASK(31, 24) ?

Alternative (and for above):

(*mask >> 24) & 0xff

(*mask >> 16) & 0xff

That's a good suggestion since GENMASK would be useful in making it clear which bits we are actually checking; the literal bitmasks such as 0xFF000000 can be difficult to read at a glance. I'll incorporate GENMASK into a version 4 release of this patch.

Quoted 5 lines
Quoted 3 lines

+ *bits |= (unsigned long)inb(idio16gpio->base + 5) << 24;

Do you need casting?

The inb function returns a u8, which is typically a typedef of an unsigned char. Since u8 only guaranteed a range of 8 bits, we require a cast to unsigned long to guarantee that the left shifted value stays intact as a 32-bit unsigned value rather than wrap around an 8-bit unsigned range.

William Breathitt Gray

Quoted 25 lines
Quoted 19 lines
drivers/gpio/gpio-104-idio-16.c +5 -1
+
+       return 0;
+}
+
 static void idio_16_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
        struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
@@ -244,6 +258,7 @@ static int idio_16_probe(struct device *dev, unsigned int id)
        idio16gpio->chip.direction_input = idio_16_gpio_direction_input;
        idio16gpio->chip.direction_output = idio_16_gpio_direction_output;
        idio16gpio->chip.get = idio_16_gpio_get;
+       idio16gpio->chip.get_multiple = idio_16_gpio_get_multiple;
        idio16gpio->chip.set = idio_16_gpio_set;
        idio16gpio->chip.set_multiple = idio_16_gpio_set_multiple;
        idio16gpio->base = base[id];
--

2.16.2

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#9 lore raw

Re: [PATCH v3 3/8] gpio: pci-idio-16: Implement get_multiple callback

In reply to William Breathitt Gray
Quoted 10 lines · William Breathitt Gray

The ACCES I/O PCI-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/gpio/gpio-pci-idio-16.c +2 -0
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+       unsigned long *mask, unsigned long *bits)

drivers/gpio/gpio-pci-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 117

Quoted 10 lines
drivers/gpio/gpio-pci-idio-16.c +9 -0
+{
+       struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+       size_t i;
+       const unsigned int gpio_reg_size = 8;
+       unsigned int bits_offset;
+       size_t word_index;
+       unsigned int word_offset;
+       unsigned long word_mask;
 
+       const unsigned long port_mask = GENMASK(gpio_reg_size, 0);

gpio_reg_size - 1?
Though I would prefer not to have that variable at all, just use 8 or 7 respectively.

drivers/gpio/gpio-pci-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 121

Quoted 6 lines
drivers/gpio/gpio-pci-idio-16.c +4 -0
+       unsigned long port_state;
 
+       u8 __iomem ports[] = {
+               idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
 
+               idio16gpio->reg->in0_7, idio16gpio->reg->in8_15

I would leave comma even here.

Quoted 16 lines
drivers/gpio/gpio-pci-idio-16.c +15 -0
+       };
 
+       /* get bits are evaluated a gpio port register at a time */
+       for (i = 0; i < ARRAY_SIZE(ports); i++) {
+               /* gpio offset in bits array */
+               bits_offset = i * gpio_reg_size;
+
+               /* word index for bits array */
+               word_index = BIT_WORD(bits_offset);
+
+               /* gpio offset within current word of bits array */
+               word_offset = bits_offset % BITS_PER_LONG;
+
+               /* mask of get bits for current gpio within current word */
+               word_mask = mask[word_index] & (port_mask << word_offset);
+               if (!word_mask) {

drivers/gpio/gpio-pci-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 150

Quoted 10 lines
drivers/gpio/gpio-pci-idio-16.c +10 -0
+                       /* no get bits in this port so skip to next one */
+                       continue;
+               }
+
+               /* read bits from current gpio port */
+               port_state = ioread8(ports + i);
+
+               /* store acquired bits at respective bits array offset */
+               bits[word_index] |= port_state << word_offset;
+       }

I would propose to do other way around, i.e.
read all ports to the bitmap array and call bitmap_and() after.

Further optimization can be something like introduction of generic

bitmap_copy_uXX_off(unsigned long *dst, u8 src, unsigned int offset);

It can be done using macros, though it's another story not quite related to the topic.

Quoted 1 line

+}

Signature · 2 lines
With Best Regards,
Andy Shevchenko
#10 lore raw

Re: [PATCH v3 3/8] gpio: pci-idio-16: Implement get_multiple callback

Quoted 21 lines · Andy Shevchenko
Quoted 18 lines · William Breathitt Gray

The ACCES I/O PCI-IDIO-16 series of devices provides 16 optically-isolated digital inputs accessed via two 8-bit ports. Since eight input lines are acquired on a single port input read, the PCI-IDIO-16 GPIO driver may improve multiple input reads by utilizing a get_multiple callback. This patch implements the idio_16_gpio_get_multiple function which serves as the respective get_multiple callback.

drivers/gpio/gpio-pci-idio-16.c +10 -0
+static int idio_16_gpio_get_multiple(struct gpio_chip *chip,
+       unsigned long *mask, unsigned long *bits)
+{
+       struct idio_16_gpio *const idio16gpio = gpiochip_get_data(chip);
+       size_t i;
+       const unsigned int gpio_reg_size = 8;
+       unsigned int bits_offset;
+       size_t word_index;
+       unsigned int word_offset;
+       unsigned long word_mask;
Quoted 3 lines
Quoted 1 line

+ const unsigned long port_mask = GENMASK(gpio_reg_size, 0);

gpio_reg_size - 1?

Oops, looks like I made an off-by-one error here so I'll make sure to fix that up.

Quoted 2 lines

Though I would prefer not to have that variable at all, just use 8 or 7 respectively.

This device is simple enough that throughout this function I could inline gpio_reg_size and port_mask to 8 and 0xFF respectively, but I would like to keep the code generic enough for reuse in other drivers. In addition, I believe the variable names help keep the intention of the code clear, so I'll stick with dedicated const variables for now if there are no other objections.

Quoted 9 lines

drivers/gpio/gpio-pci-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 121

Quoted 7 lines
drivers/gpio/gpio-pci-idio-16.c +4 -0
+       unsigned long port_state;
 
+       u8 __iomem ports[] = {
+               idio16gpio->reg->out0_7, idio16gpio->reg->out8_15,
 
+               idio16gpio->reg->in0_7, idio16gpio->reg->in8_15

I would leave comma even here.

Will do.

Quoted 31 lines
Quoted 17 lines
drivers/gpio/gpio-pci-idio-16.c +15 -0
+       };
 
+       /* get bits are evaluated a gpio port register at a time */
+       for (i = 0; i < ARRAY_SIZE(ports); i++) {
+               /* gpio offset in bits array */
+               bits_offset = i * gpio_reg_size;
+
+               /* word index for bits array */
+               word_index = BIT_WORD(bits_offset);
+
+               /* gpio offset within current word of bits array */
+               word_offset = bits_offset % BITS_PER_LONG;
+
+               /* mask of get bits for current gpio within current word */
+               word_mask = mask[word_index] & (port_mask << word_offset);
+               if (!word_mask) {

drivers/gpio/gpio-pci-idio-16.c static int idio_16_gpio_get(struct gpio_chip *chip, unsigned int offset) · line 150

Quoted 10 lines
drivers/gpio/gpio-pci-idio-16.c +10 -0
+                       /* no get bits in this port so skip to next one */
+                       continue;
+               }
+
+               /* read bits from current gpio port */
+               port_state = ioread8(ports + i);
+
+               /* store acquired bits at respective bits array offset */
+               bits[word_index] |= port_state << word_offset;
+       }

I would propose to do other way around, i.e.
read all ports to the bitmap array and call bitmap_and() after.

Quoted 6 lines

Further optimization can be something like introduction of generic

bitmap_copy_uXX_off(unsigned long *dst, u8 src, unsigned int offset);

It can be done using macros, though it's another story not quite related to the topic.

Port I/O is significantly more costly to perform than the bitmask evaluations for each port. Despite the increased complexity of the loop logic, I believe the latency improvements of skipping unnecessary I/O port reads are worth the trouble.

I do like the idea of a bitmap_copy_uXX_off macro as that could be quite useful in general. Even if not for this particular patchset, I would be interested in seeing that functionality added to the bitmap API. Perhaps I might implement it as a standlone patch when I have some free time.

William Breathitt Gray

Quoted 6 lines
Quoted 2 lines

+}

Signature · 2 lines
With Best Regards,
Andy Shevchenko