Statistics
| Branch: | Revision:

root / hw / tcx.c @ 83f7d43a

History | View | Annotate | Download (18.9 kB)

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 "console.h"
26
#include "pixel_ops.h"
27
#include "sysbus.h"
28
#include "qdev-addr.h"
29

    
30
#define MAXX 1024
31
#define MAXY 768
32
#define TCX_DAC_NREGS 16
33
#define TCX_THC_NREGS_8  0x081c
34
#define TCX_THC_NREGS_24 0x1000
35
#define TCX_TEC_NREGS    0x1000
36

    
37
typedef struct TCXState {
38
    SysBusDevice busdev;
39
    target_phys_addr_t addr;
40
    DisplayState *ds;
41
    uint8_t *vram;
42
    uint32_t *vram24, *cplane;
43
    MemoryRegion vram_mem;
44
    MemoryRegion vram_8bit;
45
    MemoryRegion vram_24bit;
46
    MemoryRegion vram_cplane;
47
    MemoryRegion dac;
48
    MemoryRegion tec;
49
    MemoryRegion thc24;
50
    MemoryRegion thc8;
51
    ram_addr_t vram24_offset, cplane_offset;
52
    uint32_t vram_size;
53
    uint32_t palette[256];
54
    uint8_t r[256], g[256], b[256];
55
    uint16_t width, height, depth;
56
    uint8_t dac_index, dac_state;
57
} TCXState;
58

    
59
static void tcx_screen_dump(void *opaque, const char *filename);
60
static void tcx24_screen_dump(void *opaque, const char *filename);
61

    
62
static void tcx_set_dirty(TCXState *s)
63
{
64
    memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
65
}
66

    
67
static void tcx24_set_dirty(TCXState *s)
68
{
69
    memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
70
    memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
71
}
72

    
73
static void update_palette_entries(TCXState *s, int start, int end)
74
{
75
    int i;
76
    for(i = start; i < end; i++) {
77
        switch(ds_get_bits_per_pixel(s->ds)) {
78
        default:
79
        case 8:
80
            s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
81
            break;
82
        case 15:
83
            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
84
            break;
85
        case 16:
86
            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
87
            break;
88
        case 32:
89
            if (is_surface_bgr(s->ds->surface))
90
                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
91
            else
92
                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
93
            break;
94
        }
95
    }
96
    if (s->depth == 24) {
97
        tcx24_set_dirty(s);
98
    } else {
99
        tcx_set_dirty(s);
100
    }
101
}
102

    
103
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
104
                            const uint8_t *s, int width)
105
{
106
    int x;
107
    uint8_t val;
108
    uint32_t *p = (uint32_t *)d;
109

    
110
    for(x = 0; x < width; x++) {
111
        val = *s++;
112
        *p++ = s1->palette[val];
113
    }
114
}
115

    
116
static void tcx_draw_line16(TCXState *s1, uint8_t *d,
117
                            const uint8_t *s, int width)
118
{
119
    int x;
120
    uint8_t val;
121
    uint16_t *p = (uint16_t *)d;
122

    
123
    for(x = 0; x < width; x++) {
124
        val = *s++;
125
        *p++ = s1->palette[val];
126
    }
127
}
128

    
129
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
130
                           const uint8_t *s, int width)
131
{
132
    int x;
133
    uint8_t val;
134

    
135
    for(x = 0; x < width; x++) {
136
        val = *s++;
137
        *d++ = s1->palette[val];
138
    }
139
}
140

    
141
/*
142
  XXX Could be much more optimal:
143
  * detect if line/page/whole screen is in 24 bit mode
144
  * if destination is also BGR, use memcpy
145
  */
146
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
147
                                     const uint8_t *s, int width,
148
                                     const uint32_t *cplane,
149
                                     const uint32_t *s24)
150
{
151
    int x, bgr, r, g, b;
152
    uint8_t val, *p8;
153
    uint32_t *p = (uint32_t *)d;
154
    uint32_t dval;
155

    
156
    bgr = is_surface_bgr(s1->ds->surface);
157
    for(x = 0; x < width; x++, s++, s24++) {
158
        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
159
            // 24-bit direct, BGR order
160
            p8 = (uint8_t *)s24;
161
            p8++;
162
            b = *p8++;
163
            g = *p8++;
164
            r = *p8;
165
            if (bgr)
166
                dval = rgb_to_pixel32bgr(r, g, b);
167
            else
168
                dval = rgb_to_pixel32(r, g, b);
169
        } else {
170
            val = *s;
171
            dval = s1->palette[val];
172
        }
173
        *p++ = dval;
174
    }
175
}
176

    
177
static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
178
                              ram_addr_t cpage)
179
{
180
    int ret;
181

    
182
    ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
183
                                  DIRTY_MEMORY_VGA);
