Statistics
| Branch: | Revision:

root / hw / ipoctal232.c @ 9a6ee9fd

History | View | Annotate | Download (16.5 kB)

1 be657dea Alberto Garcia
/*
2 be657dea Alberto Garcia
 * QEMU GE IP-Octal 232 IndustryPack emulation
3 be657dea Alberto Garcia
 *
4 be657dea Alberto Garcia
 * Copyright (C) 2012 Igalia, S.L.
5 be657dea Alberto Garcia
 * Author: Alberto Garcia <agarcia@igalia.com>
6 be657dea Alberto Garcia
 *
7 be657dea Alberto Garcia
 * This code is licensed under the GNU GPL v2 or (at your option) any
8 be657dea Alberto Garcia
 * later version.
9 be657dea Alberto Garcia
 */
10 be657dea Alberto Garcia
11 be657dea Alberto Garcia
#include "ipack.h"
12 be657dea Alberto Garcia
#include "qemu/bitops.h"
13 be657dea Alberto Garcia
#include "char/char.h"
14 be657dea Alberto Garcia
15 be657dea Alberto Garcia
/* #define DEBUG_IPOCTAL */
16 be657dea Alberto Garcia
17 be657dea Alberto Garcia
#ifdef DEBUG_IPOCTAL
18 be657dea Alberto Garcia
#define DPRINTF2(fmt, ...) \
19 be657dea Alberto Garcia
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
20 be657dea Alberto Garcia
#else
21 be657dea Alberto Garcia
#define DPRINTF2(fmt, ...) do { } while (0)
22 be657dea Alberto Garcia
#endif
23 be657dea Alberto Garcia
24 be657dea Alberto Garcia
#define DPRINTF(fmt, ...) DPRINTF2("IP-Octal: " fmt, ## __VA_ARGS__)
25 be657dea Alberto Garcia
26 be657dea Alberto Garcia
#define RX_FIFO_SIZE 3
27 be657dea Alberto Garcia
28 be657dea Alberto Garcia
/* The IP-Octal has 8 channels (a-h)
29 be657dea Alberto Garcia
   divided into 4 blocks (A-D) */
30 be657dea Alberto Garcia
#define N_CHANNELS 8
31 be657dea Alberto Garcia
#define N_BLOCKS   4
32 be657dea Alberto Garcia
33 be657dea Alberto Garcia
#define REG_MRa  0x01
34 be657dea Alberto Garcia
#define REG_MRb  0x11
35 be657dea Alberto Garcia
#define REG_SRa  0x03
36 be657dea Alberto Garcia
#define REG_SRb  0x13
37 be657dea Alberto Garcia
#define REG_CSRa 0x03
38 be657dea Alberto Garcia
#define REG_CSRb 0x13
39 be657dea Alberto Garcia
#define REG_CRa  0x05
40 be657dea Alberto Garcia
#define REG_CRb  0x15
41 be657dea Alberto Garcia
#define REG_RHRa 0x07
42 be657dea Alberto Garcia
#define REG_RHRb 0x17
43 be657dea Alberto Garcia
#define REG_THRa 0x07
44 be657dea Alberto Garcia
#define REG_THRb 0x17
45 be657dea Alberto Garcia
#define REG_ACR  0x09
46 be657dea Alberto Garcia
#define REG_ISR  0x0B
47 be657dea Alberto Garcia
#define REG_IMR  0x0B
48 be657dea Alberto Garcia
#define REG_OPCR 0x1B
49 be657dea Alberto Garcia
50 be657dea Alberto Garcia
#define CR_ENABLE_RX    BIT(0)
51 be657dea Alberto Garcia
#define CR_DISABLE_RX   BIT(1)
52 be657dea Alberto Garcia
#define CR_ENABLE_TX    BIT(2)
53 be657dea Alberto Garcia
#define CR_DISABLE_TX   BIT(3)
54 be657dea Alberto Garcia
#define CR_CMD(cr)      ((cr) >> 4)
55 be657dea Alberto Garcia
#define CR_NO_OP        0
56 be657dea Alberto Garcia
#define CR_RESET_MR     1
57 be657dea Alberto Garcia
#define CR_RESET_RX     2
58 be657dea Alberto Garcia
#define CR_RESET_TX     3
59 be657dea Alberto Garcia
#define CR_RESET_ERR    4
60 be657dea Alberto Garcia
#define CR_RESET_BRKINT 5
61 be657dea Alberto Garcia
#define CR_START_BRK    6
62 be657dea Alberto Garcia
#define CR_STOP_BRK     7
63 be657dea Alberto Garcia
#define CR_ASSERT_RTSN  8
64 be657dea Alberto Garcia
#define CR_NEGATE_RTSN  9
65 be657dea Alberto Garcia
#define CR_TIMEOUT_ON   10
66 be657dea Alberto Garcia
#define CR_TIMEOUT_OFF  12
67 be657dea Alberto Garcia
68 be657dea Alberto Garcia
#define SR_RXRDY   BIT(0)
69 be657dea Alberto Garcia
#define SR_FFULL   BIT(1)
70 be657dea Alberto Garcia
#define SR_TXRDY   BIT(2)
71 be657dea Alberto Garcia
#define SR_TXEMT   BIT(3)
72 be657dea Alberto Garcia
#define SR_OVERRUN BIT(4)
73 be657dea Alberto Garcia
#define SR_PARITY  BIT(5)
74 be657dea Alberto Garcia
#define SR_FRAMING BIT(6)
75 be657dea Alberto Garcia
#define SR_BREAK   BIT(7)
76 be657dea Alberto Garcia
77 be657dea Alberto Garcia
#define ISR_TXRDYA BIT(0)
78 be657dea Alberto Garcia
#define ISR_RXRDYA BIT(1)
79 be657dea Alberto Garcia
#define ISR_BREAKA BIT(2)
80 be657dea Alberto Garcia
#define ISR_CNTRDY BIT(3)
81 be657dea Alberto Garcia
#define ISR_TXRDYB BIT(4)
82 be657dea Alberto Garcia
#define ISR_RXRDYB BIT(5)
83 be657dea Alberto Garcia
#define ISR_BREAKB BIT(6)
84 be657dea Alberto Garcia
#define ISR_MPICHG BIT(7)
85 be657dea Alberto Garcia
#define ISR_TXRDY(CH) (((CH) & 1) ? BIT(4) : BIT(0))
86 be657dea Alberto Garcia
#define ISR_RXRDY(CH) (((CH) & 1) ? BIT(5) : BIT(1))
87 be657dea Alberto Garcia
#define ISR_BREAK(CH) (((CH) & 1) ? BIT(6) : BIT(2))
88 be657dea Alberto Garcia
89 be657dea Alberto Garcia
typedef struct IPOctalState IPOctalState;
90 be657dea Alberto Garcia
typedef struct SCC2698Channel SCC2698Channel;
91 be657dea Alberto Garcia
typedef struct SCC2698Block SCC2698Block;
92 be657dea Alberto Garcia
93 be657dea Alberto Garcia
struct SCC2698Channel {
94 be657dea Alberto Garcia
    IPOctalState *ipoctal;
95 be657dea Alberto Garcia
    CharDriverState *dev;
96 be657dea Alberto Garcia
    char *devpath;
97 be657dea Alberto Garcia
    bool rx_enabled;
98 be657dea Alberto Garcia
    uint8_t mr[2];
99 be657dea Alberto Garcia
    uint8_t mr_idx;
100 be657dea Alberto Garcia
    uint8_t sr;
101 be657dea Alberto Garcia
    uint8_t rhr[RX_FIFO_SIZE];
102 be657dea Alberto Garcia
    uint8_t rhr_idx;
103 be657dea Alberto Garcia
    uint8_t rx_pending;
104 be657dea Alberto Garcia
};
105 be657dea Alberto Garcia
106 be657dea Alberto Garcia
struct SCC2698Block {
107 be657dea Alberto Garcia
    uint8_t imr;
108 be657dea Alberto Garcia
    uint8_t isr;
109 be657dea Alberto Garcia
};
110 be657dea Alberto Garcia
111 be657dea Alberto Garcia
struct IPOctalState {
112 be657dea Alberto Garcia
    IPackDevice dev;
113 be657dea Alberto Garcia
    SCC2698Channel ch[N_CHANNELS];
114 be657dea Alberto Garcia
    SCC2698Block blk[N_BLOCKS];
115 be657dea Alberto Garcia
    uint8_t irq_vector;
116 be657dea Alberto Garcia
};
117 be657dea Alberto Garcia
118 be657dea Alberto Garcia
#define TYPE_IPOCTAL "ipoctal232"
119 be657dea Alberto Garcia
120 be657dea Alberto Garcia
#define IPOCTAL(obj) \
121 be657dea Alberto Garcia
    OBJECT_CHECK(IPOctalState, (obj), TYPE_IPOCTAL)
