Commit 1fb3d0dab277a05507009ffd4a5bb0b7e2b66b6a

Authored by Filip Navara
1 parent 3947c3d5

HD44780 LCD Controller

Only very simple emulation of the LCD controller is included.

The controller features the standard HD44780 interface and supports character
output on four lines using a static 5x7 font and optional backlight controlled
by signal on a separate pin.

Capabilities such as custom characters, cursor and 5x10 fonts are not
implemented. Saving/loading of device state is not implemented either.

Signed-off-by: Filip Navara <filip.navara@gmail.com>
Makefile.target
... ... @@ -433,7 +433,7 @@ obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
433 433 obj-arm-y += syborg_virtio.o
434 434 obj-arm-y += at91_aic.o at91_dbgu.o at91_pio.o at91_pit.o at91_pmc.o at91_rtt.o
435 435 obj-arm-y += at91_rstc.o at91_intor.o at91_tc.o at91_emac.o at91pes.o
436   -obj-arm-y += gpio_rotary.o gpio_keypad.o
  436 +obj-arm-y += gpio_rotary.o gpio_keypad.o hd44780.o
437 437  
438 438 ifeq ($(TARGET_BASE_ARCH), arm)
439 439 CPPFLAGS += -DHAS_AUDIO
... ...
hw/at91pes.c
... ... @@ -95,6 +95,17 @@ static void at91pes_init(ram_addr_t ram_size,
95 95 sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xFFFDC000);
96 96 sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[16]);
97 97  
  98 + dev = qdev_create(NULL, "gpio,hd44780");
  99 + qdev_init(dev);
  100 + for (i = 0; i < 3; i++) {
  101 + qdev_connect_gpio_out(pioa, 15 - i, qdev_get_gpio_in(dev, 8 + i));
  102 + }
  103 + qdev_connect_gpio_out(piob, 28, qdev_get_gpio_in(dev, 11));
  104 + for (i = 0; i < 4; i++) {
  105 + qdev_connect_gpio_out(pioa, 5 + i, qdev_get_gpio_in(dev, 4 + i));
  106 + qdev_connect_gpio_out(dev, 4 + i, qdev_get_gpio_in(pioa, 5 + i));
  107 + }
  108 +
