~ubuntu-branches/ubuntu/gutsy/virtualbox-ose/gutsy

« back to all changes in this revision

Viewing changes to src/VBox/Devices/PC/DevDMA.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Steve Kowalik
  • Date: 2007-09-08 16:44:58 UTC
  • Revision ID: james.westby@ubuntu.com-20070908164458-wao29470vqtr8ksy
Tags: upstream-1.5.0-dfsg2
ImportĀ upstreamĀ versionĀ 1.5.0-dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: DevDMA.cpp 4071 2007-08-07 17:07:59Z vboxsync $ */
 
2
/** @file
 
3
 * DMA Controller Device.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 innotek GmbH
 
8
 *
 
9
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
10
 * available from http://www.virtualbox.org. This file is free software;
 
11
 * you can redistribute it and/or modify it under the terms of the GNU
 
12
 * General Public License as published by the Free Software Foundation,
 
13
 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
 
14
 * distribution. VirtualBox OSE is distributed in the hope that it will
 
15
 * be useful, but WITHOUT ANY WARRANTY of any kind.
 
16
 * --------------------------------------------------------------------
 
17
 *
 
18
 * This code is based on:
 
19
 *
 
20
 * QEMU DMA emulation
 
21
 *
 
22
 * Copyright (c) 2003 Vassili Karpov (malc)
 
23
 *
 
24
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 
25
 * of this software and associated documentation files (the "Software"), to deal
 
26
 * in the Software without restriction, including without limitation the rights
 
27
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
28
 * copies of the Software, and to permit persons to whom the Software is
 
29
 * furnished to do so, subject to the following conditions:
 
30
 *
 
31
 * The above copyright notice and this permission notice shall be included in
 
32
 * all copies or substantial portions of the Software.
 
33
 *
 
34
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
35
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
36
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 
37
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
38
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
39
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
40
 * THE SOFTWARE.
 
41
 */
 
42
 
 
43
#ifdef VBOX
 
44
 
 
45
/*******************************************************************************
 
46
*   Header Files                                                               *
 
47
*******************************************************************************/
 
48
#include <VBox/pdmdev.h>
 
49
#include <VBox/err.h>
 
50
 
 
51
#define LOG_GROUP LOG_GROUP_DEFAULT ///@todo LOG_GROUP_DEV_DMA
 
52
#include <VBox/log.h>
 
53
#include <iprt/assert.h>
 
54
#include <iprt/uuid.h>
 
55
#include <iprt/string.h>
 
56
 
 
57
#include <stdio.h>
 
58
#include <stdlib.h>
 
59
 
 
60
#include "Builtins.h"
 
61
#include "../vl_vbox.h"
 
62
typedef PFNDMATRANSFERHANDLER DMA_transfer_handler;
 
63
 
 
64
#else  /* !VBOX */
 
65
#include "vl.h"
 
66
#endif
 
67
 
 
68
/* #define DEBUG_DMA */
 
69
 
 
70
#ifndef VBOX
 
71
#ifndef __WIN32__
 
72
#define dolog(...) fprintf (stderr, "dma: " __VA_ARGS__)
 
73
#ifdef DEBUG_DMA
 
74
#define lwarn(...) fprintf (stderr, "dma: " __VA_ARGS__)
 
75
#define linfo(...) fprintf (stderr, "dma: " __VA_ARGS__)
 
76
#define ldebug(...) fprintf (stderr, "dma: " __VA_ARGS__)
 
77
#else
 
78
#define lwarn(...)
 
79
#define linfo(...)
 
80
#define ldebug(...)
 
81
#endif
 
82
#else
 
83
#define dolog()
 
84
#define lwarn()
 
85
#define linfo()
 
86
#define ldebug()
 
87
#endif
 
88
#else /* VBOX */
 
89
 
 
90
#ifdef LOG_ENABLED
 
91
#endif
 
92
# ifdef LOG_ENABLED
 
93
#   define DEBUG_DMA
 
94
    static void DMA_DPRINTF (const char *fmt, ...)
 
95
    {
 
96
        if (LogIsEnabled ()) {
 
97
            va_list args;
 
98
            va_start (args, fmt);
 
99
            RTLogLogger (NULL, NULL, "dma: %N", fmt, &args); /* %N - nested va_list * type formatting call. */
 
100
            va_end (args);
 
101
        }
 
102
    }
 
103
# else
 
104
  DECLINLINE(void) DMA_DPRINTF(const char *pszFmt, ...) {}
 
105
# endif
 
106
 
 
107
#define dolog DMA_DPRINTF
 
108
#define lwarn DMA_DPRINTF
 
109
#define linfo DMA_DPRINTF
 
110
#define ldebug DMA_DPRINTF
 
111
 
 
112
#endif /* VBOX */
 
113
 
 
114
#define LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
 
115
 
 
116
struct dma_regs {
 
117
    unsigned int now[2];
 
118
    uint16_t base[2];
 
119
    uint8_t mode;
 
120
    uint8_t page;
 
121
    uint8_t pageh;
 
122
    uint8_t dack;
 
123
    uint8_t eop;
 
124
    DMA_transfer_handler transfer_handler;
 
125
    void *opaque;
 
126
};
 