122 be657dea Alberto Garcia
123 be657dea Alberto Garcia
static const VMStateDescription vmstate_scc2698_channel = {
124 be657dea Alberto Garcia
    .name = "scc2698_channel",
125 be657dea Alberto Garcia
    .version_id = 1,
126 be657dea Alberto Garcia
    .minimum_version_id = 1,
127 be657dea Alberto Garcia
    .minimum_version_id_old = 1,
128 be657dea Alberto Garcia
    .fields      = (VMStateField[]) {
129 be657dea Alberto Garcia
        VMSTATE_BOOL(rx_enabled, SCC2698Channel),
130 be657dea Alberto Garcia
        VMSTATE_UINT8_ARRAY(mr, SCC2698Channel, 2),
131 be657dea Alberto Garcia
        VMSTATE_UINT8(mr_idx, SCC2698Channel),
132 be657dea Alberto Garcia
        VMSTATE_UINT8(sr, SCC2698Channel),
133 be657dea Alberto Garcia
        VMSTATE_UINT8_ARRAY(rhr, SCC2698Channel, RX_FIFO_SIZE),
134 be657dea Alberto Garcia
        VMSTATE_UINT8(rhr_idx, SCC2698Channel),
135 be657dea Alberto Garcia
        VMSTATE_UINT8(rx_pending, SCC2698Channel),
136 be657dea Alberto Garcia
        VMSTATE_END_OF_LIST()
137 be657dea Alberto Garcia
    }
138 be657dea Alberto Garcia
};
139 be657dea Alberto Garcia
140 be657dea Alberto Garcia
static const VMStateDescription vmstate_scc2698_block = {
141 be657dea Alberto Garcia
    .name = "scc2698_block",
142 be657dea Alberto Garcia
    .version_id = 1,
143 be657dea Alberto Garcia
    .minimum_version_id = 1,
144 be657dea Alberto Garcia
    .minimum_version_id_old = 1,
145 be657dea Alberto Garcia
    .fields      = (VMStateField[]) {
146 be657dea Alberto Garcia
        VMSTATE_UINT8(imr, SCC2698Block),
147 be657dea Alberto Garcia
        VMSTATE_UINT8(isr, SCC2698Block),
148 be657dea Alberto Garcia
        VMSTATE_END_OF_LIST()
149 be657dea Alberto Garcia
    }
150 be657dea Alberto Garcia
};
151 be657dea Alberto Garcia
152 be657dea Alberto Garcia
static const VMStateDescription vmstate_ipoctal = {
153 be657dea Alberto Garcia
    .name = "ipoctal232",
154 be657dea Alberto Garcia
    .version_id = 1,
155 be657dea Alberto Garcia
    .minimum_version_id = 1,
156 be657dea Alberto Garcia
    .minimum_version_id_old = 1,
157 be657dea Alberto Garcia
    .fields      = (VMStateField[]) {
158 be657dea Alberto Garcia
        VMSTATE_IPACK_DEVICE(dev, IPOctalState),
159 be657dea Alberto Garcia
        VMSTATE_STRUCT_ARRAY(ch, IPOctalState, N_CHANNELS, 1,
160 be657dea Alberto Garcia
                             vmstate_scc2698_channel, SCC2698Channel),
161 be657dea Alberto Garcia
        VMSTATE_STRUCT_ARRAY(blk, IPOctalState, N_BLOCKS, 1,
162 be657dea Alberto Garcia
                             vmstate_scc2698_block, SCC2698Block),
163 be657dea Alberto Garcia
        VMSTATE_UINT8(irq_vector, IPOctalState),
164 be657dea Alberto Garcia
        VMSTATE_END_OF_LIST()
165 be657dea Alberto Garcia
    }
166 be657dea Alberto Garcia
};
167 be657dea Alberto Garcia
168 be657dea Alberto Garcia
/* data[10] is 0x0C, not 0x0B as the doc says */
169 be657dea Alberto Garcia
static const uint8_t id_prom_data[] = {
170 be657dea Alberto Garcia
    0x49, 0x50, 0x41, 0x43, 0xF0, 0x22,
171 be657dea Alberto Garcia
    0xA1, 0x00, 0x00, 0x00, 0x0C, 0xCC
172 be657dea Alberto Garcia
};
173 be657dea Alberto Garcia
174 be657dea Alberto Garcia
static void update_irq(IPOctalState *dev, unsigned block)
175 be657dea Alberto Garcia
{
176 be657dea Alberto Garcia
    /* Blocks A and B interrupt on INT0#, C and D on INT1#.
177 be657dea Alberto Garcia
       Thus, to get the status we have to check two blocks. */
178 be657dea Alberto Garcia
    SCC2698Block *blk0 = &dev->blk[block];
179 be657dea Alberto Garcia
    SCC2698Block *blk1 = &dev->blk[block^1];
180 be657dea Alberto Garcia
    unsigned intno = block / 2;
181 be657dea Alberto Garcia
182 be657dea Alberto Garcia
    if ((blk0->isr & blk0->imr) || (blk1->isr & blk1->imr)) {
183 be657dea Alberto Garcia
        qemu_irq_raise(dev->dev.irq[intno]);
184 be657dea Alberto Garcia
    } else {
185 be657dea Alberto Garcia
        qemu_irq_lower(dev->dev.irq[intno]);
186 be657dea Alberto Garcia
    }
187 be657dea Alberto Garcia
}
188 be657dea Alberto Garcia
189 be657dea Alberto Garcia
static void write_cr(IPOctalState *dev, unsigned channel, uint8_t val)
190 be657dea Alberto Garcia
{
191 be657dea Alberto Garcia
    SCC2698Channel *ch = &dev->ch[channel];
192 be657dea Alberto Garcia
    SCC2698Block *blk = &dev->blk[channel / 2];
193 be657dea Alberto Garcia
194 be657dea Alberto Garcia
    DPRINTF("Write CR%c %u: ", channel + 'a', val);
195 be657dea Alberto Garcia
196 be657dea Alberto Garcia
    /* The lower 4 bits are used to enable and disable Tx and Rx */
197 be657dea Alberto Garcia
    if (val & CR_ENABLE_RX) {
198 be657dea Alberto Garcia
        DPRINTF2("Rx on, ");
199 be657dea Alberto Garcia
        ch->rx_enabled = true;
200 be657dea Alberto Garcia
    }
201 be657dea Alberto Garcia
    if (val & CR_DISABLE_RX) {
202 be657dea Alberto Garcia
        DPRINTF2("Rx off, ");
203 be657dea Alberto Garcia
        ch->rx_enabled = false;
204 be657dea Alberto Garcia
    }
205 be657dea Alberto Garcia
    if (val & CR_ENABLE_TX) {
206 be657dea Alberto Garcia
        DPRINTF2("Tx on, ");
207 be657dea Alberto Garcia
        ch->sr |= SR_TXRDY | SR_TXEMT;
208 be657dea Alberto Garcia
        blk->isr |= ISR_TXRDY(channel);
209 be657dea Alberto Garcia
    }
210 be657dea Alberto Garcia
    if (val & CR_DISABLE_TX) {
211 be657dea Alberto Garcia
        DPRINTF2("Tx off, ");
212 be657dea Alberto Garcia
        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
213 be657dea Alberto Garcia
        blk->isr &= ~ISR_TXRDY(channel);
214 be657dea Alberto Garcia
    }
215 be657dea Alberto Garcia
216 be657dea Alberto Garcia
    DPRINTF2("cmd: ");
217 be657dea Alberto Garcia
218 be657dea Alberto Garcia
    /* The rest of the bits implement different commands */
219 be657dea Alberto Garcia
    switch (CR_CMD(val)) {
220 be657dea Alberto Garcia
    case CR_NO_OP:
221 be657dea Alberto Garcia
        DPRINTF2("none");
222 be657dea Alberto Garcia
        break;
223 be657dea Alberto Garcia
    case CR_RESET_MR:
224 be657dea Alberto Garcia
        DPRINTF2("reset MR");
225 be657dea Alberto Garcia
        ch->mr_idx = 0;
226 be657dea Alberto Garcia
        break;
227 be657dea Alberto Garcia
    case CR_RESET_RX:
228 be657dea Alberto Garcia
        DPRINTF2("reset Rx");
229 be657dea Alberto Garcia
        ch->rx_enabled = false;
230 be657dea Alberto Garcia
        ch->rx_pending = 0;
231 be657dea Alberto Garcia
        ch->sr &= ~SR_RXRDY;
232 be657dea Alberto Garcia
        blk->isr &= ~ISR_RXRDY(channel);
233 be657dea Alberto Garcia
        break;
234 be657dea Alberto Garcia
    case CR_RESET_TX:
235 be657dea Alberto Garcia
        DPRINTF2("reset Tx");
236 be657dea Alberto Garcia
        ch->sr &= ~(SR_TXRDY | SR_TXEMT);
237 be657dea Alberto Garcia
        blk->isr &= ~ISR_TXRDY(channel);
238 be657dea Alberto Garcia
        break;
239 be657dea Alberto Garcia
    case CR_RESET_ERR:
240 be657dea Alberto Garcia
        DPRINTF2("reset err");
241 be657dea Alberto Garcia
        ch->sr &= ~(SR_OVERRUN | SR_PARITY | SR_FRAMING | SR_BREAK);
242 be657dea Alberto Garcia
        break;
243 be657dea Alberto Garcia
    case CR_RESET_BRKINT:
244 be657dea Alberto Garcia
        DPRINTF2("reset brk ch int");
245 be657dea Alberto Garcia
        blk->isr &= ~(ISR_BREAKA | ISR_BREAKB);
246 be657dea Alberto Garcia
        break;
247 be657dea Alberto Garcia
    default:
248 be657dea Alberto Garcia
        DPRINTF2("unsupported 0x%x", CR_CMD(val));
249 be657dea Alberto Garcia
    }
250 be657dea Alberto Garcia
251 be657dea Alberto Garcia
    DPRINTF2("\n");
252 be657dea Alberto Garcia
}
253 be657dea Alberto Garcia
254 be657dea Alberto Garcia
static uint16_t io_read(IPackDevice *ip, uint8_t addr)
255 be657dea Alberto Garcia
{
256 be657dea Alberto Garcia
    IPOctalState *dev = IPOCTAL(ip);
257 be657dea Alberto Garcia
    uint16_t ret = 0;
258 be657dea Alberto Garcia
    /* addr[7:6]: block   (A-D)
259 be657dea Alberto Garcia
       addr[7:5]: channel (a-h)
260 be657dea Alberto Garcia
       addr[5:0]: register */
261 be657dea Alberto Garcia
    unsigned block = addr >> 5;
262 be657dea Alberto Garcia
    unsigned channel = addr >> 4;
263 be657dea Alberto Garcia
    /* Big endian, accessed using 8-bit bytes at odd locations */
264 be657dea Alberto Garcia
    unsigned offset = (addr & 0x1F) ^ 1;
265 be657dea Alberto Garcia
    SCC2698Channel *ch = &dev->ch[channel];
266 be657dea Alberto Garcia
    SCC2698Block *blk = &dev->blk[block];
267 be657dea Alberto Garcia
    uint8_t old_isr = blk->isr;
268 be657dea Alberto Garcia
269 be657dea Alberto Garcia
    switch (offset) {
270 be657dea Alberto Garcia
271 be657dea Alberto Garcia
    case REG_MRa:
272 be657dea Alberto Garcia
    case REG_MRb:
273 be657dea Alberto Garcia
        ret = ch->mr[ch->mr_idx];
274 be657dea Alberto Garcia
        DPRINTF("Read MR%u%c: 0x%x\n", ch->mr_idx + 1, channel + 'a', ret);
275 be657dea Alberto Garcia
        ch->mr_idx = 1;
276 be657dea Alberto Garcia
        break;
277 be657dea Alberto Garcia
278 be657dea Alberto Garcia
    case REG_SRa:
279 be657dea Alberto Garcia
    case REG_SRb:
280 be657dea Alberto Garcia
        ret = ch->sr;
281 be657dea Alberto Garcia
        DPRINTF("Read SR%c: 0x%x\n", channel + 'a', ret);
282 be657dea Alberto Garcia
        break;
283 be657dea Alberto Garcia
284 be657dea Alberto Garcia
    case REG_RHRa:
285 be657dea Alberto Garcia
    case REG_RHRb:
286 be657dea Alberto Garcia
        ret = ch->rhr[ch->rhr_idx];
287 be657dea Alberto Garcia
        if (ch->rx_pending > 0) {
288 be657dea Alberto Garcia
            ch->rx_pending--;
289 be657dea Alberto Garcia
            if (ch->rx_pending == 0) {
290 be657dea Alberto Garcia
                ch->sr &= ~SR_RXRDY;
291 be657dea Alberto Garcia
                blk->isr &= ~ISR_RXRDY(channel);
292 be657dea Alberto Garcia
                if (ch->dev) {
293 be657dea Alberto Garcia
                    qemu_chr_accept_input(ch->dev);
294 be657dea Alberto Garcia
                }
295 be657dea Alberto Garcia
            } else {
296 be657dea Alberto Garcia
                ch->rhr_idx = (ch->rhr_idx + 1) % RX_FIFO_SIZE;
297 be657dea Alberto Garcia
            }
298 be657dea Alberto Garcia
            if (ch->sr & SR_BREAK) {
299 be657dea Alberto Garcia
                ch->sr &= ~SR_BREAK;
300 be657dea Alberto Garcia
                blk->isr |= ISR_BREAK(channel);
301 be657dea Alberto Garcia
            }
302 be657dea Alberto Garcia
        }
303 be657dea Alberto Garcia
        DPRINTF("Read RHR%c (0x%x)\n", channel + 'a', ret);
304 be657dea Alberto Garcia
        break;
305 be657dea Alberto Garcia
306 be657dea Alberto Garcia
    case REG_ISR:
307 be657dea Alberto Garcia
        ret = blk->isr;
308 be657dea Alberto Garcia
        DPRINTF("Read ISR%c: 0x%x\n", block + 'A', ret);
309 be657dea Alberto Garcia
        break;
310 be657dea Alberto Garcia
311 be657dea Alberto Garcia
    default:
312 be657dea Alberto Garcia
        DPRINTF("Read unknown/unsupported register 0x%02x\n", offset);
313 be657dea Alberto Garcia
    }
314 be657dea Alberto Garcia
315 be657dea Alberto Garcia
    if (old_isr != blk->isr) {
316 be657dea Alberto Garcia
        update_irq(dev, block);
317 be657dea Alberto Garcia
    }
318 be657dea Alberto Garcia
319 be657dea Alberto Garcia
    return ret;
320 be657dea Alberto Garcia
}
321 be657dea Alberto Garcia
322 be657dea Alberto Garcia
static void io_write(IPackDevice *ip, uint8_t addr, uint16_t val)
323 be657dea Alberto Garcia
{
324 be657dea Alberto Garcia
    IPOctalState *dev = IPOCTAL(ip);
325 be657dea Alberto Garcia
    unsigned reg = val & 0xFF;
326 be657dea Alberto Garcia
    /* addr[7:6]: block   (A-D)
327 be657dea Alberto Garcia
       addr[7:5]: channel (a-h)
328 be657dea Alberto Garcia
       addr[5:0]: register */
329 be657dea Alberto Garcia
    unsigned block = addr >> 5;
330 be657dea Alberto Garcia
    unsigned channel = addr >> 4;
331 be657dea Alberto Garcia
    /* Big endian, accessed using 8-bit bytes at odd locations */
332 be657dea Alberto Garcia
    unsigned offset = (addr & 0x1F) ^ 1;
333 be657dea Alberto Garcia
    SCC2698Channel *ch = &dev->ch[channel];
334 be657dea Alberto Garcia
    SCC2698Block *blk = &dev->blk[block];
335 be657dea Alberto Garcia
    uint8_t old_isr = blk->isr;
336 be657dea Alberto Garcia
    uint8_t old_imr = blk->imr;
337 be657dea Alberto Garcia
338 be657dea Alberto Garcia
    switch (offset) {
339 be657dea Alberto Garcia
340 be657dea Alberto Garcia
    case REG_MRa:
341 be657dea Alberto Garcia
    case REG_MRb:
342 be657dea Alberto Garcia
        ch->mr[ch->mr_idx] = reg;
343 be657dea Alberto Garcia
        DPRINTF("Write MR%u%c 0x%x\n", ch->mr_idx + 1, channel + 'a', reg);
344 be657dea Alberto Garcia
        ch->mr_idx = 1;
345 be657dea Alberto Garcia
        break;
346 be657dea Alberto Garcia
347 be657dea Alberto Garcia
    /* Not implemented */
348 be657dea Alberto Garcia
    case REG_CSRa:
349 be657dea Alberto Garcia
    case REG_CSRb:
350 be657dea Alberto Garcia
        DPRINTF("Write CSR%c: 0x%x\n", channel + 'a', reg);
351 be657dea Alberto Garcia
        break;
352 be657dea Alberto Garcia
353 be657dea Alberto Garcia
    case REG_CRa:
354 be657dea Alberto Garcia
    case REG_CRb:
355 be657dea Alberto Garcia
        write_cr(dev, channel, reg);
356 be657dea Alberto Garcia
        break;
357 be657dea Alberto Garcia
358 be657dea Alberto Garcia
    case REG_THRa:
359 be657dea Alberto Garcia
    case REG_THRb:
360 be657dea Alberto Garcia
        if (ch->sr & SR_TXRDY) {
361 be657dea Alberto Garcia
            DPRINTF("Write THR%c (0x%x)\n", channel + 'a', reg);
362 be657dea Alberto Garcia
            if (ch->dev) {
363 be657dea Alberto Garcia
                uint8_t thr = reg;
364 be657dea Alberto Garcia
                qemu_chr_fe_write(ch->dev, &thr, 1);
365 be657dea Alberto Garcia
            }
366 be657dea Alberto Garcia
        } else {
367 be657dea Alberto Garcia
            DPRINTF("Write THR%c (0x%x), Tx disabled\n", channel + 'a', reg);
368 be657dea Alberto Garcia
        }
369 be657dea Alberto Garcia
        break;
370 be657dea Alberto Garcia
371 be657dea Alberto Garcia
    /* Not implemented */
372 be657dea Alberto Garcia
    case REG_ACR:
373 be657dea Alberto Garcia
        DPRINTF("Write ACR%c 0x%x\n", block + 'A', val);
374 be657dea Alberto Garcia
        break;
375 be657dea Alberto Garcia
376 be657dea Alberto Garcia
    case REG_IMR:
377 be657dea Alberto Garcia
        DPRINTF("Write IMR%c 0x%x\n", block + 'A', val);
378 be657dea Alberto Garcia
        blk->imr = reg;
379 be657dea Alberto Garcia
        break;
380 be657dea Alberto Garcia
381 be657dea Alberto Garcia
    /* Not implemented */
382 be657dea Alberto Garcia
    case REG_OPCR:
383 be657dea Alberto Garcia
        DPRINTF("Write OPCR%c 0x%x\n", block + 'A', val);
384 be657dea Alberto Garcia
        break;
385 be657dea Alberto Garcia
386 be657dea Alberto Garcia
    default:
387 be657dea Alberto Garcia
        DPRINTF("Write unknown/unsupported register 0x%02x %u\n", offset, val);
388 be657dea Alberto Garcia
    }
389 be657dea Alberto Garcia
390 be657dea Alberto Garcia
    if (old_isr != blk->isr || old_imr != blk->imr) {
391 be657dea Alberto Garcia
        update_irq(dev, block);
392 be657dea Alberto Garcia
    }
393 be657dea Alberto Garcia
}
394 be657dea Alberto Garcia
395 be657dea Alberto Garcia
static uint16_t id_read(IPackDevice *ip, uint8_t addr)
396 be657dea Alberto Garcia
{
397 be657dea Alberto Garcia
    uint16_t ret = 0;
398 be657dea Alberto Garcia
    unsigned pos = addr / 2; /* The ID PROM data is stored every other byte */
399 be657dea Alberto Garcia
400 be657dea Alberto Garcia
    if (pos < ARRAY_SIZE(id_prom_data)) {
401 be657dea Alberto Garcia
        ret = id_prom_data[pos];
402 be657dea Alberto Garcia
    } else {
403 be657dea Alberto Garcia
        DPRINTF("Attempt to read unavailable PROM data at 0x%x\n",  addr);
404 be657dea Alberto Garcia
    }
405 be657dea Alberto Garcia
406 be657dea Alberto Garcia
    return ret;
407 be657dea Alberto Garcia
}
408 be657dea Alberto Garcia
409 be657dea Alberto Garcia
static void id_write(IPackDevice *ip, uint8_t addr, uint16_t val)
410 be657dea Alberto Garcia
{
411 be657dea Alberto Garcia
    IPOctalState *dev = IPOCTAL(ip);
412 be657dea Alberto Garcia
    if (addr == 1) {
413 be657dea Alberto Garcia
        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
414 be657dea Alberto Garcia
        dev->irq_vector = val; /* Undocumented, but the hw works like that */
415 be657dea Alberto Garcia
    } else {
416 be657dea Alberto Garcia
        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
417 be657dea Alberto Garcia
    }
418 be657dea Alberto Garcia
}
419 be657dea Alberto Garcia
420 be657dea Alberto Garcia
static uint16_t int_read(IPackDevice *ip, uint8_t addr)
421 be657dea Alberto Garcia
{
422 be657dea Alberto Garcia
    IPOctalState *dev = IPOCTAL(ip);
423 be657dea Alberto Garcia
    /* Read address 0 to ACK INT0# and address 2 to ACK INT1# */
424 be657dea Alberto Garcia
    if (addr != 0 && addr != 2) {
425 be657dea Alberto Garcia
        DPRINTF("Attempt to read from 0x%x\n", addr);
426 be657dea Alberto Garcia
        return 0;
427 be657dea Alberto Garcia
    } else {
428 be657dea Alberto Garcia
        /* Update interrupts if necessary */
429 be657dea Alberto Garcia
        update_irq(dev, addr);
430 be657dea Alberto Garcia
        return dev->irq_vector;
431 be657dea Alberto Garcia
    }
432 be657dea Alberto Garcia
}
433 be657dea Alberto Garcia
434 be657dea Alberto Garcia
static void int_write(IPackDevice *ip, uint8_t addr, uint16_t val)
435 be657dea Alberto Garcia
{
436 be657dea Alberto Garcia
    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
437 be657dea Alberto Garcia
}
438 be657dea Alberto Garcia
439 be657dea Alberto Garcia
static uint16_t mem_read16(IPackDevice *ip, uint32_t addr)
440 be657dea Alberto Garcia
{
441 be657dea Alberto Garcia
    DPRINTF("Attempt to read from 0x%x\n", addr);
442 be657dea Alberto Garcia
    return 0;
443 be657dea Alberto Garcia
}
444 be657dea Alberto Garcia
445 be657dea Alberto Garcia
static void mem_write16(IPackDevice *ip, uint32_t addr, uint16_t val)
446 be657dea Alberto Garcia
{
447 be657dea Alberto Garcia
    DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
448 be657dea Alberto Garcia
}
449 be657dea Alberto Garcia
450 be657dea Alberto Garcia
static uint8_t mem_read8(IPackDevice *ip, uint32_t addr)
451 be657dea Alberto Garcia
{
452 be657dea Alberto Garcia
    DPRINTF("Attempt to read from 0x%x\n", addr);
453 be657dea Alberto Garcia
    return 0;
454 be657dea Alberto Garcia
}
455 be657dea Alberto Garcia
456 be657dea Alberto Garcia
static void mem_write8(IPackDevice *ip, uint32_t addr, uint8_t val)
457 be657dea Alberto Garcia
{
458 be657dea Alberto Garcia
    IPOctalState *dev = IPOCTAL(ip);
459 be657dea Alberto Garcia
    if (addr == 1) {
460 be657dea Alberto Garcia
        DPRINTF("Write IRQ vector: %u\n", (unsigned) val);
461 be657dea Alberto Garcia
        dev->irq_vector = val;
462 be657dea Alberto Garcia
    } else {
463 be657dea Alberto Garcia
        DPRINTF("Attempt to write 0x%x to 0x%x\n", val, addr);
464 be657dea Alberto Garcia
    }
465 be657dea Alberto Garcia
}
466 be657dea Alberto Garcia
467 be657dea Alberto Garcia
static int hostdev_can_receive(void *opaque)
468 be657dea Alberto Garcia
{
469 be657dea Alberto Garcia
    SCC2698Channel *ch = opaque;
470 be657dea Alberto Garcia
    int available_bytes = RX_FIFO_SIZE - ch->rx_pending;
471 be657dea Alberto Garcia
    return ch->rx_enabled ? available_bytes : 0;
472 be657dea Alberto Garcia
}
473 be657dea Alberto Garcia
474 be657dea Alberto Garcia
static void hostdev_receive(void *opaque, const uint8_t *buf, int size)
475 be657dea Alberto Garcia
{
476 be657dea Alberto Garcia
    SCC2698Channel *ch = opaque;
477 be657dea Alberto Garcia
    IPOctalState *dev = ch->ipoctal;
478 be657dea Alberto Garcia
    unsigned pos = ch->rhr_idx + ch->rx_pending;
479 be657dea Alberto Garcia
    int i;
480 be657dea Alberto Garcia
481 be657dea Alberto Garcia
    assert(size + ch->rx_pending <= RX_FIFO_SIZE);
482 be657dea Alberto Garcia
483 be657dea Alberto Garcia
    /* Copy data to the RxFIFO */
484 be657dea Alberto Garcia
    for (i = 0; i < size; i++) {
485 be657dea Alberto Garcia
        pos %= RX_FIFO_SIZE;
486 be657dea Alberto Garcia
        ch->rhr[pos++] = buf[i];
487 be657dea Alberto Garcia
    }
488 be657dea Alberto Garcia
489 be657dea Alberto Garcia
    ch->rx_pending += size;
490 be657dea Alberto Garcia
491 be657dea Alberto Garcia
    /* If the RxFIFO was empty raise an interrupt */
492 be657dea Alberto Garcia
    if (!(ch->sr & SR_RXRDY)) {
493 be657dea Alberto Garcia
        unsigned block, channel = 0;
494 be657dea Alberto Garcia
        /* Find channel number to update the ISR register */
495 be657dea Alberto Garcia
        while (&dev->ch[channel] != ch) {
496 be657dea Alberto Garcia
            channel++;
497 be657dea Alberto Garcia
        }
498 be657dea Alberto Garcia
        block = channel / 2;
499 be657dea Alberto Garcia
        dev->blk[block].isr |= ISR_RXRDY(channel);
500 be657dea Alberto Garcia
        ch->sr |= SR_RXRDY;
501 be657dea Alberto Garcia
        update_irq(dev, block);
502 be657dea Alberto Garcia
    }
503 be657dea Alberto Garcia
}
504 be657dea Alberto Garcia
505 be657dea Alberto Garcia
static void hostdev_event(void *opaque, int event)
506 be657dea Alberto Garcia
{
507 be657dea Alberto Garcia
    SCC2698Channel *ch = opaque;
508 be657dea Alberto Garcia
    switch (event) {
509 be657dea Alberto Garcia
    case CHR_EVENT_OPENED:
510 be657dea Alberto Garcia
        DPRINTF("Device %s opened\n", ch->dev->label);
511 be657dea Alberto Garcia
        break;
512 be657dea Alberto Garcia
    case CHR_EVENT_BREAK: {
513 be657dea Alberto Garcia
        uint8_t zero = 0;
514 be657dea Alberto Garcia
        DPRINTF("Device %s received break\n", ch->dev->label);
515 be657dea Alberto Garcia
516 be657dea Alberto Garcia
        if (!(ch->sr & SR_BREAK)) {
517 be657dea Alberto Garcia
            IPOctalState *dev = ch->ipoctal;
518 be657dea Alberto Garcia
            unsigned block, channel = 0;
519 be657dea Alberto Garcia
520 be657dea Alberto Garcia
            while (&dev->ch[channel] != ch) {
521 be657dea Alberto Garcia
                channel++;
522 be657dea Alberto Garcia
            }
523 be657dea Alberto Garcia
            block = channel / 2;
524 be657dea Alberto Garcia
525 be657dea Alberto Garcia
            ch->sr |= SR_BREAK;
526 be657dea Alberto Garcia
            dev->blk[block].isr |= ISR_BREAK(channel);
527 be657dea Alberto Garcia
        }
528 be657dea Alberto Garcia
529 be657dea Alberto Garcia
        /* Put a zero character in the buffer */
530 be657dea Alberto Garcia
        hostdev_receive(ch, &zero, 1);
531 be657dea Alberto Garcia
    }
532 be657dea Alberto Garcia
        break;
533 be657dea Alberto Garcia
    default:
534 be657dea Alberto Garcia
        DPRINTF("Device %s received event %d\n", ch->dev->label, event);
535 be657dea Alberto Garcia
    }
536 be657dea Alberto Garcia
}
537 be657dea Alberto Garcia
538 be657dea Alberto Garcia
static int ipoctal_init(IPackDevice *ip)
539 be657dea Alberto Garcia
{
540 be657dea Alberto Garcia
    IPOctalState *s = IPOCTAL(ip);
541 be657dea Alberto Garcia
    unsigned i;
542 be657dea Alberto Garcia
543 be657dea Alberto Garcia
    for (i = 0; i < N_CHANNELS; i++) {
544 be657dea Alberto Garcia
        SCC2698Channel *ch = &s->ch[i];
545 be657dea Alberto Garcia
        ch->ipoctal = s;
546 be657dea Alberto Garcia
547 be657dea Alberto Garcia
        /* Redirect IP-Octal channels to host character devices */
548 be657dea Alberto Garcia
        if (ch->devpath) {
549 be657dea Alberto Garcia
            const char chr_name[] = "ipoctal";
550 be657dea Alberto Garcia
            char label[ARRAY_SIZE(chr_name) + 2];
551 be657dea Alberto Garcia
            static int index;
552 be657dea Alberto Garcia
553 be657dea Alberto Garcia
            snprintf(label, sizeof(label), "%s%d", chr_name, index);
554 be657dea Alberto Garcia
555 be657dea Alberto Garcia
            ch->dev = qemu_chr_new(label, ch->devpath, NULL);
556 be657dea Alberto Garcia
557 be657dea Alberto Garcia
            if (ch->dev) {
558 be657dea Alberto Garcia
                index++;
559 be657dea Alberto Garcia
                qemu_chr_add_handlers(ch->dev, hostdev_can_receive,
560 be657dea Alberto Garcia
                                      hostdev_receive, hostdev_event, ch);
561 be657dea Alberto Garcia
                DPRINTF("Redirecting channel %u to %s (%s)\n",
562 be657dea Alberto Garcia
                        i, ch->devpath, label);
563 be657dea Alberto Garcia
            } else {
564 be657dea Alberto Garcia
                DPRINTF("Could not redirect channel %u to %s\n",
565 be657dea Alberto Garcia
                        i, ch->devpath);
566 be657dea Alberto Garcia
            }
567 be657dea Alberto Garcia
        }
568 be657dea Alberto Garcia
    }
569 be657dea Alberto Garcia
570 be657dea Alberto Garcia
    return 0;
571 be657dea Alberto Garcia
}
572 be657dea Alberto Garcia
573 be657dea Alberto Garcia
static Property ipoctal_properties[] = {
574 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial0", IPOctalState, ch[0].devpath),
575 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial1", IPOctalState, ch[1].devpath),
576 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial2", IPOctalState, ch[2].devpath),
577 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial3", IPOctalState, ch[3].devpath),
578 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial4", IPOctalState, ch[4].devpath),
579 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial5", IPOctalState, ch[5].devpath),
580 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial6", IPOctalState, ch[6].devpath),
581 be657dea Alberto Garcia
    DEFINE_PROP_STRING("serial7", IPOctalState, ch[7].devpath),
582 be657dea Alberto Garcia
    DEFINE_PROP_END_OF_LIST(),
583 be657dea Alberto Garcia
};
584 be657dea Alberto Garcia
585 be657dea Alberto Garcia
static void ipoctal_class_init(ObjectClass *klass, void *data)
586 be657dea Alberto Garcia
{
587 be657dea Alberto Garcia
    DeviceClass *dc = DEVICE_CLASS(klass);
588 be657dea Alberto Garcia
    IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass);
