26
#include "qemu/osdep.h"
27
#include "hw/isa/pc87312.h"
28
#include "hw/qdev-properties.h"
29
#include "migration/vmstate.h"
30
#include "qapi/error.h"
31
#include "qemu/error-report.h"
32
#include "qemu/module.h"
40
#define FER_PARALLEL_EN 0x01
41
#define FER_UART1_EN 0x02
42
#define FER_UART2_EN 0x04
43
#define FER_FDC_EN 0x08
45
#define FER_FDC_ADDR 0x20
46
#define FER_IDE_EN 0x40
47
#define FER_IDE_ADDR 0x80
49
#define FAR_PARALLEL_ADDR 0x03
50
#define FAR_UART1_ADDR 0x0C
51
#define FAR_UART2_ADDR 0x30
52
#define FAR_UART_3_4 0xC0
54
#define PTR_POWER_DOWN 0x01
55
#define PTR_CLOCK_DOWN 0x02
57
#define PTR_IRQ_5_7 0x08
58
#define PTR_UART1_TEST 0x10
59
#define PTR_UART2_TEST 0x20
60
#define PTR_LOCK_CONF 0x40
61
#define PTR_EPP_MODE 0x80
66
static bool is_parallel_enabled(ISASuperIODevice *sio, uint8_t index)
68
PC87312State *s = PC87312(sio);
69
return index ? false : s->regs[REG_FER] & FER_PARALLEL_EN;
72
static const uint16_t parallel_base[] = { 0x378, 0x3bc, 0x278, 0x00 };
74
static uint16_t get_parallel_iobase(ISASuperIODevice *sio, uint8_t index)
76
PC87312State *s = PC87312(sio);
77
return parallel_base[s->regs[REG_FAR] & FAR_PARALLEL_ADDR];
80
static const unsigned int parallel_irq[] = { 5, 7, 5, 0 };
82
static unsigned int get_parallel_irq(ISASuperIODevice *sio, uint8_t index)
84
PC87312State *s = PC87312(sio);
86
idx = (s->regs[REG_FAR] & FAR_PARALLEL_ADDR);
88
return (s->regs[REG_PTR] & PTR_IRQ_5_7) ? 7 : 5;
90
return parallel_irq[idx];
97
static const uint16_t uart_base[2][4] = {
98
{ 0x3e8, 0x338, 0x2e8, 0x220 },
99
{ 0x2e8, 0x238, 0x2e0, 0x228 }
102
static uint16_t get_uart_iobase(ISASuperIODevice *sio, uint8_t i)
104
PC87312State *s = PC87312(sio);
106
idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
109
} else if (idx == 1) {
112
return uart_base[idx & 1][(s->regs[REG_FAR] & FAR_UART_3_4) >> 6];
116
static unsigned int get_uart_irq(ISASuperIODevice *sio, uint8_t i)
118
PC87312State *s = PC87312(sio);
120
idx = (s->regs[REG_FAR] >> (2 * i + 2)) & 0x3;
121
return (idx & 1) ? 3 : 4;
124
static bool is_uart_enabled(ISASuperIODevice *sio, uint8_t i)
126
PC87312State *s = PC87312(sio);
127
return s->regs[REG_FER] & (FER_UART1_EN << i);
133
static bool is_fdc_enabled(ISASuperIODevice *sio, uint8_t index)
135
PC87312State *s = PC87312(sio);
137
return s->regs[REG_FER] & FER_FDC_EN;
140
static uint16_t get_fdc_iobase(ISASuperIODevice *sio, uint8_t index)
142
PC87312State *s = PC87312(sio);
144
return (s->regs[REG_FER] & FER_FDC_ADDR) ? 0x370 : 0x3f0;
147
static unsigned int get_fdc_irq(ISASuperIODevice *sio, uint8_t index)
156
static bool is_ide_enabled(ISASuperIODevice *sio, uint8_t index)
158
PC87312State *s = PC87312(sio);
160
return s->regs[REG_FER] & FER_IDE_EN;
163
static uint16_t get_ide_iobase(ISASuperIODevice *sio, uint8_t index)
165
PC87312State *s = PC87312(sio);
168
return get_ide_iobase(sio, 0) + 0x206;
170
return (s->regs[REG_FER] & FER_IDE_ADDR) ? 0x170 : 0x1f0;
173
static unsigned int get_ide_irq(ISASuperIODevice *sio, uint8_t index)
179
static void reconfigure_devices(PC87312State *s)
181
error_report("pc87312: unsupported device reconfiguration (%02x %02x %02x)",
182
s->regs[REG_FER], s->regs[REG_FAR], s->regs[REG_PTR]);
185
static void pc87312_soft_reset(PC87312State *s)
187
static const uint8_t fer_init[] = {
188
0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4b, 0x4b,
189
0x4b, 0x4b, 0x4b, 0x4b, 0x0f, 0x0f, 0x0f, 0x0f,
190
0x49, 0x49, 0x49, 0x49, 0x07, 0x07, 0x07, 0x07,
191
0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x08, 0x00,
193
static const uint8_t far_init[] = {
194
0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x00, 0x01,
195
0x01, 0x09, 0x08, 0x08, 0x10, 0x11, 0x39, 0x24,
196
0x00, 0x01, 0x01, 0x00, 0x10, 0x11, 0x39, 0x24,
197
0x10, 0x11, 0x11, 0x39, 0x24, 0x38, 0x10, 0x10,
199
static const uint8_t ptr_init[] = {
200
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
202
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
207
s->selected_index = REG_FER;
209
s->regs[REG_FER] = fer_init[s->config & 0x1f];
210
s->regs[REG_FAR] = far_init[s->config & 0x1f];
211
s->regs[REG_PTR] = ptr_init[s->config & 0x1f];
214
static void pc87312_hard_reset(PC87312State *s)
216
pc87312_soft_reset(s);
219
static void pc87312_io_write(void *opaque, hwaddr addr, uint64_t val,
222
PC87312State *s = opaque;
224
trace_pc87312_io_write(addr, val);
226
if ((addr & 1) == 0) {
229
s->selected_index = val;
232
if (s->selected_index < 3) {
233
s->regs[s->selected_index] = val;
234
reconfigure_devices(s);
239
static uint64_t pc87312_io_read(void *opaque, hwaddr addr, unsigned int size)
241
PC87312State *s = opaque;
244
if ((addr & 1) == 0) {
246
if (s->read_id_step++ == 0) {
248
} else if (s->read_id_step++ == 1) {
251
val = s->selected_index;
255
if (s->selected_index < 3) {
256
val = s->regs[s->selected_index];
263
trace_pc87312_io_read(addr, val);
267
static const MemoryRegionOps pc87312_io_ops = {
268
.read = pc87312_io_read,
269
.write = pc87312_io_write,
270
.endianness = DEVICE_LITTLE_ENDIAN,
272
.min_access_size = 1,
273
.max_access_size = 1,
277
static int pc87312_post_load(void *opaque, int version_id)
279
PC87312State *s = opaque;
281
reconfigure_devices(s);
285
static void pc87312_reset(DeviceState *d)
287
PC87312State *s = PC87312(d);
289
pc87312_soft_reset(s);
292
static void pc87312_realize(DeviceState *dev, Error **errp)
296
Error *local_err = NULL;
299
isa = ISA_DEVICE(dev);
300
isa_register_ioport(isa, &s->io, s->iobase);
301
pc87312_hard_reset(s);
303
ISA_SUPERIO_GET_CLASS(dev)->parent_realize(dev, &local_err);
305
error_propagate(errp, local_err);
310
static void pc87312_initfn(Object *obj)
312
PC87312State *s = PC87312(obj);
314
memory_region_init_io(&s->io, obj, &pc87312_io_ops, s, "pc87312", 2);
317
static const VMStateDescription vmstate_pc87312 = {
320
.minimum_version_id = 1,
321
.post_load = pc87312_post_load,
322
.fields = (const VMStateField[]) {
323
VMSTATE_UINT8(read_id_step, PC87312State),
324
VMSTATE_UINT8(selected_index, PC87312State),
325
VMSTATE_UINT8_ARRAY(regs, PC87312State, 3),
326
VMSTATE_END_OF_LIST()
330
static Property pc87312_properties[] = {
331
DEFINE_PROP_UINT16("iobase", PC87312State, iobase, 0x398),
332
DEFINE_PROP_UINT8("config", PC87312State, config, 1),
333
DEFINE_PROP_END_OF_LIST()
336
static void pc87312_class_init(ObjectClass *klass, void *data)
338
DeviceClass *dc = DEVICE_CLASS(klass);
339
ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass);
341
dc->reset = pc87312_reset;
342
dc->vmsd = &vmstate_pc87312;
343
device_class_set_parent_realize(dc, pc87312_realize,
344
&sc->parent_realize);
345
device_class_set_props(dc, pc87312_properties);
347
sc->parallel = (ISASuperIOFuncs){
349
.is_enabled = is_parallel_enabled,
350
.get_iobase = get_parallel_iobase,
351
.get_irq = get_parallel_irq,
353
sc->serial = (ISASuperIOFuncs){
355
.is_enabled = is_uart_enabled,
356
.get_iobase = get_uart_iobase,
357
.get_irq = get_uart_irq,
359
sc->floppy = (ISASuperIOFuncs){
361
.is_enabled = is_fdc_enabled,
362
.get_iobase = get_fdc_iobase,
363
.get_irq = get_fdc_irq,
365
sc->ide = (ISASuperIOFuncs){
367
.is_enabled = is_ide_enabled,
368
.get_iobase = get_ide_iobase,
369
.get_irq = get_ide_irq,
373
static const TypeInfo pc87312_type_info = {
374
.name = TYPE_PC87312,
375
.parent = TYPE_ISA_SUPERIO,
376
.instance_size = sizeof(PC87312State),
377
.instance_init = pc87312_initfn,
378
.class_init = pc87312_class_init,
382
static void pc87312_register_types(void)
384
type_register_static(&pc87312_type_info);
387
type_init(pc87312_register_types)