127
 
 
128
#define ADDR 0
 
129
#define COUNT 1
 
130
 
 
131
struct dma_cont {
 
132
    uint8_t status;
 
133
    uint8_t command;
 
134
    uint8_t mask;
 
135
    uint8_t flip_flop;
 
136
    unsigned int dshift;
 
137
    struct dma_regs regs[4];
 
138
};
 
139
 
 
140
typedef struct {
 
141
    PPDMDEVINS pDevIns;
 
142
    PCPDMDMACHLP pHlp;
 
143
    struct dma_cont dma_controllers[2];
 
144
} DMAState;
 
145
 
 
146
enum {
 
147
    CMD_MEMORY_TO_MEMORY = 0x01,
 
148
    CMD_FIXED_ADDRESS    = 0x02,
 
149
    CMD_BLOCK_CONTROLLER = 0x04,
 
150
    CMD_COMPRESSED_TIME  = 0x08,
 
151
    CMD_CYCLIC_PRIORITY  = 0x10,
 
152
    CMD_EXTENDED_WRITE   = 0x20,
 
153
    CMD_LOW_DREQ         = 0x40,
 
154
    CMD_LOW_DACK         = 0x80,
 
155
    CMD_NOT_SUPPORTED    = CMD_MEMORY_TO_MEMORY | CMD_FIXED_ADDRESS
 
156
    | CMD_COMPRESSED_TIME | CMD_CYCLIC_PRIORITY | CMD_EXTENDED_WRITE
 
157
    | CMD_LOW_DREQ | CMD_LOW_DACK
 
158
 
 
159
};
 
160
 
 
161
static int channels[8] = {-1, 2, 3, 1, -1, -1, -1, 0};
 
162
 
 
163
static void write_page (void *opaque, uint32_t nport, uint32_t data)
 
164
{
 
165
    struct dma_cont *d = (struct dma_cont*)opaque;
 
166
    int ichan;
 
167
 
 
168
    ichan = channels[nport & 7];
 
169
    if (-1 == ichan) {
 
170
        dolog ("invalid channel %#x %#x\n", nport, data);
 
171
        return;
 
172
    }
 
173
    d->regs[ichan].page = data;
 
174
}
 
175
 
 
176
static void write_pageh (void *opaque, uint32_t nport, uint32_t data)
 
177
{
 
178
    struct dma_cont *d = (struct dma_cont*)opaque;
 
179
    int ichan;
 
180
 
 
181
    ichan = channels[nport & 7];
 
182
    if (-1 == ichan) {
 
183
        dolog ("invalid channel %#x %#x\n", nport, data);
 
184
        return;
 
185
    }
 
186
    d->regs[ichan].pageh = data;
 
187
}
 
188
 
 
189
static uint32_t read_page (void *opaque, uint32_t nport)
 
190
{
 
191
    struct dma_cont *d = (struct dma_cont*)opaque;
 
192
    int ichan;
 
193
 
 
194
    ichan = channels[nport & 7];
 
195
    if (-1 == ichan) {
 
196
        dolog ("invalid channel read %#x\n", nport);
 
197
        return 0;
 
198
    }
 
199
    return d->regs[ichan].page;
 
200
}
 
201
 
 
202
static uint32_t read_pageh (void *opaque, uint32_t nport)
 
203
{
 
204
    struct dma_cont *d = (struct dma_cont*)opaque;
 
205
    int ichan;
 
206
 
 
207
    ichan = channels[nport & 7];
 
208
    if (-1 == ichan) {
 
209
        dolog ("invalid channel read %#x\n", nport);
 
210
        return 0;
 
211
    }
 
212
    return d->regs[ichan].pageh;
 
213
}
 
214
 
 
215
static inline void init_chan (struct dma_cont *d, int ichan)
 
216
{
 
217
    struct dma_regs *r;
 
218
 
 
219
    r = d->regs + ichan;
 
220
    r->now[ADDR] = r->base[ADDR] << d->dshift;
 
221
    r->now[COUNT] = 0;
 
222
}
 
223
 
 
224
static inline int getff (struct dma_cont *d)
 
225
{
 
226
    int ff;
 
227
 
 
228
    ff = d->flip_flop;
 
229
    d->flip_flop = !ff;
 
230
    return ff;
 
231
}
 
232
 
 
233
static uint32_t read_chan (void *opaque, uint32_t nport)
 
234
{
 
235
    struct dma_cont *d = (struct dma_cont*)opaque;
 
236
    int ichan, nreg, iport, ff, val, dir;
 
237
    struct dma_regs *r;
 
238
 
 
239
    iport = (nport >> d->dshift) & 0x0f;
 
240
    ichan = iport >> 1;
 
241
    nreg = iport & 1;
 
242
    r = d->regs + ichan;
 
243
 
 
244
    dir = ((r->mode >> 5) & 1) ? -1 : 1;
 
245
    ff = getff (d);
 
246
    if (nreg)
 
247
        val = (r->base[COUNT] << d->dshift) - r->now[COUNT];
 
248
    else
 
249
        val = r->now[ADDR] + r->now[COUNT] * dir;
 
250
 
 
251
    ldebug ("read_chan %#x -> %d\n", iport, val);
 
252
    return (val >> (d->dshift + (ff << 3))) & 0xff;
 
253
}
 
