* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
#include "hw.h"
+#include "sysbus.h"
#include "escc.h"
#include "qemu-char.h"
#include "console.h"
-
-/* debug serial */
-//#define DEBUG_SERIAL
-
-/* debug keyboard */
-//#define DEBUG_KBD
-
-/* debug mouse */
-//#define DEBUG_MOUSE
+#include "trace.h"
/*
+ * Chipset docs:
+ * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
+ * http://www.zilog.com/docs/serial/scc_escc_um.pdf
+ *
* On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
* (Slave I/O), also produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
* 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
* serial mouse queue.
* Implemented serial mouse protocol.
+ *
+ * 2010-May-23 Artyom Tarasenko: Reworked IUS logic
*/
-#ifdef DEBUG_SERIAL
-#define SER_DPRINTF(fmt, ...) \
- do { printf("SER: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define SER_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_KBD
-#define KBD_DPRINTF(fmt, ...) \
- do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define KBD_DPRINTF(fmt, ...)
-#endif
-#ifdef DEBUG_MOUSE
-#define MS_DPRINTF(fmt, ...) \
- do { printf("MSC: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define MS_DPRINTF(fmt, ...)
-#endif
-
typedef enum {
chn_a, chn_b,
-} chn_id_t;
+} ChnID;
#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
typedef enum {
ser, kbd, mouse,
-} chn_type_t;
+} ChnType;
#define SERIO_QUEUE_SIZE 256
#define SERIAL_REGS 16
typedef struct ChannelState {
qemu_irq irq;
- uint32_t reg;
uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
- chn_id_t chn; // this channel, A (base+4) or B (base+0)
- chn_type_t type;
struct ChannelState *otherchn;
- uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
+ uint32_t reg;
+ uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
SERIOQueue queue;
CharDriverState *chr;
int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
int disabled;
int clock;
+ uint32_t vmstate_dummy;
+ ChnID chn; // this channel, A (base+4) or B (base+0)
+ ChnType type;
+ uint8_t rx, tx;
} ChannelState;
struct SerialState {
+ SysBusDevice busdev;
struct ChannelState chn[2];
- int it_shift;
+ uint32_t it_shift;
+ MemoryRegion mmio;
+ uint32_t disabled;
+ uint32_t frequency;
};
#define SERIAL_CTRL 0
ChannelState *s = opaque;
SERIOQueue *q = &s->queue;
- SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
+ trace_escc_put_queue(CHN_C(s), b);
if (q->count >= SERIO_QUEUE_SIZE)
return;
q->data[q->wptr] = b;
q->rptr = 0;
q->count--;
}
- SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+ trace_escc_get_queue(CHN_C(s), val);
if (q->count > 0)
serial_receive_byte(s, 0);
return val;
static int escc_update_irq_chn(ChannelState *s)
{
- if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
+ if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
// tx ints enabled, pending
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
irq = escc_update_irq_chn(s);
irq |= escc_update_irq_chn(s->otherchn);
- SER_DPRINTF("IRQ = %d\n", irq);
+ trace_escc_update_irq(irq);
qemu_set_irq(s->irq, irq);
}
clear_queue(s);
}
-static void escc_reset(void *opaque)
+static void escc_reset(DeviceState *d)
{
- SerialState *s = opaque;
+ SerialState *s = container_of(d, SerialState, busdev.qdev);
+
escc_reset_chn(&s->chn[0]);
escc_reset_chn(&s->chn[1]);
}
static inline void set_rxint(ChannelState *s)
{
s->rxint = 1;
- if (!s->txint_under_svc) {
- s->rxint_under_svc = 1;
- if (s->chn == chn_a) {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
- else
- s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
- } else {
- if (s->wregs[W_MINTR] & MINTR_STATUSHI)
- s->rregs[R_IVEC] = IVEC_HIRXINTB;
- else
- s->rregs[R_IVEC] = IVEC_LORXINTB;
- }
- }
- if (s->chn == chn_a)
+ /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
+ than chn_a rx/tx/special_condition service*/
+ s->rxint_under_svc = 1;
+ if (s->chn == chn_a) {
s->rregs[R_INTR] |= INTR_RXINTA;
- else
+ if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+ s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
+ else
+ s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
+ } else {
s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
+ if (s->wregs[W_MINTR] & MINTR_STATUSHI)
+ s->rregs[R_IVEC] = IVEC_HIRXINTB;
+ else
+ s->rregs[R_IVEC] = IVEC_LORXINTB;
+ }
escc_update_irq(s);
}
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
if (s->chn == chn_a) {
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->rregs[R_INTR] |= INTR_TXINTA;
+ }
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
+ if (s->wregs[W_INTR] & INTR_TXINT) {
+ s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
+ }
}
- }
- if (s->chn == chn_a)
- s->rregs[R_INTR] |= INTR_TXINTA;
- else
- s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
escc_update_irq(s);
+ }
}
static inline void clr_rxint(ChannelState *s)
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
s->rregs[R_INTR] &= ~INTR_TXINTA;
} else {
+ s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->rregs[R_IVEC] = IVEC_HINOINT;
else
ssp.parity = parity;
ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits;
- SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
- speed, parity, data_bits, stop_bits);
- qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+ trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
+ qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
-static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void escc_mem_write(void *opaque, target_phys_addr_t addr,
+ uint64_t val, unsigned size)
{
SerialState *serial = opaque;
ChannelState *s;
s = &serial->chn[channel];
switch (saddr) {
case SERIAL_CTRL:
- SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
- val & 0xff);
+ trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
newreg = 0;
switch (s->reg) {
case W_CMD:
clr_txint(s);
break;
case CMD_CLR_IUS:
- if (s->rxint_under_svc)
- clr_rxint(s);
- else if (s->txint_under_svc)
- clr_txint(s);
+ if (s->rxint_under_svc) {
+ s->rxint_under_svc = 0;
+ if (s->txint) {
+ set_txint(s);
+ }
+ } else if (s->txint_under_svc) {
+ s->txint_under_svc = 0;
+ }
+ escc_update_irq(s);
break;
default:
break;
escc_reset_chn(&serial->chn[1]);
return;
case MINTR_RST_ALL:
- escc_reset(serial);
+ escc_reset(&serial->busdev.qdev);
return;
}
break;
s->reg = 0;
break;
case SERIAL_DATA:
- SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
+ trace_escc_mem_writeb_data(CHN_C(s), val);
s->tx = val;
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
if (s->chr)
- qemu_chr_write(s->chr, &s->tx, 1);
+ qemu_chr_fe_write(s->chr, &s->tx, 1);
else if (s->type == kbd && !s->disabled) {
handle_kbd_command(s, val);
}
}
}
-static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
+static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
{
SerialState *serial = opaque;
ChannelState *s;
s = &serial->chn[channel];
switch (saddr) {
case SERIAL_CTRL:
- SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
- s->rregs[s->reg]);
+ trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
ret = s->rregs[s->reg];
s->reg = 0;
return ret;
ret = get_queue(s);
else
ret = s->rx;
- SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
+ trace_escc_mem_readb_data(CHN_C(s), ret);
if (s->chr)
qemu_chr_accept_input(s->chr);
return ret;
return 0;
}
+static const MemoryRegionOps escc_mem_ops = {
+ .read = escc_mem_read,
+ .write = escc_mem_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 1,
+ },
+};
+
static int serial_can_receive(void *opaque)
{
ChannelState *s = opaque;
static void serial_receive_byte(ChannelState *s, int ch)
{
- SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
+ trace_escc_serial_receive_byte(CHN_C(s), ch);
s->rregs[R_STATUS] |= STATUS_RXAV;
s->rx = ch;
set_rxint(s);
serial_receive_break(s);
}
-static CPUReadMemoryFunc *escc_mem_read[3] = {
- escc_mem_readb,
- NULL,
- NULL,
-};
-
-static CPUWriteMemoryFunc *escc_mem_write[3] = {
- escc_mem_writeb,
- NULL,
- NULL,
+static const VMStateDescription vmstate_escc_chn = {
+ .name ="escc_chn",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT32(vmstate_dummy, ChannelState),
+ VMSTATE_UINT32(reg, ChannelState),
+ VMSTATE_UINT32(rxint, ChannelState),
+ VMSTATE_UINT32(txint, ChannelState),
+ VMSTATE_UINT32(rxint_under_svc, ChannelState),
+ VMSTATE_UINT32(txint_under_svc, ChannelState),
+ VMSTATE_UINT8(rx, ChannelState),
+ VMSTATE_UINT8(tx, ChannelState),
+ VMSTATE_BUFFER(wregs, ChannelState),
+ VMSTATE_BUFFER(rregs, ChannelState),
+ VMSTATE_END_OF_LIST()
+ }
};
-static void escc_save_chn(QEMUFile *f, ChannelState *s)
-{
- uint32_t tmp = 0;
-
- qemu_put_be32s(f, &tmp); /* unused, was IRQ. */
- qemu_put_be32s(f, &s->reg);
- qemu_put_be32s(f, &s->rxint);
- qemu_put_be32s(f, &s->txint);
- qemu_put_be32s(f, &s->rxint_under_svc);
- qemu_put_be32s(f, &s->txint_under_svc);
- qemu_put_8s(f, &s->rx);
- qemu_put_8s(f, &s->tx);
- qemu_put_buffer(f, s->wregs, SERIAL_REGS);
- qemu_put_buffer(f, s->rregs, SERIAL_REGS);
-}
-
-static void escc_save(QEMUFile *f, void *opaque)
-{
- SerialState *s = opaque;
-
- escc_save_chn(f, &s->chn[0]);
- escc_save_chn(f, &s->chn[1]);
-}
-
-static int escc_load_chn(QEMUFile *f, ChannelState *s, int version_id)
-{
- uint32_t tmp;
-
- if (version_id > 2)
- return -EINVAL;
-
- qemu_get_be32s(f, &tmp); /* unused */
- qemu_get_be32s(f, &s->reg);
- qemu_get_be32s(f, &s->rxint);
- qemu_get_be32s(f, &s->txint);
- if (version_id >= 2) {
- qemu_get_be32s(f, &s->rxint_under_svc);
- qemu_get_be32s(f, &s->txint_under_svc);
+static const VMStateDescription vmstate_escc = {
+ .name ="escc",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
+ ChannelState),
+ VMSTATE_END_OF_LIST()
}
- qemu_get_8s(f, &s->rx);
- qemu_get_8s(f, &s->tx);
- qemu_get_buffer(f, s->wregs, SERIAL_REGS);
- qemu_get_buffer(f, s->rregs, SERIAL_REGS);
- return 0;
-}
-
-static int escc_load(QEMUFile *f, void *opaque, int version_id)
-{
- SerialState *s = opaque;
- int ret;
-
- ret = escc_load_chn(f, &s->chn[0], version_id);
- if (ret != 0)
- return ret;
- ret = escc_load_chn(f, &s->chn[1], version_id);
- return ret;
-
-}
+};
-int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
+MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
CharDriverState *chrA, CharDriverState *chrB,
int clock, int it_shift)
{
- int escc_io_memory, i;
- SerialState *s;
-
- s = qemu_mallocz(sizeof(SerialState));
-
- escc_io_memory = cpu_register_io_memory(escc_mem_read,
- escc_mem_write,
- s);
- if (base)
- cpu_register_physical_memory(base, ESCC_SIZE << it_shift,
- escc_io_memory);
-
- s->it_shift = it_shift;
- s->chn[0].chr = chrB;
- s->chn[1].chr = chrA;
- s->chn[0].disabled = 0;
- s->chn[1].disabled = 0;
- s->chn[0].irq = irqB;
- s->chn[1].irq = irqA;
-
- for (i = 0; i < 2; i++) {
- s->chn[i].chn = 1 - i;
- s->chn[i].type = ser;
- s->chn[i].clock = clock / 2;
- if (s->chn[i].chr) {
- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
- serial_receive1, serial_event, &s->chn[i]);
- }
+ DeviceState *dev;
+ SysBusDevice *s;
+ SerialState *d;
+
+ dev = qdev_create(NULL, "escc");
+ qdev_prop_set_uint32(dev, "disabled", 0);
+ qdev_prop_set_uint32(dev, "frequency", clock);
+ qdev_prop_set_uint32(dev, "it_shift", it_shift);
+ qdev_prop_set_chr(dev, "chrB", chrB);
+ qdev_prop_set_chr(dev, "chrA", chrA);
+ qdev_prop_set_uint32(dev, "chnBtype", ser);
+ qdev_prop_set_uint32(dev, "chnAtype", ser);
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ sysbus_connect_irq(s, 0, irqB);
+ sysbus_connect_irq(s, 1, irqA);
+ if (base) {
+ sysbus_mmio_map(s, 0, base);
}
- s->chn[0].otherchn = &s->chn[1];
- s->chn[1].otherchn = &s->chn[0];
- if (base)
- register_savevm("escc", base, 2, escc_save, escc_load, s);
- else
- register_savevm("escc", -1, 2, escc_save, escc_load, s);
- qemu_register_reset(escc_reset, 0, s);
- escc_reset(s);
- return escc_io_memory;
+
+ d = FROM_SYSBUS(SerialState, s);
+ return &d->mmio;
}
static const uint8_t keycodes[128] = {
ChannelState *s = opaque;
int release = ch & 0x80;
- KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
- "press");
+ trace_escc_sunkbd_event_in(ch);
switch (ch) {
case 58: // Caps lock press
s->caps_lock_mode ^= 1;
} else {
ch = keycodes[ch & 0x7f];
}
- KBD_DPRINTF("Translated keycode %2.2x\n", ch);
+ trace_escc_sunkbd_event_out(ch);
put_queue(s, ch | release);
}
static void handle_kbd_command(ChannelState *s, int val)
{
- KBD_DPRINTF("Command %d\n", val);
+ trace_escc_kbd_command(val);
if (s->led_mode) { // Ignore led byte
s->led_mode = 0;
return;
ChannelState *s = opaque;
int ch;
- MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
-
+ trace_escc_sunmouse_event(dx, dy, buttons_state);
ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
if (buttons_state & MOUSE_EVENT_LBUTTON)
ch = dx;
if (ch > 127)
- ch=127;
+ ch = 127;
else if (ch < -127)
- ch=-127;
+ ch = -127;
put_queue(s, ch & 0xff);
ch = -dy;
if (ch > 127)
- ch=127;
+ ch = 127;
else if (ch < -127)
- ch=-127;
+ ch = -127;
put_queue(s, ch & 0xff);
void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
int disabled, int clock, int it_shift)
{
- int slavio_serial_io_memory, i;
- SerialState *s;
+ DeviceState *dev;
+ SysBusDevice *s;
+
+ dev = qdev_create(NULL, "escc");
+ qdev_prop_set_uint32(dev, "disabled", disabled);
+ qdev_prop_set_uint32(dev, "frequency", clock);
+ qdev_prop_set_uint32(dev, "it_shift", it_shift);
+ qdev_prop_set_chr(dev, "chrB", NULL);
+ qdev_prop_set_chr(dev, "chrA", NULL);
+ qdev_prop_set_uint32(dev, "chnBtype", mouse);
+ qdev_prop_set_uint32(dev, "chnAtype", kbd);
+ qdev_init_nofail(dev);
+ s = sysbus_from_qdev(dev);
+ sysbus_connect_irq(s, 0, irq);
+ sysbus_connect_irq(s, 1, irq);
+ sysbus_mmio_map(s, 0, base);
+}
- s = qemu_mallocz(sizeof(SerialState));
+static int escc_init1(SysBusDevice *dev)
+{
+ SerialState *s = FROM_SYSBUS(SerialState, dev);
+ unsigned int i;
- s->it_shift = it_shift;
+ s->chn[0].disabled = s->disabled;
+ s->chn[1].disabled = s->disabled;
for (i = 0; i < 2; i++) {
- s->chn[i].irq = irq;
+ sysbus_init_irq(dev, &s->chn[i].irq);
s->chn[i].chn = 1 - i;
- s->chn[i].chr = NULL;
- s->chn[i].clock = clock / 2;
+ s->chn[i].clock = s->frequency / 2;
+ if (s->chn[i].chr) {
+ qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+ serial_receive1, serial_event, &s->chn[i]);
+ }
}
s->chn[0].otherchn = &s->chn[1];
s->chn[1].otherchn = &s->chn[0];
- s->chn[0].type = mouse;
- s->chn[1].type = kbd;
- s->chn[0].disabled = disabled;
- s->chn[1].disabled = disabled;
-
- slavio_serial_io_memory = cpu_register_io_memory(escc_mem_read,
- escc_mem_write,
- s);
- cpu_register_physical_memory(base, ESCC_SIZE << it_shift,
- slavio_serial_io_memory);
-
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
- "QEMU Sun Mouse");
- qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
- register_savevm("slavio_serial_mouse", base, 2, escc_save, escc_load, s);
- qemu_register_reset(escc_reset, 0, s);
- escc_reset(s);
+
+ memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
+ ESCC_SIZE << s->it_shift);
+ sysbus_init_mmio(dev, &s->mmio);
+
+ if (s->chn[0].type == mouse) {
+ qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
+ "QEMU Sun Mouse");
+ }
+ if (s->chn[1].type == kbd) {
+ qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+ }
+
+ return 0;
}
+
+static Property escc_properties[] = {
+ DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
+ DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
+ DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
+ DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
+ DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
+ DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void escc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = escc_init1;
+ dc->reset = escc_reset;
+ dc->vmsd = &vmstate_escc;
+ dc->props = escc_properties;
+}
+
+static TypeInfo escc_info = {
+ .name = "escc",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SerialState),
+ .class_init = escc_class_init,
+};
+
+static void escc_register_types(void)
+{
+ type_register_static(&escc_info);
+}
+
+type_init(escc_register_types)