Statistics
| Branch: | Revision:

root / hw / tcx.c @ be62a2eb

History | View | Annotate | Download (18.8 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
    unsigned int i;
65

    
66
    for (i = 0; i < MAXX * MAXY; i += TARGET_PAGE_SIZE) {
67
        memory_region_set_dirty(&s->vram_mem, i);
68
    }
69
}
70

    
71
static void tcx24_set_dirty(TCXState *s)
72
{
73
    unsigned int i;
74

    
75
    for (i = 0; i < MAXX * MAXY * 4; i += TARGET_PAGE_SIZE) {
76
        memory_region_set_dirty(&s->vram_mem, s->vram24_offset + i);
77
        memory_region_set_dirty(&s->vram_mem, s->cplane_offset + i);
78
    }
79
}
80

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

    
111
static void tcx_draw_line32(TCXState *s1, uint8_t *d,
112
                            const uint8_t *s, int width)
113
{
114
    int x;
115
    uint8_t val;
116
    uint32_t *p = (uint32_t *)d;
117

    
118
    for(x = 0; x < width; x++) {
119
        val = *s++;
120
        *p++ = s1->palette[val];
121
    }
122
}
123

    
124
static void tcx_draw_line16(TCXState *s1, uint8_t *d,
125
                            const uint8_t *s, int width)
126
{
127
    int x;
128
    uint8_t val;
129
    uint16_t *p = (uint16_t *)d;
130

    
131
    for(x = 0; x < width; x++) {
132
        val = *s++;
133
        *p++ = s1->palette[val];
134
    }
135
}
136

    
137
static void tcx_draw_line8(TCXState *s1, uint8_t *d,
138
                           const uint8_t *s, int width)
139
{
140
    int x;
141
    uint8_t val;
142

    
143
    for(x = 0; x < width; x++) {
144
        val = *s++;
145
        *d++ = s1->palette[val];
146
    }
147
}
148

    
149
/*
150
  XXX Could be much more optimal:
151
  * detect if line/page/whole screen is in 24 bit mode
152
  * if destination is also BGR, use memcpy
153
  */
154
static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
155
                                     const uint8_t *s, int width,
156
                                     const uint32_t *cplane,
157
                                     const uint32_t *s24)
158
{
159
    int x, bgr, r, g, b;
160
    uint8_t val, *p8;
161
    uint32_t *p = (uint32_t *)d;
162
    uint32_t dval;
163

    
164
    bgr = is_surface_bgr(s1->ds->surface);
165
    for(x = 0; x < width; x++, s++, s24++) {
166
        if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
167
            // 24-bit direct, BGR order
168
            p8 = (uint8_t *)s24;
169
            p8++;
170
            b = *p8++;
171
            g = *p8++;
172
            r = *p8;
173
            if (bgr)
174
                dval = rgb_to_pixel32bgr(r, g, b);
175
            else
176
                dval = rgb_to_pixel32(r, g, b);
177
        } else {
178
            val = *s;
179
            dval = s1->palette[val];
180
        }
181
        *p++ = dval;
182
    }
183
}
184

    
185
static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
186
                              ram_addr_t cpage)
187
{
188
    int ret;
189
    unsigned int off;
190

    
191
    ret = memory_region_get_dirty(&s->vram_mem, page, DIRTY_MEMORY_VGA);
192
    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
193
        ret |= memory_region_get_dirty(&s->vram_mem, page24 + off,
194
                                       DIRTY_MEMORY_VGA);
195
        ret |= memory_region_get_dirty(&s->vram_mem, cpage + off,
196
                                       DIRTY_MEMORY_VGA);
197
    }
198
    return ret;
199
}
200

    
201
static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
202
                               ram_addr_t page_max, ram_addr_t page24,
203
                              ram_addr_t cpage)
204
{
205
    memory_region_reset_dirty(&ts->vram_mem,
206
                              page_min, page_max + TARGET_PAGE_SIZE,
207
                              DIRTY_MEMORY_VGA);
208
    memory_region_reset_dirty(&ts->vram_mem,
209
                              page24 + page_min * 4,
210
                              page24 + page_max * 4 + TARGET_PAGE_SIZE,
211
                              DIRTY_MEMORY_VGA);
212
    memory_region_reset_dirty(&ts->vram_mem,
213
                              cpage + page_min * 4,
214
                              cpage + page_max * 4 + TARGET_PAGE_SIZE,
215
                              DIRTY_MEMORY_VGA);
216
}
217

    
218
/* Fixed line length 1024 allows us to do nice tricks not possible on
219
   VGA... */