254
 
 
255
static void write_chan (void *opaque, uint32_t nport, uint32_t data)
 
256
{
 
257
    struct dma_cont *d = (struct dma_cont*)opaque;
 
258
    int iport, ichan, nreg;
 
259
    struct dma_regs *r;
 
260
 
 
261
    iport = (nport >> d->dshift) & 0x0f;
 
262
    ichan = iport >> 1;
 
263
    nreg = iport & 1;
 
264
    r = d->regs + ichan;
 
265
    if (getff (d)) {
 
266
        r->base[nreg] = (r->base[nreg] & 0xff) | ((data << 8) & 0xff00);
 
267
        init_chan (d, ichan);
 
268
    } else {
 
269
        r->base[nreg] = (r->base[nreg] & 0xff00) | (data & 0xff);
 
270
    }
 
271
}
 
272
 
 
273
static void write_cont (void *opaque, uint32_t nport, uint32_t data)
 
274
{
 
275
    struct dma_cont *d = (struct dma_cont*)opaque;
 
276
    int iport, ichan = 0;
 
277
 
 
278
    iport = (nport >> d->dshift) & 0x0f;
 
279
    switch (iport) {
 
280
    case 0x08:                  /* command */
 
281
        if ((data != 0) && (data & CMD_NOT_SUPPORTED)) {
 
282
            dolog ("command %#x not supported\n", data);
 
283
            return;
 
284
        }
 
285
        d->command = data;
 
286
        break;
 
287
 
 
288
    case 0x09:
 
289
        ichan = data & 3;
 
290
        if (data & 4) {
 
291
            d->status |= 1 << (ichan + 4);
 
292
        }
 
293
        else {
 
294
            d->status &= ~(1 << (ichan + 4));
 
295
        }
 
296
        d->status &= ~(1 << ichan);
 
297
        break;
 
298
 
 
299
    case 0x0a:                  /* single mask */
 
300
        if (data & 4)
 
301
            d->mask |= 1 << (data & 3);
 
302
        else
 
303
            d->mask &= ~(1 << (data & 3));
 
304
        break;
 
305
 
 
306
    case 0x0b:                  /* mode */
 
307
        {
 
308
            ichan = data & 3;
 
309
#ifdef DEBUG_DMA
 
310
            {
 
311
                int op, ai, dir, opmode;
 
312
                op = (data >> 2) & 3;
 
313
                ai = (data >> 4) & 1;
 
314
                dir = (data >> 5) & 1;
 
315
                opmode = (data >> 6) & 3;
 
316
 
 
317
                linfo ("ichan %d, op %d, ai %d, dir %d, opmode %d\n",
 
318
                       ichan, op, ai, dir, opmode);
 
319
            }
 
320
#endif
 
321
            d->regs[ichan].mode = data;
 
322
            break;
 
323
        }
 
324
 
 
325
    case 0x0c:                  /* clear flip flop */
 
326
        d->flip_flop = 0;
 
327
        break;
 
328
 
 
329
    case 0x0d:                  /* reset */
 
330
        d->flip_flop = 0;
 
331
        d->mask = ~0;
 
332
        d->status = 0;
 
333
        d->command = 0;
 
334
        break;
 
335
 
 
336
    case 0x0e:                  /* clear mask for all channels */
 
337
        d->mask = 0;
 
338
        break;
 
339
 
 
340
    case 0x0f:                  /* write mask for all channels */
 
341
        d->mask = data;
 
342
        break;
 
343
 
 
344
    default:
 
345
        dolog ("unknown iport %#x\n", iport);
 
346
        break;
 
347
    }
 
348
 
 
349
#ifdef DEBUG_DMA
 
350
    if (0xc != iport) {
 
351
        linfo ("write_cont: nport %#06x, ichan % 2d, val %#06x\n",
 
352
               nport, ichan, data);
 
353
    }
 
354
#endif
 
355
}
 
356
 
 
357
static uint32_t read_cont (void *opaque, uint32_t nport)
 
358
{
 
359
    struct dma_cont *d = (struct dma_cont*)opaque;
 
360
    int iport, val;
 
361
 
 
362
    iport = (nport >> d->dshift) & 0x0f;
 
363
    switch (iport) {
 
364
    case 0x08:                  /* status */
 
365
        val = d->status;
 
366
        d->status &= 0xf0;
 
367
        break;
 
368
    case 0x0f:                  /* mask */
 
369
        val = d->mask;
 
370
        break;
 
371
    default:
 
372
        val = 0;
 
373
        break;
 
374
    }
 
375
 
 
376
    ldebug ("read_cont: nport %#06x, iport %#04x val %#x\n", nport, iport, val);
 
377
    return val;
 
378
}
 
379
 
 
380
static uint8_t DMA_get_channel_mode (DMAState *s, int nchan)
 
