From 7cda27ee1c8753c7fa197140e634bbae514f49b4 Mon Sep 17 00:00:00 2001 From: Memotech Bill <64212746+Memotech-Bill@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:04:47 +0100 Subject: [PATCH] Re-implemented GPIO attached hardware using GPIO Character Device Userspace API --- docs/Hardware_Config.pdf | Bin 82018 -> 0 bytes docs/index.html | 143 ++++++++++++++++++- src/memu/gpio.c | 293 ++++++++++++++++++++++++--------------- src/memu/gpio.h | 62 ++++----- src/memu/hardware.c | 6 +- 5 files changed, 349 insertions(+), 155 deletions(-) delete mode 100644 docs/Hardware_Config.pdf diff --git a/docs/Hardware_Config.pdf b/docs/Hardware_Config.pdf deleted file mode 100644 index 1501038df8df218146bff0cfd6b3fb89279fdf1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82018 zcmdSAQ;=v)v##5=XWO=I+qP}nwr$&X_iWp?Z5!wNS1jx}d!2pO?H)HHBgcq}s+)YD ze5;B?URacdftDGHWUzR!d$4sd4~h|=9^cN;5{jFfPTIuQ%-I~D>7R@uov4Mivxy^} zsI`H!iLi;0ov{foFO-wBqltkHlzVoLhE&`kD^l-k-5dwM*Bb%}qB(jzjYq&1n1w!k z|BfqL8%PHB!)u#5e4{wel`hPPs}hpNY+Wy9M%49>?`IQJPJkXkXw+rtj&AAAsNc@d zyV5I{PLLm;uUD5(uZG!vYy)1`te@L1ZmW~h>-(-AUv$p~{9)~Fs^7=cd|8}-6tHjX z8%N2pxv3M=YgJJmw4T;tOBf5PTYp(~*U#nSY1{MTwHJ{LI{zF2Cql$1M&`YkiyQW^Pn{>I;-^go13?H!;1Um!@GWKgv%`W zp{E@%m(iGDy7j&szQw5Bq^^Y7{;_&$wS=GBqIhP;MZ$D-u)tNJ7dN zbJU?QH}ae6R~ZnHNvX`N&rumGANd(S|I25OuojXuwK1QzUvJAbUBUWR$iY#|6-Z}s zGf;m&3a!t?{>7F6A@Hi{n?Plw%PAEWw^#PI!{-BH^9fj%0vwI3m@$)7F6ZD6;b}iZ z3cU*Y{2z)~M{Z43GZremAUJ#lS;0s_|Aw=zae~;iwayHC>F5ARc?@ErCb# z^sN`beT4A}@=$c31ptxWjRe5AT5lS`d%RQM%&QW+?_>puRuXmcyEgsr4m1BW@vp!{ z$^O9Ll*B6(BJ@eeqqW@zNkf!xD26^8~nZejg~?IeI3qhtWpXpJ|j1ydnu zdtqIH6P78Pr1ksklt5d$1e?I-MQV7HG(){U6R7mNwYHy{L(LTv?LL&nmR}w#~ z>qOy|uF3ez5O~l83P7OF;`W1+vD%WqLy*CO;Ke>Q&wvhYMr^Leb1jER(q1}4BV&`) z6_M#BUamL5d{L$?vy03|xNVP)@W)3y&ASZ5aqoEu)y#VK=qSLg#ZQ%F0aaxcnOAM* zy$#pq?A|4oAS;Z%k}GTq#1N|~4)unOntScnL=DJ3P5_G@<#9+=PUOjPePD>PPdYGs zGE`DY1Isi8p{k&i#u8q--=sjbkb^al>EXH2cH>q;r{@o0Pqrtz zAR^8mi(5A>zNJ84Lz;KiJ0&iqmnLpDK_N3X5Ilz7uIuB95f+kCVNS+mdF*$Ye7ys%zF zJYxZUwOiBIj#e0rMr51R0Jvt6UY!@bJ7p)xSYfi#WEGS>laCy5EqAH`vM6LdAoB~m z2=k6*rqGUSkICmfU_*7W$tuoJY%jzlXz}D%0D7j9=7MbtkL!L$>e`K_lP)vZPeUl3 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 S?haQ8FBc{~y`-`f=KlxihwA?T diff --git a/docs/index.html b/docs/index.html index 6237e48..d0ff131 100644 --- a/docs/index.html +++ b/docs/index.html @@ -13,6 +13,7 @@

