qemu/hw/tcx.c
<<
>>
Prefs
   1/*
   2 * QEMU TCX Frame buffer
   3 *
   4 * Copyright (c) 2003-2005 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "sun4m.h"
  26#include "console.h"
  27#include "pixel_ops.h"
  28#include "sysbus.h"
  29#include "qdev-addr.h"
  30
  31#define MAXX 1024
  32#define MAXY 768
  33#define TCX_DAC_NREGS 16
  34#define TCX_THC_NREGS_8  0x081c
  35#define TCX_THC_NREGS_24 0x1000
  36#define TCX_TEC_NREGS    0x1000
  37
  38typedef struct TCXState {
  39    SysBusDevice busdev;
  40    target_phys_addr_t addr;
  41    DisplayState *ds;
  42    uint8_t *vram;
  43    uint32_t *vram24, *cplane;
  44    ram_addr_t vram_offset, vram24_offset, cplane_offset;
  45    uint32_t vram_size;
  46    uint16_t width, height, depth;
  47    uint8_t r[256], g[256], b[256];
  48    uint32_t palette[256];
  49    uint8_t dac_index, dac_state;
  50} TCXState;
  51
  52static void tcx_screen_dump(void *opaque, const char *filename);
  53static void tcx24_screen_dump(void *opaque, const char *filename);
  54
  55static void tcx_set_dirty(TCXState *s)
  56{
  57    unsigned int i;
  58
  59    for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
  60        cpu_physical_memory_set_dirty(s->vram_offset + i);
  61    }
  62}
  63
  64static void tcx24_set_dirty(TCXState *s)
  65{
  66    unsigned int i;
  67
  68    for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
  69        cpu_physical_memory_set_dirty(s->vram24_offset + i);
  70        cpu_physical_memory_set_dirty(s->cplane_offset + i);
  71    }
  72}
  73
  74static void update_palette_entries(TCXState *s, int start, int end)
  75{
  76    int i;
  77    for(i = start; i < end; i++) {
  78        switch(ds_get_bits_per_pixel(s->ds)) {
  79        default:
  80        case 8:
  81            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
  82            break;
  83        case 15:
  84            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
  85            break;
  86        case 16:
  87            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
  88            break;
  89        case 32:
  90            if (is_surface_bgr(s->ds->surface))
  91                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
  92            else
  93                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
  94            break;
  95        }
  96    }
  97    if (s->depth == 24) {
  98        tcx24_set_dirty(s);
  99    } else {
 100        tcx_set_dirty(s);
 101    }
 102}
 103
 104static void tcx_draw_line32(TCXState *s1, uint8_t *d,
 105                            const uint8_t *s, int width)
 106{
 107    int x;
 108    uint8_t val;
 109    uint32_t *p = (uint32_t *)d;
 110
 111    for(x = 0; x < width; x++) {
 112        val = *s++;
 113        *p++ = s1->palette[val];
 114    }
 115}
 116
 117static void tcx_draw_line16(TCXState *s1, uint8_t *d,
 118                            const uint8_t *s, int width)
 119{
 120    int x;
 121    uint8_t val;
 122    uint16_t *p = (uint16_t *)d;
 123
 124    for(x = 0; x < width; x++) {
 125        val = *s++;
 126        *p++ = s1->palette[val];
 127    }
 128}
 129
 130static void tcx_draw_line8(TCXState *s1, uint8_t *d,
 131                           const uint8_t *s, int width)
 132{
 133    int x;
 134    uint8_t val;
 135
 136    for(x = 0; x < width; x++) {
 137        val = *s++;
 138        *d++ = s1->palette[val];
 139    }
 140}
 141
 142/*
 143  XXX Could be much more optimal:
 144  * detect if line/page/whole screen is in 24 bit mode
 145  * if destination is also BGR, use memcpy
 146  */
 147static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
 148                                     const uint8_t *s, int width,
 149                                     const uint32_t *cplane,
 150                                     const uint32_t *s24)
 151{
 152    int x, bgr, r, g, b;
 153    uint8_t val, *p8;
 154    uint32_t *p = (uint32_t *)d;
 155    uint32_t dval;
 156
 157    bgr = is_surface_bgr(s1->ds->surface);
 158    for(x = 0; x < width; x++, s++, s24++) {
 159        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
 160            // 24-bit direct, BGR order
 161            p8 = (uint8_t *)s24;
 162            p8++;
 163            b = *p8++;
 164            g = *p8++;
 165            r = *p8++;
 166            if (bgr)
 167                dval = rgb_to_pixel32bgr(r, g, b);
 168            else
 169                dval = rgb_to_pixel32(r, g, b);
 170        } else {
 171            val = *s;
 172            dval = s1->palette[val];
 173        }
 174        *p++ = dval;
 175    }
 176}
 177
 178static inline int check_dirty(ram_addr_t page, ram_addr_t page24,
 179                              ram_addr_t cpage)
 180{
 181    int ret;
 182    unsigned int off;
 183
 184    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
 185    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
 186        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
 187        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
 188    }
 189    return ret;
 190}
 191
 192static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
 193                               ram_addr_t page_max, ram_addr_t page24,
 194                              ram_addr_t cpage)
 195{
 196    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
 197                                    VGA_DIRTY_FLAG);
 198    page_min -= ts->vram_offset;
 199    page_max -= ts->vram_offset;
 200    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
 201                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
 202                                    VGA_DIRTY_FLAG);
 203    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
 204                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
 205                                    VGA_DIRTY_FLAG);
 206}
 207
 208/* Fixed line length 1024 allows us to do nice tricks not possible on
 209   VGA... */
 210static void tcx_update_display(void *opaque)
 211{
 212    TCXState *ts = opaque;
 213    ram_addr_t page, page_min, page_max;
 214    int y, y_start, dd, ds;
 215    uint8_t *d, *s;
 216    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
 217
 218    if (ds_get_bits_per_pixel(ts->ds) == 0)
 219        return;
 220    page = ts->vram_offset;
 221    y_start = -1;
 222    page_min = -1;
 223    page_max = 0;
 224    d = ds_get_data(ts->ds);
 225    s = ts->vram;
 226    dd = ds_get_linesize(ts->ds);
 227    ds = 1024;
 228
 229    switch (ds_get_bits_per_pixel(ts->ds)) {
 230    case 32:
 231        f = tcx_draw_line32;
 232        break;
 233    case 15:
 234    case 16:
 235        f = tcx_draw_line16;
 236        break;
 237    default:
 238    case 8:
 239        f = tcx_draw_line8;
 240        break;
 241    case 0:
 242        return;
 243    }
 244
 245    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
 246        if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
 247            if (y_start < 0)
 248                y_start = y;
 249            if (page < page_min)
 250                page_min = page;
 251            if (page > page_max)
 252                page_max = page;
 253            f(ts, d, s, ts->width);
 254            d += dd;
 255            s += ds;
 256            f(ts, d, s, ts->width);
 257            d += dd;
 258            s += ds;
 259            f(ts, d, s, ts->width);
 260            d += dd;
 261            s += ds;
 262            f(ts, d, s, ts->width);
 263            d += dd;
 264            s += ds;
 265        } else {
 266            if (y_start >= 0) {
 267                /* flush to display */
 268                dpy_update(ts->ds, 0, y_start,
 269                           ts->width, y - y_start);
 270                y_start = -1;
 271            }
 272            d += dd * 4;
 273            s += ds * 4;
 274        }
 275    }
 276    if (y_start >= 0) {
 277        /* flush to display */
 278        dpy_update(ts->ds, 0, y_start,
 279                   ts->width, y - y_start);
 280    }
 281    /* reset modified pages */
 282    if (page_max >= page_min) {
 283        cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
 284                                        VGA_DIRTY_FLAG);
 285    }
 286}
 287
 288static void tcx24_update_display(void *opaque)
 289{
 290    TCXState *ts = opaque;
 291    ram_addr_t page, page_min, page_max, cpage, page24;
 292    int y, y_start, dd, ds;
 293    uint8_t *d, *s;
 294    uint32_t *cptr, *s24;
 295
 296    if (ds_get_bits_per_pixel(ts->ds) != 32)
 297            return;
 298    page = ts->vram_offset;
 299    page24 = ts->vram24_offset;
 300    cpage = ts->cplane_offset;
 301    y_start = -1;
 302    page_min = -1;
 303    page_max = 0;
 304    d = ds_get_data(ts->ds);
 305    s = ts->vram;
 306    s24 = ts->vram24;
 307    cptr = ts->cplane;
 308    dd = ds_get_linesize(ts->ds);
 309    ds = 1024;
 310
 311    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
 312            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
 313        if (check_dirty(page, page24, cpage)) {
 314            if (y_start < 0)
 315                y_start = y;
 316            if (page < page_min)
 317                page_min = page;
 318            if (page > page_max)
 319                page_max = page;
 320            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 321            d += dd;
 322            s += ds;
 323            cptr += ds;
 324            s24 += ds;
 325            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 326            d += dd;
 327            s += ds;
 328            cptr += ds;
 329            s24 += ds;
 330            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 331            d += dd;
 332            s += ds;
 333            cptr += ds;
 334            s24 += ds;
 335            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
 336            d += dd;
 337            s += ds;
 338            cptr += ds;
 339            s24 += ds;
 340        } else {
 341            if (y_start >= 0) {
 342                /* flush to display */
 343                dpy_update(ts->ds, 0, y_start,
 344                           ts->width, y - y_start);
 345                y_start = -1;
 346            }
 347            d += dd * 4;
 348            s += ds * 4;
 349            cptr += ds * 4;
 350            s24 += ds * 4;
 351        }
 352    }
 353    if (y_start >= 0) {
 354        /* flush to display */
 355        dpy_update(ts->ds, 0, y_start,
 356                   ts->width, y - y_start);
 357    }
 358    /* reset modified pages */
 359    if (page_max >= page_min) {
 360        reset_dirty(ts, page_min, page_max, page24, cpage);
 361    }
 362}
 363
 364static void tcx_invalidate_display(void *opaque)
 365{
 366    TCXState *s = opaque;
 367
 368    tcx_set_dirty(s);
 369    qemu_console_resize(s->ds, s->width, s->height);
 370}
 371
 372static void tcx24_invalidate_display(void *opaque)
 373{
 374    TCXState *s = opaque;
 375
 376    tcx_set_dirty(s);
 377    tcx24_set_dirty(s);
 378    qemu_console_resize(s->ds, s->width, s->height);
 379}
 380
 381static void tcx_save(QEMUFile *f, void *opaque)
 382{
 383    TCXState *s = opaque;
 384
 385    qemu_put_be16s(f, &s->height);
 386    qemu_put_be16s(f, &s->width);
 387    qemu_put_be16s(f, &s->depth);
 388    qemu_put_buffer(f, s->r, 256);
 389    qemu_put_buffer(f, s->g, 256);
 390    qemu_put_buffer(f, s->b, 256);
 391    qemu_put_8s(f, &s->dac_index);
 392    qemu_put_8s(f, &s->dac_state);
 393}
 394
 395static int tcx_load(QEMUFile *f, void *opaque, int version_id)
 396{
 397    TCXState *s = opaque;
 398    uint32_t dummy;
 399
 400    if (version_id != 3 && version_id != 4)
 401        return -EINVAL;
 402
 403    if (version_id == 3) {
 404        qemu_get_be32s(f, &dummy);
 405        qemu_get_be32s(f, &dummy);
 406        qemu_get_be32s(f, &dummy);
 407    }
 408    qemu_get_be16s(f, &s->height);
 409    qemu_get_be16s(f, &s->width);
 410    qemu_get_be16s(f, &s->depth);
 411    qemu_get_buffer(f, s->r, 256);
 412    qemu_get_buffer(f, s->g, 256);
 413    qemu_get_buffer(f, s->b, 256);
 414    qemu_get_8s(f, &s->dac_index);
 415    qemu_get_8s(f, &s->dac_state);
 416    update_palette_entries(s, 0, 256);
 417    if (s->depth == 24) {
 418        tcx24_set_dirty(s);
 419    } else {
 420        tcx_set_dirty(s);
 421    }
 422
 423    return 0;
 424}
 425
 426static void tcx_reset(void *opaque)
 427{
 428    TCXState *s = opaque;
 429
 430    /* Initialize palette */
 431    memset(s->r, 0, 256);
 432    memset(s->g, 0, 256);
 433    memset(s->b, 0, 256);
 434    s->r[255] = s->g[255] = s->b[255] = 255;
 435    update_palette_entries(s, 0, 256);
 436    memset(s->vram, 0, MAXX*MAXY);
 437    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
 438                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
 439    s->dac_index = 0;
 440    s->dac_state = 0;
 441}
 442
 443static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
 444{
 445    return 0;
 446}
 447
 448static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 449{
 450    TCXState *s = opaque;
 451
 452    switch (addr) {
 453    case 0:
 454        s->dac_index = val >> 24;
 455        s->dac_state = 0;
 456        break;
 457    case 4:
 458        switch (s->dac_state) {
 459        case 0:
 460            s->r[s->dac_index] = val >> 24;
 461            update_palette_entries(s, s->dac_index, s->dac_index + 1);
 462            s->dac_state++;
 463            break;
 464        case 1:
 465            s->g[s->dac_index] = val >> 24;
 466            update_palette_entries(s, s->dac_index, s->dac_index + 1);
 467            s->dac_state++;
 468            break;
 469        case 2:
 470            s->b[s->dac_index] = val >> 24;
 471            update_palette_entries(s, s->dac_index, s->dac_index + 1);
 472            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
 473        default:
 474            s->dac_state = 0;
 475            break;
 476        }
 477        break;
 478    default:
 479        break;
 480    }
 481    return;
 482}
 483
 484static CPUReadMemoryFunc *tcx_dac_read[3] = {
 485    NULL,
 486    NULL,
 487    tcx_dac_readl,
 488};
 489
 490static CPUWriteMemoryFunc *tcx_dac_write[3] = {
 491    NULL,
 492    NULL,
 493    tcx_dac_writel,
 494};
 495
 496static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
 497{
 498    return 0;
 499}
 500
 501static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
 502                             uint32_t val)
 503{
 504}
 505
 506static CPUReadMemoryFunc *tcx_dummy_read[3] = {
 507    NULL,
 508    NULL,
 509    tcx_dummy_readl,
 510};
 511
 512static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
 513    NULL,
 514    NULL,
 515    tcx_dummy_writel,
 516};
 517
 518void tcx_init(target_phys_addr_t addr, int vram_size, int width, int height,
 519              int depth)
 520{
 521    DeviceState *dev;
 522    SysBusDevice *s;
 523
 524    dev = qdev_create(NULL, "SUNW,tcx");
 525    qdev_prop_set_taddr(dev, "addr", addr);
 526    qdev_prop_set_uint32(dev, "vram_size", vram_size);
 527    qdev_prop_set_uint16(dev, "width", width);
 528    qdev_prop_set_uint16(dev, "height", height);
 529    qdev_prop_set_uint16(dev, "depth", depth);
 530    qdev_init(dev);
 531    s = sysbus_from_qdev(dev);
 532    /* 8-bit plane */
 533    sysbus_mmio_map(s, 0, addr + 0x00800000ULL);
 534    /* DAC */
 535    sysbus_mmio_map(s, 1, addr + 0x00200000ULL);
 536    /* TEC (dummy) */
 537    sysbus_mmio_map(s, 2, addr + 0x00700000ULL);
 538    /* THC 24 bit: NetBSD writes here even with 8-bit display: dummy */
 539    sysbus_mmio_map(s, 3, addr + 0x00301000ULL);
 540    if (depth == 24) {
 541        /* 24-bit plane */
 542        sysbus_mmio_map(s, 4, addr + 0x02000000ULL);
 543        /* Control plane */
 544        sysbus_mmio_map(s, 5, addr + 0x0a000000ULL);
 545    } else {
 546        /* THC 8 bit (dummy) */
 547        sysbus_mmio_map(s, 4, addr + 0x00300000ULL);
 548    }
 549}
 550
 551static void tcx_init1(SysBusDevice *dev)
 552{
 553    TCXState *s = FROM_SYSBUS(TCXState, dev);
 554    int io_memory, dummy_memory;
 555    ram_addr_t vram_offset;
 556    int size;
 557    uint8_t *vram_base;
 558
 559    vram_offset = qemu_ram_alloc(s->vram_size * (1 + 4 + 4));
 560    vram_base = qemu_get_ram_ptr(vram_offset);
 561    s->vram_offset = vram_offset;
 562
 563    /* 8-bit plane */
 564    s->vram = vram_base;
 565    size = s->vram_size;
 566    sysbus_init_mmio(dev, size, s->vram_offset);
 567    vram_offset += size;
 568    vram_base += size;
 569
 570    /* DAC */
 571    io_memory = cpu_register_io_memory(tcx_dac_read, tcx_dac_write, s);
 572    sysbus_init_mmio(dev, TCX_DAC_NREGS, io_memory);
 573
 574    /* TEC (dummy) */
 575    dummy_memory = cpu_register_io_memory(tcx_dummy_read, tcx_dummy_write,
 576                                          s);
 577    sysbus_init_mmio(dev, TCX_TEC_NREGS, dummy_memory);
 578    /* THC: NetBSD writes here even with 8-bit display: dummy */
 579    sysbus_init_mmio(dev, TCX_THC_NREGS_24, dummy_memory);
 580
 581    if (s->depth == 24) {
 582        /* 24-bit plane */
 583        size = s->vram_size * 4;
 584        s->vram24 = (uint32_t *)vram_base;
 585        s->vram24_offset = vram_offset;
 586        sysbus_init_mmio(dev, size, vram_offset);
 587        vram_offset += size;
 588        vram_base += size;
 589
 590        /* Control plane */
 591        size = s->vram_size * 4;
 592        s->cplane = (uint32_t *)vram_base;
 593        s->cplane_offset = vram_offset;
 594        sysbus_init_mmio(dev, size, vram_offset);
 595
 596        s->ds = graphic_console_init(tcx24_update_display,
 597                                     tcx24_invalidate_display,
 598                                     tcx24_screen_dump, NULL, s);
 599    } else {
 600        /* THC 8 bit (dummy) */
 601        sysbus_init_mmio(dev, TCX_THC_NREGS_8, dummy_memory);
 602
 603        s->ds = graphic_console_init(tcx_update_display,
 604                                     tcx_invalidate_display,
 605                                     tcx_screen_dump, NULL, s);
 606    }
 607
 608    register_savevm("tcx", -1, 4, tcx_save, tcx_load, s);
 609    qemu_register_reset(tcx_reset, s);
 610    tcx_reset(s);
 611    qemu_console_resize(s->ds, s->width, s->height);
 612}
 613
 614static void tcx_screen_dump(void *opaque, const char *filename)
 615{
 616    TCXState *s = opaque;
 617    FILE *f;
 618    uint8_t *d, *d1, v;
 619    int y, x;
 620
 621    f = fopen(filename, "wb");
 622    if (!f)
 623        return;
 624    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
 625    d1 = s->vram;
 626    for(y = 0; y < s->height; y++) {
 627        d = d1;
 628        for(x = 0; x < s->width; x++) {
 629            v = *d;
 630            fputc(s->r[v], f);
 631            fputc(s->g[v], f);
 632            fputc(s->b[v], f);
 633            d++;
 634        }
 635        d1 += MAXX;
 636    }
 637    fclose(f);
 638    return;
 639}
 640
 641static void tcx24_screen_dump(void *opaque, const char *filename)
 642{
 643    TCXState *s = opaque;
 644    FILE *f;
 645    uint8_t *d, *d1, v;
 646    uint32_t *s24, *cptr, dval;
 647    int y, x;
 648
 649    f = fopen(filename, "wb");
 650    if (!f)
 651        return;
 652    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
 653    d1 = s->vram;
 654    s24 = s->vram24;
 655    cptr = s->cplane;
 656    for(y = 0; y < s->height; y++) {
 657        d = d1;
 658        for(x = 0; x < s->width; x++, d++, s24++) {
 659            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
 660                dval = *s24 & 0x00ffffff;
 661                fputc((dval >> 16) & 0xff, f);
 662                fputc((dval >> 8) & 0xff, f);
 663                fputc(dval & 0xff, f);
 664            } else {
 665                v = *d;
 666                fputc(s->r[v], f);
 667                fputc(s->g[v], f);
 668                fputc(s->b[v], f);
 669            }
 670        }
 671        d1 += MAXX;
 672    }
 673    fclose(f);
 674    return;
 675}
 676
 677static SysBusDeviceInfo tcx_info = {
 678    .init = tcx_init1,
 679    .qdev.name  = "SUNW,tcx",
 680    .qdev.size  = sizeof(TCXState),
 681    .qdev.props = (Property[]) {
 682        {
 683            .name   = "addr",
 684            .info   = &qdev_prop_taddr,
 685            .offset = offsetof(TCXState, addr),
 686            .defval = (target_phys_addr_t[]) { -1 },
 687        },{
 688            .name   = "vram_size",
 689            .info   = &qdev_prop_hex32,
 690            .offset = offsetof(TCXState, vram_size),
 691            .defval = (uint32_t[]) { -1 },
 692        },{
 693            .name   = "width",
 694            .info   = &qdev_prop_uint16,
 695            .offset = offsetof(TCXState, width),
 696            .defval = (uint16_t[]) { -1 },
 697        },{
 698            .name   = "height",
 699            .info   = &qdev_prop_uint16,
 700            .offset = offsetof(TCXState, height),
 701            .defval = (uint16_t[]) { -1 },
 702        },{
 703            .name   = "depth",
 704            .info   = &qdev_prop_uint16,
 705            .offset = offsetof(TCXState, depth),
 706            .defval = (uint16_t[]) { -1 },
 707        },
 708        {/* end of list */}
 709    }
 710};
 711
 712static void tcx_register_devices(void)
 713{
 714    sysbus_register_withprop(&tcx_info);
 715}
 716
 717device_init(tcx_register_devices)
 718