381
{
 
382
    return s->dma_controllers[nchan > 3].regs[nchan & 3].mode;
 
383
}
 
384
 
 
385
static void DMA_hold_DREQ (DMAState *s, int nchan)
 
386
{
 
387
    int ncont, ichan;
 
388
 
 
389
    ncont = nchan > 3;
 
390
    ichan = nchan & 3;
 
391
    linfo ("held cont=%d chan=%d\n", ncont, ichan);
 
392
    s->dma_controllers[ncont].status |= 1 << (ichan + 4);
 
393
}
 
394
 
 
395
static void DMA_release_DREQ (DMAState *s, int nchan)
 
396
{
 
397
    int ncont, ichan;
 
398
 
 
399
    ncont = nchan > 3;
 
400
    ichan = nchan & 3;
 
401
    linfo ("released cont=%d chan=%d\n", ncont, ichan);
 
402
    s->dma_controllers[ncont].status &= ~(1 << (ichan + 4));
 
403
}
 
404
 
 
405
static void channel_run (DMAState *s, int ncont, int ichan)
 
406
{
 
407
    int n;
 
408
    struct dma_regs *r = &s->dma_controllers[ncont].regs[ichan];
 
409
#ifdef DEBUG_DMA
 
410
    int dir, opmode;
 
411
 
 
412
    dir = (r->mode >> 5) & 1;
 
413
    opmode = (r->mode >> 6) & 3;
 
414
 
 
415
    if (dir) {
 
416
        dolog ("DMA in address decrement mode\n");
 
417
    }
 
418
    if (opmode != 1) {
 
419
        dolog ("DMA not in single mode select %#x\n", opmode);
 
420
    }
 
421
#endif
 
422
 
 
423
    r = s->dma_controllers[ncont].regs + ichan;
 
424
    n = r->transfer_handler (s->pDevIns, r->opaque, ichan + (ncont << 2),
 
425
                             r->now[COUNT], (r->base[COUNT] + 1) << ncont);
 
426
    r->now[COUNT] = n;
 
427
    ldebug ("dma_pos %d size %d\n", n, (r->base[COUNT] + 1) << ncont);
 
428
}
 
429
 
 
430
static void DMA_run (DMAState *s)
 
431
{
 
432
    struct dma_cont *d;
 
433
    int icont, ichan;
 
434
 
 
435
    d = s->dma_controllers;
 
436
 
 
437
    for (icont = 0; icont < 2; icont++, d++) {
 
438
        for (ichan = 0; ichan < 4; ichan++) {
 
439
            int mask;
 
440
 
 
441
            mask = 1 << ichan;
 
442
 
 
443
            if ((0 == (d->mask & mask)) && (0 != (d->status & (mask << 4))))
 
444
                channel_run (s, icont, ichan);
 
445
        }
 
446
    }
 
447
}
 
448
 
 
449
static void DMA_register_channel (DMAState *s, unsigned nchan,
 
450
                                  DMA_transfer_handler transfer_handler,
 
451
                                  void *opaque)
 
452
{
 
453
    struct dma_regs *r;
 
454
    int ichan, ncont;
 
455
    LogFlow (("DMA_register_channel: s=%p nchan=%d transfer_handler=%p opaque=%p\n",
 
456
              s, nchan, transfer_handler, opaque));
 
457
 
 
458
    ncont = nchan > 3;
 
459
    ichan = nchan & 3;
 
460
 
 
461
    r = s->dma_controllers[ncont].regs + ichan;
 
462
    r->transfer_handler = transfer_handler;
 
463
    r->opaque = opaque;
 
464
}
 
465
 
 
466
static uint32_t DMA_read_memory (DMAState *s,
 
467
                                 unsigned nchan,
 
468
                                 void *buf,
 
469
                                 uint32_t pos,
 
470
                                 uint32_t len)
 
471
{
 
472
    struct dma_regs *r = &s->dma_controllers[nchan > 3].regs[nchan & 3];
 
473
    uint32_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
 
474
 
 
475
    if (r->mode & 0x20) {
 
476
        unsigned i;
 
477
        uint8_t *p = (uint8_t*)buf;
 
478
 
 
479
#ifdef VBOX
 
480
        PDMDevHlpPhysRead (s->pDevIns, addr - pos - len, buf, len);
 
481
#else
 
482
        cpu_physical_memory_read (addr - pos - len, buf, len);
 
483
#endif
 
484
        /* What about 16bit transfers? */
 
485
        for (i = 0; i < len >> 1; i++) {
 
486
            uint8_t b = p[len - i - 1];
 
487
            p[i] = b;
 
488
        }
 
489
    }
 
490
    else
 
491
#ifdef VBOX
 
492
        PDMDevHlpPhysRead (s->pDevIns, addr + pos, buf, len);
 
493
#else
 
494
        cpu_physical_memory_read (addr + pos, buf, len);
 
495
#endif
 
496
    return len;
 
497
}
 