Contents

  • Raspberry Pi Pico Build
  • Linux Build
  • Raspberry Pi Build
  • +
  • Obsolete Raspberry Pi Build
  • Bare-Metal Raspberry Pi Build
  • Windows Build
  • @@ -33,6 +34,15 @@

    Contents

  • Diagnostic Windows
  • +
  • Hardware Configuration + +
  • Introduction

    @@ -200,6 +210,27 @@

    Linux Builds

    "src/memu" sub-folder. Copy the executable into the root of the "run_time" folder.

    Raspberry Pi Build

    +

    The Linux builds of MEMU (documented above) will compile and run on any version of + Raspberry Pi. The original Raspberry Pi build (documented below) had two additional + features:

    +
      +
    • Used the VideoCore GPU to provide scaling of the MEMU displays.
    • +
    • Used GPIO to allow MEMU to interface with real hardware.
    • +
    +

    The software interfaces used to implement these features have been obsoleted by + recent versions of Raspberry Pi OS, and are not available at all for the Raspberry Pi 5.

    +

    The use of GPIO to connect to real hardware is potentially useful, so this has been + re-implemented as an optional feature of the Linux builds, using standard Linux software + interfaces. To enable this feature, add the following switches to the cmake line + of the Linux build:

    +
      +
    • -DHWGPIO=Y - To enable use of GPIO pins on the device.
    • +
    • -DHW_23017 - To enable use of GPIO pins on an I2C attached MCP23017 GPIO + expansion.
    • +
    +

    To use GPIO attached hardware, it is necessary to use the switch -hw-config + when starting MEMU to give the name of a file specifying the hardware attached.

    +

    Obsolete Raspberry Pi Build

    This build is intended to be run from an operating system, typically "Raspberry Pi OS". It does not require a GUI, instead it uses the VideoCore IV GPU to display full screen.

    This build must be done on a Raspberry Pi, as the VideoCore libraries are required. @@ -527,9 +558,9 @@

    Advanced Usage

    of audio (*.wav) files. Binary (*.mtx) files are loaded by converting them back to audio.
    -cassette-in
    -
    hardware emulation - MTX or WAV file to load
    +
    MTX or WAV file to load
    -cassette-out
    -
    hardware emulation - MTX or WAV file to save
    +
    MTX or WAV file to save
    -sdx-mfloppy file
    specify .mfloppy file in SDX first drive
    -sdx-mfloppy2 file
    @@ -692,7 +723,7 @@

    Advanced Usage

    -hw-config filename
    Specifies a separate filename describing the hardware configuration. The format of this file differs from the other configuration options and is described - here.
    + here.

    The Raspberry Pi build has one further option to control the use of the GPU:

    @@ -1262,5 +1293,111 @@

    Diagnostic Windows

    Pressing o takes a new snapshot. Pressing v toggles whether you are looking at the current value, or the value in the snapshot.

    +

    Hardware Configuration

    +

    If the optional feature of using GPIO to attach real hardware to MEMU + is enabled, then it is necessary to provide a hardware configuration + file to describe the attachments.

    +

    The hardware configuration file consists of blocks defining a particular + interface, introduced by a name in square brackets, followed by the + definition of that interface.

    +

    Pin Definitions

    +

    Most of the hardware definition file is defining which digital I/O pins + connected to what hardware. These may be built in GPIO pins, or there is + also support for one or more MCP23017 I2C port expanders.

    +

    These pin definitions take the form:

    +
    +          GPIO, <gpiochip device>, <GPIO number>
    +          MCP23017, <I2C device>, <I2C address>, <MPC pin number>
    +      
    +

    Where:

    +
    +
    <gpiochip device&>
    +
    The device name of the gpiochip device used, for example /dev/gpiochip0.
    +
    <GPIO number>
    +
    The number of the GPIO on the device.
    +
    <I2C device>
    +
    The device name of the I2C bus used. This will typically be “/dev/i2c-1” on more + recent Raspberry Pis
    +
    <I2C address>
    +
    The I2C address of the port expander. This will typically be 0x20, although up to + 8 simultaneous port expanders on different addresses are supported.
    +
    <MPC pin number>
    +
    he number of the pin on the port expander. This may either be a number in the range + 0-15, or a letter and number in the ranges A0-A7 or B0-B7.
    +
    +

    Keyboard

    +

    This block of the configuration file is used to define the connection of a MTX matrix + keyboard or equivalent. It takes the form:

    +

    +          [keyboard]
    +          kb0 = <pin definition>
    +	        :
    +          kb9 = <pin definition>
    +          dr0 = <pin definition>
    +            :
    +          dr7 = <pin definition>
    +          reset = <pin definition>
    +          reset2 = <pin definition>
    +          dr_reset = <gnd | dr0-dr7>
    +      
    +

    The lines kb0 – kb9 define the 10 keyboard sense lines, and the lines dr0-dr7 define + the 8 keyboard drive lines.

    +

    For an unmodified MTX keyboard, the reset line defines the I/O pin that one of the + keyboard reset lines is connected to. The other reset line should be connected to ground + (0v). In that case the reset2 and dr_reset lines would be omitted.

    +

    The MTX keyboard may be modified by soldering an additional connection to the track + joining the two reset keys. In that case both the existing keyboard reset lines should + be connected to IO pins, and defined by the reset and reset2 lines. The additional + connection between the reset keys should either be connected to ground (0v) or to one + of the keyboard drive lines. The dr_reset line specifies how this is connected (gnd is + the default).

    +

    Joysticks

    +

    If a matrix keyboard is fitted, then Atari style joysticks may be connected to the + drive and sense lines, in parallel with the keyboard, as per the MTX. In that case + no joystick definition is required. Alternately, the separate joystick switches may + be connected to I/O pins, and the common connection to ground, as per earlier versions + of MEMU-Pi. In that case, the joystick connections are defined by a block of the form:

    +
    +        [joystick_1]
    +        left = <pin definition>
    +        right = <pin definition>
    +        up = <pin definition>
    +        down = <pin definition>
    +        fire = <pin definition>
    +    
    +

    The second joystick, if fitted, is defined similarly in a [joystick_2] block.

    +

    Printer

    +

    A Centronics style printer port may be provided. It should be noted that the Centronics + connector uses 5v logic, while the Raspberry Pi GPIO connections are only 3.3v and are not + 5v tolerant. Therefore some form of level shifting is required, Probably the simplest + solution is to use an MCP23017 powered from 5v, but the I2C pullup resistors taken to 3.3v. + The printer hardware block takes the form:

    +
    +        [printer]
    +        d0 = <pin definition>
    +	      :
    +        d7 = <pin definition>
    +        strobe = <pin definition>
    +        busy = <pin definition>
    +        error = <pin definition>
    +        pe = <pin definition>
    +        slct = <pin definition>
    +    
    +

    Parallel Input/Output Port

    +

    ote that the MTX PIO port is 5v logic while the Raspberry Pi GPIO connections are only 3.3v + tolerant. Also it is not practical to implement the INSTB and OTSTB lines in software. HCT244, + HCT245 or HCT373 are examples of devices that could provide an OTSTB function and 3.3v to 5v + step-up (not HC chips). A HC373 or HCT373 are examples that could provide INSTB, but the + outputs would need resistor dividers to connect to the Raspberry Pi GPIO. The PIO hardware + definition block takes the form:

    +
    +        [pio]
    +        pot0 = <pin definition>
    +	      :
    +        pot0 = <pin definition>
    +        pin0 = <pin definition>
    +	      :
    +        pin7 = <pin definition>
    +    
    diff --git a/src/memu/gpio.c b/src/memu/gpio.c index d4cf29b..8aad570 100644 --- a/src/memu/gpio.c +++ b/src/memu/gpio.c @@ -1,15 +1,15 @@ -/* gpio.c - Routines to access RPi GPIO for joystick emulation. +/* gpio.c - Routines to access RPi GPIO for hardware interfacing Original version strongly based upon Gertboard test software: Copyright (C) Gert Jan van Loo & Myra VanInwegen 2012 No rights reserved You may treat this program as if it was in the public domain -Revised based upon tiny_gpio.c by @joan - tiny_gpio.c - http://abyz.co.uk/rpi/pigpio/code/tiny_gpio.zip - 2015-09-12 - Public Domain +GPIO access using Linux GPIO Character Device Userspace API (v2). Docuumented at: + https://docs.kernel.org/userspace-api/gpio/chardev.html + +Userspace is supposed to use libgpiod, however the documentation for that is unhelpful: + https://libgpiod.readthedocs.io/en/latest/index.html I2C code based upon "Interfacing an I2C GPIO expander (MCP23017) to the Raspberry Pi using C++ (i2cdev)" http://hertaville.com/interfacing-an-i2c-gpio-expander-mcp23017-to-the-raspberry-pi-using-c.html @@ -31,13 +31,14 @@ I2C code based upon "Interfacing an I2C GPIO expander (MCP23017) to the Raspberr #include #include #include -#include #include #include #include #include #include #include +#include +#include #endif // I/O access @@ -80,123 +81,187 @@ struct gio_dev *gdev = NULL; // Set up memory regions to access the peripherals. // No longer requires root access. // -int gpio_init (void) +int gpio_init (struct gio_dev *pdev) { #ifdef __circle__ gpio = (uint32_t *) ARM_GPIO_BASE; return GPIO_OK; #else - int fd; - if ( ( fd = open("/dev/gpiomem", O_RDWR|O_SYNC) ) < 0 ) return GPIO_ERR_MEM; - diag_message (DIAG_GPIO, "gpio_init: fd = %d", fd); - - // mmap GPIO - - gpio = (uint32_t *) mmap (NULL, GPIO_LEN, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); - diag_message (DIAG_GPIO, "gpio_init: gpio = %p", gpio); - close (fd); - - if ( (long) gpio < 0 ) return GPIO_ERR_MAP; - + pdev->iDirn = 0; + pdev->iPullUp = 0; + pdev->iPullDn = 0; + int chip_fd = open (pdev->sDev, O_RDWR); + if (chip_fd < 0) return errno; + struct gpio_v2_line_request lreq; + memset (&lreq, 0, sizeof (lreq)); + strcpy (lreq.consumer, "MEMU"); + int iLine = 0; + uint32_t iPins = (uint32_t) pdev->iPins; + while (iPins != 0) + { + if (iPins & 1) + { + lreq.offsets[lreq.num_lines] = iLine; + ++lreq.num_lines; + } + iPins >>= 1; + ++iLine; + } + lreq.config.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_DISABLED; + if (ioctl (chip_fd, GPIO_V2_GET_LINE_IOCTL, &lreq) < 0) return errno; + pdev->fd = lreq.fd; + close (chip_fd); return GPIO_OK; #endif } -void gpio_term (void) +void gpio_term (struct gio_dev *pdev) { #ifdef __circle__ gpio = NULL; #else - if ( gpio != NULL ) - { - munmap ((void *) gpio, GPIO_LEN); - gpio = NULL; - } + if (pdev->fd) close (pdev->fd); + pdev->fd = 0; #endif } -void gpio_input (int iMask) +static uint32_t line_mask (struct gio_dev *pdev, uint32_t iMask) + { + uint32_t lMask = 0; + uint32_t iPins = pdev->iPins; + uint32_t iBit = 1; + while (iMask > 0) + { + if (iMask & 1) lMask |= iBit; + if (iPins & 1) iBit <<= 1; + iPins >>= 1; + iMask >>= 1; + } + return iMask; + } + +void gpio_input (struct gio_dev *pdev, uint32_t iMask) { - int iPin; - int iReg; - int iBits; - diag_message (DIAG_GPIO, "gpio_input (0x%08x)", iMask); - if ( gpio == NULL ) return; - for ( iReg = 0; iReg < 3; ++iReg ) - { - iBits = 7; - for ( iPin = 0; iPin < 10; ++iPin ) - { - if ( iMask & 1 ) gpio[iReg] &= ~iBits; - iMask >>= 1; - iBits <<= 3; - } - } + diag_message (DIAG_GPIO, "gpio_input (%s, 0x%08x)", pdev->sDev, iMask); + iMask &= pdev->iDirn; + if (iMask) + { + struct gpio_v2_line_config cfg; + memset (&cfg, 0, sizeof (cfg)); + uint32_t lMask = line_mask (pdev, (~(pdev->iPullUp | pdev->iPullDn)) & iMask); + if (lMask) + { + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_DISABLED; + cfg.attrs[cfg.num_attrs].mask = lMask; + ++cfg.num_attrs; + } + lMask = line_mask (pdev, pdev->iPullUp & iMask); + if (lMask) + { + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_PULL_UP; + cfg.attrs[cfg.num_attrs].mask = lMask; + ++cfg.num_attrs; + } + lMask = line_mask (pdev, pdev->iPullDn & iMask); + if (lMask) + { + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_PULL_DOWN; + cfg.attrs[cfg.num_attrs].mask = lMask; + ++cfg.num_attrs; + } + ioctl (pdev->fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, &cfg); + pdev->iDirn &= ~ iMask; + } } -void gpio_output (int iMask) +void gpio_output (struct gio_dev *pdev, uint32_t iMask) { - int iPin; - int iReg; - int iBits; - int iOut; - diag_message (DIAG_GPIO, "gpio_output (0x%08x)", iMask); - if ( gpio == NULL ) return; - for ( iReg = 0; iReg < 3; ++iReg ) - { - iBits = 7; - iOut = PI_OUTPUT; - for ( iPin = 0; iPin < 10; ++iPin ) - { - if ( iMask & 1 ) gpio[iReg] = ( gpio[iReg] & (~iBits) ) | iOut; - iMask >>= 1; - iBits <<= 3; - iOut <<= 3; - } - } + diag_message (DIAG_GPIO, "gpio_output (%s, 0x%08x)", pdev->sDev, iMask); + iMask &= pdev->iPins & (~ pdev->iDirn); + if (iMask) + { + struct gpio_v2_line_config cfg; + memset (&cfg, 0, sizeof (cfg)); + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_OUTPUT; + cfg.attrs[cfg.num_attrs].mask = line_mask (pdev, iMask); + ++cfg.num_attrs; + ioctl (pdev->fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, &cfg); + pdev->iDirn |= iMask; + } } -void gpio_pullup (int iMask) +void gpio_pullup (struct gio_dev *pdev, uint32_t iMask) { - diag_message (DIAG_GPIO, "gpio_pullup (0x%08x)", iMask); - if ( gpio == NULL ) return; - gpio[GPPUD] = PI_PUD_UP; - usleep(20); - gpio[GPPUDCLK0] = iMask; - usleep(20); - gpio[GPPUD] = 0; - gpio[GPPUDCLK0] = 0; + diag_message (DIAG_GPIO, "gpio_pullup (%s, 0x%08x)", pdev->sDev, iMask); + iMask &= pdev->iPins & (~ pdev->iPullUp); + pdev->iPullUp |= iMask; + pdev->iPullDn &= ~ iMask; + iMask &= ~ pdev->iDirn; + if (iMask) + { + struct gpio_v2_line_config cfg; + memset (&cfg, 0, sizeof (cfg)); + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_PULL_UP; + cfg.attrs[cfg.num_attrs].mask = line_mask (pdev, iMask); + ++cfg.num_attrs; + ioctl (pdev->fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, &cfg); + } } -void gpio_pullnone (int iMask) +void gpio_pullnone (struct gio_dev *pdev, uint32_t iMask) { - diag_message (DIAG_GPIO, "gpio_pullnone (0x%08x)", iMask); - if ( gpio == NULL ) return; - gpio[GPPUD] = PI_PUD_OFF; - usleep(20); - gpio[GPPUDCLK0] = iMask; - usleep(20); - gpio[GPPUD] = 0; - gpio[GPPUDCLK0] = 0; + diag_message (DIAG_GPIO, "gpio_pullnone (%s, 0x%08x)", pdev->sDev, iMask); + iMask &= pdev->iPins & (pdev->iPullUp | pdev->iPullDn); + pdev->iPullUp &= ~ iMask; + pdev->iPullDn &= ~ iMask; + iMask &= ~ pdev->iDirn; + if (iMask) + { + struct gpio_v2_line_config cfg; + memset (&cfg, 0, sizeof (cfg)); + cfg.attrs[cfg.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS; + cfg.attrs[cfg.num_attrs].attr.flags = GPIO_V2_LINE_FLAG_INPUT + GPIO_V2_LINE_FLAG_BIAS_DISABLED; + cfg.attrs[cfg.num_attrs].mask = line_mask (pdev, iMask); + ++cfg.num_attrs; + ioctl (pdev->fd, GPIO_V2_LINE_SET_CONFIG_IOCTL, &cfg); + } } -int gpio_get (int iMask) +uint32_t gpio_get (struct gio_dev *pdev, uint32_t iMask) { - int iValue; - diag_message (DIAG_GPIO, "gpio_get: gpio = %p", gpio); - if ( gpio == NULL ) return 0; - iValue = iMask & gpio[GPLEV0]; - diag_message (DIAG_GPIO, "gpio_get (0x%08x) = 0x%08x", iMask, iValue); + struct gpio_v2_line_values getval; + iMask &= pdev->iPins; + getval.mask = line_mask (pdev, iMask); + ioctl (pdev->fd, GPIO_V2_LINE_GET_VALUES_IOCTL, &getval); + uint32_t iValue = 0; + uint32_t iBit = 1; + while (getval.bits > 0) + { + if (pdev->iPins & iBit) + { + if (getval.bits &1) iValue |= iBit; + getval.bits >>= 1; + } + iBit <<= 1; + } + diag_message (DIAG_GPIO, "gpio_get (%s, 0x%08X) = 0x%08X", pdev->sDev, iMask, iValue); return iValue; } -void gpio_put (int iMask, int iBits) +void gpio_put (struct gio_dev *pdev, uint32_t iMask, int iBits) { - diag_message (DIAG_GPIO, "gpio_put (0x%08x, 0x%08x)\n", iMask, iBits); - if ( gpio == NULL ) return; - gpio[GPSET0] = iMask & iBits; - gpio[GPCLR0] = iMask & ( ~iBits ); + diag_message (DIAG_GPIO, "gpio_put (%s, 0x%08x, 0x%08x)\n", pdev->sDev, iMask, iBits); + struct gpio_v2_line_values setval; + iMask &= pdev->iPins; + setval.mask = line_mask (pdev, iMask); + setval.bits = line_mask (pdev, iMask & iBits); + ioctl (pdev->fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &setval); } #ifndef __circle__ @@ -379,7 +444,7 @@ void xio_term (int fd) i2c_term (fd); } -void xio_input (int fd, int iMask) +void xio_input (int fd, uint32_t iMask) { unsigned char bDir[2]; i2c_get (fd, 0x00, 2, bDir); @@ -388,7 +453,7 @@ void xio_input (int fd, int iMask) i2c_put (fd, 0x00, 2, bDir); } -void xio_output (int fd, int iMask) +void xio_output (int fd, uint32_t iMask) { unsigned char bDir[2]; i2c_get (fd, 0x00, 2, bDir); @@ -397,7 +462,7 @@ void xio_output (int fd, int iMask) i2c_put (fd, 0x00, 2, bDir); } -void xio_pullup (int fd, int iMask) +void xio_pullup (int fd, uint32_t iMask) { unsigned char bPull[2]; i2c_get (fd, 0x0C, 2, bPull); @@ -406,7 +471,7 @@ void xio_pullup (int fd, int iMask) i2c_put (fd, 0x0C, 2, bPull); } -void xio_pullnone (int fd, int iMask) +void xio_pullnone (int fd, uint32_t iMask) { unsigned char bPull[2]; i2c_get (fd, 0x0C, 2, bPull); @@ -415,14 +480,14 @@ void xio_pullnone (int fd, int iMask) i2c_put (fd, 0x0C, 2, bPull); } -int xio_get (int fd, int iMask) +int xio_get (int fd, uint32_t iMask) { unsigned char bData[2]; i2c_get (fd, 0x12, 2, bData); return ( ( (int) bData[1] << 8 ) | ( (int) bData[0] ) ) & iMask; } -void xio_put (int fd, int iMask, int iBits) +void xio_put (int fd, uint32_t iMask, int iBits) { unsigned char bData[2]; i2c_get (fd, 0x14, 2, bData); @@ -443,7 +508,7 @@ int gio_init (void) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - int iSta = gpio_init (); + int iSta = gpio_init (pdev); if ( iSta != GPIO_OK ) return iSta; } #endif @@ -467,7 +532,7 @@ void gio_term (void) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - gpio_term (); + gpio_term (pdev); } #endif #if HAVE_HW_MCP23017 @@ -491,7 +556,7 @@ void gio_clear (void) } } -void gio_set (struct gio_pin *ppin, int iData) +void gio_set (struct gio_pin *ppin, uint32_t iData) { if ( ppin->pdev ) { @@ -500,7 +565,7 @@ void gio_set (struct gio_pin *ppin, int iData) } } -void gio_pins (int nPin, struct gio_pin *ppin, int iData) +void gio_pins (int nPin, struct gio_pin *ppin, uint32_t iData) { int iMask = 1; int iPin; @@ -513,7 +578,7 @@ void gio_pins (int nPin, struct gio_pin *ppin, int iData) } } -void gio_input (int nPin, struct gio_pin *ppin, int iData) +void gio_input (int nPin, struct gio_pin *ppin, uint32_t iData) { diag_message (DIAG_GPIO, "gio_input (%d, %p, 0x%02x)", nPin, ppin, iData); gio_pins (nPin, ppin, iData); @@ -523,7 +588,7 @@ void gio_input (int nPin, struct gio_pin *ppin, int iData) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - if ( pdev->iData ) gpio_input (pdev->iData); + if ( pdev->iData ) gpio_input (pdev, pdev->iData); } #endif #if HAVE_HW_MCP23017 @@ -536,7 +601,7 @@ void gio_input (int nPin, struct gio_pin *ppin, int iData) } } -void gio_output (int nPin, struct gio_pin *ppin, int iData) +void gio_output (int nPin, struct gio_pin *ppin, uint32_t iData) { diag_message (DIAG_GPIO, "gio_output (%d, %p, 0x%02x)", nPin, ppin, iData); gio_pins (nPin, ppin, iData); @@ -546,7 +611,7 @@ void gio_output (int nPin, struct gio_pin *ppin, int iData) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - if ( pdev->iData ) gpio_output (pdev->iData); + if ( pdev->iData ) gpio_output (pdev, pdev->iData); } #endif #if HAVE_HW_MCP23017 @@ -559,7 +624,7 @@ void gio_output (int nPin, struct gio_pin *ppin, int iData) } } -void gio_pullup (int nPin, struct gio_pin *ppin, int iData) +void gio_pullup (int nPin, struct gio_pin *ppin, uint32_t iData) { diag_message (DIAG_GPIO, "gio_pullup (%d, %p, 0x%02x)", nPin, ppin, iData); gio_pins (nPin, ppin, iData); @@ -569,7 +634,7 @@ void gio_pullup (int nPin, struct gio_pin *ppin, int iData) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - if ( pdev->iData ) gpio_pullup (pdev->iData); + if ( pdev->iData ) gpio_pullup (pdev, pdev->iData); } #endif #if HAVE_HW_MCP23017 @@ -582,7 +647,7 @@ void gio_pullup (int nPin, struct gio_pin *ppin, int iData) } } -void gio_pullnone (int nPin, struct gio_pin *ppin, int iData) +void gio_pullnone (int nPin, struct gio_pin *ppin, uint32_t iData) { diag_message (DIAG_GPIO, "gio_pullnone (%d, %p, 0x%02x)", nPin, ppin, iData); gio_pins (nPin, ppin, iData); @@ -592,7 +657,7 @@ void gio_pullnone (int nPin, struct gio_pin *ppin, int iData) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - if ( pdev->iData ) gpio_pullnone (pdev->iData); + if ( pdev->iData ) gpio_pullnone (pdev, pdev->iData); } #endif #if HAVE_HW_MCP23017 @@ -605,7 +670,7 @@ void gio_pullnone (int nPin, struct gio_pin *ppin, int iData) } } -int gio_get (int nPin, struct gio_pin *ppin) +uint32_t gio_get (int nPin, struct gio_pin *ppin) { diag_message (DIAG_GPIO, "gio_get (%d, %p)", nPin, ppin); gio_pins (nPin, ppin, -1); @@ -616,7 +681,7 @@ int gio_get (int nPin, struct gio_pin *ppin) if ( pdev->type == gio_gpio ) { diag_message (DIAG_GPIO, "pdev->iMask = 0x%08x", pdev->iMask); - if ( pdev->iMask ) pdev->iData = gpio_get (pdev->iMask); + if ( pdev->iMask ) pdev->iData = gpio_get (pdev, pdev->iMask); diag_message (DIAG_GPIO, "*(%p) = 0x%08x", &gdev, pdev->iData); } #endif @@ -628,8 +693,8 @@ int gio_get (int nPin, struct gio_pin *ppin) #endif pdev = pdev->pnext; } - int iData = 0; - int iMask = 1; + uint32_t iData = 0; + uint32_t iMask = 1; int iPin; for ( iPin = 0; iPin < nPin; ++iPin ) { @@ -652,7 +717,7 @@ int gio_get (int nPin, struct gio_pin *ppin) return iData; } -void gio_put (int nPin, struct gio_pin *ppin, int iData) +void gio_put (int nPin, struct gio_pin *ppin, uint32_t iData) { diag_message (DIAG_GPIO, "gio_put (%d, %p, 0x%02x)", nPin, ppin, iData); gio_pins (nPin, ppin, iData); @@ -663,7 +728,7 @@ void gio_put (int nPin, struct gio_pin *ppin, int iData) #if HAVE_HW_GPIO if ( pdev->type == gio_gpio ) { - if ( pdev->iData ) gpio_put (pdev->iMask, pdev->iData); + if ( pdev->iData ) gpio_put (pdev, pdev->iMask, pdev->iData); } #endif #if HAVE_HW_MCP23017 diff --git a/src/memu/gpio.h b/src/memu/gpio.h index f4bbd99..6b2c1d4 100644 --- a/src/memu/gpio.h +++ b/src/memu/gpio.h @@ -3,6 +3,8 @@ #ifndef H_GPIO #define H_GPIO +#include + #define GPIO_OK 0 #define GPIO_ERR_MEM -1 #define GPIO_ERR_ALLOC -2 @@ -10,39 +12,12 @@ #define GPIO_PIN(i) ( 1 << i ) -#ifdef __cplusplus -extern "C" - { -#endif -int gpio_init (void); -void gpio_term (void); -void gpio_input (int iMask); -void gpio_pullup (int iMask); -void gpio_pullnone (int iMask); -int gpio_get (int iMask); -int gpio_revision (void); -#ifdef __cplusplus - } -#endif - #define I2C_OK 0 #define I2C_EOPEN -11 #define I2C_EADDR -12 #define I2C_EMEM -13 #define I2C_EIO -14 -#ifdef __cplusplus -extern "C" - { -#endif -int i2c_init (const char *psDev, int iAddr); -void i2c_term (int fd); -int i2c_put (int fd, int iAddr, int iLen, unsigned char *pbData); -int i2c_get (int fd, int iAddr, int iLen, unsigned char *pbData); -#ifdef __cplusplus - } -#endif - // Generalised Input / Output definitions #define LDEVNAME 20 @@ -62,8 +37,12 @@ struct gio_dev char sDev[LDEVNAME]; // Device name int fd; // File number int iAddr; // I2C address - int iMask; // Bit selection mask - int iData; // Data bits + uint32_t iPins; // 1 = Active pin, 0 = Inactive pin + uint32_t iDirn; // Direction: 0 = Input, 1 = Output + uint32_t iPullUp; // Pull Up: 0 = Disabled, 1 = Enabled + uint32_t iPullDn; // Pull Down: 0 = Disabled, 1 = Enabled + uint32_t iMask; // Bit selection mask + uint32_t iData; // Data bits struct gio_dev * pnext; // Next device definition }; @@ -80,16 +59,27 @@ extern struct gio_dev *gdev; extern "C" { #endif +int gpio_init (struct gio_dev *pdev); +void gpio_term (struct gio_dev *pdev); +void gpio_input (struct gio_dev *pdev, uint32_t iMask); +void gpio_pullup (struct gio_dev *pdev, uint32_t iMask); +void gpio_pullnone (struct gio_dev *pdev, uint32_t iMask); +uint32_t gpio_get (struct gio_dev *pdev, uint32_t iMask); +int gpio_revision (void); +int i2c_init (const char *psDev, int iAddr); +void i2c_term (int fd); +int i2c_put (int fd, int iAddr, int iLen, unsigned char *pbData); +int i2c_get (int fd, int iAddr, int iLen, unsigned char *pbData); int gio_init (void); void gio_term (void); void gio_clear (void); -void gio_set (struct gio_pin *ppin, int iData); -void gio_input (int nPin, struct gio_pin *ppin, int iData); -void gio_output (int nPin, struct gio_pin *ppin, int iData); -void gio_pullup (int nPin, struct gio_pin *ppin, int iData); -void gio_pullnone (int nPin, struct gio_pin *ppin, int iData); -int gio_get (int nPin, struct gio_pin *ppin); -void gio_put (int nPin, struct gio_pin *ppin, int iData); +void gio_set (struct gio_pin *ppin, uint32_t iData); +void gio_input (int nPin, struct gio_pin *ppin, uint32_t iData); +void gio_output (int nPin, struct gio_pin *ppin, uint32_t iData); +void gio_pullup (int nPin, struct gio_pin *ppin, uint32_t iData); +void gio_pullnone (int nPin, struct gio_pin *ppin, uint32_t iData); +uint32_t gio_get (int nPin, struct gio_pin *ppin); +void gio_put (int nPin, struct gio_pin *ppin, uint32_t iData); #ifdef __cplusplus } #endif diff --git a/src/memu/hardware.c b/src/memu/hardware.c index 7a0330a..1f434b0 100644 --- a/src/memu/hardware.c +++ b/src/memu/hardware.c @@ -62,7 +62,7 @@ void hw_pindef (TXR *ptxr, struct gio_pin *ppin) } if ( ! pdev ) { - pdev = (struct gio_dev *) malloc (sizeof (struct gio_dev)); + pdev = (struct gio_dev *) calloc (1, sizeof (struct gio_dev)); if ( pdev == NULL ) fatal ("Failed to allocate I/O device definition"); pdev->type = gio_gpio; pdev->pnext = gdev; @@ -72,6 +72,7 @@ void hw_pindef (TXR *ptxr, struct gio_pin *ppin) iPin = TxrGetInt (ptxr); if ( ( iPin < 0 ) || ( iPin >= 30 ) ) fatal ("Invalid GPIO pin number: %d", iPin); ppin->iMask = 1 << iPin; + pdev->iPins |= ppin->iMask; #else fatal ("GPIO pins not supported"); #endif @@ -91,7 +92,7 @@ void hw_pindef (TXR *ptxr, struct gio_pin *ppin) } if ( ! pdev ) { - pdev = (struct gio_dev *) malloc (sizeof (struct gio_dev)); + pdev = (struct gio_dev *) calloc (1, sizeof (struct gio_dev)); if ( pdev == NULL ) fatal ("Failed to allocate I/O device definition"); pdev->type = gio_xio; strcpy (pdev->sDev, sDev); @@ -109,6 +110,7 @@ void hw_pindef (TXR *ptxr, struct gio_pin *ppin) else sscanf (sText, "%i", &iPin); if ( ( iPin < 0 ) || ( iPin >= 16 ) ) fatal ("Invalid MCP23017 pin number: %s", sText); ppin->iMask = 1 << iPin; + pdev->iPins |= ppin->iMask; #else fatal ("MCP23017 pins not supported"); #endif