diff --git a/docs/Hardware_Config.pdf b/docs/Hardware_Config.pdf deleted file mode 100644 index 1501038..0000000 Binary files a/docs/Hardware_Config.pdf and /dev/null differ 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:

    + +

    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:

    + +

    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