498
 
 
499
static uint32_t DMA_write_memory (DMAState *s,
 
500
                                  unsigned nchan,
 
501
                                  const void *buf,
 
502
                                  uint32_t pos,
 
503
                                  uint32_t len)
 
504
{
 
505
    struct dma_regs *r = &s->dma_controllers[nchan > 3].regs[nchan & 3];
 
506
    uint32_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
 
507
 
 
508
    if (r->mode & 0x20) {
 
509
        unsigned i;
 
510
        uint8_t *p = (uint8_t *) buf;
 
511
 
 
512
#ifdef VBOX
 
513
        PDMDevHlpPhysWrite (s->pDevIns, addr - pos - len, buf, len);
 
514
#else
 
515
        cpu_physical_memory_write (addr - pos - len, buf, len);
 
516
#endif
 
517
        /* What about 16bit transfers? */
 
518
        for (i = 0; i < len; i++) {
 
519
            uint8_t b = p[len - i - 1];
 
520
            p[i] = b;
 
521
        }
 
522
    }
 
523
    else
 
524
#ifdef VBOX
 
525
        PDMDevHlpPhysWrite (s->pDevIns, addr + pos, buf, len);
 
526
#else
 
527
        cpu_physical_memory_write (addr + pos, buf, len);
 
528
#endif
 
529
 
 
530
    return len;
 
531
}
 
532
 
 
533
 
 
534
#ifndef VBOX
 
535
/* request the emulator to transfer a new DMA memory block ASAP */
 
536
void DMA_schedule(int nchan)
 
537
{
 
538
    cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 
539
}
 
540
#endif
 
541
 
 
542
static void dma_reset(void *opaque)
 
543
{
 
544
    struct dma_cont *d = (struct dma_cont*)opaque;
 
545
    write_cont (d, (0x0d << d->dshift), 0);
 
546
}
 
547
 
 
548
#ifdef VBOX
 
549
#define IO_READ_PROTO(n)                                        \
 
550
static DECLCALLBACK(int) io_read_##n (PPDMDEVINS pDevIns,       \
 
551
                                      void *pvUser,             \
 
552
                                      RTIOPORT Port,          \
 
553
                                      uint32_t *pu32,           \
 
554
                                      unsigned cb)
 
555
 
 
556
 
 
557
#define IO_WRITE_PROTO(n)                                       \
 
558
static DECLCALLBACK(int) io_write_##n (PPDMDEVINS pDevIns,      \
 
559
                                       void *pvUser,            \
 
560
                                       RTIOPORT Port,         \
 
561
                                       uint32_t u32,            \
 
562
                                       unsigned cb)
 
563
 
 
564
IO_WRITE_PROTO (chan)
 
565
{
 
566
    if (cb == 1) {
 
567
        write_chan (pvUser, Port, u32);
 
568
    }
 
569
#ifdef PARANOID
 
570
    else {
 
571
        Log (("Unknown write to %#x of size %d, value %#x\n",
 
572
              Port, cb, u32));
 
573
    }
 
574
#endif
 
575
    return VINF_SUCCESS;
 
576
}
 
577
 
 
578
IO_WRITE_PROTO (page)
 
579
{
 
580
    if (cb == 1) {
 
581
        write_page (pvUser, Port, u32);
 
582
    }
 
583
#ifdef PARANOID
 
584
    else {
 
585
        Log (("Unknown write to %#x of size %d, value %#x\n",
 
586
              Port, cb, u32));
 
587
    }
 
588
#endif
 
589
    return VINF_SUCCESS;
 
590
}
 
591
 
 
592
IO_WRITE_PROTO (pageh)
 
593
{
 
594
    if (cb == 1) {
 
595
        write_pageh (pvUser, Port, u32);
 
596
    }
 
597
#ifdef PARANOID
 
598
    else {
 
599
        Log (("Unknown write to %#x of size %d, value %#x\n",
 
600
              Port, cb, u32));
 
601
    }
 
602
#endif
 
603
    return VINF_SUCCESS;
 
604
}
 
605
 
 
606
IO_WRITE_PROTO (cont)
 
607
{
 
608
    if (cb == 1) {
 
609
        write_cont (pvUser, Port, u32);
 
610
    }
 
611
#ifdef PARANOID
 
612
    else {
 
613
        Log (("Unknown write to %#x of size %d, value %#x\n",
 
614
              Port, cb, u32));
 
615
    }
 
616
#endif
 
617
    return VINF_SUCCESS;
 
618
}
 
619
 
 
620
IO_READ_PROTO (chan)
 
621
{
 
622
    if (cb == 1) {
 
623
        *pu32 = read_chan (pvUser, Port);
 
624
        return VINF_SUCCESS;
 
625
    }
 
626
    else {
 
627
        return VERR_IOM_IOPORT_UNUSED;
 
628
    }
 
629
}
 
630
 
 
631
IO_READ_PROTO (page)
 
632
{
 
633
    if (cb == 1) {
 
634
        *pu32 = read_page (pvUser, Port);
 
635
        return VINF_SUCCESS;
 
636
    }
 
637
    else {
 
638
        return VERR_IOM_IOPORT_UNUSED;
 
639
    }
 
640
}
 