184
    ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
185
                                   DIRTY_MEMORY_VGA);
186
    ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
187
                                   DIRTY_MEMORY_VGA);
188
    return ret;
189
}
190

    
191
static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
192
                               ram_addr_t page_max, ram_addr_t page24,
193
                              ram_addr_t cpage)
194
{
195
    memory_region_reset_dirty(&ts->vram_mem,
196
                              page_min, page_max + TARGET_PAGE_SIZE,
197
                              DIRTY_MEMORY_VGA);
198
    memory_region_reset_dirty(&ts->vram_mem,
199
                              page24 + page_min * 4,
200
                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
201
                              DIRTY_MEMORY_VGA);
202
    memory_region_reset_dirty(&ts->vram_mem,
203
                              cpage + page_min * 4,
204
                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
205
                              DIRTY_MEMORY_VGA);
206
}
207

    
208
/* Fixed line length 1024 allows us to do nice tricks not possible on
209
   VGA... */
210
static 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 = 0;
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 (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
247
                                    DIRTY_MEMORY_VGA)) {
248
            if (y_start < 0)
249
                y_start = y;
250
            if (page < page_min)
251
                page_min = page;
252
            if (page > page_max)
253
                page_max = page;
254
            f(ts, d, s, ts->width);
255
            d += dd;
256
            s += ds;
257
            f(ts, d, s, ts->width);
258
            d += dd;
259
            s += ds;
260
            f(ts, d, s, ts->width);
261
            d += dd;
262
            s += ds;
263
            f(ts, d, s, ts->width);
264
            d += dd;
265
            s += ds;
266
        } else {
267
            if (y_start >= 0) {
268
                /* flush to display */
269
                dpy_update(ts->ds, 0, y_start,
270
                           ts->width, y - y_start);
271
                y_start = -1;
272
            }
273
            d += dd * 4;
274
            s += ds * 4;
275
        }
276
    }
277
    if (y_start >= 0) {
278
        /* flush to display */
279
        dpy_update(ts->ds, 0, y_start,
280
                   ts->width, y - y_start);
281
    }
282
    /* reset modified pages */
283
    if (page_max >= page_min) {
284
        memory_region_reset_dirty(&ts->vram_mem,
285
                                  page_min, page_max + TARGET_PAGE_SIZE,
286
                                  DIRTY_MEMORY_VGA);
287
    }
288
}
289

    
290
static void tcx24_update_display(void *opaque)
291
{
292
    TCXState *ts = opaque;
293
    ram_addr_t page, page_min, page_max, cpage, page24;
294
    int y, y_start, dd, ds;
295
    uint8_t *d, *s;
296
    uint32_t *cptr, *s24;
297

    
298
    if (ds_get_bits_per_pixel(ts->ds) != 32)
299
            return;
300
    page = 0;
301
    page24 = ts->vram24_offset;
302
    cpage = ts->cplane_offset;
303
    y_start = -1;
304
    page_min = -1;
305
    page_max = 0;
306
    d = ds_get_data(ts->ds);
307
    s = ts->vram;
308
    s24 = ts->vram24;
309
    cptr = ts->cplane;
310
    dd = ds_get_linesize(ts->ds);
311
    ds = 1024;
312

    
313
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
314
            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
315
        if (check_dirty(ts, page, page24, cpage)) {
316
            if (y_start < 0)
317
                y_start = y;
318
            if (page < page_min)
319
                page_min = page;
320
            if (page > page_max)
321
                page_max = page;
322
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
323
            d += dd;
324
            s += ds;
325
            cptr += ds;
326
            s24 += ds;
327
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
328
            d += dd;
329
            s += ds;
330
            cptr += ds;
331
            s24 += ds;
332
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
333
            d += dd;
334
            s += ds;
335
            cptr += ds;
336
            s24 += ds;
337
            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
338
            d += dd;
339
            s += ds;
340
            cptr += ds;
341
            s24 += ds;
342
        } else {
343
            if (y_start >= 0) {
344
                /* flush to display */
345
                dpy_update(ts->ds, 0, y_start,
346
                           ts->width, y - y_start);
347
                y_start = -1;
348
            }
349
            d += dd * 4;
350
            s += ds * 4;
351
            cptr += ds * 4;
352
            s24 += ds * 4;
353
        }
354
    }
355
    if (y_start >= 0) {
356
        /* flush to display */
357
        dpy_update(ts->ds, 0, y_start,
358
                   ts->width, y - y_start);
359
    }
360
    /* reset modified pages */
361
    if (page_max >= page_min) {
362
        reset_dirty(ts, page_min, page_max, page24, cpage);
363
    }
