qemu-patch-raspberry4/hw/i2c/versatile_i2c.c
Peter Maydell 41742927ee hw/i2c/bitbang_i2c: Use in-place rather than malloc'd bitbang_i2c_interface struct
Currently the bitbang_i2c_init() function allocates a
bitbang_i2c_interface struct which it returns.  This is unfortunate
because it means that if the function is used from a DeviceState
init method then the memory will be leaked by an "init then delete"
cycle, as used by the qmp/hmp commands that list device properties.

Since three out of four of the uses of this function are in
device init methods, switch the function to do an in-place
initialization of a struct that can be embedded in the
device state struct of the caller.

This fixes LeakSanitizer leak warnings that have appeared in the
patchew configuration (which only tries to run the sanitizers
for the x86_64-softmmu target) now that we use the bitbang-i2c
code in an x86-64 config.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: BALATON Zoltan <balaton@eik.bme.hu>
Tested-by: BALATON Zoltan <balaton@eik.bme.hu>
Acked-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20190702163844.20458-1-peter.maydell@linaro.org
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2019-07-03 10:51:35 +02:00

110 lines
3.1 KiB
C

/*
* ARM Versatile I2C controller
*
* Copyright (c) 2006-2007 CodeSourcery.
* Copyright (c) 2012 Oskar Andero <oskar.andero@gmail.com>
*
* This file is derived from hw/realview.c by Paul Brook
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "hw/i2c/bitbang_i2c.h"
#include "qemu/log.h"
#include "qemu/module.h"
#define TYPE_VERSATILE_I2C "versatile_i2c"
#define VERSATILE_I2C(obj) \
OBJECT_CHECK(VersatileI2CState, (obj), TYPE_VERSATILE_I2C)
typedef struct VersatileI2CState {
SysBusDevice parent_obj;
MemoryRegion iomem;
bitbang_i2c_interface bitbang;
int out;
int in;
} VersatileI2CState;
static uint64_t versatile_i2c_read(void *opaque, hwaddr offset,
unsigned size)
{
VersatileI2CState *s = (VersatileI2CState *)opaque;
if (offset == 0) {
return (s->out & 1) | (s->in << 1);
} else {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%x\n", __func__, (int)offset);
return -1;
}
}
static void versatile_i2c_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
VersatileI2CState *s = (VersatileI2CState *)opaque;
switch (offset) {
case 0:
s->out |= value & 3;
break;
case 4:
s->out &= ~value;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%x\n", __func__, (int)offset);
}
bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SCL, (s->out & 1) != 0);
s->in = bitbang_i2c_set(&s->bitbang, BITBANG_I2C_SDA, (s->out & 2) != 0);
}
static const MemoryRegionOps versatile_i2c_ops = {
.read = versatile_i2c_read,
.write = versatile_i2c_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
static void versatile_i2c_init(Object *obj)
{
DeviceState *dev = DEVICE(obj);
VersatileI2CState *s = VERSATILE_I2C(obj);
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
I2CBus *bus;
bus = i2c_init_bus(dev, "i2c");
bitbang_i2c_init(&s->bitbang, bus);
memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
"versatile_i2c", 0x1000);
sysbus_init_mmio(sbd, &s->iomem);
}
static const TypeInfo versatile_i2c_info = {
.name = TYPE_VERSATILE_I2C,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(VersatileI2CState),
.instance_init = versatile_i2c_init,
};
static void versatile_i2c_register_types(void)
{
type_register_static(&versatile_i2c_info);
}
type_init(versatile_i2c_register_types)