220
static void tcx_update_display(void *opaque)
221
{
222
    TCXState *ts = opaque;
223
    ram_addr_t page, page_min, page_max;
224
    int y, y_start, dd, ds;
225
    uint8_t *d, *s;
226
    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
227

    
228
    if (ds_get_bits_per_pixel(ts->ds) == 0)
229
        return;
230
    page = 0;
231
    y_start = -1;
232
    page_min = -1;
233
    page_max = 0;
234
    d = ds_get_data(ts->ds);
235
    s = ts->vram;
236
    dd = ds_get_linesize(ts->ds);
237
    ds = 1024;
238

    
239
    switch (ds_get_bits_per_pixel(ts->ds)) {
240
    case 32:
241
        f = tcx_draw_line32;
242
        break;
243
    case 15:
244
    case 16:
245
        f = tcx_draw_line16;
246
        break;
247
    default:
248
    case 8:
249
        f = tcx_draw_line8;
250
        break;
251
    case 0:
252
        return;
253
    }
254

    
255
    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
256
        if (memory_region_get_dirty(&ts->vram_mem, page, DIRTY_MEMORY_VGA)) {
257
            if (y_start < 0)
258
                y_start = y;
259
            if (page < page_min)
260
                page_min = page;
261
            if (page > page_max)
262
                page_max = page;
263
            f(ts, d, s, ts->width);
264
            d += dd;
265
            s += ds;
266
            f(ts, d, s, ts->width);
267
            d += dd;
268
            s += ds;
269
            f(ts, d, s, ts->width);
270
            d += dd;
271
            s += ds;
272
            f(ts, d, s, ts->width);
273
            d += dd;
274
            s += ds;
275
        } else {
276
            if (y_start >= 0) {
277
                /* flush to display */
278
                dpy_update(ts->ds, 0, y_start,
279
                           ts->width, y - y_start);
280
                y_start = -1;
281
            }
282
            d += dd * 4;
283
            s += ds * 4;
284
        }
285
    }
286
    if (y_start >= 0) {
287
        /* flush to display */
288
        dpy_update(ts->ds, 0, y_start,
289
                   ts->width, y - y_start);
290
    }
291
    /* reset modified pages */
292
    if (page_max >= page_min) {
293
        memory_region_reset_dirty(&ts->vram_mem,
294
                                  page_min, page_max + TARGET_PAGE_SIZE,
295
                                  DIRTY_MEMORY_VGA);
296
    }
