samples: improve gpio-pci-idio-16 emulation (#821)
Newer kernels implement read register caching for the gpio-pci-idio-16 which
means that the pin counter is never incremented, making it impossible to change
the input register for testing.
Improve the gpio-pci-idio-16 emulation so that the input and output registers
match those of the real hardware, and update the logic so that toggling an
output line 3 times will toggle the corresponding input line to allow testing
individual inputs and outputs.
Signed-off-by: Mark Cave-Ayland <mark.caveayland@nutanix.com>
diff --git a/samples/gpio-pci-idio-16.c b/samples/gpio-pci-idio-16.c
index 6c4e99b..739e242 100644
--- a/samples/gpio-pci-idio-16.c
+++ b/samples/gpio-pci-idio-16.c
@@ -51,17 +51,62 @@
fprintf(stderr, "gpio: %s\n", msg);
}
-static int pin;
+static int pin[16];
bool dirty = true;
static ssize_t
bar2_access(vfu_ctx_t *vfu_ctx UNUSED, char * const buf,
size_t count, loff_t offset, const bool is_write)
{
- if (offset == 0 && !is_write)
- buf[0] = pin++ / 3;
+ int i;
- dirty = true;
+ if (is_write) {
+ /* Output registers are 0x0 and 0x4 */
+ switch (offset) {
+ case 0x0:
+ /* Output pins 0-7 */
+ for (i = 0; i < 8; i++) {
+ if (buf[0] & (1 << i)) {
+ pin[i]++;
+ }
+ }
+ break;
+
+ case 0x4:
+ /* Output pins 8-15 */
+ for (i = 0; i < 8; i++) {
+ if (buf[0] & (1 << i)) {
+ pin[i + 8]++;
+ }
+ }
+ break;
+ }
+
+ dirty = true;
+ } else {
+ /* Input registers are 0x1 and 0x5 */
+ switch (offset) {
+ case 0x1:
+ /* Input pins 0-7 */
+ buf[0] = 0;
+ for (i = 0; i < 8; i++) {
+ if ((pin[i] % 3) == 0) {
+ buf[0] |= (1 << i);
+ }
+ }
+ break;
+
+ case 0x5:
+ /* Input pins 8-15 */
+ buf[0] = 0;
+ for (i = 0; i < 8; i++) {
+ if ((pin[i + 8] % 3) == 0) {
+ buf[0] |= (1 << i);
+ }
+ }
+ break;
+ }
+ }
return count;
}