641
 
 
642
IO_READ_PROTO (pageh)
 
643
{
 
644
    if (cb == 1) {
 
645
        *pu32 = read_pageh (pvUser, Port);
 
646
        return VINF_SUCCESS;
 
647
    }
 
648
    else {
 
649
        return VERR_IOM_IOPORT_UNUSED;
 
650
    }
 
651
}
 
652
 
 
653
IO_READ_PROTO (cont)
 
654
{
 
655
    if (cb == 1) {
 
656
        *pu32 = read_cont (pvUser, Port);
 
657
        return VINF_SUCCESS;
 
658
    }
 
659
    else {
 
660
        return VERR_IOM_IOPORT_UNUSED;
 
661
    }
 
662
}
 
663
#endif
 
664
 
 
665
/* dshift = 0: 8 bit DMA, 1 = 16 bit DMA */
 
666
static void dma_init2(DMAState *s, struct dma_cont *d, int base, int dshift,
 
667
                      int page_base, int pageh_base)
 
668
{
 
669
    const static int page_port_list[] = { 0x1, 0x2, 0x3, 0x7 };
 
670
    int i;
 
671
 
 
672
    d->dshift = dshift;
 
673
    for (i = 0; i < 8; i++) {
 
674
#ifdef VBOX
 
675
        PDMDevHlpIOPortRegister (s->pDevIns, base + (i << dshift), 1, d,
 
676
                                 io_write_chan, io_read_chan, NULL, NULL, "DMA");
 
677
#else
 
678
        register_ioport_write (base + (i << dshift), 1, 1, write_chan, d);
 
679
        register_ioport_read (base + (i << dshift), 1, 1, read_chan, d);
 
680
#endif
 
681
    }
 
682
    for (i = 0; i < LENOFA (page_port_list); i++) {
 
683
#ifdef VBOX
 
684
        PDMDevHlpIOPortRegister (s->pDevIns, page_base + page_port_list[i], 1, d,
 
685
                                 io_write_page, io_read_page, NULL, NULL, "DMA Page");
 
686
#else
 
687
        register_ioport_write (page_base + page_port_list[i], 1, 1,
 
688
                               write_page, d);
 
689
        register_ioport_read (page_base + page_port_list[i], 1, 1,
 
690
                              read_page, d);
 
691
#endif
 
692
        if (pageh_base >= 0) {
 
693
#ifdef VBOX
 
694
            PDMDevHlpIOPortRegister (s->pDevIns, pageh_base + page_port_list[i], 1, d,
 
695
                                     io_write_pageh, io_read_pageh, NULL, NULL, "DMA Page High");
 
696
#else
 
697
            register_ioport_write (pageh_base + page_port_list[i], 1, 1,
 
698
                                   write_pageh, d);
 
699
            register_ioport_read (pageh_base + page_port_list[i], 1, 1,
 
700
                                  read_pageh, d);
 
701
#endif
 
702
        }
 
703
    }
 
704
    for (i = 0; i < 8; i++) {
 
705
#ifdef VBOX
 
706
        PDMDevHlpIOPortRegister (s->pDevIns, base + ((i + 8) << dshift), 1, d,
 
707
                                 io_write_cont, io_read_cont, NULL, NULL, "DMA cont");
 
708
#else
 
709
        register_ioport_write (base + ((i + 8) << dshift), 1, 1,
 
710
                               write_cont, d);
 
711
        register_ioport_read (base + ((i + 8) << dshift), 1, 1,
 
712
                              read_cont, d);
 
713
#endif
 
714
    }
 
715
#ifndef VBOX
 
716
    qemu_register_reset(dma_reset, d);
 
717
#endif
 
718
    dma_reset(d);
 
719
}
 
720
 
 
721
static void dma_save (QEMUFile *f, void *opaque)
 
722
{
 
723
    struct dma_cont *d = (struct dma_cont*)opaque;
 
724
    int i;
 
725
 
 
726
    /* qemu_put_8s (f, &d->status); */
 
727
    qemu_put_8s (f, &d->command);
 
728
    qemu_put_8s (f, &d->mask);
 
729
    qemu_put_8s (f, &d->flip_flop);
 
730
    qemu_put_be32s (f, &d->dshift);
 
731
 
 
732
    for (i = 0; i < 4; ++i) {
 
733
        struct dma_regs *r = &d->regs[i];
 
734
        qemu_put_be32s (f, &r->now[0]);
 
735
        qemu_put_be32s (f, &r->now[1]);
 
736
        qemu_put_be16s (f, &r->base[0]);
 
737
        qemu_put_be16s (f, &r->base[1]);
 
738
        qemu_put_8s (f, &r->mode);
 
739
        qemu_put_8s (f, &r->page);
 
740
        qemu_put_8s (f, &r->pageh);
 
741
        qemu_put_8s (f, &r->dack);
 
742
        qemu_put_8s (f, &r->eop);
 
743
    }
 
744
}
 
745
 
 
746
static int dma_load (QEMUFile *f, void *opaque, int version_id)
 
