DBoxLCD: Initialize _buffer to prevent segfault
[openblackhole/openblackhole-enigma2.git] / lib / gdi / lcd.cpp
1 #include <lib/gdi/lcd.h>
2
3 #include <unistd.h>
4 #include <fcntl.h>
5 #include <sys/ioctl.h>
6
7 #include <lib/gdi/esize.h>
8 #include <lib/base/init.h>
9 #include <lib/base/init_num.h>
10 #ifdef HAVE_TEXTLCD
11         #include <lib/base/estring.h>
12 #endif
13 #include <lib/gdi/glcddc.h>
14
15 eLCD *eLCD::instance;
16
17 eLCD::eLCD()
18 {
19         _buffer = 0;
20         lcdfd = -1;
21         locked = 0;
22         instance = this;
23 }
24
25 eLCD *eLCD::getInstance()
26 {
27         return instance;
28 }
29
30 void eLCD::setSize(int xres, int yres, int bpp)
31 {
32         res = eSize(xres, yres);
33         _buffer = new unsigned char[xres * yres * bpp/8];
34         memset(_buffer, 0, res.height() * res.width() * bpp / 8);
35         _stride = res.width() * bpp / 8;
36         eDebug("[eLCD] (%dx%dx%d) buffer %p %d bytes, stride %d", xres, yres, bpp, _buffer, xres * yres * bpp / 8, _stride);
37 }
38
39 eLCD::~eLCD()
40 {
41         if (_buffer)
42                 delete [] _buffer;
43 }
44
45 int eLCD::lock()
46 {
47         if (locked)
48                 return -1;
49
50         locked = 1;
51         return lcdfd;
52 }
53
54 void eLCD::unlock()
55 {
56         locked = 0;
57 }
58
59 #ifdef HAVE_TEXTLCD
60 void eLCD::renderText(ePoint start, const char *text)
61 {
62         if (lcdfd >= 0 && start.y() < 5)
63         {
64                 std::string message = text;
65                 message = replace_all(message, "\n", " ");
66                 ::write(lcdfd, message.c_str(), message.size());
67         }
68 }
69 #endif
70
71 eDBoxLCD::eDBoxLCD()
72 {
73         int xres = 132, yres = 64, bpp = 8;
74         flipped = false;
75         inverted = 0;
76         lcd_type = 0;
77 #ifndef NO_LCD
78         lcdfd = open("/dev/dbox/oled0", O_RDWR);
79         if (lcdfd < 0)
80         {
81                 if (!access("/proc/stb/lcd/oled_brightness", W_OK) ||
82                     !access("/proc/stb/fp/oled_brightness", W_OK) )
83                         lcd_type = 2;
84                 lcdfd = open("/dev/dbox/lcd0", O_RDWR);
85         }
86         else
87                 lcd_type = 1;
88
89         if (lcdfd < 0)
90                 eDebug("[eDboxLCD] No oled0 or lcd0 device found!");
91         else
92         {
93
94 #ifndef LCD_IOCTL_ASC_MODE
95 #define LCDSET                  0x1000
96 #define LCD_IOCTL_ASC_MODE      (21|LCDSET)
97 #define LCD_MODE_ASC            0
98 #define LCD_MODE_BIN            1
99 #endif
100
101                 int i = LCD_MODE_BIN;
102                 ioctl(lcdfd, LCD_IOCTL_ASC_MODE, &i);
103                 FILE *f = fopen("/proc/stb/lcd/xres", "r");
104                 if (f)
105                 {
106                         int tmp;
107                         if (fscanf(f, "%x", &tmp) == 1)
108                                 xres = tmp;
109                         fclose(f);
110                         f = fopen("/proc/stb/lcd/yres", "r");
111                         if (f)
112                         {
113                                 if (fscanf(f, "%x", &tmp) == 1)
114                                         yres = tmp;
115                                 fclose(f);
116                                 f = fopen("/proc/stb/lcd/bpp", "r");
117                                 if (f)
118                                 {
119                                         if (fscanf(f, "%x", &tmp) == 1)
120                                                 bpp = tmp;
121                                         fclose(f);
122                                 }
123                         }
124                         lcd_type = 3;
125                 }
126                 eDebug("[eDboxLCD] xres=%d, yres=%d, bpp=%d lcd_type=%d", xres, yres, bpp, lcd_type);
127
128                 instance = this;
129                 setSize(xres, yres, bpp);
130         }
131 #endif
132 }
133
134 void eDBoxLCD::setInverted(unsigned char inv)
135 {
136         inverted = inv;
137         update();
138 }
139
140 void eDBoxLCD::setFlipped(bool onoff)
141 {
142         flipped = onoff;
143         update();
144 }
145
146 int eDBoxLCD::setLCDContrast(int contrast)
147 {
148 #ifndef NO_LCD
149         if (lcdfd < 0)
150                 return(0);
151
152 #ifndef LCD_IOCTL_SRV
153 #define LCDSET                  0x1000
154 #define LCD_IOCTL_SRV                   (10|LCDSET)
155 #endif
156         eDebug("[eDboxLCD] setLCDContrast %d", contrast);
157
158         int fp;
159         if((fp = open("/dev/dbox/fp0", O_RDWR)) < 0)
160         {
161                 eDebug("[eDboxLCD] can't open /dev/dbox/fp0: %m");
162                 return(-1);
163         }
164
165         if(ioctl(lcdfd, LCD_IOCTL_SRV, &contrast) < 0)
166                 eDebug("[eDboxLCD] can't set lcd contrast: %m");
167         close(fp);
168 #endif
169         return(0);
170 }
171
172 int eDBoxLCD::setLCDBrightness(int brightness)
173 {
174 #ifndef NO_LCD
175         if (lcdfd < 0)
176                 return(0);
177
178         eDebug("[eDboxLCD] setLCDBrightness %d", brightness);
179         FILE *f = fopen("/proc/stb/lcd/oled_brightness", "w");
180         if (!f)
181                 f = fopen("/proc/stb/fp/oled_brightness", "w");
182         if (f)
183         {
184                 if (fprintf(f, "%d", brightness) == 0)
185                         eDebug("[eDboxLCD] write /proc/stb/lcd|fp/oled_brightness failed: %m");
186                 fclose(f);
187         }
188         else
189         {
190                 int fp;
191                 if ((fp = open("/dev/dbox/fp0", O_RDWR)) < 0)
192                 {
193                         eDebug("[eDboxLCD] can't open /dev/dbox/fp0: %m");
194                         return(-1);
195                 }
196 #ifndef FP_IOCTL_LCD_DIMM
197 #define FP_IOCTL_LCD_DIMM       3
198 #endif
199                 if (ioctl(fp, FP_IOCTL_LCD_DIMM, &brightness) < 0)
200                         eDebug("[eDboxLCD] can't set lcd brightness: %m");
201                 close(fp);
202         }
203 #endif
204         return(0);
205 }
206
207 eDBoxLCD::~eDBoxLCD()
208 {
209         if (lcdfd >= 0)
210         {
211                 close(lcdfd);
212                 lcdfd = -1;
213         }
214 }
215
216 void eDBoxLCD::update()
217 {
218 #ifndef HAVE_TEXTLCD
219         if (lcdfd < 0)
220                 return;
221
222         if (lcd_type == 0 || lcd_type == 2)
223         {
224                 unsigned char raw[132 * 8];
225                 int x, y, yy;
226                 for (y = 0; y < 8; y++)
227                 {
228                         for (x = 0; x < 132; x++)
229                         {
230                                 int pix = 0;
231                                 for (yy = 0; yy < 8; yy++)
232                                         pix |= (_buffer[(y * 8 + yy) * 132 + x] >= 108) << yy;
233                                 if (flipped)
234                                 {
235                                         /* 8 pixels per byte, swap bits */
236 #define BIT_SWAP(a) (( ((a << 7)&0x80) + ((a << 5)&0x40) + ((a << 3)&0x20) + ((a << 1)&0x10) + ((a >> 1)&0x08) + ((a >> 3)&0x04) + ((a >> 5)&0x02) + ((a >> 7)&0x01) )&0xff)
237                                         raw[(7 - y) * 132 + (131 - x)] = BIT_SWAP(pix ^ inverted);
238                                 }
239                                 else
240                                         raw[y * 132 + x] = pix ^ inverted;
241                         }
242                 }
243                 write(lcdfd, raw, 132 * 8);
244         }
245         else if (lcd_type == 3)
246         {
247                 /* for now, only support flipping / inverting for 8bpp displays */
248                 if ((flipped || inverted) && _stride == res.width())
249                 {
250                         unsigned int height = res.height();
251                         unsigned int width = res.width();
252                         unsigned char raw[_stride * height];
253                         for (unsigned int y = 0; y < height; y++)
254                         {
255                                 for (unsigned int x = 0; x < width; x++)
256                                 {
257                                         if (flipped)
258                                                 /* 8bpp, no bit swapping */
259                                                 raw[(height - 1 - y) * width + (width - 1 - x)] = _buffer[y * width + x] ^ inverted;
260                                         else
261                                                 raw[y * width + x] = _buffer[y * width + x] ^ inverted;
262                                 }
263                         }
264                         write(lcdfd, raw, _stride * height);
265                 }
266                 else
267                         write(lcdfd, _buffer, _stride * res.height());
268         }
269         else /* lcd_type == 1 */
270         {
271                 unsigned char raw[64 * 64];
272                 int x, y;
273                 memset(raw, 0, 64 * 64);
274                 for (y = 0; y < 64; y++)
275                 {
276                         int pix = 0;
277                         for (x = 0; x < 128 / 2; x++)
278                         {
279                                 pix = (_buffer[y * 132 + x * 2 + 2] & 0xF0) | (_buffer[y * 132 + x * 2 + 1 + 2] >> 4);
280                                 if (inverted)
281                                         pix = 0xFF - pix;
282                                 if (flipped)
283                                 {
284                                         /* device seems to be 4bpp, swap nibbles */
285                                         unsigned char byte;
286                                         byte = (pix >> 4) & 0x0f;
287                                         byte |= (pix << 4) & 0xf0;
288                                         raw[(63 - y) * 64 + (63 - x)] = byte;
289                                 }
290                                 else
291                                         raw[y * 64 + x] = pix;
292                         }
293                 }
294                 write(lcdfd, raw, 64 * 64);
295         }
296 #endif
297 }