]> Git Repo - qemu.git/blob - hw/tcx.c
qemu-ga: move qemu-ga files to qga/
[qemu.git] / hw / tcx.c
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 "qemu-common.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
38 typedef struct TCXState {
39     SysBusDevice busdev;
40     hwaddr addr;
41     DisplayState *ds;
42     uint8_t *vram;
43     uint32_t *vram24, *cplane;
44     MemoryRegion vram_mem;
45     MemoryRegion vram_8bit;
46     MemoryRegion vram_24bit;
47     MemoryRegion vram_cplane;
48     MemoryRegion dac;
49     MemoryRegion tec;
50     MemoryRegion thc24;
51     MemoryRegion thc8;
52     ram_addr_t vram24_offset, cplane_offset;
53     uint32_t vram_size;
54     uint32_t palette[256];
55     uint8_t r[256], g[256], b[256];
56     uint16_t width, height, depth;
57     uint8_t dac_index, dac_state;
58 } TCXState;
59
60 static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
61                             Error **errp);
62 static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
63                             Error **errp);
64
65 static void tcx_set_dirty(TCXState *s)
66 {
67     memory_region_set_dirty(&s->vram_mem, 0, MAXX * MAXY);
68 }
69
70 static void tcx24_set_dirty(TCXState *s)
71 {
72     memory_region_set_dirty(&s->vram_mem, s->vram24_offset, MAXX * MAXY * 4);
73     memory_region_set_dirty(&s->vram_mem, s->cplane_offset, MAXX * MAXY * 4);
74 }
75
76 static void update_palette_entries(TCXState *s, int start, int end)
77 {
78     int i;
79     for(i = start; i < end; i++) {
80         switch(ds_get_bits_per_pixel(s->ds)) {
81         default:
82         case 8:
83             s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
84             break;
85         case 15:
86             s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
87             break;
88         case 16:
89             s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
90             break;
91         case 32:
92             if (is_surface_bgr(s->ds->surface))
93                 s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
94             else
95                 s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
96             break;
97         }
98     }
99     if (s->depth == 24) {
100         tcx24_set_dirty(s);
101     } else {
102         tcx_set_dirty(s);
103     }
104 }
105
106 static void tcx_draw_line32(TCXState *s1, uint8_t *d,
107                             const uint8_t *s, int width)
108 {
109     int x;
110     uint8_t val;
111     uint32_t *p = (uint32_t *)d;
112
113     for(x = 0; x < width; x++) {
114         val = *s++;
115         *p++ = s1->palette[val];
116     }
117 }
118
119 static void tcx_draw_line16(TCXState *s1, uint8_t *d,
120                             const uint8_t *s, int width)
121 {
122     int x;
123     uint8_t val;
124     uint16_t *p = (uint16_t *)d;
125
126     for(x = 0; x < width; x++) {
127         val = *s++;
128         *p++ = s1->palette[val];
129     }
130 }
131
132 static void tcx_draw_line8(TCXState *s1, uint8_t *d,
133                            const uint8_t *s, int width)
134 {
135     int x;
136     uint8_t val;
137
138     for(x = 0; x < width; x++) {
139         val = *s++;
140         *d++ = s1->palette[val];
141     }
142 }
143
144 /*
145   XXX Could be much more optimal:
146   * detect if line/page/whole screen is in 24 bit mode
147   * if destination is also BGR, use memcpy
148   */
149 static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
150                                      const uint8_t *s, int width,
151                                      const uint32_t *cplane,
152                                      const uint32_t *s24)
153 {
154     int x, bgr, r, g, b;
155     uint8_t val, *p8;
156     uint32_t *p = (uint32_t *)d;
157     uint32_t dval;
158
159     bgr = is_surface_bgr(s1->ds->surface);
160     for(x = 0; x < width; x++, s++, s24++) {
161         if ((be32_to_cpu(*cplane++) & 0xff000000) == 0x03000000) {
162             // 24-bit direct, BGR order
163             p8 = (uint8_t *)s24;
164             p8++;
165             b = *p8++;
166             g = *p8++;
167             r = *p8;
168             if (bgr)
169                 dval = rgb_to_pixel32bgr(r, g, b);
170             else
171                 dval = rgb_to_pixel32(r, g, b);
172         } else {
173             val = *s;
174             dval = s1->palette[val];
175         }
176         *p++ = dval;
177     }
178 }
179
180 static inline int check_dirty(TCXState *s, ram_addr_t page, ram_addr_t page24,
181                               ram_addr_t cpage)
182 {
183     int ret;
184
185     ret = memory_region_get_dirty(&s->vram_mem, page, TARGET_PAGE_SIZE,
186                                   DIRTY_MEMORY_VGA);
187     ret |= memory_region_get_dirty(&s->vram_mem, page24, TARGET_PAGE_SIZE * 4,
188                                    DIRTY_MEMORY_VGA);
189     ret |= memory_region_get_dirty(&s->vram_mem, cpage, TARGET_PAGE_SIZE * 4,
190                                    DIRTY_MEMORY_VGA);
191     return ret;
192 }
193
194 static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
195                                ram_addr_t page_max, ram_addr_t page24,
196                               ram_addr_t cpage)
197 {
198     memory_region_reset_dirty(&ts->vram_mem,
199                               page_min, page_max + TARGET_PAGE_SIZE,
200                               DIRTY_MEMORY_VGA);
201     memory_region_reset_dirty(&ts->vram_mem,
202                               page24 + page_min * 4,
203                               page24 + page_max * 4 + TARGET_PAGE_SIZE,
204                               DIRTY_MEMORY_VGA);
205     memory_region_reset_dirty(&ts->vram_mem,
206                               cpage + page_min * 4,
207                               cpage + page_max * 4 + TARGET_PAGE_SIZE,
208                               DIRTY_MEMORY_VGA);
209 }
210
211 /* Fixed line length 1024 allows us to do nice tricks not possible on
212    VGA... */
213 static void tcx_update_display(void *opaque)
214 {
215     TCXState *ts = opaque;
216     ram_addr_t page, page_min, page_max;
217     int y, y_start, dd, ds;
218     uint8_t *d, *s;
219     void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
220
221     if (ds_get_bits_per_pixel(ts->ds) == 0)
222         return;
223     page = 0;
224     y_start = -1;
225     page_min = -1;
226     page_max = 0;
227     d = ds_get_data(ts->ds);
228     s = ts->vram;
229     dd = ds_get_linesize(ts->ds);
230     ds = 1024;
231
232     switch (ds_get_bits_per_pixel(ts->ds)) {
233     case 32:
234         f = tcx_draw_line32;
235         break;
236     case 15:
237     case 16:
238         f = tcx_draw_line16;
239         break;
240     default:
241     case 8:
242         f = tcx_draw_line8;
243         break;
244     case 0:
245         return;
246     }
247
248     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
249         if (memory_region_get_dirty(&ts->vram_mem, page, TARGET_PAGE_SIZE,
250                                     DIRTY_MEMORY_VGA)) {
251             if (y_start < 0)
252                 y_start = y;
253             if (page < page_min)
254                 page_min = page;
255             if (page > page_max)
256                 page_max = page;
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             f(ts, d, s, ts->width);
267             d += dd;
268             s += ds;
269         } else {
270             if (y_start >= 0) {
271                 /* flush to display */
272                 dpy_gfx_update(ts->ds, 0, y_start,
273                                ts->width, y - y_start);
274                 y_start = -1;
275             }
276             d += dd * 4;
277             s += ds * 4;
278         }
279     }
280     if (y_start >= 0) {
281         /* flush to display */
282         dpy_gfx_update(ts->ds, 0, y_start,
283                        ts->width, y - y_start);
284     }
285     /* reset modified pages */
286     if (page_max >= page_min) {
287         memory_region_reset_dirty(&ts->vram_mem,
288                                   page_min, page_max + TARGET_PAGE_SIZE,
289                                   DIRTY_MEMORY_VGA);
290     }
291 }
292
293 static void tcx24_update_display(void *opaque)
294 {
295     TCXState *ts = opaque;
296     ram_addr_t page, page_min, page_max, cpage, page24;
297     int y, y_start, dd, ds;
298     uint8_t *d, *s;
299     uint32_t *cptr, *s24;
300
301     if (ds_get_bits_per_pixel(ts->ds) != 32)
302             return;
303     page = 0;
304     page24 = ts->vram24_offset;
305     cpage = ts->cplane_offset;
306     y_start = -1;
307     page_min = -1;
308     page_max = 0;
309     d = ds_get_data(ts->ds);
310     s = ts->vram;
311     s24 = ts->vram24;
312     cptr = ts->cplane;
313     dd = ds_get_linesize(ts->ds);
314     ds = 1024;
315
316     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
317             page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
318         if (check_dirty(ts, page, page24, cpage)) {
319             if (y_start < 0)
320                 y_start = y;
321             if (page < page_min)
322                 page_min = page;
323             if (page > page_max)
324                 page_max = page;
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             tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
341             d += dd;
342             s += ds;
343             cptr += ds;
344             s24 += ds;
345         } else {
346             if (y_start >= 0) {
347                 /* flush to display */
348                 dpy_gfx_update(ts->ds, 0, y_start,
349                                ts->width, y - y_start);
350                 y_start = -1;
351             }
352             d += dd * 4;
353             s += ds * 4;
354             cptr += ds * 4;
355             s24 += ds * 4;
356         }
357     }
358     if (y_start >= 0) {
359         /* flush to display */
360         dpy_gfx_update(ts->ds, 0, y_start,
361                        ts->width, y - y_start);
362     }
363     /* reset modified pages */
364     if (page_max >= page_min) {
365         reset_dirty(ts, page_min, page_max, page24, cpage);
366     }
367 }
368
369 static void tcx_invalidate_display(void *opaque)
370 {
371     TCXState *s = opaque;
372
373     tcx_set_dirty(s);
374     qemu_console_resize(s->ds, s->width, s->height);
375 }
376
377 static void tcx24_invalidate_display(void *opaque)
378 {
379     TCXState *s = opaque;
380
381     tcx_set_dirty(s);
382     tcx24_set_dirty(s);
383     qemu_console_resize(s->ds, s->width, s->height);
384 }
385
386 static int vmstate_tcx_post_load(void *opaque, int version_id)
387 {
388     TCXState *s = opaque;
389
390     update_palette_entries(s, 0, 256);
391     if (s->depth == 24) {
392         tcx24_set_dirty(s);
393     } else {
394         tcx_set_dirty(s);
395     }
396
397     return 0;
398 }
399
400 static const VMStateDescription vmstate_tcx = {
401     .name ="tcx",
402     .version_id = 4,
403     .minimum_version_id = 4,
404     .minimum_version_id_old = 4,
405     .post_load = vmstate_tcx_post_load,
406     .fields      = (VMStateField []) {
407         VMSTATE_UINT16(height, TCXState),
408         VMSTATE_UINT16(width, TCXState),
409         VMSTATE_UINT16(depth, TCXState),
410         VMSTATE_BUFFER(r, TCXState),
411         VMSTATE_BUFFER(g, TCXState),
412         VMSTATE_BUFFER(b, TCXState),
413         VMSTATE_UINT8(dac_index, TCXState),
414         VMSTATE_UINT8(dac_state, TCXState),
415         VMSTATE_END_OF_LIST()
416     }
417 };
418
419 static void tcx_reset(DeviceState *d)
420 {
421     TCXState *s = container_of(d, TCXState, busdev.qdev);
422
423     /* Initialize palette */
424     memset(s->r, 0, 256);
425     memset(s->g, 0, 256);
426     memset(s->b, 0, 256);
427     s->r[255] = s->g[255] = s->b[255] = 255;
428     update_palette_entries(s, 0, 256);
429     memset(s->vram, 0, MAXX*MAXY);
430     memory_region_reset_dirty(&s->vram_mem, 0, MAXX * MAXY * (1 + 4 + 4),
431                               DIRTY_MEMORY_VGA);
432     s->dac_index = 0;
433     s->dac_state = 0;
434 }
435
436 static uint64_t tcx_dac_readl(void *opaque, hwaddr addr,
437                               unsigned size)
438 {
439     return 0;
440 }
441
442 static void tcx_dac_writel(void *opaque, hwaddr addr, uint64_t val,
443                            unsigned size)
444 {
445     TCXState *s = opaque;
446
447     switch (addr) {
448     case 0:
449         s->dac_index = val >> 24;
450         s->dac_state = 0;
451         break;
452     case 4:
453         switch (s->dac_state) {
454         case 0:
455             s->r[s->dac_index] = val >> 24;
456             update_palette_entries(s, s->dac_index, s->dac_index + 1);
457             s->dac_state++;
458             break;
459         case 1:
460             s->g[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 2:
465             s->b[s->dac_index] = val >> 24;
466             update_palette_entries(s, s->dac_index, s->dac_index + 1);
467             s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
468         default:
469             s->dac_state = 0;
470             break;
471         }
472         break;
473     default:
474         break;
475     }
476 }
477
478 static const MemoryRegionOps tcx_dac_ops = {
479     .read = tcx_dac_readl,
480     .write = tcx_dac_writel,
481     .endianness = DEVICE_NATIVE_ENDIAN,
482     .valid = {
483         .min_access_size = 4,
484         .max_access_size = 4,
485     },
486 };
487
488 static uint64_t dummy_readl(void *opaque, hwaddr addr,
489                             unsigned size)
490 {
491     return 0;
492 }
493
494 static void dummy_writel(void *opaque, hwaddr addr,
495                          uint64_t val, unsigned size)
496 {
497 }
498
499 static const MemoryRegionOps dummy_ops = {
500     .read = dummy_readl,
501     .write = dummy_writel,
502     .endianness = DEVICE_NATIVE_ENDIAN,
503     .valid = {
504         .min_access_size = 4,
505         .max_access_size = 4,
506     },
507 };
508
509 static int tcx_init1(SysBusDevice *dev)
510 {
511     TCXState *s = FROM_SYSBUS(TCXState, dev);
512     ram_addr_t vram_offset = 0;
513     int size;
514     uint8_t *vram_base;
515
516     memory_region_init_ram(&s->vram_mem, "tcx.vram",
517                            s->vram_size * (1 + 4 + 4));
518     vmstate_register_ram_global(&s->vram_mem);
519     vram_base = memory_region_get_ram_ptr(&s->vram_mem);
520
521     /* 8-bit plane */
522     s->vram = vram_base;
523     size = s->vram_size;
524     memory_region_init_alias(&s->vram_8bit, "tcx.vram.8bit",
525                              &s->vram_mem, vram_offset, size);
526     sysbus_init_mmio(dev, &s->vram_8bit);
527     vram_offset += size;
528     vram_base += size;
529
530     /* DAC */
531     memory_region_init_io(&s->dac, &tcx_dac_ops, s, "tcx.dac", TCX_DAC_NREGS);
532     sysbus_init_mmio(dev, &s->dac);
533
534     /* TEC (dummy) */
535     memory_region_init_io(&s->tec, &dummy_ops, s, "tcx.tec", TCX_TEC_NREGS);
536     sysbus_init_mmio(dev, &s->tec);
537     /* THC: NetBSD writes here even with 8-bit display: dummy */
538     memory_region_init_io(&s->thc24, &dummy_ops, s, "tcx.thc24",
539                           TCX_THC_NREGS_24);
540     sysbus_init_mmio(dev, &s->thc24);
541
542     if (s->depth == 24) {
543         /* 24-bit plane */
544         size = s->vram_size * 4;
545         s->vram24 = (uint32_t *)vram_base;
546         s->vram24_offset = vram_offset;
547         memory_region_init_alias(&s->vram_24bit, "tcx.vram.24bit",
548                                  &s->vram_mem, vram_offset, size);
549         sysbus_init_mmio(dev, &s->vram_24bit);
550         vram_offset += size;
551         vram_base += size;
552
553         /* Control plane */
554         size = s->vram_size * 4;
555         s->cplane = (uint32_t *)vram_base;
556         s->cplane_offset = vram_offset;
557         memory_region_init_alias(&s->vram_cplane, "tcx.vram.cplane",
558                                  &s->vram_mem, vram_offset, size);
559         sysbus_init_mmio(dev, &s->vram_cplane);
560
561         s->ds = graphic_console_init(tcx24_update_display,
562                                      tcx24_invalidate_display,
563                                      tcx24_screen_dump, NULL, s);
564     } else {
565         /* THC 8 bit (dummy) */
566         memory_region_init_io(&s->thc8, &dummy_ops, s, "tcx.thc8",
567                               TCX_THC_NREGS_8);
568         sysbus_init_mmio(dev, &s->thc8);
569
570         s->ds = graphic_console_init(tcx_update_display,
571                                      tcx_invalidate_display,
572                                      tcx_screen_dump, NULL, s);
573     }
574
575     qemu_console_resize(s->ds, s->width, s->height);
576     return 0;
577 }
578
579 static void tcx_screen_dump(void *opaque, const char *filename, bool cswitch,
580                             Error **errp)
581 {
582     TCXState *s = opaque;
583     FILE *f;
584     uint8_t *d, *d1, v;
585     int ret, y, x;
586
587     f = fopen(filename, "wb");
588     if (!f) {
589         error_setg(errp, "failed to open file '%s': %s", filename,
590                    strerror(errno));
591         return;
592     }
593     ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
594     if (ret < 0) {
595         goto write_err;
596     }
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             ret = fputc(s->r[v], f);
603             if (ret == EOF) {
604                 goto write_err;
605             }
606             ret = fputc(s->g[v], f);
607             if (ret == EOF) {
608                 goto write_err;
609             }
610             ret = fputc(s->b[v], f);
611             if (ret == EOF) {
612                 goto write_err;
613             }
614             d++;
615         }
616         d1 += MAXX;
617     }
618
619 out:
620     fclose(f);
621     return;
622
623 write_err:
624     error_setg(errp, "failed to write to file '%s': %s", filename,
625                strerror(errno));
626     unlink(filename);
627     goto out;
628 }
629
630 static void tcx24_screen_dump(void *opaque, const char *filename, bool cswitch,
631                               Error **errp)
632 {
633     TCXState *s = opaque;
634     FILE *f;
635     uint8_t *d, *d1, v;
636     uint32_t *s24, *cptr, dval;
637     int ret, y, x;
638
639     f = fopen(filename, "wb");
640     if (!f) {
641         error_setg(errp, "failed to open file '%s': %s", filename,
642                    strerror(errno));
643         return;
644     }
645     ret = fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
646     if (ret < 0) {
647         goto write_err;
648     }
649     d1 = s->vram;
650     s24 = s->vram24;
651     cptr = s->cplane;
652     for(y = 0; y < s->height; y++) {
653         d = d1;
654         for(x = 0; x < s->width; x++, d++, s24++) {
655             if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
656                 dval = *s24 & 0x00ffffff;
657                 ret = fputc((dval >> 16) & 0xff, f);
658                 if (ret == EOF) {
659                     goto write_err;
660                 }
661                 ret = fputc((dval >> 8) & 0xff, f);
662                 if (ret == EOF) {
663                     goto write_err;
664                 }
665                 ret = fputc(dval & 0xff, f);
666                 if (ret == EOF) {
667                     goto write_err;
668                 }
669             } else {
670                 v = *d;
671                 ret = fputc(s->r[v], f);
672                 if (ret == EOF) {
673                     goto write_err;
674                 }
675                 ret = fputc(s->g[v], f);
676                 if (ret == EOF) {
677                     goto write_err;
678                 }
679                 ret = fputc(s->b[v], f);
680                 if (ret == EOF) {
681                     goto write_err;
682                 }
683             }
684         }
685         d1 += MAXX;
686     }
687
688 out:
689     fclose(f);
690     return;
691
692 write_err:
693     error_setg(errp, "failed to write to file '%s': %s", filename,
694                strerror(errno));
695     unlink(filename);
696     goto out;
697 }
698
699 static Property tcx_properties[] = {
700     DEFINE_PROP_TADDR("addr",      TCXState, addr,      -1),
701     DEFINE_PROP_HEX32("vram_size", TCXState, vram_size, -1),
702     DEFINE_PROP_UINT16("width",    TCXState, width,     -1),
703     DEFINE_PROP_UINT16("height",   TCXState, height,    -1),
704     DEFINE_PROP_UINT16("depth",    TCXState, depth,     -1),
705     DEFINE_PROP_END_OF_LIST(),
706 };
707
708 static void tcx_class_init(ObjectClass *klass, void *data)
709 {
710     DeviceClass *dc = DEVICE_CLASS(klass);
711     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
712
713     k->init = tcx_init1;
714     dc->reset = tcx_reset;
715     dc->vmsd = &vmstate_tcx;
716     dc->props = tcx_properties;
717 }
718
719 static TypeInfo tcx_info = {
720     .name          = "SUNW,tcx",
721     .parent        = TYPE_SYS_BUS_DEVICE,
722     .instance_size = sizeof(TCXState),
723     .class_init    = tcx_class_init,
724 };
725
726 static void tcx_register_types(void)
727 {
728     type_register_static(&tcx_info);
729 }
730
731 type_init(tcx_register_types)
This page took 0.0707 seconds and 4 git commands to generate.