747
{
 
748
    struct dma_cont *d = (struct dma_cont*)opaque;
 
749
    int i;
 
750
 
 
751
    if (version_id != 1)
 
752
#ifdef VBOX
 
753
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
754
#else
 
755
        return -EINVAL;
 
756
#endif
 
757
 
 
758
    /* qemu_get_8s (f, &d->status); */
 
759
    qemu_get_8s (f, &d->command);
 
760
    qemu_get_8s (f, &d->mask);
 
761
    qemu_get_8s (f, &d->flip_flop);
 
762
    qemu_get_be32s (f, &d->dshift);
 
763
 
 
764
    for (i = 0; i < 4; ++i) {
 
765
        struct dma_regs *r = &d->regs[i];
 
766
        qemu_get_be32s (f, &r->now[0]);
 
767
        qemu_get_be32s (f, &r->now[1]);
 
768
        qemu_get_be16s (f, &r->base[0]);
 
769
        qemu_get_be16s (f, &r->base[1]);
 
770
        qemu_get_8s (f, &r->mode);
 
771
        qemu_get_8s (f, &r->page);
 
772
        qemu_get_8s (f, &r->pageh);
 
773
        qemu_get_8s (f, &r->dack);
 
774
        qemu_get_8s (f, &r->eop);
 
775
    }
 
776
    return 0;
 
777
}
 
778
 
 
779
#ifndef VBOX
 
780
void DMA_init (int high_page_enable)
 
781
{
 
782
    dma_init2(&dma_controllers[0], 0x00, 0, 0x80,
 
783
              high_page_enable ? 0x480 : -1);
 
784
    dma_init2(&dma_controllers[1], 0xc0, 1, 0x88,
 
785
              high_page_enable ? 0x488 : -1);
 
786
    register_savevm ("dma", 0, 1, dma_save, dma_load, &dma_controllers[0]);
 
787
    register_savevm ("dma", 1, 1, dma_save, dma_load, &dma_controllers[1]);
 
788
}
 
789
#endif
 
790
 
 
791
#ifdef VBOX
 
792
static bool run_wrapper (PPDMDEVINS pDevIns)
 
793
{
 
794
    DMA_run (PDMINS2DATA (pDevIns, DMAState *));
 
795
    return 0;
 
796
}
 
797
 
 
798
static void register_channel_wrapper (PPDMDEVINS pDevIns,
 
799
                                      unsigned nchan,
 
800
                                      PFNDMATRANSFERHANDLER f,
 
801
                                      void *opaque)
 
802
{
 
803
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
804
    DMA_register_channel (s, nchan, f, opaque);
 
805
}
 
806
 
 
807
static uint32_t rd_mem_wrapper (PPDMDEVINS pDevIns,
 
808
                                unsigned nchan,
 
809
                                void *buf,
 
810
                                uint32_t pos,
 
811
                                uint32_t len)
 
812
{
 
813
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
814
    return DMA_read_memory (s, nchan, buf, pos, len);
 
815
}
 
816
 
 
817
static uint32_t wr_mem_wrapper (PPDMDEVINS pDevIns,
 
818
                                unsigned nchan,
 
819
                                const void *buf,
 
820
                                uint32_t pos,
 
821
                                uint32_t len)
 
822
{
 
823
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
824
    return DMA_write_memory (s, nchan, buf, pos, len);
 
825
}
 
826
 
 
827
static void set_DREQ_wrapper (PPDMDEVINS pDevIns,
 
828
                              unsigned nchan,
 
829
                              unsigned level)
 
830
{
 
831
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
832
    if (level) {
 
833
        DMA_hold_DREQ (s, nchan);
 
834
    }
 
835
    else {
 
836
        DMA_release_DREQ (s, nchan);
 
837
    }
 
838
}
 
839
 
 
840
static uint8_t get_mode_wrapper (PPDMDEVINS pDevIns, unsigned nchan)
 
841
{
 
842
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
843
    return DMA_get_channel_mode (s, nchan);
 
844
}
 
845
 
 
846
static void DMAReset (PPDMDEVINS pDevIns)
 
847
{
 
848
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
849
    dma_reset (&s->dma_controllers[0]);
 
850
    dma_reset (&s->dma_controllers[1]);
 
851
}
 
852
 
 
853
static DECLCALLBACK(int) SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
 
854
{
 
855
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
856
    dma_save (pSSMHandle, &s->dma_controllers[0]);
 
857
    dma_save (pSSMHandle, &s->dma_controllers[1]);
 
858
    return VINF_SUCCESS;
 
859
}
 
860
 
 
861
static DECLCALLBACK(int) LoadExec (PPDMDEVINS pDevIns,
 
862
                                   PSSMHANDLE pSSMHandle,
 
863
                                   uint32_t u32Version)
 
864
{
 
865
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
866
 
 
867
    if (u32Version != 1) {
 
868
        AssertFailed ();
 
869
        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
 
870
    }
 
871
 
 
872
    dma_load (pSSMHandle, &s->dma_controllers[0], u32Version);
 
873
    return dma_load (pSSMHandle, &s->dma_controllers[1], u32Version);
 
874
}
 