98 109 dev = qdev_create(NULL, "gpio,keypad");
99 110 qdev_prop_set_ptr(dev, "keys", keys);
100 111 qdev_init(dev);
... ...
hw/hd44780.c 0 → 100644
  1 +/*
  2 + * HD44780 LCD Controller
  3 + *
  4 + * Copyright (c) 2009 Filip Navara
  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 "sysbus.h"
  26 +#include "console.h"
  27 +#include "pixel_ops.h"
  28 +
  29 +/* pin mapping:
  30 + 8x Data
  31 + Register Select (input only)
  32 + Read/Write (input only)
  33 + Enable (input only)
  34 + Backlight (input only) */
  35 +
  36 +#define D(x) x
  37 +
  38 +#define PIN_RS 8
  39 +#define PIN_RW 9
  40 +#define PIN_E 10
  41 +#define PIN_BL 11
  42 +
  43 +#define LCD_CLR 1 /* DB0: clear display */
  44 +#define LCD_HOME 2 /* DB1: return to home position */
  45 +#define LCD_ENTRY_MODE 4 /* DB2: set entry mode */
  46 +#define LCD_ENTRY_INC 2 /* DB1: increment */
  47 +#define LCD_ENTRY_SHIFT 1 /* DB2: shift */
  48 +#define LCD_ON_CTRL 8 /* DB3: turn lcd/cursor on */
  49 +#define LCD_ON_DISPLAY 4 /* DB2: turn display on */
  50 +#define LCD_ON_CURSOR 2 /* DB1: turn cursor on */
  51 +#define LCD_ON_BLINK 1 /* DB0: blinking cursor */
  52 +#define LCD_MOVE 16 /* DB4: move cursor/display */
  53 +#define LCD_MOVE_DISP 8 /* DB3: move display (0-> move cursor) */
  54 +#define LCD_MOVE_RIGHT 4 /* DB2: move right (0-> left) */
  55 +#define LCD_FUNCTION 32 /* DB5: function set */
  56 +#define LCD_FUNCTION_8BIT 16 /* DB4: set 8BIT mode (0->4BIT mode) */
  57 +#define LCD_FUNCTION_2LINES 8 /* DB3: two lines (0->one line) */
  58 +#define LCD_FUNCTION_10DOTS 4 /* DB2: 5x10 font (0->5x7 font) */
  59 +#define LCD_CGRAM 64 /* DB6: set CG RAM address */
  60 +#define LCD_DDRAM 128 /* DB7: set DD RAM address */
  61 +#define LCD_BUSY 64 /* DB7: LCD is busy */
  62 +
  63 +#define WIDTH 20
  64 +#define HEIGHT 4
  65 +#define CZOOM 3
  66 +
  67 +uint8_t font5x7[][7]={
  68 +/* */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00},
  69 +/* ! */ {0x04,0x04,0x04,0x04,0x00,0x00,0x04},
  70 +/* " */ {0x0A,0x0A,0x0A,0x00,0x00,0x00,0x00},
  71 +/* # */ {0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A},
  72 +/* $ */ {0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04},
  73 +/* % */ {0x18,0x19,0x02,0x04,0x08,0x13,0x03},
  74 +/* & */ {0x00,0x00,0x00,0x00,0x00,0x00,0x00},
  75 +/* ' */ {0x0C,0x04,0x08,0x00,0x00,0x00,0x00},
  76 +/* ( */ {0x02,0x04,0x08,0x08,0x08,0x04,0x02},
  77 +/* ) */ {0x08,0x04,0x02,0x02,0x02,0x04,0x08},
  78 +/* * */ {0x00,0x04,0x15,0x0E,0x15,0x04,0x00},
  79 +/* + */ {0x00,0x04,0x04,0x1F,0x04,0x04,0x00},
  80 +/* , */ {0x00,0x00,0x00,0x00,0x0C,0x04,0x08},
  81 +/* - */ {0x00,0x00,0x00,0x1F,0x00,0x00,0x00},
  82 +/* . */ {0x00,0x00,0x00,0x00,0x00,0x0C,0x0C},
  83 +/* / */ {0x00,0x01,0x02,0x04,0x08,0x10,0x00},
  84 +/* 0 */ {0x0E,0x11,0x13,0x15,0x19,0x11,0x0E},
  85 +/* 1 */ {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E},
  86 +/* 2 */ {0x0E,0x11,0x01,0x02,0x04,0x08,0x1F},
  87 +/* 3 */ {0x1F,0x02,0x04,0x02,0x01,0x11,0x0E},
  88 +/* 4 */ {0x02,0x06,0x0A,0x12,0x1F,0x02,0x02},
  89 +/* 5 */ {0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E},
  90 +/* 6 */ {0x06,0x08,0x10,0x1E,0x11,0x11,0x0E},
  91 +/* 7 */ {0x1F,0x01,0x02,0x04,0x08,0x08,0x08},
  92 +/* 8 */ {0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E},
  93 +/* 9 */ {0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C},
  94 +/* : */ {0x00,0x0C,0x0C,0x00,0x0C,0x0C,0x00},
  95 +/* ; */ {0x00,0x0C,0x0C,0x00,0x0C,0x04,0x08},
  96 +/* < */ {0x02,0x04,0x08,0x10,0x08,0x04,0x02},
  97 +/* = */ {0x00,0x00,0x1F,0x00,0x1F,0x00,0x00},
  98 +/* > */ {0x08,0x04,0x02,0x01,0x02,0x04,0x08},
  99 +/* ? */ {0x0E,0x11,0x01,0x02,0x04,0x00,0x04},
  100 +/* @ */ {0x0E,0x11,0x01,0x0D,0x15,0x15,0x0E},
  101 +/* A */ {0x0E,0x11,0x11,0x11,0x1F,0x11,0x11},
  102 +/* B */ {0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E},
  103 +/* C */ {0x0E,0x11,0x10,0x10,0x10,0x11,0x0E},
  104 +/* D */ {0x1C,0x12,0x11,0x11,0x11,0x12,0x1C},
  105 +/* E */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F},
  106 +/* F */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x10},
  107 +/* G */ {0x0E,0x11,0x10,0x17,0x11,0x11,0x0F},
  108 +/* H */ {0x11,0x11,0x11,0x1F,0x11,0x11,0x11},
  109 +/* I */ {0x0E,0x04,0x04,0x04,0x04,0x04,0x0E},
  110 +/* J */ {0x07,0x02,0x02,0x02,0x02,0x12,0x0C},
  111 +/* K */ {0x11,0x12,0x14,0x18,0x14,0x12,0x11},
  112 +/* L */ {0x10,0x10,0x10,0x10,0x10,0x10,0x1F},
  113 +/* M */ {0x11,0x1B,0x15,0x15,0x11,0x11,0x11},
  114 +/* N */ {0x11,0x11,0x19,0x15,0x13,0x11,0x11},
  115 +/* O */ {0x0E,0x11,0x11,0x11,0x11,0x11,0x0E},
  116 +/* P */ {0x1E,0x11,0x11,0x1E,0x10,0x10,0x10},
  117 +/* Q */ {0x0E,0x11,0x11,0x11,0x15,0x12,0x0D},
  118 +/* R */ {0x1E,0x11,0x11,0x1E,0x14,0x12,0x11},
  119 +/* S */ {0x0F,0x10,0x10,0x0E,0x01,0x01,0x1E},
  120 +/* T */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x04},
  121 +/* U */ {0x11,0x11,0x11,0x11,0x11,0x11,0x0E},
  122 +/* V */ {0x11,0x11,0x11,0x11,0x11,0x0A,0x04},
  123 +/* W */ {0x11,0x11,0x11,0x15,0x15,0x15,0x0A},
  124 +/* X */ {0x11,0x11,0x0A,0x04,0x0A,0x11,0x11},
  125 +/* Y */ {0x11,0x11,0x11,0x0A,0x04,0x04,0x04},
  126 +/* Z */ {0x1F,0x01,0x02,0x04,0x08,0x10,0x1F},
  127 +/* [ */ {0x0E,0x08,0x08,0x08,0x08,0x08,0x0E},
  128 +/* \ */ {0x00,0x10,0x08,0x04,0x02,0x01,0x00},
  129 +/* ] */ {0x0E,0x02,0x02,0x02,0x02,0x02,0x0E},
  130 +/* ^ */ {0x04,0x0A,0x11,0x00,0x00,0x00,0x00},
  131 +/* _ */ {0x00,0x00,0x00,0x00,0x00,0x00,0x1F},
  132 +/* ` */ {0x08,0x04,0x02,0x00,0x00,0x00,0x00},
  133 +/* a */ {0x00,0x00,0x0E,0x01,0x0F,0x11,0x0F},
  134 +/* b */ {0x10,0x10,0x10,0x16,0x19,0x11,0x1E},
  135 +/* c */ {0x00,0x00,0x0E,0x10,0x10,0x11,0x0E},
  136 +/* d */ {0x01,0x01,0x01,0x0D,0x13,0x11,0x0F},
  137 +/* e */ {0x00,0x00,0x0E,0x11,0x1F,0x10,0x0E},
  138 +/* f */ {0x06,0x09,0x08,0x1C,0x08,0x08,0x08},
  139 +/* g */ {0x00,0x0F,0x11,0x11,0x0F,0x01,0x0E},
  140 +/* h */ {0x10,0x10,0x16,0x19,0x11,0x11,0x11},
  141 +/* i */ {0x00,0x04,0x00,0x04,0x04,0x04,0x04},
  142 +/* j */ {0x02,0x00,0x06,0x02,0x02,0x12,0x0C},
  143 +/* k */ {0x10,0x10,0x12,0x14,0x18,0x14,0x12},
  144 +/* l */ {0x04,0x04,0x04,0x04,0x04,0x04,0x0F},
  145 +/* m */ {0x00,0x00,0x1A,0x15,0x15,0x11,0x11},
  146 +/* n */ {0x00,0x00,0x16,0x19,0x11,0x11,0x11},
  147 +/* o */ {0x00,0x00,0x0E,0x11,0x11,0x11,0x0E},
  148 +/* p */ {0x00,0x00,0x1E,0x11,0x1E,0x10,0x10},
  149 +/* q */ {0x00,0x00,0x0D,0x13,0x0F,0x01,0x01},
  150 +/* r */ {0x00,0x00,0x16,0x19,0x10,0x10,0x10},
  151 +/* s */ {0x00,0x00,0x0E,0x10,0x0E,0x01,0x1E},
  152 +/* t */ {0x08,0x08,0x1C,0x08,0x08,0x09,0x06},
  153 +/* u */ {0x00,0x00,0x11,0x11,0x11,0x13,0x0D},
  154 +/* v */ {0x00,0x00,0x11,0x11,0x11,0x0A,0x04},
  155 +/* w */ {0x00,0x00,0x11,0x11,0x15,0x15,0x0A},
  156 +/* x */ {0x00,0x00,0x11,0x0A,0x04,0x0A,0x11},
  157 +/* y */ {0x00,0x00,0x11,0x11,0x0F,0x01,0x0E},
  158 +/* z */ {0x00,0x00,0x1F,0x02,0x04,0x08,0x1F},
  159 +/* { */ {0x02,0x04,0x04,0x08,0x04,0x04,0x02},
  160 +/* | */ {0x04,0x04,0x04,0x04,0x04,0x04,0x04},
  161 +/* } */ {0x08,0x04,0x04,0x02,0x04,0x04,0x08},
  162 +};
  163 +
  164 +typedef struct LCDState {
  165 + SysBusDevice busdev;
  166 + qemu_irq out[8];
  167 + DisplayState *ds;
  168 +
  169 + uint8_t input;
  170 + uint32_t control : 1;
  171 + uint32_t rw : 1;
  172 + uint32_t backlight : 1;
  173 +
  174 + uint8_t mode8bit : 1;
  175 + uint8_t write_low : 1;
  176 +
  177 + uint8_t ac; /* address counter */
  178 + uint8_t dispcol; /* first visible column (display shift!) */
  179 + uint8_t id : 1; /* cursor move increase(1)/decrease(0) */
  180 + uint8_t sh : 1; /* shift display(1) */
  181 + uint8_t ddram : 1; /* access ddram(1)/cgram(0) */
  182 +
  183 + uint8_t display : 1;
  184 + uint8_t cursor : 1;
  185 + uint8_t blink : 1;
  186 +
  187 + uint8_t two_lines : 1;
  188 + uint8_t font5x10 : 1;
  189 +
  190 + uint8_t need_update : 1;
  191 + char data[20 * 4];
  192 +} LCDState;
  193 +
  194 +static void draw_char(DisplayState *ds, int x, int y, char ch, uint32_t color, uint32_t backcolor)
  195 +{
  196 + uint8_t *d;
  197 + uint8_t cdata;
  198 + int i, bpp, line;
  199 +
  200 + bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
  201 + for (line = 0; line < 7 * CZOOM; line++) {
  202 + d = ds_get_data(ds) + ds_get_linesize(ds) * y + bpp * x;
  203 + if (ch >= ' ' && (ch - ' ') < sizeof(font5x7)/sizeof(font5x7[0]))
  204 + cdata = font5x7[(int)(ch - ' ')][line / CZOOM];
  205 + else
  206 + cdata = font5x7[0][line / CZOOM];
  207 + switch(bpp) {
  208 + case 1:
  209 + d += 5 * CZOOM;
  210 + for (i = 0; i < 5 * CZOOM; i++) {
  211 + *((uint8_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor;
  212 + d--;
  213 + }
  214 + break;
  215 + case 2:
  216 + d += 10 * CZOOM;
  217 + for (i = 0; i < 5 * CZOOM; i++) {
  218 + *((uint16_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor;
  219 + d -= 2;
  220 + }
  221 + break;
  222 + case 4:
  223 + d += 20 * CZOOM;
  224 + for (i = 0; i < 5 * CZOOM; i++) {
  225 + *((uint32_t *)d) = (cdata & (1 << (i / CZOOM))) ? color : backcolor;
  226 + d -= 4;
  227 + }
  228 + break;
  229 + }
  230 + y++;
  231 + }
  232 +}
  233 +
  234 +static void hd44780_enable(LCDState *s)
  235 +{
  236 + if (s->control) {
  237 + //D(printf("CONTROL: %x\n", s->input));
  238 + if (s->input & LCD_DDRAM) {
  239 + int ddram_addr = s->input & ~LCD_DDRAM;
  240 + if (ddram_addr >= 0 && ddram_addr < WIDTH)
  241 + s->ac = ddram_addr;
  242 + else if (ddram_addr >= 64 && ddram_addr < 64 + WIDTH)
  243 + s->ac = (ddram_addr - 64) + WIDTH;
  244 + else if (ddram_addr >= 20 && ddram_addr < 20 + WIDTH)
  245 + s->ac = (ddram_addr - 20) + WIDTH * 2;
  246 + else if (ddram_addr >= 84 && ddram_addr < 84 + WIDTH)
  247 + s->ac = (ddram_addr - 84) + WIDTH * 3;
  248 + s->ddram = 1;
  249 + } else if (s->input & LCD_CGRAM) {
  250 + s->ac = s->input & ~LCD_CGRAM;
  251 + s->ddram = 0;
  252 + } else if (s->input & LCD_FUNCTION) {
  253 + s->mode8bit = !!(s->input & LCD_FUNCTION_8BIT);
  254 + s->two_lines = !!(s->input & LCD_FUNCTION_2LINES);
  255 + s->font5x10 = !!(s->input & LCD_FUNCTION_10DOTS);
  256 + } else if (s->input & LCD_MOVE) {
  257 + if (s->input & LCD_MOVE_DISP) {
  258 + if (s->input & LCD_MOVE_RIGHT) {
  259 + s->dispcol--;
  260 + } else {
  261 + s->dispcol++;
  262 + }
  263 + s->dispcol %= sizeof(s->data);
  264 + } else {
  265 + // ...
  266 + }
  267 + } else if (s->input & LCD_ON_CTRL) {
  268 + s->display = !!(s->input & LCD_ON_DISPLAY);
  269 + s->cursor = !!(s->input & LCD_ON_CURSOR);
  270 + s->blink = !!(s->input & LCD_ON_BLINK);
  271 + } else if (s->input & LCD_ENTRY_MODE) {
  272 + s->id = !!(s->input & LCD_ENTRY_INC);
  273 + s->sh = !!(s->input & LCD_ENTRY_SHIFT);
  274 + } else if (s->input & LCD_HOME) {
  275 + s->ac = 0;
  276 + s->dispcol = 0;
  277 + s->ddram = 1;
  278 + } else if (s->input & LCD_CLR) {
  279 + memset(s->data, 32, sizeof(s->data));
  280 + s->ac = 0;
  281 + s->dispcol = 0;
  282 + s->id = 1;
  283 + s->ddram = 1;
  284 + }
  285 + } else {
  286 + if (s->ddram) {
  287 + s->data[s->ac] = s->input;
  288 + s->ac++;
  289 + s->ac %= sizeof(s->data);
  290 + if (s->sh) {
  291 + if (s->id) {
  292 + s->dispcol++;
  293 + } else {
  294 + s->dispcol--;
  295 + }
  296 + s->dispcol %= sizeof(s->data);
  297 + }
  298 + s->need_update = 1;
  299 + } else {
  300 + // ...
  301 + }
  302 + }
  303 +}
  304 +
  305 +static void hd44780_set_pin(void *opaque, int pin, int level)
  306 +{
  307 + LCDState *s = opaque;
  308 +
  309 + if (pin >= 0 && pin <= 7) {
  310 + if (!s->rw) {
  311 + if (!s->mode8bit && s->write_low)
  312 + pin -= 4;
  313 + if (level)
  314 + s->input |= 1 << pin;
  315 + else
  316 + s->input &= ~(1 << pin);
  317 + }
  318 + } else if (pin == PIN_RS) {
  319 + s->control = !level;
  320 + } else if (pin == PIN_RW) {
  321 + s->rw = level;
  322 + } else if (pin == PIN_E) {
  323 + if (!level && !s->rw) {
  324 + if (!s->mode8bit) {
  325 + s->write_low = !s->write_low;
  326 + if (!s->write_low)
  327 + hd44780_enable(s);
  328 + } else {
  329 + hd44780_enable(s);
  330 + }
  331 + }
  332 + } else if (pin == PIN_BL) {
  333 + s->backlight = level;
  334 + s->need_update = 1;
  335 + }
  336 +}
  337 +
  338 +static void hd44780_update_display(void *opaque)
  339 +{
  340 + LCDState *s = opaque;
  341 + uint32_t color_segment, color_led;
  342 + int y, x, r, g, b;
  343 +
  344 + if (s->need_update) {
  345 + if (s->backlight) {
  346 + r = 0;
  347 + g = 0xff;
  348 + b = 0x80;
  349 + } else {
  350 + r = 0xf0;
  351 + g = 0xe0;
  352 + b = 0xb0;
  353 + }
  354 +
  355 + switch (ds_get_bits_per_pixel(s->ds)) {
  356 + case 8:
  357 + color_segment = rgb_to_pixel8(0, 0, 0);
  358 + color_led = rgb_to_pixel8(r, g, b);
  359 + break;
  360 + case 15:
  361 + color_segment = rgb_to_pixel15(0, 0, 0);
  362 + color_led = rgb_to_pixel15(r, g, b);
  363 + break;
  364 + case 16:
  365 + color_segment = rgb_to_pixel16(0, 0, 0);
  366 + color_led = rgb_to_pixel16(r, g, b);
  367 + break;
  368 + case 24:
  369 + color_segment = rgb_to_pixel24(0, 0, 0);
  370 + color_led = rgb_to_pixel24(r, g, b);
  371 + break;
  372 + case 32:
  373 + color_segment = rgb_to_pixel32(0, 0, 0);
  374 + color_led = rgb_to_pixel32(r, g, b);
  375 + break;
  376 + default:
  377 + return;
  378 + }
  379 +
  380 + if (s->display) {
  381 + for (y = 0; y < HEIGHT; y++) {
  382 + for (x = 0; x < WIDTH; x++) {
  383 + draw_char(s->ds, x * 5 * CZOOM, y * 7 * CZOOM, s->data[y * WIDTH + x], color_segment, color_led);
  384 + }
  385 + }
  386 + }
  387 +
  388 + dpy_update(s->ds, 0, 0, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7);
  389 + }
  390 +}
  391 +
  392 +static void hd44780_invalidate_display(void * opaque)
  393 +{
  394 + LCDState *s = opaque;
  395 + s->need_update = 1;
  396 +}
  397 +
  398 +static void hd44780_init(SysBusDevice *dev)
  399 +{
  400 + LCDState *s = FROM_SYSBUS(LCDState, dev);
  401 +
  402 + s->need_update = 1;
  403 +
  404 + qdev_init_gpio_in(&dev->qdev, hd44780_set_pin, 12);
  405 + qdev_init_gpio_out(&dev->qdev, s->out, 8);
  406 +
  407 + s->ds = graphic_console_init(hd44780_update_display,
  408 + hd44780_invalidate_display,
  409 + NULL, NULL, s);
  410 + qemu_console_resize(s->ds, WIDTH * CZOOM * 5, HEIGHT * CZOOM * 7);
  411 +}
  412 +
  413 +static void hd44780_register(void)
  414 +{
  415 + sysbus_register_dev("gpio,hd44780", sizeof(LCDState),
  416 + hd44780_init);
  417 +}
  418 +
  419 +device_init(hd44780_register)
... ...