364
}
365

    
366
static void tcx_invalidate_display(void *opaque)
367
{
368
    TCXState *s = opaque;
369

    
370
    tcx_set_dirty(s);
371
    qemu_console_resize(s->ds, s->width, s->height);
372
}
373

    
374
static void tcx24_invalidate_display(void *opaque)
375
{
376
    TCXState *s = opaque;
377

    
378
    tcx_set_dirty(s);
379
    tcx24_set_dirty(s);
380
    qemu_console_resize(s->ds, s->width, s->height);
381
}
382

    
383
static int vmstate_tcx_post_load(void *opaque, int version_id)
384
{
385
    TCXState *s = opaque;
386

    
387
    update_palette_entries(s, 0, 256);
388
    if (s->depth == 24) {
389
        tcx24_set_dirty(s);
390
    } else {
391
        tcx_set_dirty(s);
392
    }
393

    
394
    return 0;
395
}
396

    
397
static const VMStateDescription vmstate_tcx = {
398
    .name ="tcx",
399
    .version_id = 4,
400
    .minimum_version_id = 4,
401
    .minimum_version_id_old = 4,
402
    .post_load = vmstate_tcx_post_load,
403
    .fields      = (VMStateField []) {
404
        VMSTATE_UINT16(height, TCXState),
405
        VMSTATE_UINT16(width, TCXState),
406
        VMSTATE_UINT16(depth, TCXState),
407
        VMSTATE_BUFFER(r, TCXState),
408
        VMSTATE_BUFFER(g, TCXState),
409
        VMSTATE_BUFFER(b, TCXState),
410
        VMSTATE_UINT8(dac_index, TCXState),
411
        VMSTATE_UINT8(dac_state, TCXState),
412
        VMSTATE_END_OF_LIST()
413
    }
414
};
415

    
416
static void tcx_reset(DeviceState *d)
417
{
418
    TCXState *s = container_of(d, TCXState, busdev.qdev);
419

    
420
    /* Initialize palette */
421
    memset(s->r, 0, 256);
422
    memset(s->g, 0, 256);
423
    memset(s->b, 0, 256);
424
    s->r[255] = s->g[255] = s->b[255] = 255;
425
    update_palette_entries(s, 0, 256);
426
    memset(s->vram, 0, MAXX*MAXY);
427
    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
428
                              DIRTY_MEMORY_VGA);
429
    s->dac_index = 0;
430
    s->dac_state = 0;
431
}
432

    
433
static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
434
                              unsigned size)
435
{
436
    return 0;
437
}
438

    
439
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
440
                           unsigned size)
441
{
442
    TCXState *s = opaque;
443

    
444
    switch (addr) {
445
    case 0:
446
        s->dac_index = val >> 24;
447
        s->dac_state = 0;
448
        break;
449
    case 4:
450
        switch (s->dac_state) {
451
        case 0:
452
            s->r[s->dac_index] = val >> 24;
453
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
454
            s->dac_state++;
455
            break;
456
        case 1:
457
            s->g[s->dac_index] = val >> 24;
458
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
459
            s->dac_state++;
460
            break;
461
        case 2:
462
            s->b[s->dac_index] = val >> 24;
463
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
464
            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
465
        default:
466
            s->dac_state = 0;
467
            break;
468
        }
469
        break;
470
    default:
471
        break;
472
    }
473
    return;
474
}
475

    
476
static const MemoryRegionOps tcx_dac_ops = {
477
    .read = tcx_dac_readl,
478
    .write = tcx_dac_writel,
479
    .endianness = DEVICE_NATIVE_ENDIAN,
480
    .valid = {
481
        .min_access_size = 4,
482
        .max_access_size = 4,
483
    },
484
};
485

    
486
static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
487
                            unsigned size)
488
{
489
    return 0;
490
}
491

    
492
static void dummy_writel(void *opaque, target_phys_addr_t addr,
493
                         uint64_t val, unsigned size)
494
{
495
}
496

    
497
static const MemoryRegionOps dummy_ops = {
498
    .read = dummy_readl,
499
    .write = dummy_writel,
500
    .endianness = DEVICE_NATIVE_ENDIAN,
501
    .valid = {
502
        .min_access_size = 4,
503
        .max_access_size = 4,
504
    },
505
};
506

    
507
static int tcx_init1(SysBusDevice *dev)
508
{
509
    TCXState *s = FROM_SYSBUS(TCXState, dev);
510
    ram_addr_t vram_offset = 0;
511
    int size;
512
    uint8_t *vram_base;
513

    
514
    memory_region_init_ram(&s->vram_mem, "tcx.vram",
515
                           s->vram_size * (1 + 4 + 4));
516
    vmstate_register_ram_global(&s->vram_mem);
517
    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
518

    
519
    /* 8-bit plane */
520
    s->vram = vram_base;
521
    size = s->vram_size;
522
    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
523
                             &s->vram_mem, vram_offset, size);
524
    sysbus_init_mmio(dev, &s->vram_8bit);
