diff options
-rw-r--r-- | docs/CREDITS | 1 | ||||
-rw-r--r-- | firmware/drivers/lcd-2bit-horz.c | 813 | ||||
-rw-r--r-- | firmware/drivers/lcd-ipod.c | 201 |
3 files changed, 1002 insertions, 13 deletions
diff --git a/docs/CREDITS b/docs/CREDITS index cd20905178..71d3480a55 100644 --- a/docs/CREDITS +++ b/docs/CREDITS | |||
@@ -164,3 +164,4 @@ Tim Crist | |||
164 | Jvo Studer | 164 | Jvo Studer |
165 | Dan Everton | 165 | Dan Everton |
166 | Imre Herceg | 166 | Imre Herceg |
167 | Seven Le Mesle | ||
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c new file mode 100644 index 0000000000..01f5d93cf3 --- /dev/null +++ b/firmware/drivers/lcd-2bit-horz.c | |||
@@ -0,0 +1,813 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * LCD driver for horizontally-packed 2bpp greyscale display | ||
11 | * | ||
12 | * Based on code from the rockbox lcd's driver | ||
13 | * | ||
14 | * Copyright (c) 2006 Seven Le Mesle (sevlm@free.fr) | ||
15 | * | ||
16 | * All files in this archive are subject to the GNU General Public License. | ||
17 | * See the file COPYING in the source tree root for full license agreement. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "config.h" | ||
24 | #include "cpu.h" | ||
25 | #include "lcd.h" | ||
26 | #include "kernel.h" | ||
27 | #include "thread.h" | ||
28 | #include <string.h> | ||
29 | #include <stdlib.h> | ||
30 | #include "file.h" | ||
31 | #include "debug.h" | ||
32 | #include "system.h" | ||
33 | #include "font.h" | ||
34 | #include "rbunicode.h" | ||
35 | #include "bidi.h" | ||
36 | |||
37 | #define SCROLLABLE_LINES 26 | ||
38 | |||
39 | /*** globals ***/ | ||
40 | |||
41 | unsigned char lcd_framebuffer[LCD_HEIGHT][LCD_WIDTH/4] IBSS_ATTR; | ||
42 | |||
43 | static const unsigned char dibits[16] ICONST_ATTR = { | ||
44 | 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, | ||
45 | 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF | ||
46 | }; | ||
47 | |||
48 | static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */ | ||
49 | static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */ | ||
50 | static int drawmode = DRMODE_SOLID; | ||
51 | static int xmargin = 0; | ||
52 | static int ymargin = 0; | ||
53 | static int curfont = FONT_SYSFIXED; | ||
54 | |||
55 | /* scrolling */ | ||
56 | static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ | ||
57 | static void scroll_thread(void); | ||
58 | static long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)]; | ||
59 | static const char scroll_name[] = "scroll"; | ||
60 | static int scroll_ticks = 12; /* # of ticks between updates*/ | ||
61 | static int scroll_delay = HZ/2; /* ticks delay before start */ | ||
62 | static int scroll_step = 6; /* pixels per scroll step */ | ||
63 | static int bidir_limit = 50; /* percent */ | ||
64 | static struct scrollinfo scroll[SCROLLABLE_LINES]; | ||
65 | |||
66 | static const char scroll_tick_table[16] = { | ||
67 | /* Hz values: | ||
68 | 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */ | ||
69 | 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 | ||
70 | }; | ||
71 | |||
72 | |||
73 | static unsigned char notmask[4] = { 0xfc, 0xf3, 0xcf, 0x3f }; | ||
74 | |||
75 | /* LCD init */ | ||
76 | void lcd_init(void) | ||
77 | { | ||
78 | lcd_clear_display(); | ||
79 | /* Call device specific init */ | ||
80 | lcd_init_device(); | ||
81 | create_thread(scroll_thread, scroll_stack, | ||
82 | sizeof(scroll_stack), scroll_name); | ||
83 | } | ||
84 | |||
85 | /*** parameter handling ***/ | ||
86 | |||
87 | void lcd_set_drawmode(int mode) | ||
88 | { | ||
89 | drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
90 | } | ||
91 | |||
92 | int lcd_get_drawmode(void) | ||
93 | { | ||
94 | return drawmode; | ||
95 | } | ||
96 | |||
97 | void lcd_set_foreground(unsigned brightness) | ||
98 | { | ||
99 | fg_pattern = 0x55 * (~brightness & 3); | ||
100 | } | ||
101 | |||
102 | unsigned lcd_get_foreground(void) | ||
103 | { | ||
104 | return ~fg_pattern & 3; | ||
105 | } | ||
106 | |||
107 | void lcd_set_background(unsigned brightness) | ||
108 | { | ||
109 | bg_pattern = 0x55 * (~brightness & 3); | ||
110 | } | ||
111 | |||
112 | unsigned lcd_get_background(void) | ||
113 | { | ||
114 | return ~bg_pattern & 3; | ||
115 | } | ||
116 | |||
117 | void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness) | ||
118 | { | ||
119 | lcd_set_drawmode(mode); | ||
120 | lcd_set_foreground(fg_brightness); | ||
121 | lcd_set_background(bg_brightness); | ||
122 | } | ||
123 | |||
124 | void lcd_setmargins(int x, int y) | ||
125 | { | ||
126 | xmargin = x; | ||
127 | ymargin = y; | ||
128 | } | ||
129 | |||
130 | int lcd_getxmargin(void) | ||
131 | { | ||
132 | return xmargin; | ||
133 | } | ||
134 | |||
135 | int lcd_getymargin(void) | ||
136 | { | ||
137 | return ymargin; | ||
138 | } | ||
139 | |||
140 | void lcd_setfont(int newfont) | ||
141 | { | ||
142 | curfont = newfont; | ||
143 | } | ||
144 | |||
145 | int lcd_getstringsize(const unsigned char *str, int *w, int *h) | ||
146 | { | ||
147 | return font_getstringsize(str, w, h, curfont); | ||
148 | } | ||
149 | |||
150 | /*** low-level drawing functions ***/ | ||
151 | |||
152 | static void setpixel_value(int x, int y, unsigned val) | ||
153 | { | ||
154 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | ||
155 | |||
156 | *data = (*data & notmask[x&3]) | (val << ((x&3)<<1)); | ||
157 | } | ||
158 | |||
159 | static void setpixel(int x, int y) | ||
160 | { | ||
161 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | ||
162 | |||
163 | *data = (*data & notmask[x&3]) | (fg_pattern << ((x&3)<<1)); | ||
164 | } | ||
165 | |||
166 | static void clearpixel(int x, int y) | ||
167 | { | ||
168 | unsigned char *data = &lcd_framebuffer[y][x>>2]; | ||
169 | *data = (*data & notmask[x&3]) | (bg_pattern << ((x&3)<<1)); | ||
170 | } | ||
171 | |||
172 | static void flippixel(int x, int y) | ||
173 | { | ||
174 | lcd_framebuffer[y][x>>2] ^= 3 << (2 * (x & 3)); | ||
175 | } | ||
176 | |||
177 | static void nopixel(int x, int y) | ||
178 | { | ||
179 | (void)x; | ||
180 | (void)y; | ||
181 | } | ||
182 | |||
183 | lcd_pixelfunc_type* const lcd_pixelfuncs[8] = { | ||
184 | flippixel, nopixel, setpixel, setpixel, | ||
185 | nopixel, clearpixel, nopixel, clearpixel | ||
186 | }; | ||
187 | |||
188 | |||
189 | /*** drawing functions ***/ | ||
190 | |||
191 | /* Clear the whole display */ | ||
192 | void lcd_clear_display(void) | ||
193 | { | ||
194 | unsigned bits = (drawmode & DRMODE_INVERSEVID) ? fg_pattern : bg_pattern; | ||
195 | |||
196 | memset(lcd_framebuffer, bits, sizeof lcd_framebuffer); | ||
197 | scrolling_lines = 0; | ||
198 | } | ||
199 | |||
200 | /* Set a single pixel */ | ||
201 | void lcd_drawpixel(int x, int y) | ||
202 | { | ||
203 | if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) | ||
204 | lcd_pixelfuncs[drawmode](x, y); | ||
205 | } | ||
206 | |||
207 | /* Draw a line */ | ||
208 | void lcd_drawline(int x1, int y1, int x2, int y2) | ||
209 | { | ||
210 | int numpixels; | ||
211 | int i; | ||
212 | int deltax, deltay; | ||
213 | int d, dinc1, dinc2; | ||
214 | int x, xinc1, xinc2; | ||
215 | int y, yinc1, yinc2; | ||
216 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | ||
217 | |||
218 | deltax = abs(x2 - x1); | ||
219 | deltay = abs(y2 - y1); | ||
220 | xinc2 = 1; | ||
221 | yinc2 = 1; | ||
222 | |||
223 | if (deltax >= deltay) | ||
224 | { | ||
225 | numpixels = deltax; | ||
226 | d = 2 * deltay - deltax; | ||
227 | dinc1 = deltay * 2; | ||
228 | dinc2 = (deltay - deltax) * 2; | ||
229 | xinc1 = 1; | ||
230 | yinc1 = 0; | ||
231 | } | ||
232 | else | ||
233 | { | ||
234 | numpixels = deltay; | ||
235 | d = 2 * deltax - deltay; | ||
236 | dinc1 = deltax * 2; | ||
237 | dinc2 = (deltax - deltay) * 2; | ||
238 | xinc1 = 0; | ||
239 | yinc1 = 1; | ||
240 | } | ||
241 | numpixels++; /* include endpoints */ | ||
242 | |||
243 | if (x1 > x2) | ||
244 | { | ||
245 | xinc1 = -xinc1; | ||
246 | xinc2 = -xinc2; | ||
247 | } | ||
248 | |||
249 | if (y1 > y2) | ||
250 | { | ||
251 | yinc1 = -yinc1; | ||
252 | yinc2 = -yinc2; | ||
253 | } | ||
254 | |||
255 | x = x1; | ||
256 | y = y1; | ||
257 | |||
258 | for (i = 0; i < numpixels; i++) | ||
259 | { | ||
260 | if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) | ||
261 | pfunc(x, y); | ||
262 | |||
263 | if (d < 0) | ||
264 | { | ||
265 | d += dinc1; | ||
266 | x += xinc1; | ||
267 | y += yinc1; | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | d += dinc2; | ||
272 | x += xinc2; | ||
273 | y += yinc2; | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | |||
278 | /* Draw a horizontal line (optimised) */ | ||
279 | void lcd_hline(int x1, int x2, int y) | ||
280 | { | ||
281 | int x; | ||
282 | |||
283 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | ||
284 | |||
285 | /* direction flip */ | ||
286 | if (x2 < x1) | ||
287 | { | ||
288 | x = x1; | ||
289 | x1 = x2; | ||
290 | x2 = x; | ||
291 | } | ||
292 | |||
293 | /* nothing to draw? */ | ||
294 | if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) | ||
295 | return; | ||
296 | |||
297 | /* clipping */ | ||
298 | if (x1 < 0) | ||
299 | x1 = 0; | ||
300 | if (x2 >= LCD_WIDTH) | ||
301 | x2 = LCD_WIDTH-1; | ||
302 | |||
303 | while(x1 <= x2) { | ||
304 | pfunc(x1,y); | ||
305 | ++x1; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | /* Draw a vertical line (optimised) */ | ||
310 | void lcd_vline(int x, int y1, int y2) | ||
311 | { | ||
312 | int ny; | ||
313 | |||
314 | lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode]; | ||
315 | |||
316 | /* direction flip */ | ||
317 | if (y2 < y1) | ||
318 | { | ||
319 | ny = y1; | ||
320 | y1 = y2; | ||
321 | y2 = ny; | ||
322 | } | ||
323 | |||
324 | /* nothing to draw? */ | ||
325 | if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) | ||
326 | return; | ||
327 | |||
328 | /* clipping */ | ||
329 | if (y1 < 0) | ||
330 | y1 = 0; | ||
331 | if (y2 >= LCD_HEIGHT) | ||
332 | y2 = LCD_HEIGHT-1; | ||
333 | |||
334 | |||
335 | while(y1++ <= y2) { | ||
336 | pfunc(x, y1); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | /* Draw a rectangular box */ | ||
341 | void lcd_drawrect(int x, int y, int width, int height) | ||
342 | { | ||
343 | if ((width <= 0) || (height <= 0)) | ||
344 | return; | ||
345 | |||
346 | int x2 = x + width - 1; | ||
347 | int y2 = y + height - 1; | ||
348 | |||
349 | lcd_vline(x, y, y2); | ||
350 | lcd_vline(x2, y, y2); | ||
351 | lcd_hline(x, x2, y); | ||
352 | lcd_hline(x, x2, y2); | ||
353 | } | ||
354 | |||
355 | /* Fill a rectangular area */ | ||
356 | void lcd_fillrect(int x, int y, int width, int height) | ||
357 | { | ||
358 | int ny; | ||
359 | |||
360 | |||
361 | /* nothing to draw? */ | ||
362 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
363 | || (x + width <= 0) || (y + height <= 0)) | ||
364 | return; | ||
365 | |||
366 | /* clipping */ | ||
367 | if (x < 0) | ||
368 | { | ||
369 | width += x; | ||
370 | x = 0; | ||
371 | } | ||
372 | if (y < 0) | ||
373 | { | ||
374 | height += y; | ||
375 | y = 0; | ||
376 | } | ||
377 | if (x + width > LCD_WIDTH) | ||
378 | width = LCD_WIDTH - x; | ||
379 | if (y + height > LCD_HEIGHT) | ||
380 | height = LCD_HEIGHT - y; | ||
381 | |||
382 | ny = y; | ||
383 | while (ny <= height) | ||
384 | { | ||
385 | lcd_hline (x, width, ny); | ||
386 | ny++; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | /* About Rockbox' internal monochrome bitmap format: | ||
391 | * | ||
392 | * A bitmap contains one bit for every pixel that defines if that pixel is | ||
393 | * black (1) or white (0). Bits within a byte are arranged horizontally, LSB | ||
394 | * at top. | ||
395 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
396 | * byte 1 2nd from left etc. The first row of bytes defines pixel row | ||
397 | * 0, the second row defines pixel row 1 etc. | ||
398 | * | ||
399 | * This is similar to the internal lcd hw format. */ | ||
400 | |||
401 | /* Draw a partial monochrome bitmap */ | ||
402 | void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
403 | int stride, int x, int y, int width, int height) | ||
404 | ICODE_ATTR; | ||
405 | void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
406 | int stride, int x, int y, int width, int height) | ||
407 | { | ||
408 | int ny, nx, ymax; | ||
409 | const unsigned char * src_end; | ||
410 | |||
411 | /* nothing to draw? */ | ||
412 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
413 | || (x + width <= 0) || (y + height <= 0)) | ||
414 | return; | ||
415 | |||
416 | /* clipping */ | ||
417 | if (x < 0) | ||
418 | { | ||
419 | width += x; | ||
420 | src_x -= x; | ||
421 | x = 0; | ||
422 | } | ||
423 | if (y < 0) | ||
424 | { | ||
425 | height += y; | ||
426 | src_y -= y; | ||
427 | y = 0; | ||
428 | } | ||
429 | if (x + width > LCD_WIDTH) | ||
430 | width = LCD_WIDTH - x; | ||
431 | if (y + height > LCD_HEIGHT) | ||
432 | height = LCD_HEIGHT - y; | ||
433 | |||
434 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
435 | src_y &= 7; | ||
436 | src_end = src + width; | ||
437 | |||
438 | nx = x; | ||
439 | do | ||
440 | { | ||
441 | const unsigned char *src_col = src++; | ||
442 | unsigned data = *src_col >> src_y; | ||
443 | int numbits = 8 - ((int)src_y); | ||
444 | |||
445 | ymax = y + height; | ||
446 | ny = y; | ||
447 | do | ||
448 | { | ||
449 | if (data & 0x01) | ||
450 | setpixel (nx,ny); | ||
451 | else | ||
452 | clearpixel (nx,ny); | ||
453 | |||
454 | ny++; | ||
455 | |||
456 | data >>= 1; | ||
457 | if (--numbits == 0) | ||
458 | { | ||
459 | src_col += stride; | ||
460 | data = *src_col; | ||
461 | numbits = 8; | ||
462 | } | ||
463 | } | ||
464 | while (ny < ymax); | ||
465 | nx++; | ||
466 | } | ||
467 | while (src < src_end); | ||
468 | } | ||
469 | |||
470 | /* Draw a full monochrome bitmap */ | ||
471 | void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) | ||
472 | { | ||
473 | lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
474 | } | ||
475 | |||
476 | /* About Rockbox' internal native bitmap format: | ||
477 | * | ||
478 | * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey, | ||
479 | * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB | ||
480 | * at top. | ||
481 | * The bytes are stored in row-major order, with byte 0 being top left, | ||
482 | * byte 1 2nd from left etc. The first row of bytes defines pixel rows | ||
483 | * 0..3, the second row defines pixel row 4..7 etc. | ||
484 | * | ||
485 | * This is the same as the internal lcd hw format. */ | ||
486 | |||
487 | /* Draw a partial native bitmap */ | ||
488 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
489 | int stride, int x, int y, int width, int height) | ||
490 | ICODE_ATTR; | ||
491 | void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, | ||
492 | int stride, int x, int y, int width, int height) | ||
493 | { | ||
494 | int ny, nx, ymax; | ||
495 | const unsigned char * src_end; | ||
496 | |||
497 | /* nothing to draw? */ | ||
498 | if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) | ||
499 | || (x + width <= 0) || (y + height <= 0)) | ||
500 | return; | ||
501 | |||
502 | /* clipping */ | ||
503 | if (x < 0) | ||
504 | { | ||
505 | width += x; | ||
506 | src_x -= x; | ||
507 | x = 0; | ||
508 | } | ||
509 | if (y < 0) | ||
510 | { | ||
511 | height += y; | ||
512 | src_y -= y; | ||
513 | y = 0; | ||
514 | } | ||
515 | if (x + width > LCD_WIDTH) | ||
516 | width = LCD_WIDTH - x; | ||
517 | if (y + height > LCD_HEIGHT) | ||
518 | height = LCD_HEIGHT - y; | ||
519 | |||
520 | src += stride * (src_y >> 3) + src_x; /* move starting point */ | ||
521 | src_y &= 7; | ||
522 | src_end = src + width; | ||
523 | |||
524 | nx = x; | ||
525 | do | ||
526 | { | ||
527 | const unsigned char *src_col = src++; | ||
528 | unsigned data = *src_col >> src_y; | ||
529 | int numbits = 8 - src_y; | ||
530 | |||
531 | ymax = y + height; | ||
532 | ny = y; | ||
533 | do | ||
534 | { | ||
535 | if (data & 0x03) | ||
536 | setpixel_value (nx,ny, 0xFF); | ||
537 | else | ||
538 | if (data & 0x01) | ||
539 | setpixel_value (nx,ny, 0x3F); | ||
540 | else | ||
541 | if (data & 0x02) | ||
542 | setpixel_value (nx,ny, 0xCF); | ||
543 | else | ||
544 | setpixel_value (nx,ny, 0x00); | ||
545 | |||
546 | ny++; | ||
547 | |||
548 | data >>= 2; | ||
549 | if (--numbits == 0) | ||
550 | { | ||
551 | src_col += stride; | ||
552 | data = *src_col; | ||
553 | numbits = 4; | ||
554 | } | ||
555 | } | ||
556 | while (ny < ymax); | ||
557 | nx++; | ||
558 | } | ||
559 | while (src < src_end); | ||
560 | } | ||
561 | |||
562 | /* Draw a full native bitmap */ | ||
563 | void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height) | ||
564 | { | ||
565 | lcd_bitmap_part(src, 0, 0, width, x, y, width, height); | ||
566 | } | ||
567 | |||
568 | /* put a string at a given pixel position, skipping first ofs pixel columns */ | ||
569 | static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) | ||
570 | { | ||
571 | unsigned short ch; | ||
572 | unsigned short *ucs; | ||
573 | struct font* pf = font_get(curfont); | ||
574 | |||
575 | ucs = bidi_l2v(str, 1); | ||
576 | |||
577 | while ((ch = *ucs++) != 0 && x < LCD_WIDTH) | ||
578 | { | ||
579 | int width; | ||
580 | const unsigned char *bits; | ||
581 | |||
582 | /* check input range */ | ||
583 | if (ch < pf->firstchar || ch >= pf->firstchar+pf->size) | ||
584 | ch = pf->defaultchar; | ||
585 | ch -= pf->firstchar; | ||
586 | |||
587 | /* get proportional width and glyph bits */ | ||
588 | width = font_get_width(pf,ch); | ||
589 | |||
590 | if (ofs > width) | ||
591 | { | ||
592 | ofs -= width; | ||
593 | continue; | ||
594 | } | ||
595 | |||
596 | bits = font_get_bits(pf, ch); | ||
597 | |||
598 | lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); | ||
599 | |||
600 | x += width - ofs; | ||
601 | ofs = 0; | ||
602 | } | ||
603 | } | ||
604 | |||
605 | /* put a string at a given pixel position */ | ||
606 | void lcd_putsxy(int x, int y, const unsigned char *str) | ||
607 | { | ||
608 | lcd_putsxyofs(x, y, 0, str); | ||
609 | } | ||
610 | |||
611 | /*** line oriented text output ***/ | ||
612 | |||
613 | void lcd_puts_style(int x, int y, const unsigned char *str, int style) | ||
614 | { | ||
615 | int xpos,ypos,w,h; | ||
616 | int lastmode = drawmode; | ||
617 | |||
618 | /* make sure scrolling is turned off on the line we are updating */ | ||
619 | scrolling_lines &= ~(1 << y); | ||
620 | |||
621 | if(!str || !str[0]) | ||
622 | return; | ||
623 | |||
624 | lcd_getstringsize(str, &w, &h); | ||
625 | xpos = xmargin + x*w / utf8length((char *)str); | ||
626 | ypos = ymargin + y*h; | ||
627 | lcd_putsxy(xpos, ypos, str); | ||
628 | drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
629 | lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); | ||
630 | if (style & STYLE_INVERT) | ||
631 | { | ||
632 | drawmode = DRMODE_COMPLEMENT; | ||
633 | lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); | ||
634 | } | ||
635 | drawmode = lastmode; | ||
636 | } | ||
637 | |||
638 | /* put a string at a given char position */ | ||
639 | void lcd_puts(int x, int y, const unsigned char *str) | ||
640 | { | ||
641 | lcd_puts_style(x, y, str, STYLE_DEFAULT); | ||
642 | } | ||
643 | |||
644 | /*** scrolling ***/ | ||
645 | |||
646 | /* Reverse the invert setting of the scrolling line (if any) at given char | ||
647 | position. Setting will go into affect next time line scrolls. */ | ||
648 | void lcd_invertscroll(int x, int y) | ||
649 | { | ||
650 | struct scrollinfo* s; | ||
651 | |||
652 | (void)x; | ||
653 | |||
654 | s = &scroll[y]; | ||
655 | s->invert = !s->invert; | ||
656 | } | ||
657 | |||
658 | void lcd_stop_scroll(void) | ||
659 | { | ||
660 | scrolling_lines=0; | ||
661 | } | ||
662 | |||
663 | void lcd_scroll_speed(int speed) | ||
664 | { | ||
665 | scroll_ticks = scroll_tick_table[speed]; | ||
666 | } | ||
667 | |||
668 | void lcd_scroll_step(int step) | ||
669 | { | ||
670 | scroll_step = step; | ||
671 | } | ||
672 | |||
673 | void lcd_scroll_delay(int ms) | ||
674 | { | ||
675 | scroll_delay = ms / (HZ / 10); | ||
676 | } | ||
677 | |||
678 | void lcd_bidir_scroll(int percent) | ||
679 | { | ||
680 | bidir_limit = percent; | ||
681 | } | ||
682 | |||
683 | void lcd_puts_scroll(int x, int y, const unsigned char *string) | ||
684 | { | ||
685 | lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT); | ||
686 | } | ||
687 | |||
688 | void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style) | ||
689 | { | ||
690 | struct scrollinfo* s; | ||
691 | int w, h; | ||
692 | |||
693 | s = &scroll[y]; | ||
694 | |||
695 | s->start_tick = current_tick + scroll_delay; | ||
696 | s->invert = false; | ||
697 | if (style & STYLE_INVERT) { | ||
698 | s->invert = true; | ||
699 | lcd_puts_style(x,y,string,STYLE_INVERT); | ||
700 | } | ||
701 | else | ||
702 | lcd_puts(x,y,string); | ||
703 | |||
704 | lcd_getstringsize(string, &w, &h); | ||
705 | |||
706 | if (LCD_WIDTH - x * 8 - xmargin < w) { | ||
707 | /* prepare scroll line */ | ||
708 | char *end; | ||
709 | |||
710 | memset(s->line, 0, sizeof s->line); | ||
711 | strcpy(s->line, (char *)string); | ||
712 | |||
713 | /* get width */ | ||
714 | s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h); | ||
715 | |||
716 | /* scroll bidirectional or forward only depending on the string | ||
717 | width */ | ||
718 | if ( bidir_limit ) { | ||
719 | s->bidir = s->width < (LCD_WIDTH - xmargin) * | ||
720 | (100 + bidir_limit) / 100; | ||
721 | } | ||
722 | else | ||
723 | s->bidir = false; | ||
724 | |||
725 | if (!s->bidir) { /* add spaces if scrolling in the round */ | ||
726 | strcat(s->line, " "); | ||
727 | /* get new width incl. spaces */ | ||
728 | s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h); | ||
729 | } | ||
730 | |||
731 | end = strchr(s->line, '\0'); | ||
732 | strncpy(end, (char *)string, LCD_WIDTH/2); | ||
733 | |||
734 | s->len = utf8length((char *)string); | ||
735 | s->offset = 0; | ||
736 | s->startx = x; | ||
737 | s->backward = false; | ||
738 | scrolling_lines |= (1<<y); | ||
739 | } | ||
740 | else | ||
741 | /* force a bit switch-off since it doesn't scroll */ | ||
742 | scrolling_lines &= ~(1<<y); | ||
743 | } | ||
744 | |||
745 | static void scroll_thread(void) | ||
746 | { | ||
747 | struct font* pf; | ||
748 | struct scrollinfo* s; | ||
749 | int index; | ||
750 | int xpos, ypos; | ||
751 | int lastmode; | ||
752 | |||
753 | /* initialize scroll struct array */ | ||
754 | scrolling_lines = 0; | ||
755 | |||
756 | while ( 1 ) { | ||
757 | for ( index = 0; index < SCROLLABLE_LINES; index++ ) { | ||
758 | /* really scroll? */ | ||
759 | if ( !(scrolling_lines&(1<<index)) ) | ||
760 | continue; | ||
761 | |||
762 | s = &scroll[index]; | ||
763 | |||
764 | /* check pause */ | ||
765 | if (TIME_BEFORE(current_tick, s->start_tick)) | ||
766 | continue; | ||
767 | |||
768 | if (s->backward) | ||
769 | s->offset -= scroll_step; | ||
770 | else | ||
771 | s->offset += scroll_step; | ||
772 | |||
773 | pf = font_get(curfont); | ||
774 | xpos = xmargin + s->startx * s->width / s->len; | ||
775 | ypos = ymargin + index * pf->height; | ||
776 | |||
777 | if (s->bidir) { /* scroll bidirectional */ | ||
778 | if (s->offset <= 0) { | ||
779 | /* at beginning of line */ | ||
780 | s->offset = 0; | ||
781 | s->backward = false; | ||
782 | s->start_tick = current_tick + scroll_delay * 2; | ||
783 | } | ||
784 | if (s->offset >= s->width - (LCD_WIDTH - xpos)) { | ||
785 | /* at end of line */ | ||
786 | s->offset = s->width - (LCD_WIDTH - xpos); | ||
787 | s->backward = true; | ||
788 | s->start_tick = current_tick + scroll_delay * 2; | ||
789 | } | ||
790 | } | ||
791 | else { | ||
792 | /* scroll forward the whole time */ | ||
793 | if (s->offset >= s->width) | ||
794 | s->offset %= s->width; | ||
795 | } | ||
796 | |||
797 | lastmode = drawmode; | ||
798 | drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); | ||
799 | lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); | ||
800 | drawmode = DRMODE_SOLID; | ||
801 | lcd_putsxyofs(xpos, ypos, s->offset, (unsigned char *)s->line); | ||
802 | if (s->invert) | ||
803 | { | ||
804 | drawmode = DRMODE_COMPLEMENT; | ||
805 | lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); | ||
806 | } | ||
807 | drawmode = lastmode; | ||
808 | lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); | ||
809 | } | ||
810 | |||
811 | sleep(scroll_ticks); | ||
812 | } | ||
813 | } | ||
diff --git a/firmware/drivers/lcd-ipod.c b/firmware/drivers/lcd-ipod.c index 0ff22ab9b5..2d165551e6 100644 --- a/firmware/drivers/lcd-ipod.c +++ b/firmware/drivers/lcd-ipod.c | |||
@@ -29,7 +29,192 @@ | |||
29 | #include "kernel.h" | 29 | #include "kernel.h" |
30 | #include "system.h" | 30 | #include "system.h" |
31 | 31 | ||
32 | /*** definitions ***/ | 32 | |
33 | /* check if number of useconds has past */ | ||
34 | static int timer_check(int clock_start, int usecs) | ||
35 | { | ||
36 | if ( ((int)(USEC_TIMER - clock_start)) >= usecs ) { | ||
37 | return 1; | ||
38 | } else { | ||
39 | return 0; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | |||
44 | #if (CONFIG_LCD == LCD_IPOD2BPP) | ||
45 | |||
46 | /*** hardware configuration ***/ | ||
47 | |||
48 | #define IPOD_LCD_BASE 0xc0001000 | ||
49 | #define IPOD_LCD_BUSY_MASK 0x80000000 | ||
50 | |||
51 | /* LCD command codes for HD66789R */ | ||
52 | |||
53 | |||
54 | #define LCD_CMD 0x08 | ||
55 | #define LCD_DATA 0x10 | ||
56 | |||
57 | static unsigned int lcd_contrast = 0x6a; | ||
58 | |||
59 | |||
60 | /* wait for LCD with timeout */ | ||
61 | static void lcd_wait_write(void) | ||
62 | { | ||
63 | int start = USEC_TIMER; | ||
64 | |||
65 | do { | ||
66 | if ((inl(IPOD_LCD_BASE) & 0x8000) == 0) break; | ||
67 | } while (timer_check(start, 1000) == 0); | ||
68 | } | ||
69 | |||
70 | |||
71 | /* send LCD data */ | ||
72 | static void lcd_send_data(int data_lo, int data_hi) | ||
73 | { | ||
74 | lcd_wait_write(); | ||
75 | outl(data_lo, IPOD_LCD_BASE + LCD_DATA); | ||
76 | lcd_wait_write(); | ||
77 | outl(data_hi, IPOD_LCD_BASE + LCD_DATA); | ||
78 | } | ||
79 | |||
80 | /* send LCD command */ | ||
81 | static void lcd_prepare_cmd(int cmd) | ||
82 | { | ||
83 | lcd_wait_write(); | ||
84 | |||
85 | outl(0x0, IPOD_LCD_BASE + LCD_CMD); | ||
86 | lcd_wait_write(); | ||
87 | outl(cmd, IPOD_LCD_BASE + LCD_CMD); | ||
88 | |||
89 | } | ||
90 | |||
91 | /* send LCD command and data */ | ||
92 | static void lcd_cmd_and_data(int cmd, int data_lo, int data_hi) | ||
93 | { | ||
94 | lcd_prepare_cmd(cmd); | ||
95 | |||
96 | lcd_send_data(data_lo, data_hi); | ||
97 | } | ||
98 | |||
99 | int lcd_default_contrast(void) | ||
100 | { | ||
101 | return 28; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * | ||
106 | * LCD init | ||
107 | **/ | ||
108 | void lcd_init_device(void){ | ||
109 | /* driver output control - 160x128 */ | ||
110 | lcd_cmd_and_data(0x1, 0x1, 0xf); | ||
111 | lcd_cmd_and_data(0x5, 0x0, 0x10); | ||
112 | } | ||
113 | |||
114 | /*** update functions ***/ | ||
115 | /* srccopy bitblt, opcode is currently ignored*/ | ||
116 | |||
117 | /* Performance function that works with an external buffer | ||
118 | note that x and bwidtht are in 8-pixel units! */ | ||
119 | void lcd_blit(const unsigned char* data, int x, int by, int width, | ||
120 | int bheight, int stride) | ||
121 | { | ||
122 | /* TODO implement this on iPod */ | ||
123 | (void)data; | ||
124 | (void)x; | ||
125 | (void)by; | ||
126 | (void)width; | ||
127 | (void)bheight; | ||
128 | (void)stride; | ||
129 | } | ||
130 | |||
131 | /* Rolls up the lcd display by the specified amount of lines. | ||
132 | * Lines that are rolled out over the top of the screen are | ||
133 | * rolled in from the bottom again. This is a hardware | ||
134 | * remapping only and all operations on the lcd are affected. | ||
135 | * -> | ||
136 | * @param int lines - The number of lines that are rolled. | ||
137 | * The value must be 0 <= pixels < LCD_HEIGHT. */ | ||
138 | void lcd_roll(int lines) | ||
139 | { | ||
140 | /* TODO Implement lcd_roll() */ | ||
141 | lines &= LCD_HEIGHT-1; | ||
142 | } | ||
143 | |||
144 | /*** hardware configuration ***/ | ||
145 | |||
146 | /* Update the display. | ||
147 | This must be called after all other LCD functions that change the display. */ | ||
148 | void lcd_update(void) | ||
149 | { | ||
150 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | ||
151 | } | ||
152 | |||
153 | void lcd_set_contrast(int val) | ||
154 | { | ||
155 | lcd_cmd_and_data(0x4, 0x4, val); | ||
156 | lcd_contrast = val; | ||
157 | } | ||
158 | |||
159 | void lcd_update_rect(int x, int y, int width, int height) | ||
160 | { | ||
161 | int cursor_pos, xx; | ||
162 | int ny; | ||
163 | int sx = x, sy = y, mx = width, my = height; | ||
164 | |||
165 | /* only update the ipod if we are writing to the screen */ | ||
166 | |||
167 | sx >>= 3; | ||
168 | //mx = (mx+7)>>3; | ||
169 | mx >>= 3; | ||
170 | |||
171 | cursor_pos = sx + (sy << 5); | ||
172 | |||
173 | for ( ny = sy; ny <= my; ny++ ) { | ||
174 | unsigned char * img_data; | ||
175 | |||
176 | |||
177 | // move the cursor | ||
178 | lcd_cmd_and_data(0x11, cursor_pos >> 8, cursor_pos & 0xff); | ||
179 | |||
180 | // setup for printing | ||
181 | lcd_prepare_cmd(0x12); | ||
182 | |||
183 | img_data = &lcd_framebuffer[ny][sx<<1]; | ||
184 | |||
185 | // 160/8 -> 20 == loops 20 times | ||
186 | // make sure we loop at least once | ||
187 | for ( xx = sx; xx <= mx; xx++ ) { | ||
188 | // display a character | ||
189 | lcd_send_data(*(img_data+1), *img_data); | ||
190 | |||
191 | img_data += 2; | ||
192 | } | ||
193 | |||
194 | // update cursor pos counter | ||
195 | cursor_pos += 0x20; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /** Switch on or off the backlight **/ | ||
200 | void lcd_enable (bool on){ | ||
201 | int lcd_state; | ||
202 | |||
203 | lcd_state = inl(IPOD_LCD_BASE); | ||
204 | if (on){ | ||
205 | lcd_state = lcd_state | 0x2; | ||
206 | outl(lcd_state, IPOD_LCD_BASE); | ||
207 | lcd_cmd_and_data(0x7, 0x0, 0x11); | ||
208 | } | ||
209 | else { | ||
210 | lcd_state = lcd_state & ~0x2; | ||
211 | outl(lcd_state, IPOD_LCD_BASE); | ||
212 | lcd_cmd_and_data(0x7, 0x0, 0x9); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | #else | ||
217 | |||
33 | #define IPOD_LCD_BASE 0x70008a0c | 218 | #define IPOD_LCD_BASE 0x70008a0c |
34 | #define IPOD_LCD_BUSY_MASK 0x80000000 | 219 | #define IPOD_LCD_BUSY_MASK 0x80000000 |
35 | 220 | ||
@@ -42,17 +227,6 @@ | |||
42 | /*** globals ***/ | 227 | /*** globals ***/ |
43 | static int lcd_type = 1; /* 0 = "old" Color/Photo, 1 = "new" Color & Nano */ | 228 | static int lcd_type = 1; /* 0 = "old" Color/Photo, 1 = "new" Color & Nano */ |
44 | 229 | ||
45 | |||
46 | /* check if number of useconds has past */ | ||
47 | static inline int timer_check(unsigned long clock_start, unsigned long usecs) | ||
48 | { | ||
49 | if ( (USEC_TIMER - clock_start) >= usecs ) { | ||
50 | return 1; | ||
51 | } else { | ||
52 | return 0; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static void lcd_wait_write(void) | 230 | static void lcd_wait_write(void) |
57 | { | 231 | { |
58 | if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) != 0) { | 232 | if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) != 0) { |
@@ -229,7 +403,7 @@ void lcd_update_rect(int x, int y, int width, int height) | |||
229 | 403 | ||
230 | /* start vert = max vert */ | 404 | /* start vert = max vert */ |
231 | #if CONFIG_LCD == LCD_IPODCOLOR | 405 | #if CONFIG_LCD == LCD_IPODCOLOR |
232 | x0 = x1; | 406 | x0 = x1; |
233 | #endif | 407 | #endif |
234 | 408 | ||
235 | /* position cursor (set AD0-AD15) */ | 409 | /* position cursor (set AD0-AD15) */ |
@@ -288,3 +462,4 @@ void lcd_update(void) | |||
288 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); | 462 | lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); |
289 | } | 463 | } |
290 | 464 | ||
465 | #endif | ||