remap lfb on resolution change
[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         lfb=0;
31         fb_fix_screeninfo fix;
32         m_manual_blit=-1;
33         instance=this;
34         locked=0;
35         cmap.start=0;
36         cmap.len=256;
37         cmap.red=red;
38         cmap.green=green;
39         cmap.blue=blue;
40         cmap.transp=trans;
41
42         fd=open(fb, O_RDWR);
43         if (fd<0)
44                 perror(fb);
45         else if (ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo)<0)
46                 perror("FBIOGET_VSCREENINFO");
47         else if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
48                 perror("FBIOGET_FSCREENINFO");
49         else
50         {
51                 memcpy(&oldscreen, &screeninfo, sizeof(screeninfo));
52                 available=fix.smem_len;
53                 lfb=(unsigned char*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
54                 if (!lfb)
55                         perror("mmap");
56                 else
57                 {
58                         showConsole(0);
59                         enableManualBlit();
60                         stride=fix.line_length;
61                 }
62         }
63         return;
64 }
65
66 int fbClass::showConsole(int state)
67 {
68         int fd=open("/dev/vc/0", O_RDWR);
69         if(fd>=0)
70         {
71                 if(ioctl(fd, KDSETMODE, state?KD_TEXT:KD_GRAPHICS)<0)
72                 {
73                         eDebug("setting /dev/vc/0 status failed.");
74                 }
75                 close(fd);
76         }
77         return 0;
78 }
79
80 int fbClass::SetMode(unsigned int nxRes, unsigned int nyRes, unsigned int nbpp)
81 {
82         screeninfo.xres_virtual=screeninfo.xres=nxRes;
83         screeninfo.yres_virtual=(screeninfo.yres=nyRes)*2;
84         screeninfo.height=0;
85         screeninfo.width=0;
86         screeninfo.xoffset=screeninfo.yoffset=0;
87         screeninfo.bits_per_pixel=nbpp;
88
89         if (lfb) {
90                 munmap(lfb, available);
91                 lfb = 0;
92         }
93
94         if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0)
95         {
96                 // try single buffering
97                 screeninfo.yres_virtual=screeninfo.yres=nyRes;
98                 
99                 if (ioctl(fd, FBIOPUT_VSCREENINFO, &screeninfo)<0)
100                 {
101                         perror("FBIOPUT_VSCREENINFO");
102                         printf("fb failed\n");
103                         return -1;
104                 }
105                 eDebug(" - double buffering not available.");
106         } else
107                 eDebug(" - double buffering available!");
108         
109         m_number_of_pages = screeninfo.yres_virtual / nyRes;
110         
111         ioctl(fd, FBIOGET_VSCREENINFO, &screeninfo);
112         
113         if ((screeninfo.xres!=nxRes) && (screeninfo.yres!=nyRes) && (screeninfo.bits_per_pixel!=nbpp))
114         {
115                 eDebug("SetMode failed: wanted: %dx%dx%d, got %dx%dx%d",
116                         nxRes, nyRes, nbpp,
117                         screeninfo.xres, screeninfo.yres, screeninfo.bits_per_pixel);
118         }
119         xRes=screeninfo.xres;
120         yRes=screeninfo.yres;
121         bpp=screeninfo.bits_per_pixel;
122
123         fb_fix_screeninfo fix;
124         if (ioctl(fd, FBIOGET_FSCREENINFO, &fix)<0)
125         {
126                 perror("FBIOGET_FSCREENINFO");
127                 printf("fb failed\n");
128                 goto nolfb;
129         }
130
131         available=fix.smem_len;
132         eDebug("%dk video mem", available/1024);
133         lfb=(unsigned char*)mmap(0, available, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
134         if (!lfb)
135         {
136                 perror("mmap");
137                 goto nolfb;
138         }
139
140         stride=fix.line_length;
141
142         return 0;
143 nolfb:
144         lfb=0;
145         eFatal("framebuffer no more ready after SetMode(%d, %d, %d)", nxRes, nyRes, nbpp);
146         return -1;
147 }
148
149 int fbClass::setOffset(int off)
150 {
151         screeninfo.xoffset = 0;
152         screeninfo.yoffset = off;
153         return ioctl(fd, FBIOPAN_DISPLAY, &screeninfo);
154 }
155
156 int fbClass::waitVSync()
157 {
158         int c = 0;
159         return ioctl(fd, FBIO_WAITFORVSYNC, &c);
160 }
161
162 void fbClass::blit()
163 {
164         if (m_manual_blit == 1) {
165                 if (ioctl(fd, FBIO_BLIT) < 0)
166                         perror("FBIO_BLIT");
167         }
168 }
169
170 fbClass::~fbClass()
171 {
172         if (available)
173                 ioctl(fd, FBIOPUT_VSCREENINFO, &oldscreen);
174         if (lfb)
175                 munmap(lfb, available);
176         showConsole(1);
177         disableManualBlit();
178 }
179
180 int fbClass::PutCMAP()
181 {
182         return ioctl(fd, FBIOPUTCMAP, &cmap);
183 }
184
185 int fbClass::lock()
186 {
187         if (locked)
188                 return -1;
189         if (m_manual_blit == 1)
190         {
191                 locked = 2;
192                 disableManualBlit();
193         }
194         else
195                 locked = 1;
196         return fd;
197 }
198
199 void fbClass::unlock()
200 {
201         if (!locked)
202                 return;
203         if (locked == 2)  // re-enable manualBlit
204                 enableManualBlit();
205         locked=0;
206         SetMode(xRes, yRes, bpp);
207         PutCMAP();
208 }
209
210 void fbClass::enableManualBlit()
211 {
212         unsigned char tmp = 1;
213         if (ioctl(fd,FBIO_SET_MANUAL_BLIT, &tmp)<0)
214                 perror("FBIO_SET_MANUAL_BLIT");
215         else
216                 m_manual_blit = 1;
217 }
218
219 void fbClass::disableManualBlit()
220 {
221         unsigned char tmp = 0;
222         if (ioctl(fd,FBIO_SET_MANUAL_BLIT, &tmp)<0) 
223                 perror("FBIO_SET_MANUAL_BLIT");
224         else
225                 m_manual_blit = 0;
226 }
227