297
}
298

    
299
static void tcx24_update_display(void *opaque)
300
{
301
    TCXState *ts = opaque;
302
    ram_addr_t page, page_min, page_max, cpage, page24;
303
    int y, y_start, dd, ds;
304
    uint8_t *d, *s;
305
    uint32_t *cptr, *s24;
306

    
307
    if (ds_get_bits_per_pixel(ts->ds) != 32)
308
            return;
309
    page = 0;
310
    page24 = ts->vram24_offset;
311
    cpage = ts->cplane_offset;
312
    y_start = -1;
313
    page_min = -1;
314
    page_max = 0;
315
    d = ds_get_data(ts->ds);
316
    s = ts->vram;
317
    s24 = ts->vram24;
318
    cptr = ts->cplane;
319
    dd = ds_get_linesize(ts->ds);
320
    ds = 1024;
321

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

    
375
static void tcx_invalidate_display(void *opaque)
376
{
377
    TCXState *s = opaque;
378

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

    
383
static void tcx24_invalidate_display(void *opaque)
384
{
385
    TCXState *s = opaque;
386

    
387
    tcx_set_dirty(s);
388
    tcx24_set_dirty(s);
389
    qemu_console_resize(s->ds, s->width, s->height);
390
}
391

    
392
static int vmstate_tcx_post_load(void *opaque, int version_id)
393
{
394
    TCXState *s = opaque;
395

    
396
    update_palette_entries(s, 0, 256);
397
    if (s->depth == 24) {
398
        tcx24_set_dirty(s);
399
    } else {
400
        tcx_set_dirty(s);
401
    }
402

    
403
    return 0;
404
}
405

    
406
static const VMStateDescription vmstate_tcx = {
407
    .name ="tcx",
408
    .version_id = 4,
409
    .minimum_version_id = 4,
410
    .minimum_version_id_old = 4,
411
    .post_load = vmstate_tcx_post_load,
412
    .fields      = (VMStateField []) {
413
        VMSTATE_UINT16(height, TCXState),
414
        VMSTATE_UINT16(width, TCXState),
415
        VMSTATE_UINT16(depth, TCXState),
416
        VMSTATE_BUFFER(r, TCXState),
417
        VMSTATE_BUFFER(g, TCXState),
418
        VMSTATE_BUFFER(b, TCXState),
419
        VMSTATE_UINT8(dac_index, TCXState),
420
        VMSTATE_UINT8(dac_state, TCXState),
421
        VMSTATE_END_OF_LIST()
422
    }
423
};
424

    
425
static void tcx_reset(DeviceState *d)
426
{
427
    TCXState *s = container_of(d, TCXState, busdev.qdev);
428

    
429
    /* Initialize palette */
430
    memset(s->r, 0, 256);
431
    memset(s->g, 0, 256);
432
    memset(s->b, 0, 256);
433
    s->r[255] = s->g[255] = s->b[255] = 255;
434
    update_palette_entries(s, 0, 256);
435
    memset(s->vram, 0, MAXX*MAXY);
436
    memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
437
                              DIRTY_MEMORY_VGA);
438
    s->dac_index = 0;
439
    s->dac_state = 0;
440
}
441

    
442
static uint64_t tcx_dac_readl(void *opaque, target_phys_addr_t addr,
443
                              unsigned size)
444
{
445
    return 0;
446
}
447

    
448
static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint64_t val,
449
                           unsigned size)
450
{
451
    TCXState *s = opaque;
452

    
453
    switch (addr) {
454
    case 0:
455
        s->dac_index = val >> 24;
456
        s->dac_state = 0;
457
        break;
458
    case 4:
459
        switch (s->dac_state) {
460
        case 0:
461
            s->r[s->dac_index] = val >> 24;
462
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
463
            s->dac_state++;
464
            break;
465
        case 1:
466
            s->g[s->dac_index] = val >> 24;
467
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
468
            s->dac_state++;
469
            break;
470
        case 2:
471
            s->b[s->dac_index] = val >> 24;
472
            update_palette_entries(s, s->dac_index, s->dac_index + 1);
473
            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
474
        default:
475
            s->dac_state = 0;
476
            break;
477
        }
478
        break;
479
    default:
480
        break;
481
    }
482
    return;
483
}
484

    
485
static const MemoryRegionOps tcx_dac_ops = {
486
    .read = tcx_dac_readl,
487
    .write = tcx_dac_writel,
488
    .endianness = DEVICE_NATIVE_ENDIAN,
489
    .valid = {
490
        .min_access_size = 4,
491
        .max_access_size = 4,
492
    },
493
};
494

    
495
static uint64_t dummy_readl(void *opaque, target_phys_addr_t addr,
496
                            unsigned size)
497
{
498
    return 0;
499
}
500

    
501
static void dummy_writel(void *opaque, target_phys_addr_t addr,
502
                         uint64_t val, unsigned size)
503
{
504
}
505

    
506
static const MemoryRegionOps dummy_ops = {
507
    .read = dummy_readl,
508
    .write = dummy_writel,
509
    .endianness = DEVICE_NATIVE_ENDIAN,
510
    .valid = {
511
        .min_access_size = 4,
512
        .max_access_size = 4,
513
    },
514
};
515

    
516
static int tcx_init1(SysBusDevice *dev)
517
{
518
    TCXState *s = FROM_SYSBUS(TCXState, dev);
519
    ram_addr_t vram_offset = 0;
520
    int size;
521
    uint8_t *vram_base;
522

    
523
    memory_region_init_ram(&s->vram_mem, "tcx.vram",
524
                           s->vram_size * (1 + 4 + 4));
525
    vmstate_register_ram_global(&s->vram_mem);
526
    vram_base = memory_region_get_ram_ptr(&s->vram_mem);
527

    
528
    /* 8-bit plane */
529
    s->vram = vram_base;
530
    size = s->vram_size;
531
    memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
532
                             &s->vram_mem, vram_offset, size);
533
    sysbus_init_mmio(dev, &s->vram_8bit);