875
 
 
876
/**
 
877
 * Construct a device instance for a VM.
 
878
 *
 
879
 * @returns VBox status.
 
880
 * @param   pDevIns     The device instance data.
 
881
 *                      If the registration structure is needed, pDevIns->pDevReg points to it.
 
882
 * @param   iInstance   Instance number. Use this to figure out which registers and such to use.
 
883
 *                      The device number is also found in pDevIns->iInstance, but since it's
 
884
 *                      likely to be freqently used PDM passes it as parameter.
 
885
 * @param   pCfgHandle  Configuration node handle for the device. Use this to obtain the configuration
 
886
 *                      of the device instance. It's also found in pDevIns->pCfgHandle, but like
 
887
 *                      iInstance it's expected to be used a bit in this function.
 
888
 */
 
889
static DECLCALLBACK(int) DMAConstruct(PPDMDEVINS pDevIns,
 
890
                                      int iInstance,
 
891
                                      PCFGMNODE pCfgHandle)
 
892
{
 
893
    DMAState *s = PDMINS2DATA (pDevIns, DMAState *);
 
894
    bool high_page_enable = 0;
 
895
    PDMDMACREG reg;
 
896
    int rc;
 
897
 
 
898
    s->pDevIns = pDevIns;
 
899
 
 
900
    /*
 
901
     * Validate configuration.
 
902
     */
 
903
    if (!CFGMR3AreValuesValid(pCfgHandle, "\0")) /* "HighPageEnable\0")) */
 
904
        return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
 
905
 
 
906
#if 0
 
907
    rc = CFGMR3QueryBool (pCfgHandle, "HighPageEnable", &high_page_enable);
 
908
    if (VBOX_FAILURE (rc)) {
 
909
        return rc;
 
910
    }
 
911
#endif
 
912
 
 
913
    dma_init2(s, &s->dma_controllers[0], 0x00, 0, 0x80,
 
914
              high_page_enable ? 0x480 : -1);
 
915
    dma_init2(s, &s->dma_controllers[1], 0xc0, 1, 0x88,
 
916
              high_page_enable ? 0x488 : -1);
 
917
 
 
918
    reg.u32Version        = PDM_DMACREG_VERSION;
 
919
    reg.pfnRun            = run_wrapper;
 
920
    reg.pfnRegister       = register_channel_wrapper;
 
921
    reg.pfnReadMemory     = rd_mem_wrapper;
 
922
    reg.pfnWriteMemory    = wr_mem_wrapper;
 
923
    reg.pfnSetDREQ        = set_DREQ_wrapper;
 
924
    reg.pfnGetChannelMode = get_mode_wrapper;
 
925
 
 
926
    Assert(pDevIns->pDevHlp->pfnDMARegister);
 
927
    rc = pDevIns->pDevHlp->pfnDMACRegister (pDevIns, &reg, &s->pHlp);
 
928
    if (VBOX_FAILURE (rc)) {
 
929
        return rc;
 
930
    }
 
931
 
 
932
    rc = PDMDevHlpSSMRegister (pDevIns, pDevIns->pDevReg->szDeviceName, iInstance, 1, sizeof (*s),
 
933
                               NULL, SaveExec, NULL, NULL, LoadExec, NULL);
 
934
    if (VBOX_FAILURE(rc))
 
935
        return rc;
 
936
 
 
937
    return VINF_SUCCESS;
 
938
}
 
939
 
 
940
/**
 
941
 * The device registration structure.
 
942
 */
 
943
const PDMDEVREG g_DeviceDMA =
 
944
{
 
945
    /* u32Version */
 
946
    PDM_DEVREG_VERSION,
 
947
    /* szDeviceName */
 
948
    "8237A",
 
949
    /* szGCMod */
 
950
    "",
 
951
    /* szR0Mod */
 
952
    "",
 
953
    /* pszDescription */
 
954
    "DMA Controller Device",
 
955
    /* fFlags */
 
956
    PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT,
 
957
    /* fClass */
 
958
    PDM_DEVREG_CLASS_DMA,
 
959
    /* cMaxInstances */
 
960
    1,
 
961
    /* cbInstance */
 
962
    sizeof(DMAState),
 
963
    /* pfnConstruct */
 
964
    DMAConstruct,
 
965
    /* pfnDestruct */
 
966
    NULL,
 
967
    /* pfnRelocate */
 
968
    NULL,
 
969
    /* pfnIOCtl */
 
970
    NULL,
 
971
    /* pfnPowerOn */
 
972
    NULL,
 
973
    /* pfnReset */
 
974
    DMAReset,
 
975
    /* pfnSuspend */
 
976
    NULL,
 
977
    /* pfnResume */
 
978
    NULL,
 
979
    /* pfnAttach */
 
980
    NULL,
 
981
    /* pfnDetach */
 
982
    NULL,
 
983
    /* pfnQueryInterface. */
 
984
    NULL,
 
985
    /* pfnInitComplete */
 
986
    NULL,
 
987
    /* pfnPowerOff */
 
988
    NULL
 
989
};
 
990
#endif /* VBOX */