589 be657dea Alberto Garcia
590 be657dea Alberto Garcia
    ic->init        = ipoctal_init;
591 be657dea Alberto Garcia
    ic->io_read     = io_read;
592 be657dea Alberto Garcia
    ic->io_write    = io_write;
593 be657dea Alberto Garcia
    ic->id_read     = id_read;
594 be657dea Alberto Garcia
    ic->id_write    = id_write;
595 be657dea Alberto Garcia
    ic->int_read    = int_read;
596 be657dea Alberto Garcia
    ic->int_write   = int_write;
597 be657dea Alberto Garcia
    ic->mem_read16  = mem_read16;
598 be657dea Alberto Garcia
    ic->mem_write16 = mem_write16;
599 be657dea Alberto Garcia
    ic->mem_read8   = mem_read8;
600 be657dea Alberto Garcia
    ic->mem_write8  = mem_write8;
601 be657dea Alberto Garcia
602 be657dea Alberto Garcia
    dc->desc    = "GE IP-Octal 232 8-channel RS-232 IndustryPack";
603 be657dea Alberto Garcia
    dc->props   = ipoctal_properties;
604 be657dea Alberto Garcia
    dc->vmsd    = &vmstate_ipoctal;
605 be657dea Alberto Garcia
}
606 be657dea Alberto Garcia
607 be657dea Alberto Garcia
static const TypeInfo ipoctal_info = {
608 be657dea Alberto Garcia
    .name          = TYPE_IPOCTAL,
609 be657dea Alberto Garcia
    .parent        = TYPE_IPACK_DEVICE,
610 be657dea Alberto Garcia
    .instance_size = sizeof(IPOctalState),
611 be657dea Alberto Garcia
    .class_init    = ipoctal_class_init,
612 be657dea Alberto Garcia
};
613 be657dea Alberto Garcia
614 be657dea Alberto Garcia
static void ipoctal_register_types(void)
615 be657dea Alberto Garcia
{
616 be657dea Alberto Garcia
    type_register_static(&ipoctal_info);
617 be657dea Alberto Garcia
}
618 be657dea Alberto Garcia
619 be657dea Alberto Garcia
type_init(ipoctal_register_types)