534
    vram_offset += size;
535
    vram_base += size;
536

    
537
    /* DAC */
538
    memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
539
    sysbus_init_mmio(dev, &s->dac);
540

    
541
    /* TEC (dummy) */
542
    memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
543
    sysbus_init_mmio(dev, &s->tec);
544
    /* THC: NetBSD writes here even with 8-bit display: dummy */
545
    memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
546
                          TCX_THC_NREGS_24);
547
    sysbus_init_mmio(dev, &s->thc24);
548

    
549
    if (s->depth == 24) {
550
        /* 24-bit plane */
551
        size = s->vram_size * 4;
552
        s->vram24 = (uint32_t *)vram_base;
553
        s->vram24_offset = vram_offset;
554
        memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
555
                                 &s->vram_mem, vram_offset, size);
556
        sysbus_init_mmio(dev, &s->vram_24bit);
557
        vram_offset += size;
558
        vram_base += size;
559

    
560
        /* Control plane */
561
        size = s->vram_size * 4;
562
        s->cplane = (uint32_t *)vram_base;
563
        s->cplane_offset = vram_offset;
564
        memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
565
                                 &s->vram_mem, vram_offset, size);
566
        sysbus_init_mmio(dev, &s->vram_cplane);
567

    
568
        s->ds = graphic_console_init(tcx24_update_display,
569
                                     tcx24_invalidate_display,
570
                                     tcx24_screen_dump, NULL, s);
571
    } else {
572
        /* THC 8 bit (dummy) */
573
        memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
574
                              TCX_THC_NREGS_8);
575
        sysbus_init_mmio(dev, &s->thc8);
576

    
577
        s->ds = graphic_console_init(tcx_update_display,
578
                                     tcx_invalidate_display,
579
                                     tcx_screen_dump, NULL, s);
580
    }
581

    
582
    qemu_console_resize(s->ds, s->width, s->height);
583
    return 0;
584
}
585

    
586
static void tcx_screen_dump(void *opaque, const char *filename)
587
{
588
    TCXState *s = opaque;
589
    FILE *f;
590
    uint8_t *d, *d1, v;
591
    int y, x;
592

    
593
    f = fopen(filename, "wb");
594
    if (!f)
595
        return;
596
    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
597
    d1 = s->vram;
598
    for(y = 0; y < s->height; y++) {
599
        d = d1;
600
        for(x = 0; x < s->width; x++) {
601
            v = *d;
602
            fputc(s->r[v], f);
603
            fputc(s->g[v], f);
604
            fputc(s->b[v], f);
605
            d++;
606
        }
607
        d1 += MAXX;
608
    }
609
    fclose(f);
610
    return;
611
}
612

    
613
static void tcx24_screen_dump(void *opaque, const char *filename)
614
{
615
    TCXState *s = opaque;
616
    FILE *f;
617
    uint8_t *d, *d1, v;
618
    uint32_t *s24, *cptr, dval;
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
    s24 = s->vram24;
627
    cptr = s->cplane;
628
    for(y = 0; y < s->height; y++) {
629
        d = d1;
630
        for(x = 0; x < s->width; x++, d++, s24++) {
631
            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
632
                dval = *s24 & 0x00ffffff;
633
                fputc((dval >> 16) & 0xff, f);
634
                fputc((dval >> 8) & 0xff, f);
635
                fputc(dval & 0xff, f);
636
            } else {
637
                v = *d;
638
                fputc(s->r[v], f);
639
                fputc(s->g[v], f);
640
                fputc(s->b[v], f);
641
            }
642
        }
643
        d1 += MAXX;
644
    }
645
    fclose(f);
646
    return;
647
}
648

    
649
static SysBusDeviceInfo tcx_info = {
650
    .init = tcx_init1,
651
    .qdev.name  = "SUNW,tcx",
652
    .qdev.size  = sizeof(TCXState),
653
    .qdev.reset = tcx_reset,
654
    .qdev.vmsd  = &vmstate_tcx,
655
    .qdev.props = (Property[]) {
656
        DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
657
        DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
658
        DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
659
        DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
660
        DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
661
        DEFINE_PROP_END_OF_LIST(),
662
    }
663
};
664

    
665
static void tcx_register_devices(void)
666
{
667
    sysbus_register_withprop(&tcx_info);
668
}
669

    
670
device_init(tcx_register_devices)