summaryrefslogtreecommitdiff
path: root/firmware/target/coldfire/iriver/h100
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2006-11-08 16:13:04 +0000
committerMichael Sevakis <jethead71@rockbox.org>2006-11-08 16:13:04 +0000
commite89a3940f9f8c6c6c437354ed49070649976f10e (patch)
tree4abca9ca6a4483791d8a25a49a08c348234b4dd4 /firmware/target/coldfire/iriver/h100
parentf9c8a891af12fdb76c6e6ff0bec3ce47d8a47e9f (diff)
downloadrockbox-e89a3940f9f8c6c6c437354ed49070649976f10e.tar.gz
rockbox-e89a3940f9f8c6c6c437354ed49070649976f10e.zip
More exodus to the target tree for ColdFire and a bonus sorting of firmware/SOURCES.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11468 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/coldfire/iriver/h100')
-rw-r--r--firmware/target/coldfire/iriver/h100/lcd-h100.c1298
1 files changed, 1298 insertions, 0 deletions
diff --git a/firmware/target/coldfire/iriver/h100/lcd-h100.c b/firmware/target/coldfire/iriver/h100/lcd-h100.c
new file mode 100644
index 0000000000..9ed63661a0
--- /dev/null
+++ b/firmware/target/coldfire/iriver/h100/lcd-h100.c
@@ -0,0 +1,1298 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2004 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "config.h"
20
21#include "cpu.h"
22#include "lcd.h"
23#include "kernel.h"
24#include "thread.h"
25#include <string.h>
26#include <stdlib.h>
27#include "file.h"
28#include "debug.h"
29#include "system.h"
30#include "font.h"
31#include "rbunicode.h"
32#include "bidi.h"
33
34/*** definitions ***/
35
36/* LCD command codes */
37#define LCD_CNTL_POWER_CONTROL 0x25
38#define LCD_CNTL_VOLTAGE_SELECT 0x2b
39#define LCD_CNTL_LINE_INVERT_DRIVE 0x36
40#define LCD_CNTL_GRAY_SCALE_PATTERN 0x39
41#define LCD_CNTL_TEMP_GRADIENT_SELECT 0x4e
42#define LCD_CNTL_OSC_FREQUENCY 0x5f
43#define LCD_CNTL_ON_OFF 0xae
44#define LCD_CNTL_OSC_ON_OFF 0xaa
45#define LCD_CNTL_OFF_MODE 0xbe
46#define LCD_CNTL_REVERSE 0xa6
47#define LCD_CNTL_ALL_LIGHTING 0xa4
48#define LCD_CNTL_COMMON_OUTPUT_STATUS 0xc4
49#define LCD_CNTL_COLUMN_ADDRESS_DIR 0xa0
50#define LCD_CNTL_NLINE_ON_OFF 0xe4
51#define LCD_CNTL_DISPLAY_MODE 0x66
52#define LCD_CNTL_DUTY_SET 0x6d
53#define LCD_CNTL_ELECTRONIC_VOLUME 0x81
54#define LCD_CNTL_DATA_INPUT_DIR 0x84
55#define LCD_CNTL_DISPLAY_START_LINE 0x8a
56#define LCD_CNTL_AREA_SCROLL 0x10
57
58#define LCD_CNTL_PAGE 0xb1
59#define LCD_CNTL_COLUMN 0x13
60#define LCD_CNTL_DATA_WRITE 0x1d
61
62#define SCROLLABLE_LINES 26
63
64/*** globals ***/
65
66fb_data lcd_framebuffer[LCD_HEIGHT/4][LCD_WIDTH] IBSS_ATTR;
67
68static const unsigned char dibits[16] ICONST_ATTR = {
69 0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F,
70 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF
71};
72
73static const unsigned char pixmask[4] ICONST_ATTR = {
74 0x03, 0x0C, 0x30, 0xC0
75};
76
77static unsigned fg_pattern IDATA_ATTR = 0xFF; /* initially black */
78static unsigned bg_pattern IDATA_ATTR = 0x00; /* initially white */
79static int drawmode = DRMODE_SOLID;
80static int xmargin = 0;
81static int ymargin = 0;
82static int curfont = FONT_SYSFIXED;
83
84/* scrolling */
85static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */
86static void scroll_thread(void);
87static long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)];
88static const char scroll_name[] = "scroll";
89static int scroll_ticks = 12; /* # of ticks between updates*/
90static int scroll_delay = HZ/2; /* ticks delay before start */
91static int scroll_step = 6; /* pixels per scroll step */
92static int bidir_limit = 50; /* percent */
93static struct scrollinfo scroll[SCROLLABLE_LINES];
94
95static const char scroll_tick_table[16] = {
96 /* Hz values:
97 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */
98 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3
99};
100
101/*** driver code is in lcd.S ***/
102
103/*** hardware configuration ***/
104
105#ifndef SIMULATOR
106
107int lcd_default_contrast(void)
108{
109 return 28;
110}
111
112void lcd_set_contrast(int val)
113{
114 lcd_write_command_ex(LCD_CNTL_ELECTRONIC_VOLUME, val, -1);
115}
116
117void lcd_set_invert_display(bool yesno)
118{
119 lcd_write_command(LCD_CNTL_REVERSE | (yesno?1:0));
120}
121
122/* turn the display upside down (call lcd_update() afterwards) */
123void lcd_set_flip(bool yesno)
124{
125 if (yesno)
126 {
127 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 1);
128 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 0);
129 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 0);
130 }
131 else
132 {
133 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0);
134 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1);
135 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1);
136 }
137}
138
139#endif /* !SIMULATOR */
140
141/* LCD init */
142#ifdef SIMULATOR
143
144void lcd_init(void)
145{
146 create_thread(scroll_thread, scroll_stack,
147 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
148}
149#else
150
151void lcd_init(void)
152{
153 /* GPO35 is the LCD A0 pin
154 GPO46 is LCD RESET */
155 or_l(0x00004008, &GPIO1_OUT);
156 or_l(0x00004008, &GPIO1_ENABLE);
157 or_l(0x00004008, &GPIO1_FUNCTION);
158
159 /* Reset LCD */
160 sleep(1);
161 and_l(~0x00004000, &GPIO1_OUT);
162 sleep(1);
163 or_l(0x00004000, &GPIO1_OUT);
164 sleep(1);
165
166 lcd_write_command(LCD_CNTL_COLUMN_ADDRESS_DIR | 0); /* Normal */
167 lcd_write_command(LCD_CNTL_COMMON_OUTPUT_STATUS | 1); /* Reverse dir */
168 lcd_write_command(LCD_CNTL_REVERSE | 0); /* Reverse OFF */
169 lcd_write_command(LCD_CNTL_ALL_LIGHTING | 0); /* Normal */
170 lcd_write_command_ex(LCD_CNTL_DUTY_SET, 0x20, 1);
171 lcd_write_command(LCD_CNTL_OFF_MODE | 1); /* OFF -> VCC on drivers */
172 lcd_write_command_ex(LCD_CNTL_VOLTAGE_SELECT, 3, -1);
173 lcd_write_command_ex(LCD_CNTL_ELECTRONIC_VOLUME, 0x1c, -1);
174 lcd_write_command_ex(LCD_CNTL_TEMP_GRADIENT_SELECT, 0, -1);
175
176 lcd_write_command_ex(LCD_CNTL_LINE_INVERT_DRIVE, 0x10, -1);
177 lcd_write_command(LCD_CNTL_NLINE_ON_OFF | 1); /* N-line ON */
178
179 lcd_write_command_ex(LCD_CNTL_OSC_FREQUENCY, 3, -1);
180 lcd_write_command(LCD_CNTL_OSC_ON_OFF | 1); /* Oscillator ON */
181
182 lcd_write_command_ex(LCD_CNTL_POWER_CONTROL, 0x16, -1);
183 sleep(HZ/10); /* 100 ms pause */
184 lcd_write_command_ex(LCD_CNTL_POWER_CONTROL, 0x17, -1);
185
186 lcd_write_command_ex(LCD_CNTL_DISPLAY_START_LINE, 0, -1);
187 lcd_write_command_ex(LCD_CNTL_GRAY_SCALE_PATTERN, 0x32, -1);
188 lcd_write_command_ex(LCD_CNTL_DISPLAY_MODE, 0, -1); /* Greyscale mode */
189 lcd_write_command(LCD_CNTL_DATA_INPUT_DIR | 0); /* Column mode */
190
191 lcd_clear_display();
192 lcd_update();
193 lcd_write_command(LCD_CNTL_ON_OFF | 1); /* LCD ON */
194
195 create_thread(scroll_thread, scroll_stack,
196 sizeof(scroll_stack), scroll_name IF_PRIO(, PRIORITY_USER_INTERFACE));
197}
198
199/*** update functions ***/
200
201/* Performance function that works with an external buffer
202 note that by and bheight are in 8-pixel units! */
203void lcd_blit(const unsigned char* data, int x, int by, int width,
204 int bheight, int stride)
205{
206 const unsigned char *src, *src_end;
207 unsigned char *dst_u, *dst_l;
208 static unsigned char upper[LCD_WIDTH] IBSS_ATTR;
209 static unsigned char lower[LCD_WIDTH] IBSS_ATTR;
210 unsigned int byte;
211
212 by *= 2;
213
214 while (bheight--)
215 {
216 src = data;
217 src_end = data + width;
218 dst_u = upper;
219 dst_l = lower;
220 do
221 {
222 byte = *src++;
223 *dst_u++ = dibits[byte & 0x0F];
224 byte >>= 4;
225 *dst_l++ = dibits[byte & 0x0F];
226 }
227 while (src < src_end);
228
229 lcd_write_command_ex(LCD_CNTL_PAGE, by++, -1);
230 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
231 lcd_write_command(LCD_CNTL_DATA_WRITE);
232 lcd_write_data(upper, width);
233
234 lcd_write_command_ex(LCD_CNTL_PAGE, by++, -1);
235 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
236 lcd_write_command(LCD_CNTL_DATA_WRITE);
237 lcd_write_data(lower, width);
238
239 data += stride;
240 }
241}
242
243
244/* Update the display.
245 This must be called after all other LCD functions that change the display. */
246void lcd_update(void) ICODE_ATTR;
247void lcd_update(void)
248{
249 int y;
250
251 /* Copy display bitmap to hardware */
252 for (y = 0; y < LCD_HEIGHT/4; y++)
253 {
254 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
255 lcd_write_command_ex(LCD_CNTL_COLUMN, 0, -1);
256
257 lcd_write_command(LCD_CNTL_DATA_WRITE);
258 lcd_write_data (lcd_framebuffer[y], LCD_WIDTH);
259 }
260}
261
262/* Update a fraction of the display. */
263void lcd_update_rect(int, int, int, int) ICODE_ATTR;
264void lcd_update_rect(int x, int y, int width, int height)
265{
266 int ymax;
267
268 /* The Y coordinates have to work on even 8 pixel rows */
269 ymax = (y + height-1) >> 2;
270 y >>= 2;
271
272 if(x + width > LCD_WIDTH)
273 width = LCD_WIDTH - x;
274 if (width <= 0)
275 return; /* nothing left to do, 0 is harmful to lcd_write_data() */
276 if(ymax >= LCD_HEIGHT/4)
277 ymax = LCD_HEIGHT/4-1;
278
279 /* Copy specified rectange bitmap to hardware */
280 for (; y <= ymax; y++)
281 {
282 lcd_write_command_ex(LCD_CNTL_PAGE, y, -1);
283 lcd_write_command_ex(LCD_CNTL_COLUMN, x, -1);
284
285 lcd_write_command(LCD_CNTL_DATA_WRITE);
286 lcd_write_data (&lcd_framebuffer[y][x], width);
287 }
288}
289#endif /* !SIMULATOR */
290
291/*** parameter handling ***/
292
293void lcd_set_drawmode(int mode)
294{
295 drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID);
296}
297
298int lcd_get_drawmode(void)
299{
300 return drawmode;
301}
302
303void lcd_set_foreground(unsigned brightness)
304{
305 fg_pattern = 0x55 * (~brightness & 3);
306}
307
308unsigned lcd_get_foreground(void)
309{
310 return ~fg_pattern & 3;
311}
312
313void lcd_set_background(unsigned brightness)
314{
315 bg_pattern = 0x55 * (~brightness & 3);
316}
317
318unsigned lcd_get_background(void)
319{
320 return ~bg_pattern & 3;
321}
322
323void lcd_set_drawinfo(int mode, unsigned fg_brightness, unsigned bg_brightness)
324{
325 lcd_set_drawmode(mode);
326 lcd_set_foreground(fg_brightness);
327 lcd_set_background(bg_brightness);
328}
329
330void lcd_setmargins(int x, int y)
331{
332 xmargin = x;
333 ymargin = y;
334}
335
336int lcd_getxmargin(void)
337{
338 return xmargin;
339}
340
341int lcd_getymargin(void)
342{
343 return ymargin;
344}
345
346void lcd_setfont(int newfont)
347{
348 curfont = newfont;
349}
350
351int lcd_getstringsize(const unsigned char *str, int *w, int *h)
352{
353 return font_getstringsize(str, w, h, curfont);
354}
355
356/*** low-level drawing functions ***/
357
358static void setpixel(int x, int y)
359{
360 unsigned mask = pixmask[y & 3];
361 fb_data *address = &lcd_framebuffer[y>>2][x];
362 unsigned data = *address;
363
364 *address = data ^ ((data ^ fg_pattern) & mask);
365}
366
367static void clearpixel(int x, int y)
368{
369 unsigned mask = pixmask[y & 3];
370 fb_data *address = &lcd_framebuffer[y>>2][x];
371 unsigned data = *address;
372
373 *address = data ^ ((data ^ bg_pattern) & mask);
374}
375
376static void flippixel(int x, int y)
377{
378 unsigned mask = pixmask[y & 3];
379 fb_data *address = &lcd_framebuffer[y>>2][x];
380
381 *address ^= mask;
382}
383
384static void nopixel(int x, int y)
385{
386 (void)x;
387 (void)y;
388}
389
390lcd_pixelfunc_type* const lcd_pixelfuncs[8] = {
391 flippixel, nopixel, setpixel, setpixel,
392 nopixel, clearpixel, nopixel, clearpixel
393};
394
395/* 'mask' and 'bits' contain 2 bits per pixel */
396static void flipblock(fb_data *address, unsigned mask, unsigned bits)
397 ICODE_ATTR;
398static void flipblock(fb_data *address, unsigned mask, unsigned bits)
399{
400 *address ^= bits & mask;
401}
402
403static void bgblock(fb_data *address, unsigned mask, unsigned bits)
404 ICODE_ATTR;
405static void bgblock(fb_data *address, unsigned mask, unsigned bits)
406{
407 unsigned data = *address;
408
409 *address = data ^ ((data ^ bg_pattern) & mask & ~bits);
410}
411
412static void fgblock(fb_data *address, unsigned mask, unsigned bits)
413 ICODE_ATTR;
414static void fgblock(fb_data *address, unsigned mask, unsigned bits)
415{
416 unsigned data = *address;
417
418 *address = data ^ ((data ^ fg_pattern) & mask & bits);
419}
420
421static void solidblock(fb_data *address, unsigned mask, unsigned bits)
422 ICODE_ATTR;
423static void solidblock(fb_data *address, unsigned mask, unsigned bits)
424{
425 unsigned data = *address;
426 unsigned bgp = bg_pattern;
427
428 bits = bgp ^ ((bgp ^ fg_pattern) & bits);
429 *address = data ^ ((data ^ bits) & mask);
430}
431
432static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
433 ICODE_ATTR;
434static void flipinvblock(fb_data *address, unsigned mask, unsigned bits)
435{
436 *address ^= ~bits & mask;
437}
438
439static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
440 ICODE_ATTR;
441static void bginvblock(fb_data *address, unsigned mask, unsigned bits)
442{
443 unsigned data = *address;
444
445 *address = data ^ ((data ^ bg_pattern) & mask & bits);
446}
447
448static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
449 ICODE_ATTR;
450static void fginvblock(fb_data *address, unsigned mask, unsigned bits)
451{
452 unsigned data = *address;
453
454 *address = data ^ ((data ^ fg_pattern) & mask & ~bits);
455}
456
457static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
458 ICODE_ATTR;
459static void solidinvblock(fb_data *address, unsigned mask, unsigned bits)
460{
461 unsigned data = *address;
462 unsigned fgp = fg_pattern;
463
464 bits = fgp ^ ((fgp ^ bg_pattern) & bits);
465 *address = data ^ ((data ^ bits) & mask);
466}
467
468lcd_blockfunc_type* const lcd_blockfuncs[8] = {
469 flipblock, bgblock, fgblock, solidblock,
470 flipinvblock, bginvblock, fginvblock, solidinvblock
471};
472
473static inline void setblock(fb_data *address, unsigned mask, unsigned bits)
474{
475 unsigned data = *address;
476
477 bits ^= data;
478 *address = data ^ (bits & mask);
479}
480
481/*** drawing functions ***/
482
483/* Clear the whole display */
484void lcd_clear_display(void)
485{
486 unsigned bits = (drawmode & DRMODE_INVERSEVID) ? fg_pattern : bg_pattern;
487
488 memset(lcd_framebuffer, bits, sizeof lcd_framebuffer);
489 scrolling_lines = 0;
490}
491
492/* Set a single pixel */
493void lcd_drawpixel(int x, int y)
494{
495 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
496 lcd_pixelfuncs[drawmode](x, y);
497}
498
499/* Draw a line */
500void lcd_drawline(int x1, int y1, int x2, int y2)
501{
502 int numpixels;
503 int i;
504 int deltax, deltay;
505 int d, dinc1, dinc2;
506 int x, xinc1, xinc2;
507 int y, yinc1, yinc2;
508 lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
509
510 deltax = abs(x2 - x1);
511 deltay = abs(y2 - y1);
512 xinc2 = 1;
513 yinc2 = 1;
514
515 if (deltax >= deltay)
516 {
517 numpixels = deltax;
518 d = 2 * deltay - deltax;
519 dinc1 = deltay * 2;
520 dinc2 = (deltay - deltax) * 2;
521 xinc1 = 1;
522 yinc1 = 0;
523 }
524 else
525 {
526 numpixels = deltay;
527 d = 2 * deltax - deltay;
528 dinc1 = deltax * 2;
529 dinc2 = (deltax - deltay) * 2;
530 xinc1 = 0;
531 yinc1 = 1;
532 }
533 numpixels++; /* include endpoints */
534
535 if (x1 > x2)
536 {
537 xinc1 = -xinc1;
538 xinc2 = -xinc2;
539 }
540
541 if (y1 > y2)
542 {
543 yinc1 = -yinc1;
544 yinc2 = -yinc2;
545 }
546
547 x = x1;
548 y = y1;
549
550 for (i = 0; i < numpixels; i++)
551 {
552 if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
553 pfunc(x, y);
554
555 if (d < 0)
556 {
557 d += dinc1;
558 x += xinc1;
559 y += yinc1;
560 }
561 else
562 {
563 d += dinc2;
564 x += xinc2;
565 y += yinc2;
566 }
567 }
568}
569
570/* Draw a horizontal line (optimised) */
571void lcd_hline(int x1, int x2, int y)
572{
573 int x;
574 fb_data *dst, *dst_end;
575 unsigned mask;
576 lcd_blockfunc_type *bfunc;
577
578 /* direction flip */
579 if (x2 < x1)
580 {
581 x = x1;
582 x1 = x2;
583 x2 = x;
584 }
585
586 /* nothing to draw? */
587 if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0))
588 return;
589
590 /* clipping */
591 if (x1 < 0)
592 x1 = 0;
593 if (x2 >= LCD_WIDTH)
594 x2 = LCD_WIDTH-1;
595
596 bfunc = lcd_blockfuncs[drawmode];
597 dst = &lcd_framebuffer[y>>2][x1];
598 mask = pixmask[y & 3];
599
600 dst_end = dst + x2 - x1;
601 do
602 bfunc(dst++, mask, 0xFFu);
603 while (dst <= dst_end);
604}
605
606/* Draw a vertical line (optimised) */
607void lcd_vline(int x, int y1, int y2)
608{
609 int ny;
610 fb_data *dst;
611 unsigned mask, mask_bottom;
612 lcd_blockfunc_type *bfunc;
613
614 /* direction flip */
615 if (y2 < y1)
616 {
617 ny = y1;
618 y1 = y2;
619 y2 = ny;
620 }
621
622 /* nothing to draw? */
623 if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0))
624 return;
625
626 /* clipping */
627 if (y1 < 0)
628 y1 = 0;
629 if (y2 >= LCD_HEIGHT)
630 y2 = LCD_HEIGHT-1;
631
632 bfunc = lcd_blockfuncs[drawmode];
633 dst = &lcd_framebuffer[y1>>2][x];
634 ny = y2 - (y1 & ~3);
635 mask = 0xFFu << (2 * (y1 & 3));
636 mask_bottom = 0xFFu >> (2 * (~ny & 3));
637
638 for (; ny >= 4; ny -= 4)
639 {
640 bfunc(dst, mask, 0xFFu);
641 dst += LCD_WIDTH;
642 mask = 0xFFu;
643 }
644 mask &= mask_bottom;
645 bfunc(dst, mask, 0xFFu);
646}
647
648/* Draw a rectangular box */
649void lcd_drawrect(int x, int y, int width, int height)
650{
651 if ((width <= 0) || (height <= 0))
652 return;
653
654 int x2 = x + width - 1;
655 int y2 = y + height - 1;
656
657 lcd_vline(x, y, y2);
658 lcd_vline(x2, y, y2);
659 lcd_hline(x, x2, y);
660 lcd_hline(x, x2, y2);
661}
662
663/* Fill a rectangular area */
664void lcd_fillrect(int x, int y, int width, int height)
665{
666 int ny;
667 fb_data *dst, *dst_end;
668 unsigned mask, mask_bottom;
669 unsigned bits = 0;
670 lcd_blockfunc_type *bfunc;
671 bool fillopt = false;
672
673 /* nothing to draw? */
674 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
675 || (x + width <= 0) || (y + height <= 0))
676 return;
677
678 /* clipping */
679 if (x < 0)
680 {
681 width += x;
682 x = 0;
683 }
684 if (y < 0)
685 {
686 height += y;
687 y = 0;
688 }
689 if (x + width > LCD_WIDTH)
690 width = LCD_WIDTH - x;
691 if (y + height > LCD_HEIGHT)
692 height = LCD_HEIGHT - y;
693
694 if (drawmode & DRMODE_INVERSEVID)
695 {
696 if (drawmode & DRMODE_BG)
697 {
698 fillopt = true;
699 bits = bg_pattern;
700 }
701 }
702 else
703 {
704 if (drawmode & DRMODE_FG)
705 {
706 fillopt = true;
707 bits = fg_pattern;
708 }
709 }
710 bfunc = lcd_blockfuncs[drawmode];
711 dst = &lcd_framebuffer[y>>2][x];
712 ny = height - 1 + (y & 3);
713 mask = 0xFFu << (2 * (y & 3));
714 mask_bottom = 0xFFu >> (2 * (~ny & 3));
715
716 for (; ny >= 4; ny -= 4)
717 {
718 if (fillopt && (mask == 0xFFu))
719 memset(dst, bits, width);
720 else
721 {
722 fb_data *dst_row = dst;
723
724 dst_end = dst_row + width;
725 do
726 bfunc(dst_row++, mask, 0xFFu);
727 while (dst_row < dst_end);
728 }
729
730 dst += LCD_WIDTH;
731 mask = 0xFFu;
732 }
733 mask &= mask_bottom;
734
735 if (fillopt && (mask == 0xFFu))
736 memset(dst, bits, width);
737 else
738 {
739 dst_end = dst + width;
740 do
741 bfunc(dst++, mask, 0xFFu);
742 while (dst < dst_end);
743 }
744}
745
746/* About Rockbox' internal monochrome bitmap format:
747 *
748 * A bitmap contains one bit for every pixel that defines if that pixel is
749 * black (1) or white (0). Bits within a byte are arranged vertically, LSB
750 * at top.
751 * The bytes are stored in row-major order, with byte 0 being top left,
752 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
753 * 0..7, the second row defines pixel row 8..15 etc.
754 *
755 * This is similar to the internal lcd hw format. */
756
757/* Draw a partial monochrome bitmap */
758void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
759 int stride, int x, int y, int width, int height)
760 ICODE_ATTR;
761void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y,
762 int stride, int x, int y, int width, int height)
763{
764 int shift, ny;
765 fb_data *dst, *dst_end;
766 unsigned mask, mask_bottom;
767 lcd_blockfunc_type *bfunc;
768
769 /* nothing to draw? */
770 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
771 || (x + width <= 0) || (y + height <= 0))
772 return;
773
774 /* clipping */
775 if (x < 0)
776 {
777 width += x;
778 src_x -= x;
779 x = 0;
780 }
781 if (y < 0)
782 {
783 height += y;
784 src_y -= y;
785 y = 0;
786 }
787 if (x + width > LCD_WIDTH)
788 width = LCD_WIDTH - x;
789 if (y + height > LCD_HEIGHT)
790 height = LCD_HEIGHT - y;
791
792 src += stride * (src_y >> 3) + src_x; /* move starting point */
793 src_y &= 7;
794 y -= src_y;
795 dst = &lcd_framebuffer[y>>2][x];
796 shift = y & 3;
797 ny = height - 1 + shift + src_y;
798
799 bfunc = lcd_blockfuncs[drawmode];
800 mask = 0xFFu << (shift + src_y);
801 mask_bottom = 0xFFu >> (~ny & 7);
802
803 if (shift == 0)
804 {
805 unsigned dmask1, dmask2, data;
806
807 for (; ny >= 8; ny -= 8)
808 {
809 const unsigned char *src_row = src;
810 fb_data *dst_row = dst + LCD_WIDTH;
811
812 dmask1 = dibits[mask&0x0F];
813 dmask2 = dibits[(mask>>4)&0x0F];
814 dst_end = dst_row + width;
815
816 if (dmask1 != 0)
817 {
818 do
819 {
820 data = *src_row++;
821 bfunc(dst_row - LCD_WIDTH, dmask1, dibits[data&0x0F]);
822 bfunc(dst_row++, dmask2, dibits[(data>>4)&0x0F]);
823 }
824 while (dst_row < dst_end);
825 }
826 else
827 {
828 do
829 bfunc(dst_row++, dmask2, dibits[((*src_row++)>>4)&0x0F]);
830 while (dst_row < dst_end);
831 }
832 src += stride;
833 dst += 2*LCD_WIDTH;
834 mask = 0xFFu;
835 }
836 mask &= mask_bottom;
837 dmask1 = dibits[mask&0x0F];
838 dmask2 = dibits[(mask>>4)&0x0F];
839 dst_end = dst + width;
840
841 if (dmask1 != 0)
842 {
843 if (dmask2 != 0)
844 {
845 do
846 {
847 data = *src++;
848 bfunc(dst, dmask1, dibits[data&0x0F]);
849 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[(data>>4)&0x0F]);
850 }
851 while (dst < dst_end);
852 }
853 else
854 {
855 do
856 bfunc(dst++, dmask1, dibits[(*src++)&0x0F]);
857 while (dst < dst_end);
858 }
859 }
860 else
861 {
862 do
863 bfunc((dst++) + LCD_WIDTH, dmask2, dibits[((*src++)>>4)&0x0F]);
864 while (dst < dst_end);
865 }
866 }
867 else
868 {
869 dst_end = dst + width;
870 do
871 {
872 const unsigned char *src_col = src++;
873 fb_data *dst_col = dst++;
874 unsigned mask_col = mask;
875 unsigned data = 0;
876
877 for (y = ny; y >= 8; y -= 8)
878 {
879 data |= *src_col << shift;
880
881 if (mask_col & 0xFFu)
882 {
883 if (mask_col & 0x0F)
884 bfunc(dst_col, dibits[mask_col&0x0F], dibits[data&0x0F]);
885 bfunc(dst_col + LCD_WIDTH, dibits[(mask_col>>4)&0x0F],
886 dibits[(data>>4)&0x0F]);
887 mask_col = 0xFFu;
888 }
889 else
890 mask_col >>= 8;
891
892 src_col += stride;
893 dst_col += 2*LCD_WIDTH;
894 data >>= 8;
895 }
896 data |= *src_col << shift;
897 mask_bottom &= mask_col;
898 if (mask_bottom & 0x0F)
899 bfunc(dst_col, dibits[mask_bottom&0x0F], dibits[data&0x0F]);
900 if (mask_bottom & 0xF0)
901 bfunc(dst_col + LCD_WIDTH, dibits[(mask_bottom&0xF0)>>4],
902 dibits[(data>>4)&0x0F]);
903 }
904 while (dst < dst_end);
905 }
906}
907
908/* Draw a full monochrome bitmap */
909void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height)
910{
911 lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height);
912}
913
914/* About Rockbox' internal native bitmap format:
915 *
916 * A bitmap contains two bits for every pixel. 00 = white, 01 = light grey,
917 * 10 = dark grey, 11 = black. Bits within a byte are arranged vertically, LSB
918 * at top.
919 * The bytes are stored in row-major order, with byte 0 being top left,
920 * byte 1 2nd from left etc. The first row of bytes defines pixel rows
921 * 0..3, the second row defines pixel row 4..7 etc.
922 *
923 * This is the same as the internal lcd hw format. */
924
925/* Draw a partial native bitmap */
926void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
927 int stride, int x, int y, int width, int height)
928 ICODE_ATTR;
929void lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
930 int stride, int x, int y, int width, int height)
931{
932 int shift, ny;
933 fb_data *dst, *dst_end;
934 unsigned mask, mask_bottom;
935
936 /* nothing to draw? */
937 if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
938 || (x + width <= 0) || (y + height <= 0))
939 return;
940
941 /* clipping */
942 if (x < 0)
943 {
944 width += x;
945 src_x -= x;
946 x = 0;
947 }
948 if (y < 0)
949 {
950 height += y;
951 src_y -= y;
952 y = 0;
953 }
954 if (x + width > LCD_WIDTH)
955 width = LCD_WIDTH - x;
956 if (y + height > LCD_HEIGHT)
957 height = LCD_HEIGHT - y;
958
959 src += stride * (src_y >> 2) + src_x; /* move starting point */
960 src_y &= 3;
961 y -= src_y;
962 dst = &lcd_framebuffer[y>>2][x];
963 shift = y & 3;
964 ny = height - 1 + shift + src_y;
965
966 mask = 0xFFu << (2 * (shift + src_y));
967 mask_bottom = 0xFFu >> (2 * (~ny & 3));
968
969 if (shift == 0)
970 {
971 for (; ny >= 4; ny -= 4)
972 {
973 if (mask == 0xFFu)
974 memcpy(dst, src, width);
975 else
976 {
977 const fb_data *src_row = src;
978 fb_data *dst_row = dst;
979
980 dst_end = dst_row + width;
981 do
982 setblock(dst_row++, mask, *src_row++);
983 while (dst_row < dst_end);
984 }
985 src += stride;
986 dst += LCD_WIDTH;
987 mask = 0xFFu;
988 }
989 mask &= mask_bottom;
990
991 if (mask == 0xFFu)
992 memcpy(dst, src, width);
993 else
994 {
995 dst_end = dst + width;
996 do
997 setblock(dst++, mask, *src++);
998 while (dst < dst_end);
999 }
1000 }
1001 else
1002 {
1003 shift *= 2;
1004 dst_end = dst + width;
1005 do
1006 {
1007 const fb_data *src_col = src++;
1008 fb_data *dst_col = dst++;
1009 unsigned mask_col = mask;
1010 unsigned data = 0;
1011
1012 for (y = ny; y >= 4; y -= 4)
1013 {
1014 data |= *src_col << shift;
1015
1016 if (mask_col & 0xFFu)
1017 {
1018 setblock(dst_col, mask_col, data);
1019 mask_col = 0xFFu;
1020 }
1021 else
1022 mask_col >>= 8;
1023
1024 src_col += stride;
1025 dst_col += LCD_WIDTH;
1026 data >>= 8;
1027 }
1028 data |= *src_col << shift;
1029 setblock(dst_col, mask_col & mask_bottom, data);
1030 }
1031 while (dst < dst_end);
1032 }
1033}
1034
1035/* Draw a full native bitmap */
1036void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
1037{
1038 lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
1039}
1040
1041/* put a string at a given pixel position, skipping first ofs pixel columns */
1042static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1043{
1044 unsigned short ch;
1045 unsigned short *ucs;
1046 struct font* pf = font_get(curfont);
1047
1048 ucs = bidi_l2v(str, 1);
1049
1050 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
1051 {
1052 int width;
1053 const unsigned char *bits;
1054
1055 /* get proportional width and glyph bits */
1056 width = font_get_width(pf,ch);
1057
1058 if (ofs > width)
1059 {
1060 ofs -= width;
1061 continue;
1062 }
1063
1064 bits = font_get_bits(pf, ch);
1065
1066 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
1067 pf->height);
1068
1069 x += width - ofs;
1070 ofs = 0;
1071 }
1072}
1073
1074/* put a string at a given pixel position */
1075void lcd_putsxy(int x, int y, const unsigned char *str)
1076{
1077 lcd_putsxyofs(x, y, 0, str);
1078}
1079
1080/*** line oriented text output ***/
1081
1082/* put a string at a given char position */
1083void lcd_puts(int x, int y, const unsigned char *str)
1084{
1085 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, 0);
1086}
1087
1088void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1089{
1090 lcd_puts_style_offset(x, y, str, style, 0);
1091}
1092
1093void lcd_puts_offset(int x, int y, const unsigned char *str, int offset)
1094{
1095 lcd_puts_style_offset(x, y, str, STYLE_DEFAULT, offset);
1096}
1097
1098/* put a string at a given char position, style, and pixel position,
1099 * skipping first offset pixel columns */
1100void lcd_puts_style_offset(int x, int y, const unsigned char *str,
1101 int style, int offset)
1102{
1103 int xpos,ypos,w,h,xrect;
1104 int lastmode = drawmode;
1105
1106 /* make sure scrolling is turned off on the line we are updating */
1107 scrolling_lines &= ~(1 << y);
1108
1109 if(!str || !str[0])
1110 return;
1111
1112 lcd_getstringsize(str, &w, &h);
1113 xpos = xmargin + x*w / utf8length((char *)str);
1114 ypos = ymargin + y*h;
1115 drawmode = (style & STYLE_INVERT) ?
1116 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1117 lcd_putsxyofs(xpos, ypos, offset, str);
1118 drawmode ^= DRMODE_INVERSEVID;
1119 xrect = xpos + MAX(w - offset, 0);
1120 lcd_fillrect(xrect, ypos, LCD_WIDTH - xrect, h);
1121 drawmode = lastmode;
1122}
1123
1124/*** scrolling ***/
1125
1126/* Reverse the invert setting of the scrolling line (if any) at given char
1127 position. Setting will go into affect next time line scrolls. */
1128void lcd_invertscroll(int x, int y)
1129{
1130 struct scrollinfo* s;
1131
1132 (void)x;
1133
1134 s = &scroll[y];
1135 s->invert = !s->invert;
1136}
1137
1138void lcd_stop_scroll(void)
1139{
1140 scrolling_lines=0;
1141}
1142
1143void lcd_scroll_speed(int speed)
1144{
1145 scroll_ticks = scroll_tick_table[speed];
1146}
1147
1148void lcd_scroll_step(int step)
1149{
1150 scroll_step = step;
1151}
1152
1153void lcd_scroll_delay(int ms)
1154{
1155 scroll_delay = ms / (HZ / 10);
1156}
1157
1158void lcd_bidir_scroll(int percent)
1159{
1160 bidir_limit = percent;
1161}
1162
1163void lcd_puts_scroll(int x, int y, const unsigned char *string)
1164{
1165 lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT);
1166}
1167
1168void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1169{
1170 lcd_puts_scroll_style_offset(x, y, string, style, 0);
1171}
1172
1173void lcd_puts_scroll_offset(int x, int y, const unsigned char *string, int offset)
1174{
1175 lcd_puts_scroll_style_offset(x, y, string, STYLE_DEFAULT, offset);
1176}
1177
1178void lcd_puts_scroll_style_offset(int x, int y, const unsigned char *string,
1179 int style, int offset)
1180{
1181 struct scrollinfo* s;
1182 int w, h;
1183
1184 s = &scroll[y];
1185
1186 s->start_tick = current_tick + scroll_delay;
1187 s->invert = false;
1188 if (style & STYLE_INVERT) {
1189 s->invert = true;
1190 lcd_puts_style_offset(x,y,string,STYLE_INVERT,offset);
1191 }
1192 else
1193 lcd_puts_offset(x,y,string,offset);
1194
1195 lcd_getstringsize(string, &w, &h);
1196
1197 if (LCD_WIDTH - x * 8 - xmargin < w) {
1198 /* prepare scroll line */
1199 char *end;
1200
1201 memset(s->line, 0, sizeof s->line);
1202 strcpy(s->line, (char *)string);
1203
1204 /* get width */
1205 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1206
1207 /* scroll bidirectional or forward only depending on the string
1208 width */
1209 if ( bidir_limit ) {
1210 s->bidir = s->width < (LCD_WIDTH - xmargin) *
1211 (100 + bidir_limit) / 100;
1212 }
1213 else
1214 s->bidir = false;
1215
1216 if (!s->bidir) { /* add spaces if scrolling in the round */
1217 strcat(s->line, " ");
1218 /* get new width incl. spaces */
1219 s->width = lcd_getstringsize((unsigned char *)s->line, &w, &h);
1220 }
1221
1222 end = strchr(s->line, '\0');
1223 strncpy(end, (char *)string, LCD_WIDTH/2);
1224
1225 s->len = utf8length((char *)string);
1226 s->offset = offset;
1227 s->startx = xmargin + x * s->width / s->len;
1228 s->backward = false;
1229 scrolling_lines |= (1<<y);
1230 }
1231 else
1232 /* force a bit switch-off since it doesn't scroll */
1233 scrolling_lines &= ~(1<<y);
1234}
1235
1236static void scroll_thread(void)
1237{
1238 struct font* pf;
1239 struct scrollinfo* s;
1240 int index;
1241 int xpos, ypos;
1242 int lastmode;
1243
1244 /* initialize scroll struct array */
1245 scrolling_lines = 0;
1246
1247 while ( 1 ) {
1248 for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
1249 /* really scroll? */
1250 if ( !(scrolling_lines&(1<<index)) )
1251 continue;
1252
1253 s = &scroll[index];
1254
1255 /* check pause */
1256 if (TIME_BEFORE(current_tick, s->start_tick))
1257 continue;
1258
1259 if (s->backward)
1260 s->offset -= scroll_step;
1261 else
1262 s->offset += scroll_step;
1263
1264 pf = font_get(curfont);
1265 xpos = s->startx;
1266 ypos = ymargin + index * pf->height;
1267
1268 if (s->bidir) { /* scroll bidirectional */
1269 if (s->offset <= 0) {
1270 /* at beginning of line */
1271 s->offset = 0;
1272 s->backward = false;
1273 s->start_tick = current_tick + scroll_delay * 2;
1274 }
1275 if (s->offset >= s->width - (LCD_WIDTH - xpos)) {
1276 /* at end of line */
1277 s->offset = s->width - (LCD_WIDTH - xpos);
1278 s->backward = true;
1279 s->start_tick = current_tick + scroll_delay * 2;
1280 }
1281 }
1282 else {
1283 /* scroll forward the whole time */
1284 if (s->offset >= s->width)
1285 s->offset %= s->width;
1286 }
1287
1288 lastmode = drawmode;
1289 drawmode = s->invert ?
1290 (DRMODE_SOLID|DRMODE_INVERSEVID) : DRMODE_SOLID;
1291 lcd_putsxyofs(xpos, ypos, s->offset, s->line);
1292 drawmode = lastmode;
1293 lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height);
1294 }
1295
1296 sleep(scroll_ticks);
1297 }
1298}