Commit 1fb3d0dab277a05507009ffd4a5bb0b7e2b66b6a
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>
Showing
3 changed files
with
431 additions
and
1 deletions
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) | ... | ... |