Merge branch 'master' of git.opendreambox.org:/git/enigma2
[enigma2.git] / lib / gdi / fb.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <sys/ioctl.h>
5 #include <unistd.h>
6 #include <sys/mman.h>
7 #include <memory.h>
8 #include <linux/kd.h>
9
10 #include <lib/gdi/fb.h>
11
12 #ifndef FBIO_WAITFORVSYNC
13 #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
14 #endif
15
16 #ifndef FBIO_BLIT
17 #define FBIO_SET_MANUAL_BLIT _IOW('F', 0x21, __u8)
18 #define FBIO_BLIT 0x22
19 #endif
20
21 fbClass *fbClass::instance;
22
23 fbClass *fbClass::getInstance()
24 {
25         return instance;
26 }
27
28 fbClass::fbClass(const char *fb)
29 {
30         m_manual_blit=-1;
31         instance=this;
32         locked=0;
33         available=0;
34         cmap.start=0;
35         cmap.len=256;
36         cmap.red=red;
37         cmap.green=green;
38         cmap.blue=blue;
39         cmap.transp=trans;
40
41         fd=open(fb, O_RDWR);
42         if (fd<0)
43         {
44                 perror(fb);
45                 goto nolfb;
46         }
47
48
49         if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo)<0)
50         {
51                 perror("FBIOGET_VSCREENINFO");
52                 goto nolfb;
53         }
54         
55         memcpy(&oldscreen, &screeninfo, sizeof(screeninfo));
56
57         fb_fix_screeninfo fix;
58         if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
59         {
60                 perror("FBIOGET_FSCREENINFO");
61                 goto nolfb;
62         }
63
64         available=fix.smem_len;
65         m_phys_mem = fix.smem_start;
66         eDebug("%dk video mem", available/1024);
67         lfb=(unsigned char*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
68         if (!lfb)
69         {
70                 perror("mmap");
71                 goto nolfb;
72         }
73
74         showConsole(0);
75
76         enableManualBlit();
77         return;
78 nolfb:
79         lfb=0;
80         printf("framebuffer not available.\n");
81         return;
82 }
83
84 int fbClass::showConsole(int state)
85 {
86         int fd=open("/dev/vc/0", O_RDWR);
87         if(fd>=0)
88         {
89                 if(ioctl(fd, KDSETMODE, state?KD_TEXT:KD_GRAPHICS)<0)
90                 {
91                         eDebug("setting /dev/vc/0 status failed.");
92                 }
93                 close(fd);
94         }
95         return 0;
96 }
97
98 int fbClass::SetMode(unsigned int nxRes, unsigned int nyRes, unsigned int nbpp)
99 {
100         screeninfo.xres_virtual=screeninfo.xres=nxRes;
101         screeninfo.yres_virtual=(screeninfo.yres=nyRes)*2;
102         screeninfo.height=0;
103         screeninfo.width=0;
104         screeninfo.xoffset=screeninfo.yoffset=0;
105         screeninfo.bits_per_pixel=nbpp;
106
107         switch (nbpp) {
108         case 16:
109                 // ARGB 1555
110                 screeninfo.transp.offset = 15;
111                 screeninfo.transp.length = 1;
112                 screeninfo.red.offset = 10;
113                 screeninfo.red.length = 5;
114                 screeninfo.green.offset = 5;
115                 screeninfo.green.length = 5;
116                 screeninfo.blue.offset = 0;
117                 screeninfo.blue.length = 5;
118                 break;
119         case 32:
120                 // ARGB 8888
121                 screeninfo.transp.offset = 24;
122                 screeninfo.transp.length = 8;
123                 screeninfo.red.offset = 16;
124                 screeninfo.red.length = 8;
125                 screeninfo.green.offset = 8;
126                 screeninfo.green.length = 8;
127                 screeninfo.blue.offset = 0;
128                 screeninfo.blue.length = 8;
129                 break;
130         }
131
132         if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0)
133         {
134                 // try single buffering
135                 screeninfo.yres_virtual=screeninfo.yres=nyRes;
136                 
137                 if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0)
138                 {
139                         perror("FBIOPUT_VSCREENINFO");
140                         printf("fb failed\n");
141                         return -1;
142                 }
143                 eDebug(" - double buffering not available.");
144         } else
145                 eDebug(" - double buffering available!");
146         
147         m_number_of_pages = screeninfo.yres_virtual / nyRes;
148         
149         ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo);
150         
151         if ((screeninfo.xres!=nxRes) && (screeninfo.yres!=nyRes) && (screeninfo.bits_per_pixel!=nbpp))
152         {
153                 eDebug("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d",
154                         nxRes, nyRes, nbpp,
155                         screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
156         }
157         xRes=screeninfo.xres;
158         yRes=screeninfo.yres;
159         bpp=screeninfo.bits_per_pixel;
160         fb_fix_screeninfo fix;
161         if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
162         {
163                 perror("FBIOGET_FSCREENINFO");
164                 printf("fb failed\n");
165         }
166         stride=fix.line_length;
167         memset(lfb, 0, stride*yRes);
168         return 0;
169 }
170
171 int fbClass::setOffset(int off)
172 {
173         screeninfo.xoffset = 0;
174         screeninfo.yoffset = off;
175         return ioctl(fd, FBIOPAN_DISPLAY, &screeninfo);
176 }
177
178 int fbClass::waitVSync()
179 {
180         int c = 0;
181         return ioctl(fd, FBIO_WAITFORVSYNC, &c);
182 }
183
184 void fbClass::blit()
185 {
186         if (m_manual_blit == 1) {
187                 if (ioctl(fd, FBIO_BLIT) < 0)
188                         perror("FBIO_BLIT");
189         }
190 }
191
192 fbClass::~fbClass()
193 {
194         if (available)
195                 ioctl(fd, FBIOPUT_VSCREENINFO, &oldscreen);
196         if (lfb)
197                 munmap(lfb, available);
198         showConsole(1);
199         disableManualBlit();
200 }
201
202 int fbClass::PutCMAP()
203 {
204         return ioctl(fd, FBIOPUTCMAP, &cmap);
205 }
206
207 int fbClass::lock()
208 {
209         if (locked)
210                 return -1;
211         if (m_manual_blit == 1)
212         {
213                 locked = 2;
214                 disableManualBlit();
215         }
216         else
217                 locked = 1;
218         return fd;
219 }
220
221 void fbClass::unlock()
222 {
223         if (!locked)
224                 return;
225         if (locked == 2)  // re-enable manualBlit
226                 enableManualBlit();
227         locked=0;
228         SetMode(xRes, yRes, bpp);
229         PutCMAP();
230 }
231
232 void fbClass::enableManualBlit()
233 {
234         unsigned char tmp = 1;
235         if (ioctl(fd,FBIO_SET_MANUAL_BLIT, &tmp)<0)
236                 perror("FBIO_SET_MANUAL_BLIT");
237         else
238                 m_manual_blit = 1;
239 }
240
241 void fbClass::disableManualBlit()
242 {
243         unsigned char tmp = 0;
244         if (ioctl(fd,FBIO_SET_MANUAL_BLIT, &tmp)<0) 
245                 perror("FBIO_SET_MANUAL_BLIT");
246         else
247                 m_manual_blit = 0;
248 }
249