On Sun, Nov 26, 2017 at 03:59:03PM -0600, Michael Davidsaver wrote: > Support for: ds1307, ds1337, ds1338, ds1339, > ds1340, ds1375, ds1388, and ds3231. > > Tested with ds1338 and ds1375. > > Signed-off-by: Michael Davidsaver <mdavidsa...@gmail.com>
I certainly like the idea of consolidating this code, but reviewing to see that the new code really is a generalization of the old is something I won't have time for for a while. Also, hw/timer is not within my purview so it'll probably need to go another path to merge. > --- > default-configs/arm-softmmu.mak | 2 +- > hw/timer/Makefile.objs | 2 +- > hw/timer/ds-rtc-i2c.c | 461 > ++++++++++++++++++++++++++++++++++++++++ > hw/timer/ds1338.c | 239 --------------------- > 4 files changed, 463 insertions(+), 241 deletions(-) > create mode 100644 hw/timer/ds-rtc-i2c.c > delete mode 100644 hw/timer/ds1338.c > > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak > index d37edc4312..b857823681 100644 > --- a/default-configs/arm-softmmu.mak > +++ b/default-configs/arm-softmmu.mak > @@ -31,7 +31,7 @@ CONFIG_SMC91C111=y > CONFIG_ALLWINNER_EMAC=y > CONFIG_IMX_FEC=y > CONFIG_FTGMAC100=y > -CONFIG_DS1338=y > +CONFIG_DSRTCI2C=y > CONFIG_PFLASH_CFI01=y > CONFIG_PFLASH_CFI02=y > CONFIG_MICRODRIVE=y > diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs > index 8c19eac3b6..290015ebec 100644 > --- a/hw/timer/Makefile.objs > +++ b/hw/timer/Makefile.objs > @@ -3,7 +3,7 @@ common-obj-$(CONFIG_ARM_MPTIMER) += arm_mptimer.o > common-obj-$(CONFIG_ARM_V7M) += armv7m_systick.o > common-obj-$(CONFIG_A9_GTIMER) += a9gtimer.o > common-obj-$(CONFIG_CADENCE) += cadence_ttc.o > -common-obj-$(CONFIG_DS1338) += ds1338.o > +common-obj-$(CONFIG_DSRTCI2C) += ds-rtc-i2c.o > common-obj-$(CONFIG_HPET) += hpet.o > common-obj-$(CONFIG_I8254) += i8254_common.o i8254.o > common-obj-$(CONFIG_M48T59) += m48t59.o > diff --git a/hw/timer/ds-rtc-i2c.c b/hw/timer/ds-rtc-i2c.c > new file mode 100644 > index 0000000000..ad2f8f2a68 > --- /dev/null > +++ b/hw/timer/ds-rtc-i2c.c > @@ -0,0 +1,461 @@ > +/* Emulation of various Dallas/Maxim RTCs accessed via I2C bus > + * > + * Copyright (c) 2017 Michael Davidsaver > + * Copyright (c) 2009 CodeSourcery > + * > + * Authors: Michael Davidsaver > + * Paul Brook > + * > + * This work is licensed under the terms of the GNU GPL, version 2. See > + * the LICENSE file in the top-level directory. > + * > + * Models real time read/set and NVRAM. > + * Does not model alarms, or control/status registers. > + * > + * Generalized register map is: > + * [Current time] > + * [Alarm settings] (optional) > + * [Control/Status] (optional) > + * [Non-volatile memory] (optional) > + * > + * The current time registers are almost always the same, > + * with the exception being that some have a CENTURY bit > + * in the month register. > + */ > +#include "qemu/osdep.h" > +#include "qemu/log.h" > +#include "qemu/timer.h" > +#include "qemu/bcd.h" > +#include "hw/hw.h" > +#include "hw/registerfields.h" > +#include "hw/i2c/i2c.h" > +#include "sysemu/qtest.h" > +#include "qemu/error-report.h" > + > +/* #define DEBUG_DSRTC */ > + > +#ifdef DEBUG_DSRTC > +#define DPRINTK(FMT, ...) info_report(TYPE_DSRTC " : " FMT, ## __VA_ARGS__) > +#else > +#define DPRINTK(FMT, ...) do {} while (0) > +#endif > + > +#define LOG(MSK, FMT, ...) qemu_log_mask(MSK, TYPE_DSRTC " : " FMT "\n", \ > + ## __VA_ARGS__) > + > +#define DSRTC_REGSIZE (0x40) > + > +/* values stored in BCD */ > +/* 00-59 */ > +#define R_SEC (0x0) > +/* 00-59 */ > +#define R_MIN (0x1) > +#define R_HOUR (0x2) > +/* 1-7 */ > +#define R_WDAY (0x3) > +/* 0-31 */ > +#define R_DATE (0x4) > +#define R_MONTH (0x5) > +/* 0-99 */ > +#define R_YEAR (0x6) > + > +/* use 12 hour mode when set */ > +FIELD(HOUR, SET12, 6, 1) > +/* 00-23 */ > +FIELD(HOUR, HOUR24, 0, 6) > +FIELD(HOUR, AMPM, 5, 1) > +/* 1-12 (not 0-11!) */ > +FIELD(HOUR, HOUR12, 0, 5) > + > +/* 1-12 */ > +FIELD(MONTH, MONTH, 0, 5) > +FIELD(MONTH, CENTURY, 7, 1) > + > +typedef struct DSRTCInfo { > + /* if bit 7 of the Month register is set after Y2K */ > + bool has_century; > + /* address of first non-volatile memory cell. > + * nv_start >= reg_end means no NV memory. > + */ > + uint8_t nv_start; > + /* total size of register range. When address counter rolls over. */ > + uint8_t reg_size; > +} DSRTCInfo; > + > +typedef struct DSRTCState { > + I2CSlave parent_obj; > + > + const DSRTCInfo *info; > + > + qemu_irq alarm_irq; > + > + /* register address counter */ > + uint8_t addr; > + /* when writing, whether the address has been sent */ > + bool addrd; > + > + int64_t time_offset; > + int8_t wday_offset; > + > + uint8_t regs[DSRTC_REGSIZE]; > +} DSRTCState; > + > +typedef struct DSRTCClass { > + I2CSlaveClass parent_class; > + > + const DSRTCInfo *info; > +} DSRTCClass; > + > +#define TYPE_DSRTC "ds-rtc-i2c" > +#define DSRTC(obj) OBJECT_CHECK(DSRTCState, (obj), TYPE_DSRTC) > +#define DSRTC_GET_CLASS(obj) \ > + OBJECT_GET_CLASS(DSRTCClass, obj, TYPE_DSRTC) > +#define DSRTC_CLASS(klass) \ > + OBJECT_CLASS_CHECK(DSRTCClass, klass, TYPE_DSRTC) > + > +static const VMStateDescription vmstate_dsrtc = { > + .name = TYPE_DSRTC, > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_I2C_SLAVE(parent_obj, DSRTCState), > + VMSTATE_INT64(time_offset, DSRTCState), > + VMSTATE_INT8_V(wday_offset, DSRTCState, 2), > + VMSTATE_UINT8_ARRAY(regs, DSRTCState, DSRTC_REGSIZE), > + VMSTATE_UINT8(addr, DSRTCState), > + VMSTATE_BOOL(addrd, DSRTCState), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static void dsrtc_reset(DeviceState *device); > + > +/* update current time registers */ > +static > +void dsrtc_latch(DSRTCState *ds) > +{ > + struct tm now; > + bool use12; > + > + qemu_get_timedate(&now, ds->time_offset); > + > + DPRINTK("Current Time %3u/%2u/%u %2u:%2u:%2u (wday %u)", > + now.tm_year, now.tm_mon, now.tm_mday, > + now.tm_hour, now.tm_min, now.tm_sec, > + now.tm_wday); > + > + use12 = ARRAY_FIELD_EX32(ds->regs, HOUR, SET12); > + > + /* ensure unused bits are zero */ > + memset(ds->regs, 0, R_YEAR + 1); > + > + ds->regs[R_SEC] = to_bcd(now.tm_sec); > + ds->regs[R_MIN] = to_bcd(now.tm_min); > + > + if (!use12) { > + /* 24 hour (0-23) */ > + ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR24, to_bcd(now.tm_hour)); > + } else { > + /* 12 hour am/pm (1-12) */ > + ARRAY_FIELD_DP32(ds->regs, HOUR, SET12, 1); > + ARRAY_FIELD_DP32(ds->regs, HOUR, AMPM, now.tm_hour >= 12u); > + ARRAY_FIELD_DP32(ds->regs, HOUR, HOUR12, > + to_bcd(1u + (now.tm_hour % 12u))); > + } > + > + ds->regs[R_WDAY] = (now.tm_wday + ds->wday_offset) % 7u + 1u; > + ds->regs[R_DATE] = to_bcd(now.tm_mday); > + > + ARRAY_FIELD_DP32(ds->regs, MONTH, MONTH, to_bcd(now.tm_mon + 1)); > + if (ds->info->has_century) { > + ARRAY_FIELD_DP32(ds->regs, MONTH, CENTURY, now.tm_year >= 100u); > + } > + > + ds->regs[R_YEAR] = to_bcd(now.tm_year % 100u); > + > + DPRINTK("Latched time"); > +} > + > +/* call after guest writes to current time registers > + * to re-compute our offset from host time. > + */ > +static > +void dsrtc_update(DSRTCState *ds) > +{ > + int user_wday; > + struct tm now; > + > + now.tm_sec = from_bcd(ds->regs[R_SEC]); > + now.tm_min = from_bcd(ds->regs[R_MIN]); > + > + if (ARRAY_FIELD_EX32(ds->regs, HOUR, SET12)) { > + /* 12 hour (1-12) */ > + now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR12)) - > 1u; > + if (ARRAY_FIELD_EX32(ds->regs, HOUR, AMPM)) { > + now.tm_hour += 12; > + } > + > + } else { > + /* 23 hour (0-23) */ > + now.tm_hour = from_bcd(ARRAY_FIELD_EX32(ds->regs, HOUR, HOUR24)); > + } > + > + now.tm_wday = from_bcd(ds->regs[R_WDAY]) - 1u; > + now.tm_mday = from_bcd(ds->regs[R_DATE]); > + now.tm_mon = from_bcd(ARRAY_FIELD_EX32(ds->regs, MONTH, MONTH)) - 1; > + > + now.tm_year = from_bcd(ds->regs[R_YEAR]); > + if (ARRAY_FIELD_EX32(ds->regs, MONTH, CENTURY) || > !ds->info->has_century) { > + now.tm_year += 100; > + } > + > + DPRINTK("New Time %3u/%2u/%u %2u:%2u:%2u (wday %u)", > + now.tm_year, now.tm_mon, now.tm_mday, > + now.tm_hour, now.tm_min, now.tm_sec, > + now.tm_wday); > + > + /* round trip to get real wday_offset based on time delta */ > + user_wday = now.tm_wday; > + ds->time_offset = qemu_timedate_diff(&now); > + /* race possible if we run at midnight > + * TODO: make qemu_timedate_diff() calculate wday offset as well? > + */ > + qemu_get_timedate(&now, ds->time_offset); > + /* calculate wday_offset to achieve guest requested wday */ > + ds->wday_offset = user_wday - now.tm_wday; > + > + DPRINTK("Update offset = %" PRId64 ", wday_offset = %d", > + ds->time_offset, ds->wday_offset); > +} > + > +static > +void dsrtc_advance(DSRTCState *ds) > +{ > + ds->addr = (ds->addr + 1) % ds->info->reg_size; > + if (ds->addr == 0) { > + /* latch time on roll over */ > + dsrtc_latch(ds); > + } > +} > + > +static > +int dsrtc_event(I2CSlave *s, enum i2c_event event) > +{ > + DSRTCState *ds = DSRTC(s); > + > + switch (event) { > + case I2C_START_SEND: > + ds->addrd = false; > + /* fall through */ > + case I2C_START_RECV: > + dsrtc_latch(ds); > + /* fall through */ > + case I2C_FINISH: > + DPRINTK("Event %d", (int)event); > + /* fall through */ > + case I2C_NACK: > + break; > + } > + return 0; > +} > + > +static > +int dsrtc_recv(I2CSlave *s) > +{ > + DSRTCState *ds = DSRTC(s); > + int ret = 0; > + > + ret = ds->regs[ds->addr]; > + > + if (ds->addr > R_YEAR && ds->addr < ds->info->nv_start) { > + LOG(LOG_UNIMP, "Read from unimplemented (%02x) %02x", ds->addr, ret); > + } > + > + DPRINTK("Recv (%02x) %02x", ds->addr, ret); > + > + dsrtc_advance(ds); > + > + return ret; > +} > + > +static > +int dsrtc_send(I2CSlave *s, uint8_t data) > +{ > + DSRTCState *ds = DSRTC(s); > + > + if (!ds->addrd) { > + if (data == 0xff && qtest_enabled()) { > + /* allow test runner to zero offsets */ > + DPRINTK("Testing reset"); > + dsrtc_reset(DEVICE(s)); > + return 0; > + } > + ds->addr = data % DSRTC_REGSIZE; > + ds->addrd = true; > + DPRINTK("Set address pointer %02x", data); > + return 0; > + } > + > + DPRINTK("Send (%02x) %02x", ds->addr, data); > + > + if (ds->addr <= R_YEAR) { > + ds->regs[ds->addr] = data; > + dsrtc_update(ds); > + > + } else if (ds->addr >= ds->info->nv_start) { > + ds->regs[ds->addr] = data; > + > + } else { > + LOG(LOG_UNIMP, "Register not modeled"); > + } > + > + dsrtc_advance(ds); > + > + return 0; > +} > + > +static > +void dsrtc_reset(DeviceState *device) > +{ > + DSRTCState *ds = DSRTC(device); > + > + memset(ds->regs, 0, sizeof(ds->regs)); > + > + ds->addr = 0; > + ds->addrd = false; > + ds->time_offset = 0; > + ds->wday_offset = 0; > + > + DPRINTK("Reset"); > +} > + > +static > +void dsrtc_realize(DeviceState *device, Error **errp) > +{ > + DSRTCState *ds = DSRTC(device); > + DSRTCClass *r = DSRTC_GET_CLASS(device); > + > + ds->info = r->info; > + > + /* Alarms not yet implemented, but allow > + * board code to wire up the alarm interrupt > + * output anyway. > + */ > + qdev_init_gpio_out(device, &ds->alarm_irq, 1); > +} > + > +static > +void dsrtc_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); > + DSRTCClass *r = DSRTC_CLASS(klass); > + > + r->info = data; > + > + k->event = &dsrtc_event; > + k->recv = &dsrtc_recv; > + k->send = &dsrtc_send; > + > + dc->vmsd = &vmstate_dsrtc; > + dc->realize = dsrtc_realize; > + dc->reset = dsrtc_reset; > + dc->user_creatable = true; > +} > + > +static > +const TypeInfo ds_rtc_base_type = { > + .abstract = true, > + .name = TYPE_DSRTC, > + .parent = TYPE_I2C_SLAVE, > + .instance_size = sizeof(DSRTCState), > +}; > + > +#define DSRTC_CONFIG(NAME) \ > +static const TypeInfo NAME##_type = { \ > + .name = #NAME, \ > + .parent = TYPE_DSRTC, \ > + .class_size = sizeof(I2CSlaveClass), \ > + .class_init = dsrtc_class_init, \ > + .class_data = (void *)&NAME##_info, \ > +}; > + > +/* ds3231 - alarms, no eeprom */ > +static const DSRTCInfo ds3231_info = { > + .has_century = true, > + .nv_start = 0x13, /* no nv memory */ > + .reg_size = 0x13, > +}; > +DSRTC_CONFIG(ds3231) > + > +/* only model block 0 (RTC), blocks 1,2 (eeprom) not modeled. > + * blocks have different i2c addresses > + */ > +static const DSRTCInfo ds1388_info = { > + .has_century = false, > + .nv_start = 0x0d, > + .reg_size = 0x0d, > +}; > +DSRTC_CONFIG(ds1388) > + > +/* alarms, eeprom */ > +static const DSRTCInfo ds1375_info = { > + .has_century = true, > + .nv_start = 0x10, > + .reg_size = 0x20, > +}; > +DSRTC_CONFIG(ds1375) > + > +/* no alarms, no eeprom */ > +static const DSRTCInfo ds1340_info = { > + .has_century = false, > + .nv_start = 0x10, > + .reg_size = 0x10, > +}; > +DSRTC_CONFIG(ds1340) > + > +/* alarms, no eeprom */ > +static const DSRTCInfo ds1339_info = { > + .has_century = false, > + .nv_start = 0x11, > + .reg_size = 0x11, > +}; > +DSRTC_CONFIG(ds1339) > + > +/* no alarms, eeprom */ > +static const DSRTCInfo ds1338_info = { > + .has_century = false, > + .nv_start = 0x08, > + .reg_size = 0x40, > +}; > +DSRTC_CONFIG(ds1338) > + > +/* alarms, no eeprom */ > +static const DSRTCInfo ds1337_info = { > + .has_century = true, > + .nv_start = 0x10, > + .reg_size = 0x10, > +}; > +DSRTC_CONFIG(ds1337) > + > +/* ds1307 registers are identical to ds1338 */ > +static > +const TypeInfo ds1307_type = { > + .name = "ds1307", > + .parent = "ds1338", > +}; > + > +static void ds_rtc_i2c_register(void) > +{ > + type_register_static(&ds_rtc_base_type); > + type_register_static(&ds3231_type); > + type_register_static(&ds1388_type); > + type_register_static(&ds1375_type); > + type_register_static(&ds1340_type); > + type_register_static(&ds1339_type); > + type_register_static(&ds1338_type); > + type_register_static(&ds1337_type); > + type_register_static(&ds1307_type); > +} > + > +type_init(ds_rtc_i2c_register) > diff --git a/hw/timer/ds1338.c b/hw/timer/ds1338.c > deleted file mode 100644 > index 3849b74a68..0000000000 > --- a/hw/timer/ds1338.c > +++ /dev/null > @@ -1,239 +0,0 @@ > -/* > - * MAXIM DS1338 I2C RTC+NVRAM > - * > - * Copyright (c) 2009 CodeSourcery. > - * Written by Paul Brook > - * > - * This code is licensed under the GNU GPL v2. > - * > - * Contributions after 2012-01-13 are licensed under the terms of the > - * GNU GPL, version 2 or (at your option) any later version. > - */ > - > -#include "qemu/osdep.h" > -#include "qemu-common.h" > -#include "hw/i2c/i2c.h" > -#include "qemu/bcd.h" > - > -/* Size of NVRAM including both the user-accessible area and the > - * secondary register area. > - */ > -#define NVRAM_SIZE 64 > - > -/* Flags definitions */ > -#define SECONDS_CH 0x80 > -#define HOURS_12 0x40 > -#define HOURS_PM 0x20 > -#define CTRL_OSF 0x20 > - > -#define TYPE_DS1338 "ds1338" > -#define DS1338(obj) OBJECT_CHECK(DS1338State, (obj), TYPE_DS1338) > - > -typedef struct DS1338State { > - I2CSlave parent_obj; > - > - int64_t offset; > - uint8_t wday_offset; > - uint8_t nvram[NVRAM_SIZE]; > - int32_t ptr; > - bool addr_byte; > -} DS1338State; > - > -static const VMStateDescription vmstate_ds1338 = { > - .name = "ds1338", > - .version_id = 2, > - .minimum_version_id = 1, > - .fields = (VMStateField[]) { > - VMSTATE_I2C_SLAVE(parent_obj, DS1338State), > - VMSTATE_INT64(offset, DS1338State), > - VMSTATE_UINT8_V(wday_offset, DS1338State, 2), > - VMSTATE_UINT8_ARRAY(nvram, DS1338State, NVRAM_SIZE), > - VMSTATE_INT32(ptr, DS1338State), > - VMSTATE_BOOL(addr_byte, DS1338State), > - VMSTATE_END_OF_LIST() > - } > -}; > - > -static void capture_current_time(DS1338State *s) > -{ > - /* Capture the current time into the secondary registers > - * which will be actually read by the data transfer operation. > - */ > - struct tm now; > - qemu_get_timedate(&now, s->offset); > - s->nvram[0] = to_bcd(now.tm_sec); > - s->nvram[1] = to_bcd(now.tm_min); > - if (s->nvram[2] & HOURS_12) { > - int tmp = now.tm_hour; > - if (tmp % 12 == 0) { > - tmp += 12; > - } > - if (tmp <= 12) { > - s->nvram[2] = HOURS_12 | to_bcd(tmp); > - } else { > - s->nvram[2] = HOURS_12 | HOURS_PM | to_bcd(tmp - 12); > - } > - } else { > - s->nvram[2] = to_bcd(now.tm_hour); > - } > - s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1; > - s->nvram[4] = to_bcd(now.tm_mday); > - s->nvram[5] = to_bcd(now.tm_mon + 1); > - s->nvram[6] = to_bcd(now.tm_year - 100); > -} > - > -static void inc_regptr(DS1338State *s) > -{ > - /* The register pointer wraps around after 0x3F; wraparound > - * causes the current time/date to be retransferred into > - * the secondary registers. > - */ > - s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1); > - if (!s->ptr) { > - capture_current_time(s); > - } > -} > - > -static int ds1338_event(I2CSlave *i2c, enum i2c_event event) > -{ > - DS1338State *s = DS1338(i2c); > - > - switch (event) { > - case I2C_START_RECV: > - /* In h/w, capture happens on any START condition, not just a > - * START_RECV, but there is no need to actually capture on > - * START_SEND, because the guest can't get at that data > - * without going through a START_RECV which would overwrite it. > - */ > - capture_current_time(s); > - break; > - case I2C_START_SEND: > - s->addr_byte = true; > - break; > - default: > - break; > - } > - > - return 0; > -} > - > -static int ds1338_recv(I2CSlave *i2c) > -{ > - DS1338State *s = DS1338(i2c); > - uint8_t res; > - > - res = s->nvram[s->ptr]; > - inc_regptr(s); > - return res; > -} > - > -static int ds1338_send(I2CSlave *i2c, uint8_t data) > -{ > - DS1338State *s = DS1338(i2c); > - > - if (s->addr_byte) { > - s->ptr = data & (NVRAM_SIZE - 1); > - s->addr_byte = false; > - return 0; > - } > - if (s->ptr < 7) { > - /* Time register. */ > - struct tm now; > - qemu_get_timedate(&now, s->offset); > - switch(s->ptr) { > - case 0: > - /* TODO: Implement CH (stop) bit. */ > - now.tm_sec = from_bcd(data & 0x7f); > - break; > - case 1: > - now.tm_min = from_bcd(data & 0x7f); > - break; > - case 2: > - if (data & HOURS_12) { > - int tmp = from_bcd(data & (HOURS_PM - 1)); > - if (data & HOURS_PM) { > - tmp += 12; > - } > - if (tmp % 12 == 0) { > - tmp -= 12; > - } > - now.tm_hour = tmp; > - } else { > - now.tm_hour = from_bcd(data & (HOURS_12 - 1)); > - } > - break; > - case 3: > - { > - /* The day field is supposed to contain a value in > - the range 1-7. Otherwise behavior is undefined. > - */ > - int user_wday = (data & 7) - 1; > - s->wday_offset = (user_wday - now.tm_wday + 7) % 7; > - } > - break; > - case 4: > - now.tm_mday = from_bcd(data & 0x3f); > - break; > - case 5: > - now.tm_mon = from_bcd(data & 0x1f) - 1; > - break; > - case 6: > - now.tm_year = from_bcd(data) + 100; > - break; > - } > - s->offset = qemu_timedate_diff(&now); > - } else if (s->ptr == 7) { > - /* Control register. */ > - > - /* Ensure bits 2, 3 and 6 will read back as zero. */ > - data &= 0xB3; > - > - /* Attempting to write the OSF flag to logic 1 leaves the > - value unchanged. */ > - data = (data & ~CTRL_OSF) | (data & s->nvram[s->ptr] & CTRL_OSF); > - > - s->nvram[s->ptr] = data; > - } else { > - s->nvram[s->ptr] = data; > - } > - inc_regptr(s); > - return 0; > -} > - > -static void ds1338_reset(DeviceState *dev) > -{ > - DS1338State *s = DS1338(dev); > - > - /* The clock is running and synchronized with the host */ > - s->offset = 0; > - s->wday_offset = 0; > - memset(s->nvram, 0, NVRAM_SIZE); > - s->ptr = 0; > - s->addr_byte = false; > -} > - > -static void ds1338_class_init(ObjectClass *klass, void *data) > -{ > - DeviceClass *dc = DEVICE_CLASS(klass); > - I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); > - > - k->event = ds1338_event; > - k->recv = ds1338_recv; > - k->send = ds1338_send; > - dc->reset = ds1338_reset; > - dc->vmsd = &vmstate_ds1338; > -} > - > -static const TypeInfo ds1338_info = { > - .name = TYPE_DS1338, > - .parent = TYPE_I2C_SLAVE, > - .instance_size = sizeof(DS1338State), > - .class_init = ds1338_class_init, > -}; > - > -static void ds1338_register_types(void) > -{ > - type_register_static(&ds1338_info); > -} > - > -type_init(ds1338_register_types) -- David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson
signature.asc
Description: PGP signature