root / hw / ssd0323.c @ 3c892168
History | View | Annotate | Download (9 kB)
1 | 9ee6e8bb | pbrook | /*
|
---|---|---|---|
2 | 9ee6e8bb | pbrook | * SSD0323 OLED controller with OSRAM Pictiva 128x64 display.
|
3 | 9ee6e8bb | pbrook | *
|
4 | 9ee6e8bb | pbrook | * Copyright (c) 2006-2007 CodeSourcery.
|
5 | 9ee6e8bb | pbrook | * Written by Paul Brook
|
6 | 9ee6e8bb | pbrook | *
|
7 | 9ee6e8bb | pbrook | * This code is licenced under the GPL.
|
8 | 9ee6e8bb | pbrook | */
|
9 | 9ee6e8bb | pbrook | |
10 | 9ee6e8bb | pbrook | /* The controller can support a variety of different displays, but we only
|
11 | 9ee6e8bb | pbrook | implement one. Most of the commends relating to brightness and geometry
|
12 | 9ee6e8bb | pbrook | setup are ignored. */
|
13 | 87ecb68b | pbrook | #include "hw.h" |
14 | 87ecb68b | pbrook | #include "devices.h" |
15 | 87ecb68b | pbrook | #include "console.h" |
16 | 9ee6e8bb | pbrook | |
17 | 9ee6e8bb | pbrook | //#define DEBUG_SSD0323 1
|
18 | 9ee6e8bb | pbrook | |
19 | 9ee6e8bb | pbrook | #ifdef DEBUG_SSD0323
|
20 | 9ee6e8bb | pbrook | #define DPRINTF(fmt, args...) \
|
21 | 9ee6e8bb | pbrook | do { printf("ssd0323: " fmt , ##args); } while (0) |
22 | 9ee6e8bb | pbrook | #define BADF(fmt, args...) \
|
23 | 9ee6e8bb | pbrook | do { fprintf(stderr, "ssd0323: error: " fmt , ##args); exit(1);} while (0) |
24 | 9ee6e8bb | pbrook | #else
|
25 | 9ee6e8bb | pbrook | #define DPRINTF(fmt, args...) do {} while(0) |
26 | 9ee6e8bb | pbrook | #define BADF(fmt, args...) \
|
27 | 9ee6e8bb | pbrook | do { fprintf(stderr, "ssd0323: error: " fmt , ##args);} while (0) |
28 | 9ee6e8bb | pbrook | #endif
|
29 | 9ee6e8bb | pbrook | |
30 | 9ee6e8bb | pbrook | /* Scaling factor for pixels. */
|
31 | 9ee6e8bb | pbrook | #define MAGNIFY 4 |
32 | 9ee6e8bb | pbrook | |
33 | 7ac56ff0 | pbrook | #define REMAP_SWAP_COLUMN 0x01 |
34 | 7ac56ff0 | pbrook | #define REMAP_SWAP_NYBBLE 0x02 |
35 | 7ac56ff0 | pbrook | #define REMAP_VERTICAL 0x04 |
36 | 7ac56ff0 | pbrook | #define REMAP_SWAP_COM 0x10 |
37 | 7ac56ff0 | pbrook | #define REMAP_SPLIT_COM 0x40 |
38 | 7ac56ff0 | pbrook | |
39 | 9ee6e8bb | pbrook | enum ssd0323_mode
|
40 | 9ee6e8bb | pbrook | { |
41 | 9ee6e8bb | pbrook | SSD0323_CMD, |
42 | 9ee6e8bb | pbrook | SSD0323_DATA |
43 | 9ee6e8bb | pbrook | }; |
44 | 9ee6e8bb | pbrook | |
45 | 9ee6e8bb | pbrook | typedef struct { |
46 | 9ee6e8bb | pbrook | DisplayState *ds; |
47 | 9ee6e8bb | pbrook | |
48 | 9ee6e8bb | pbrook | int cmd_len;
|
49 | 9ee6e8bb | pbrook | int cmd;
|
50 | 9ee6e8bb | pbrook | int cmd_data[8]; |
51 | 9ee6e8bb | pbrook | int row;
|
52 | 9ee6e8bb | pbrook | int row_start;
|
53 | 9ee6e8bb | pbrook | int row_end;
|
54 | 9ee6e8bb | pbrook | int col;
|
55 | 9ee6e8bb | pbrook | int col_start;
|
56 | 9ee6e8bb | pbrook | int col_end;
|
57 | 9ee6e8bb | pbrook | int redraw;
|
58 | 7ac56ff0 | pbrook | int remap;
|
59 | 9ee6e8bb | pbrook | enum ssd0323_mode mode;
|
60 | 9ee6e8bb | pbrook | uint8_t framebuffer[128 * 80 / 2]; |
61 | 9ee6e8bb | pbrook | } ssd0323_state; |
62 | 9ee6e8bb | pbrook | |
63 | 9ee6e8bb | pbrook | int ssd0323_xfer_ssi(void *opaque, int data) |
64 | 9ee6e8bb | pbrook | { |
65 | 9ee6e8bb | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
66 | 9ee6e8bb | pbrook | switch (s->mode) {
|
67 | 9ee6e8bb | pbrook | case SSD0323_DATA:
|
68 | 9ee6e8bb | pbrook | DPRINTF("data 0x%02x\n", data);
|
69 | 9ee6e8bb | pbrook | s->framebuffer[s->col + s->row * 64] = data;
|
70 | 7ac56ff0 | pbrook | if (s->remap & REMAP_VERTICAL) {
|
71 | 9ee6e8bb | pbrook | s->row++; |
72 | 7ac56ff0 | pbrook | if (s->row > s->row_end) {
|
73 | 7ac56ff0 | pbrook | s->row = s->row_start; |
74 | 7ac56ff0 | pbrook | s->col++; |
75 | 7ac56ff0 | pbrook | } |
76 | 7ac56ff0 | pbrook | if (s->col > s->col_end) {
|
77 | 7ac56ff0 | pbrook | s->col = s->col_start; |
78 | 7ac56ff0 | pbrook | } |
79 | 7ac56ff0 | pbrook | } else {
|
80 | 7ac56ff0 | pbrook | s->col++; |
81 | 7ac56ff0 | pbrook | if (s->col > s->col_end) {
|
82 | 7ac56ff0 | pbrook | s->row++; |
83 | 7ac56ff0 | pbrook | s->col = s->col_start; |
84 | 7ac56ff0 | pbrook | } |
85 | 7ac56ff0 | pbrook | if (s->row > s->row_end) {
|
86 | 7ac56ff0 | pbrook | s->row = s->row_start; |
87 | 7ac56ff0 | pbrook | } |
88 | 9ee6e8bb | pbrook | } |
89 | 9ee6e8bb | pbrook | s->redraw = 1;
|
90 | 9ee6e8bb | pbrook | break;
|
91 | 9ee6e8bb | pbrook | case SSD0323_CMD:
|
92 | 9ee6e8bb | pbrook | DPRINTF("cmd 0x%02x\n", data);
|
93 | 9ee6e8bb | pbrook | if (s->cmd_len == 0) { |
94 | 9ee6e8bb | pbrook | s->cmd = data; |
95 | 9ee6e8bb | pbrook | } else {
|
96 | 9ee6e8bb | pbrook | s->cmd_data[s->cmd_len - 1] = data;
|
97 | 9ee6e8bb | pbrook | } |
98 | 9ee6e8bb | pbrook | s->cmd_len++; |
99 | 9ee6e8bb | pbrook | switch (s->cmd) {
|
100 | 9ee6e8bb | pbrook | #define DATA(x) if (s->cmd_len <= (x)) return 0 |
101 | 9ee6e8bb | pbrook | case 0x15: /* Set column. */ |
102 | 9ee6e8bb | pbrook | DATA(2);
|
103 | 7ac56ff0 | pbrook | s->col = s->col_start = s->cmd_data[0] % 64; |
104 | 9ee6e8bb | pbrook | s->col_end = s->cmd_data[1] % 64; |
105 | 9ee6e8bb | pbrook | break;
|
106 | 9ee6e8bb | pbrook | case 0x75: /* Set row. */ |
107 | 9ee6e8bb | pbrook | DATA(2);
|
108 | 7ac56ff0 | pbrook | s->row = s->row_start = s->cmd_data[0] % 80; |
109 | 9ee6e8bb | pbrook | s->row_end = s->cmd_data[1] % 80; |
110 | 9ee6e8bb | pbrook | break;
|
111 | 9ee6e8bb | pbrook | case 0x81: /* Set contrast */ |
112 | 9ee6e8bb | pbrook | DATA(1);
|
113 | 9ee6e8bb | pbrook | break;
|
114 | 9ee6e8bb | pbrook | case 0x84: case 0x85: case 0x86: /* Max current. */ |
115 | 9ee6e8bb | pbrook | DATA(0);
|
116 | 9ee6e8bb | pbrook | break;
|
117 | 9ee6e8bb | pbrook | case 0xa0: /* Set remapping. */ |
118 | 9ee6e8bb | pbrook | /* FIXME: Implement this. */
|
119 | 9ee6e8bb | pbrook | DATA(1);
|
120 | 7ac56ff0 | pbrook | s->remap = s->cmd_data[0];
|
121 | 9ee6e8bb | pbrook | break;
|
122 | 9ee6e8bb | pbrook | case 0xa1: /* Set display start line. */ |
123 | 9ee6e8bb | pbrook | case 0xa2: /* Set display offset. */ |
124 | 9ee6e8bb | pbrook | /* FIXME: Implement these. */
|
125 | 9ee6e8bb | pbrook | DATA(1);
|
126 | 9ee6e8bb | pbrook | break;
|
127 | 9ee6e8bb | pbrook | case 0xa4: /* Normal mode. */ |
128 | 9ee6e8bb | pbrook | case 0xa5: /* All on. */ |
129 | 9ee6e8bb | pbrook | case 0xa6: /* All off. */ |
130 | 9ee6e8bb | pbrook | case 0xa7: /* Inverse. */ |
131 | 9ee6e8bb | pbrook | /* FIXME: Implement these. */
|
132 | 9ee6e8bb | pbrook | DATA(0);
|
133 | 9ee6e8bb | pbrook | break;
|
134 | 9ee6e8bb | pbrook | case 0xa8: /* Set multiplex ratio. */ |
135 | 9ee6e8bb | pbrook | case 0xad: /* Set DC-DC converter. */ |
136 | 9ee6e8bb | pbrook | DATA(1);
|
137 | 9ee6e8bb | pbrook | /* Ignored. Don't care. */
|
138 | 9ee6e8bb | pbrook | break;
|
139 | 9ee6e8bb | pbrook | case 0xae: /* Display off. */ |
140 | 9ee6e8bb | pbrook | case 0xaf: /* Display on. */ |
141 | 9ee6e8bb | pbrook | DATA(0);
|
142 | 9ee6e8bb | pbrook | /* TODO: Implement power control. */
|
143 | 9ee6e8bb | pbrook | break;
|
144 | 9ee6e8bb | pbrook | case 0xb1: /* Set phase length. */ |
145 | 9ee6e8bb | pbrook | case 0xb2: /* Set row period. */ |
146 | 9ee6e8bb | pbrook | case 0xb3: /* Set clock rate. */ |
147 | 9ee6e8bb | pbrook | case 0xbc: /* Set precharge. */ |
148 | 9ee6e8bb | pbrook | case 0xbe: /* Set VCOMH. */ |
149 | 9ee6e8bb | pbrook | case 0xbf: /* Set segment low. */ |
150 | 9ee6e8bb | pbrook | DATA(1);
|
151 | 9ee6e8bb | pbrook | /* Ignored. Don't care. */
|
152 | 9ee6e8bb | pbrook | break;
|
153 | 9ee6e8bb | pbrook | case 0xb8: /* Set grey scale table. */ |
154 | 9ee6e8bb | pbrook | /* FIXME: Implement this. */
|
155 | 9ee6e8bb | pbrook | DATA(8);
|
156 | 9ee6e8bb | pbrook | break;
|
157 | 9ee6e8bb | pbrook | case 0xe3: /* NOP. */ |
158 | 9ee6e8bb | pbrook | DATA(0);
|
159 | 9ee6e8bb | pbrook | break;
|
160 | 775616c3 | pbrook | case 0xff: /* Nasty hack because we don't handle chip selects |
161 | 775616c3 | pbrook | properly. */
|
162 | 775616c3 | pbrook | break;
|
163 | 9ee6e8bb | pbrook | default:
|
164 | 9ee6e8bb | pbrook | BADF("Unknown command: 0x%x\n", data);
|
165 | 9ee6e8bb | pbrook | } |
166 | 9ee6e8bb | pbrook | s->cmd_len = 0;
|
167 | 9ee6e8bb | pbrook | return 0; |
168 | 9ee6e8bb | pbrook | } |
169 | 9ee6e8bb | pbrook | return 0; |
170 | 9ee6e8bb | pbrook | } |
171 | 9ee6e8bb | pbrook | |
172 | 9ee6e8bb | pbrook | static void ssd0323_update_display(void *opaque) |
173 | 9ee6e8bb | pbrook | { |
174 | 9ee6e8bb | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
175 | 9ee6e8bb | pbrook | uint8_t *dest; |
176 | 9ee6e8bb | pbrook | uint8_t *src; |
177 | 9ee6e8bb | pbrook | int x;
|
178 | 9ee6e8bb | pbrook | int y;
|
179 | 9ee6e8bb | pbrook | int i;
|
180 | 9ee6e8bb | pbrook | int line;
|
181 | 9ee6e8bb | pbrook | char *colors[16]; |
182 | 9ee6e8bb | pbrook | char colortab[MAGNIFY * 64]; |
183 | 9ee6e8bb | pbrook | char *p;
|
184 | 9ee6e8bb | pbrook | int dest_width;
|
185 | 9ee6e8bb | pbrook | |
186 | b115bb3f | pbrook | if (!s->redraw)
|
187 | b115bb3f | pbrook | return;
|
188 | b115bb3f | pbrook | |
189 | 0e1f5a0c | aliguori | switch (ds_get_bits_per_pixel(s->ds)) {
|
190 | b115bb3f | pbrook | case 0: |
191 | b115bb3f | pbrook | return;
|
192 | b115bb3f | pbrook | case 15: |
193 | b115bb3f | pbrook | dest_width = 2;
|
194 | b115bb3f | pbrook | break;
|
195 | b115bb3f | pbrook | case 16: |
196 | b115bb3f | pbrook | dest_width = 2;
|
197 | b115bb3f | pbrook | break;
|
198 | b115bb3f | pbrook | case 24: |
199 | b115bb3f | pbrook | dest_width = 3;
|
200 | b115bb3f | pbrook | break;
|
201 | b115bb3f | pbrook | case 32: |
202 | b115bb3f | pbrook | dest_width = 4;
|
203 | b115bb3f | pbrook | break;
|
204 | b115bb3f | pbrook | default:
|
205 | b115bb3f | pbrook | BADF("Bad color depth\n");
|
206 | b115bb3f | pbrook | return;
|
207 | b115bb3f | pbrook | } |
208 | b115bb3f | pbrook | p = colortab; |
209 | b115bb3f | pbrook | for (i = 0; i < 16; i++) { |
210 | b115bb3f | pbrook | int n;
|
211 | b115bb3f | pbrook | colors[i] = p; |
212 | 0e1f5a0c | aliguori | switch (ds_get_bits_per_pixel(s->ds)) {
|
213 | 9ee6e8bb | pbrook | case 15: |
214 | b115bb3f | pbrook | n = i * 2 + (i >> 3); |
215 | b115bb3f | pbrook | p[0] = n | (n << 5); |
216 | b115bb3f | pbrook | p[1] = (n << 2) | (n >> 3); |
217 | 9ee6e8bb | pbrook | break;
|
218 | 9ee6e8bb | pbrook | case 16: |
219 | b115bb3f | pbrook | n = i * 2 + (i >> 3); |
220 | b115bb3f | pbrook | p[0] = n | (n << 6) | ((n << 1) & 0x20); |
221 | b115bb3f | pbrook | p[1] = (n << 3) | (n >> 2); |
222 | 9ee6e8bb | pbrook | break;
|
223 | 9ee6e8bb | pbrook | case 24: |
224 | 9ee6e8bb | pbrook | case 32: |
225 | b115bb3f | pbrook | n = (i << 4) | i;
|
226 | b115bb3f | pbrook | p[0] = p[1] = p[2] = n; |
227 | 9ee6e8bb | pbrook | break;
|
228 | 9ee6e8bb | pbrook | default:
|
229 | 9ee6e8bb | pbrook | BADF("Bad color depth\n");
|
230 | 9ee6e8bb | pbrook | return;
|
231 | 9ee6e8bb | pbrook | } |
232 | b115bb3f | pbrook | p += dest_width; |
233 | b115bb3f | pbrook | } |
234 | b115bb3f | pbrook | /* TODO: Implement row/column remapping. */
|
235 | 0e1f5a0c | aliguori | dest = ds_get_data(s->ds); |
236 | b115bb3f | pbrook | for (y = 0; y < 64; y++) { |
237 | b115bb3f | pbrook | line = y; |
238 | b115bb3f | pbrook | src = s->framebuffer + 64 * line;
|
239 | b115bb3f | pbrook | for (x = 0; x < 64; x++) { |
240 | b115bb3f | pbrook | int val;
|
241 | b115bb3f | pbrook | val = *src >> 4;
|
242 | b115bb3f | pbrook | for (i = 0; i < MAGNIFY; i++) { |
243 | b115bb3f | pbrook | memcpy(dest, colors[val], dest_width); |
244 | b115bb3f | pbrook | dest += dest_width; |
245 | 9ee6e8bb | pbrook | } |
246 | b115bb3f | pbrook | val = *src & 0xf;
|
247 | b115bb3f | pbrook | for (i = 0; i < MAGNIFY; i++) { |
248 | b115bb3f | pbrook | memcpy(dest, colors[val], dest_width); |
249 | b115bb3f | pbrook | dest += dest_width; |
250 | 9ee6e8bb | pbrook | } |
251 | b115bb3f | pbrook | src++; |
252 | b115bb3f | pbrook | } |
253 | b115bb3f | pbrook | for (i = 1; i < MAGNIFY; i++) { |
254 | b115bb3f | pbrook | memcpy(dest, dest - dest_width * MAGNIFY * 128,
|
255 | b115bb3f | pbrook | dest_width * 128 * MAGNIFY);
|
256 | b115bb3f | pbrook | dest += dest_width * 128 * MAGNIFY;
|
257 | 9ee6e8bb | pbrook | } |
258 | 9ee6e8bb | pbrook | } |
259 | b115bb3f | pbrook | s->redraw = 0;
|
260 | 9ee6e8bb | pbrook | dpy_update(s->ds, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY); |
261 | 9ee6e8bb | pbrook | } |
262 | 9ee6e8bb | pbrook | |
263 | 9ee6e8bb | pbrook | static void ssd0323_invalidate_display(void * opaque) |
264 | 9ee6e8bb | pbrook | { |
265 | 9ee6e8bb | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
266 | 9ee6e8bb | pbrook | s->redraw = 1;
|
267 | 9ee6e8bb | pbrook | } |
268 | 9ee6e8bb | pbrook | |
269 | 9ee6e8bb | pbrook | /* Command/data input. */
|
270 | 9ee6e8bb | pbrook | static void ssd0323_cd(void *opaque, int n, int level) |
271 | 9ee6e8bb | pbrook | { |
272 | 9ee6e8bb | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
273 | 9ee6e8bb | pbrook | DPRINTF("%s mode\n", level ? "Data" : "Command"); |
274 | 9ee6e8bb | pbrook | s->mode = level ? SSD0323_DATA : SSD0323_CMD; |
275 | 9ee6e8bb | pbrook | } |
276 | 9ee6e8bb | pbrook | |
277 | 23e39294 | pbrook | static void ssd0323_save(QEMUFile *f, void *opaque) |
278 | 23e39294 | pbrook | { |
279 | 23e39294 | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
280 | 23e39294 | pbrook | int i;
|
281 | 23e39294 | pbrook | |
282 | 23e39294 | pbrook | qemu_put_be32(f, s->cmd_len); |
283 | 23e39294 | pbrook | qemu_put_be32(f, s->cmd); |
284 | 23e39294 | pbrook | for (i = 0; i < 8; i++) |
285 | 23e39294 | pbrook | qemu_put_be32(f, s->cmd_data[i]); |
286 | 23e39294 | pbrook | qemu_put_be32(f, s->row); |
287 | 23e39294 | pbrook | qemu_put_be32(f, s->row_start); |
288 | 23e39294 | pbrook | qemu_put_be32(f, s->row_end); |
289 | 23e39294 | pbrook | qemu_put_be32(f, s->col); |
290 | 23e39294 | pbrook | qemu_put_be32(f, s->col_start); |
291 | 23e39294 | pbrook | qemu_put_be32(f, s->col_end); |
292 | 23e39294 | pbrook | qemu_put_be32(f, s->redraw); |
293 | 23e39294 | pbrook | qemu_put_be32(f, s->remap); |
294 | 23e39294 | pbrook | qemu_put_be32(f, s->mode); |
295 | 23e39294 | pbrook | qemu_put_buffer(f, s->framebuffer, sizeof(s->framebuffer));
|
296 | 23e39294 | pbrook | } |
297 | 23e39294 | pbrook | |
298 | 23e39294 | pbrook | static int ssd0323_load(QEMUFile *f, void *opaque, int version_id) |
299 | 23e39294 | pbrook | { |
300 | 23e39294 | pbrook | ssd0323_state *s = (ssd0323_state *)opaque; |
301 | 23e39294 | pbrook | int i;
|
302 | 23e39294 | pbrook | |
303 | 23e39294 | pbrook | if (version_id != 1) |
304 | 23e39294 | pbrook | return -EINVAL;
|
305 | 23e39294 | pbrook | |
306 | 23e39294 | pbrook | s->cmd_len = qemu_get_be32(f); |
307 | 23e39294 | pbrook | s->cmd = qemu_get_be32(f); |
308 | 23e39294 | pbrook | for (i = 0; i < 8; i++) |
309 | 23e39294 | pbrook | s->cmd_data[i] = qemu_get_be32(f); |
310 | 23e39294 | pbrook | s->row = qemu_get_be32(f); |
311 | 23e39294 | pbrook | s->row_start = qemu_get_be32(f); |
312 | 23e39294 | pbrook | s->row_end = qemu_get_be32(f); |
313 | 23e39294 | pbrook | s->col = qemu_get_be32(f); |
314 | 23e39294 | pbrook | s->col_start = qemu_get_be32(f); |
315 | 23e39294 | pbrook | s->col_end = qemu_get_be32(f); |
316 | 23e39294 | pbrook | s->redraw = qemu_get_be32(f); |
317 | 23e39294 | pbrook | s->remap = qemu_get_be32(f); |
318 | 23e39294 | pbrook | s->mode = qemu_get_be32(f); |
319 | 23e39294 | pbrook | qemu_get_buffer(f, s->framebuffer, sizeof(s->framebuffer));
|
320 | 23e39294 | pbrook | |
321 | 23e39294 | pbrook | return 0; |
322 | 23e39294 | pbrook | } |
323 | 23e39294 | pbrook | |
324 | 3023f332 | aliguori | void *ssd0323_init(qemu_irq *cmd_p)
|
325 | 9ee6e8bb | pbrook | { |
326 | 9ee6e8bb | pbrook | ssd0323_state *s; |
327 | 9ee6e8bb | pbrook | qemu_irq *cmd; |
328 | 9ee6e8bb | pbrook | |
329 | 9ee6e8bb | pbrook | s = (ssd0323_state *)qemu_mallocz(sizeof(ssd0323_state));
|
330 | 9ee6e8bb | pbrook | s->col_end = 63;
|
331 | 9ee6e8bb | pbrook | s->row_end = 79;
|
332 | 3023f332 | aliguori | s->ds = graphic_console_init(ssd0323_update_display, |
333 | 3023f332 | aliguori | ssd0323_invalidate_display, |
334 | 3023f332 | aliguori | NULL, NULL, s); |
335 | 3023f332 | aliguori | qemu_console_resize(s->ds, 128 * MAGNIFY, 64 * MAGNIFY); |
336 | 9ee6e8bb | pbrook | |
337 | 9ee6e8bb | pbrook | cmd = qemu_allocate_irqs(ssd0323_cd, s, 1);
|
338 | 9ee6e8bb | pbrook | *cmd_p = *cmd; |
339 | 9ee6e8bb | pbrook | |
340 | 23e39294 | pbrook | register_savevm("ssd0323_oled", -1, 1, ssd0323_save, ssd0323_load, s); |
341 | 23e39294 | pbrook | |
342 | 9ee6e8bb | pbrook | return s;
|
343 | 9ee6e8bb | pbrook | } |