525
    vram_offset += size;
526
    vram_base += size;
527

    
528
    /* DAC */
529
    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
530
    sysbus_init_mmio(dev, &s->dac);
531

    
532
    /* TEC (dummy) */
533
    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
534
    sysbus_init_mmio(dev, &s->tec);
535
    /* THC: NetBSD writes here even with 8-bit display: dummy */
536
    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
537
                          TCX_THC_NREGS_24);
538
    sysbus_init_mmio(dev, &s->thc24);
539

    
540
    if (s->depth == 24) {
541
        /* 24-bit plane */
542
        size = s->vram_size * 4;
543
        s->vram24 = (uint32_t *)vram_base;
544
        s->vram24_offset = vram_offset;
545
        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
546
                                 &s->vram_mem, vram_offset, size);
547
        sysbus_init_mmio(dev, &s->vram_24bit);
548
        vram_offset += size;
549
        vram_base += size;
550

    
551
        /* Control plane */
552
        size = s->vram_size * 4;
553
        s->cplane = (uint32_t *)vram_base;
554
        s->cplane_offset = vram_offset;
555
        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
556
                                 &s->vram_mem, vram_offset, size);
557
        sysbus_init_mmio(dev, &s->vram_cplane);
558

    
559
        s->ds = graphic_console_init(tcx24_update_display,
560
                                     tcx24_invalidate_display,
561
                                     tcx24_screen_dump, NULL, s);
562
    } else {
563
        /* THC 8 bit (dummy) */
564
        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
565
                              TCX_THC_NREGS_8);
566
        sysbus_init_mmio(dev, &s->thc8);
567

    
568
        s->ds = graphic_console_init(tcx_update_display,
569
                                     tcx_invalidate_display,
570
                                     tcx_screen_dump, NULL, s);
571
    }
572

    
573
    qemu_console_resize(s->ds, s->width, s->height);
574
    return 0;
575
}
576

    
577
static void tcx_screen_dump(void *opaque, const char *filename)
578
{
579
    TCXState *s = opaque;
580
    FILE *f;
581
    uint8_t *d, *d1, v;
582
    int y, x;
583

    
584
    f = fopen(filename, "wb");
585
    if (!f)
586
        return;
587
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
588
    d1 = s->vram;
589
    for(y = 0; y < s->height; y++) {
590
        d = d1;
591
        for(x = 0; x < s->width; x++) {
592
            v = *d;
593
            fputc(s->r[v], f);
594
            fputc(s->g[v], f);
595
            fputc(s->b[v], f);
596
            d++;
597
        }
598
        d1 += MAXX;
599
    }
600
    fclose(f);
601
    return;
602
}
603

    
604
static void tcx24_screen_dump(void *opaque, const char *filename)
605
{
606
    TCXState *s = opaque;
607
    FILE *f;
608
    uint8_t *d, *d1, v;
609
    uint32_t *s24, *cptr, dval;
610
    int y, x;
611

    
612
    f = fopen(filename, "wb");
613
    if (!f)
614
        return;
615
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
616
    d1 = s->vram;
617
    s24 = s->vram24;
618
    cptr = s->cplane;
619
    for(y = 0; y < s->height; y++) {
620
        d = d1;
621
        for(x = 0; x < s->width; x++, d++, s24++) {
622
            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
623
                dval = *s24 & 0x00ffffff;
624
                fputc((dval >> 16) & 0xff, f);
625
                fputc((dval >> 8) & 0xff, f);
626
                fputc(dval & 0xff, f);
627
            } else {
628
                v = *d;
629
                fputc(s->r[v], f);
630
                fputc(s->g[v], f);
631
                fputc(s->b[v], f);
632
            }
633
        }
634
        d1 += MAXX;
635
    }
636
    fclose(f);
637
    return;
638
}
639

    
640
static Property tcx_properties[] = {
641
    DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
642
    DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
643
    DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
644
    DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
645
    DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
646
    DEFINE_PROP_END_OF_LIST(),
647
};
648

    
649
static void tcx_class_init(ObjectClass *klass, void *data)
650
{
651
    DeviceClass *dc = DEVICE_CLASS(klass);
652
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
653

    
654
    k->init = tcx_init1;
655
    dc->reset = tcx_reset;
656
    dc->vmsd = &vmstate_tcx;
657
    dc->props = tcx_properties;
658
}
659

    
660
static TypeInfo tcx_info = {
661
    .name          = "SUNW,tcx",
662
    .parent        = TYPE_SYS_BUS_DEVICE,
663
    .instance_size = sizeof(TCXState),
664
    .class_init    = tcx_class_init,
665
};
666

    
667
static void tcx_register_types(void)
668
{
669
    type_register_static(&tcx_info);
670
}
671

    
672
type_init(tcx_register_types)