Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* all driver need this */ |
2 | #ifdef HAVE_XORG_CONFIG_H | |
3 | #include <xorg-config.h> | |
4 | #endif | |
5 | ||
6 | #include <string.h> | |
7 | ||
8 | #include "xf86.h" | |
9 | #include "xf86Modes.h" | |
10 | #include "xf86_OSproc.h" | |
11 | ||
12 | /* pci stuff */ | |
13 | #include "xf86Pci.h" | |
14 | ||
15 | #include "xf86cmap.h" | |
16 | ||
17 | #include "fbdevhw.h" | |
18 | #include "fbpriv.h" | |
19 | #include "globals.h" | |
20 | #include <X11/extensions/dpmsconst.h> | |
21 | ||
22 | #define PAGE_MASK (~(getpagesize() - 1)) | |
23 | ||
24 | static XF86ModuleVersionInfo fbdevHWVersRec = { | |
25 | "fbdevhw", | |
26 | MODULEVENDORSTRING, | |
27 | MODINFOSTRING1, | |
28 | MODINFOSTRING2, | |
29 | XORG_VERSION_CURRENT, | |
30 | 0, 0, 2, | |
31 | ABI_CLASS_VIDEODRV, | |
32 | ABI_VIDEODRV_VERSION, | |
33 | MOD_CLASS_NONE, | |
34 | {0, 0, 0, 0} | |
35 | }; | |
36 | ||
37 | _X_EXPORT XF86ModuleData fbdevhwModuleData = { | |
38 | &fbdevHWVersRec, | |
39 | NULL, | |
40 | NULL | |
41 | }; | |
42 | ||
43 | #include <fcntl.h> | |
44 | #include <errno.h> | |
45 | #include <sys/mman.h> | |
46 | #include <sys/ioctl.h> | |
47 | #include <stdio.h> | |
48 | #include <stdlib.h> | |
49 | #include <unistd.h> | |
50 | ||
51 | /* -------------------------------------------------------------------- */ | |
52 | /* our private data, and two functions to allocate/free this */ | |
53 | ||
54 | #define FBDEVHWPTRLVAL(p) (p)->privates[fbdevHWPrivateIndex].ptr | |
55 | #define FBDEVHWPTR(p) ((fbdevHWPtr)(FBDEVHWPTRLVAL(p))) | |
56 | ||
57 | static int fbdevHWPrivateIndex = -1; | |
58 | ||
59 | typedef struct { | |
60 | /* framebuffer device: filename (/dev/fb*), handle, more */ | |
61 | char *device; | |
62 | int fd; | |
63 | void *fbmem; | |
64 | unsigned int fbmem_len; | |
65 | unsigned int fboff; | |
66 | char *mmio; | |
67 | unsigned int mmio_len; | |
68 | ||
69 | /* current hardware state */ | |
70 | struct fb_fix_screeninfo fix; | |
71 | struct fb_var_screeninfo var; | |
72 | ||
73 | /* saved video mode */ | |
74 | struct fb_var_screeninfo saved_var; | |
75 | ||
76 | /* buildin video mode */ | |
77 | DisplayModeRec buildin; | |
78 | ||
79 | } fbdevHWRec, *fbdevHWPtr; | |
80 | ||
81 | Bool | |
82 | fbdevHWGetRec(ScrnInfoPtr pScrn) | |
83 | { | |
84 | fbdevHWPtr fPtr; | |
85 | ||
86 | if (fbdevHWPrivateIndex < 0) | |
87 | fbdevHWPrivateIndex = xf86AllocateScrnInfoPrivateIndex(); | |
88 | ||
89 | if (FBDEVHWPTR(pScrn) != NULL) | |
90 | return TRUE; | |
91 | ||
92 | fPtr = FBDEVHWPTRLVAL(pScrn) = xnfcalloc(sizeof(fbdevHWRec), 1); | |
93 | return TRUE; | |
94 | } | |
95 | ||
96 | void | |
97 | fbdevHWFreeRec(ScrnInfoPtr pScrn) | |
98 | { | |
99 | if (fbdevHWPrivateIndex < 0) | |
100 | return; | |
101 | free(FBDEVHWPTR(pScrn)); | |
102 | FBDEVHWPTRLVAL(pScrn) = NULL; | |
103 | } | |
104 | ||
105 | int | |
106 | fbdevHWGetFD(ScrnInfoPtr pScrn) | |
107 | { | |
108 | fbdevHWPtr fPtr; | |
109 | ||
110 | fbdevHWGetRec(pScrn); | |
111 | fPtr = FBDEVHWPTR(pScrn); | |
112 | ||
113 | return fPtr->fd; | |
114 | } | |
115 | ||
116 | /* -------------------------------------------------------------------- */ | |
117 | /* some helpers for printing debug informations */ | |
118 | ||
119 | #if DEBUG | |
120 | static void | |
121 | print_fbdev_mode(char *txt, struct fb_var_screeninfo *var) | |
122 | { | |
123 | ErrorF("fbdev %s mode:\t%d %d %d %d %d %d %d %d %d %d %d:%d:%d\n", | |
124 | txt, var->pixclock, | |
125 | var->xres, var->right_margin, var->hsync_len, var->left_margin, | |
126 | var->yres, var->lower_margin, var->vsync_len, var->upper_margin, | |
127 | var->bits_per_pixel, | |
128 | var->red.length, var->green.length, var->blue.length); | |
129 | } | |
130 | ||
131 | static void | |
132 | print_xfree_mode(char *txt, DisplayModePtr mode) | |
133 | { | |
134 | ErrorF("xfree %s mode:\t%d %d %d %d %d %d %d %d %d\n", | |
135 | txt, mode->Clock, | |
136 | mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal, | |
137 | mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal); | |
138 | } | |
139 | #endif | |
140 | ||
141 | /* -------------------------------------------------------------------- */ | |
142 | /* Convert timings between the XFree and the Frame Buffer Device */ | |
143 | ||
144 | static void | |
145 | xfree2fbdev_fblayout(ScrnInfoPtr pScrn, struct fb_var_screeninfo *var) | |
146 | { | |
147 | var->xres_virtual = pScrn->displayWidth ? pScrn->displayWidth : | |
148 | pScrn->virtualX; | |
149 | var->yres_virtual = pScrn->virtualY; | |
150 | var->bits_per_pixel = pScrn->bitsPerPixel; | |
151 | if (pScrn->defaultVisual == TrueColor || | |
152 | pScrn->defaultVisual == DirectColor) { | |
153 | var->red.length = pScrn->weight.red; | |
154 | var->green.length = pScrn->weight.green; | |
155 | var->blue.length = pScrn->weight.blue; | |
156 | } | |
157 | else { | |
158 | var->red.length = 8; | |
159 | var->green.length = 8; | |
160 | var->blue.length = 8; | |
161 | } | |
162 | } | |
163 | ||
164 | static void | |
165 | xfree2fbdev_timing(DisplayModePtr mode, struct fb_var_screeninfo *var) | |
166 | { | |
167 | var->xres = mode->HDisplay; | |
168 | var->yres = mode->VDisplay; | |
169 | if (var->xres_virtual < var->xres) | |
170 | var->xres_virtual = var->xres; | |
171 | if (var->yres_virtual < var->yres) | |
172 | var->yres_virtual = var->yres; | |
173 | var->xoffset = var->yoffset = 0; | |
174 | var->pixclock = mode->Clock ? 1000000000 / mode->Clock : 0; | |
175 | var->right_margin = mode->HSyncStart - mode->HDisplay; | |
176 | var->hsync_len = mode->HSyncEnd - mode->HSyncStart; | |
177 | var->left_margin = mode->HTotal - mode->HSyncEnd; | |
178 | var->lower_margin = mode->VSyncStart - mode->VDisplay; | |
179 | var->vsync_len = mode->VSyncEnd - mode->VSyncStart; | |
180 | var->upper_margin = mode->VTotal - mode->VSyncEnd; | |
181 | var->sync = 0; | |
182 | if (mode->Flags & V_PHSYNC) | |
183 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | |
184 | if (mode->Flags & V_PVSYNC) | |
185 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | |
186 | if (mode->Flags & V_PCSYNC) | |
187 | var->sync |= FB_SYNC_COMP_HIGH_ACT; | |
188 | if (mode->Flags & V_BCAST) | |
189 | var->sync |= FB_SYNC_BROADCAST; | |
190 | if (mode->Flags & V_INTERLACE) | |
191 | var->vmode = FB_VMODE_INTERLACED; | |
192 | else if (mode->Flags & V_DBLSCAN) | |
193 | var->vmode = FB_VMODE_DOUBLE; | |
194 | else | |
195 | var->vmode = FB_VMODE_NONINTERLACED; | |
196 | } | |
197 | ||
198 | static Bool | |
199 | fbdev_modes_equal(struct fb_var_screeninfo *set, struct fb_var_screeninfo *req) | |
200 | { | |
201 | return (set->xres_virtual >= req->xres_virtual && | |
202 | set->yres_virtual >= req->yres_virtual && | |
203 | set->bits_per_pixel == req->bits_per_pixel && | |
204 | set->red.length == req->red.length && | |
205 | set->green.length == req->green.length && | |
206 | set->blue.length == req->blue.length && | |
207 | set->xres == req->xres && set->yres == req->yres && | |
208 | set->right_margin == req->right_margin && | |
209 | set->hsync_len == req->hsync_len && | |
210 | set->left_margin == req->left_margin && | |
211 | set->lower_margin == req->lower_margin && | |
212 | set->vsync_len == req->vsync_len && | |
213 | set->upper_margin == req->upper_margin && | |
214 | set->sync == req->sync && set->vmode == req->vmode); | |
215 | } | |
216 | ||
217 | static void | |
218 | fbdev2xfree_timing(struct fb_var_screeninfo *var, DisplayModePtr mode) | |
219 | { | |
220 | mode->Clock = var->pixclock ? 1000000000 / var->pixclock : 0; | |
221 | mode->HDisplay = var->xres; | |
222 | mode->HSyncStart = mode->HDisplay + var->right_margin; | |
223 | mode->HSyncEnd = mode->HSyncStart + var->hsync_len; | |
224 | mode->HTotal = mode->HSyncEnd + var->left_margin; | |
225 | mode->VDisplay = var->yres; | |
226 | mode->VSyncStart = mode->VDisplay + var->lower_margin; | |
227 | mode->VSyncEnd = mode->VSyncStart + var->vsync_len; | |
228 | mode->VTotal = mode->VSyncEnd + var->upper_margin; | |
229 | mode->Flags = 0; | |
230 | mode->Flags |= var->sync & FB_SYNC_HOR_HIGH_ACT ? V_PHSYNC : V_NHSYNC; | |
231 | mode->Flags |= var->sync & FB_SYNC_VERT_HIGH_ACT ? V_PVSYNC : V_NVSYNC; | |
232 | mode->Flags |= var->sync & FB_SYNC_COMP_HIGH_ACT ? V_PCSYNC : V_NCSYNC; | |
233 | if (var->sync & FB_SYNC_BROADCAST) | |
234 | mode->Flags |= V_BCAST; | |
235 | if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) | |
236 | mode->Flags |= V_INTERLACE; | |
237 | else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) | |
238 | mode->Flags |= V_DBLSCAN; | |
239 | mode->SynthClock = mode->Clock; | |
240 | mode->CrtcHDisplay = mode->HDisplay; | |
241 | mode->CrtcHSyncStart = mode->HSyncStart; | |
242 | mode->CrtcHSyncEnd = mode->HSyncEnd; | |
243 | mode->CrtcHTotal = mode->HTotal; | |
244 | mode->CrtcVDisplay = mode->VDisplay; | |
245 | mode->CrtcVSyncStart = mode->VSyncStart; | |
246 | mode->CrtcVSyncEnd = mode->VSyncEnd; | |
247 | mode->CrtcVTotal = mode->VTotal; | |
248 | mode->CrtcHAdjusted = FALSE; | |
249 | mode->CrtcVAdjusted = FALSE; | |
250 | } | |
251 | ||
252 | /* -------------------------------------------------------------------- */ | |
253 | /* open correct framebuffer device */ | |
254 | ||
255 | /** | |
256 | * Try to find the framebuffer device for a given PCI device | |
257 | */ | |
258 | static int | |
259 | fbdev_open_pci(struct pci_device *pPci, char **namep) | |
260 | { | |
261 | struct fb_fix_screeninfo fix; | |
262 | char filename[256]; | |
263 | int fd, i; | |
264 | ||
265 | for (i = 0; i < 8; i++) { | |
266 | snprintf(filename, sizeof(filename), | |
267 | "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics/fb%d", | |
268 | pPci->domain, pPci->bus, pPci->dev, pPci->func, i); | |
269 | ||
270 | fd = open(filename, O_RDONLY, 0); | |
271 | if (fd < 0) { | |
272 | snprintf(filename, sizeof(filename), | |
273 | "/sys/bus/pci/devices/%04x:%02x:%02x.%d/graphics:fb%d", | |
274 | pPci->domain, pPci->bus, pPci->dev, pPci->func, i); | |
275 | fd = open(filename, O_RDONLY, 0); | |
276 | } | |
277 | if (fd >= 0) { | |
278 | close(fd); | |
279 | snprintf(filename, sizeof(filename), "/dev/fb%d", i); | |
280 | ||
281 | fd = open(filename, O_RDWR, 0); | |
282 | if (fd != -1) { | |
283 | if (ioctl(fd, FBIOGET_FSCREENINFO, (void *) &fix) != -1) { | |
284 | if (namep) { | |
285 | *namep = xnfalloc(16); | |
286 | strncpy(*namep, fix.id, 16); | |
287 | } | |
288 | ||
289 | return fd; | |
290 | } | |
291 | close(fd); | |
292 | } | |
293 | } | |
294 | } | |
295 | ||
296 | if (namep) | |
297 | *namep = NULL; | |
298 | ||
299 | xf86DrvMsg(-1, X_ERROR, "Unable to find a valid framebuffer device\n"); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | static int | |
304 | fbdev_open(int scrnIndex, char *dev, char **namep) | |
305 | { | |
306 | struct fb_fix_screeninfo fix; | |
307 | int fd; | |
308 | ||
309 | /* try argument (from XF86Config) first */ | |
310 | if (dev) { | |
311 | fd = open(dev, O_RDWR, 0); | |
312 | } | |
313 | else { | |
314 | /* second: environment variable */ | |
315 | dev = getenv("FRAMEBUFFER"); | |
316 | if ((NULL == dev) || ((fd = open(dev, O_RDWR, 0)) == -1)) { | |
317 | /* last try: default device */ | |
318 | dev = "/dev/fb0"; | |
319 | fd = open(dev, O_RDWR, 0); | |
320 | } | |
321 | } | |
322 | ||
323 | if (fd == -1) { | |
324 | xf86DrvMsg(scrnIndex, X_ERROR, "open %s: %s\n", dev, strerror(errno)); | |
325 | return -1; | |
326 | } | |
327 | ||
328 | if (namep) { | |
329 | if (-1 == ioctl(fd, FBIOGET_FSCREENINFO, (void *) (&fix))) { | |
330 | *namep = NULL; | |
331 | xf86DrvMsg(scrnIndex, X_ERROR, | |
332 | "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); | |
333 | return -1; | |
334 | } | |
335 | else { | |
336 | *namep = xnfalloc(16); | |
337 | strncpy(*namep, fix.id, 16); | |
338 | } | |
339 | } | |
340 | return fd; | |
341 | } | |
342 | ||
343 | /* -------------------------------------------------------------------- */ | |
344 | ||
345 | Bool | |
346 | fbdevHWProbe(struct pci_device *pPci, char *device, char **namep) | |
347 | { | |
348 | int fd; | |
349 | ||
350 | if (pPci) | |
351 | fd = fbdev_open_pci(pPci, namep); | |
352 | else | |
353 | fd = fbdev_open(-1, device, namep); | |
354 | ||
355 | if (-1 == fd) | |
356 | return FALSE; | |
357 | close(fd); | |
358 | return TRUE; | |
359 | } | |
360 | ||
361 | Bool | |
362 | fbdevHWInit(ScrnInfoPtr pScrn, struct pci_device *pPci, char *device) | |
363 | { | |
364 | fbdevHWPtr fPtr; | |
365 | ||
366 | fbdevHWGetRec(pScrn); | |
367 | fPtr = FBDEVHWPTR(pScrn); | |
368 | ||
369 | /* open device */ | |
370 | if (pPci) | |
371 | fPtr->fd = fbdev_open_pci(pPci, NULL); | |
372 | else | |
373 | fPtr->fd = fbdev_open(pScrn->scrnIndex, device, NULL); | |
374 | if (-1 == fPtr->fd) { | |
375 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
376 | "Failed to open framebuffer device, consult warnings" | |
377 | " and/or errors above for possible reasons\n" | |
378 | "\t(you may have to look at the server log to see" | |
379 | " warnings)\n"); | |
380 | return FALSE; | |
381 | } | |
382 | ||
383 | /* get current fb device settings */ | |
384 | if (-1 == ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) { | |
385 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
386 | "ioctl FBIOGET_FSCREENINFO: %s\n", strerror(errno)); | |
387 | return FALSE; | |
388 | } | |
389 | if (-1 == ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) { | |
390 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
391 | "ioctl FBIOGET_VSCREENINFO: %s\n", strerror(errno)); | |
392 | return FALSE; | |
393 | } | |
394 | ||
395 | /* we can use the current settings as "buildin mode" */ | |
396 | fbdev2xfree_timing(&fPtr->var, &fPtr->buildin); | |
397 | fPtr->buildin.name = "current"; | |
398 | fPtr->buildin.next = &fPtr->buildin; | |
399 | fPtr->buildin.prev = &fPtr->buildin; | |
400 | fPtr->buildin.type |= M_T_BUILTIN; | |
401 | ||
402 | return TRUE; | |
403 | } | |
404 | ||
405 | char * | |
406 | fbdevHWGetName(ScrnInfoPtr pScrn) | |
407 | { | |
408 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
409 | ||
410 | return fPtr->fix.id; | |
411 | } | |
412 | ||
413 | int | |
414 | fbdevHWGetDepth(ScrnInfoPtr pScrn, int *fbbpp) | |
415 | { | |
416 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
417 | ||
418 | if (fbbpp) | |
419 | *fbbpp = fPtr->var.bits_per_pixel; | |
420 | ||
421 | if (fPtr->fix.visual == FB_VISUAL_TRUECOLOR || | |
422 | fPtr->fix.visual == FB_VISUAL_DIRECTCOLOR) | |
423 | return fPtr->var.red.length + fPtr->var.green.length + | |
424 | fPtr->var.blue.length; | |
425 | else | |
426 | return fPtr->var.bits_per_pixel; | |
427 | } | |
428 | ||
429 | int | |
430 | fbdevHWGetLineLength(ScrnInfoPtr pScrn) | |
431 | { | |
432 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
433 | ||
434 | if (fPtr->fix.line_length) | |
435 | return fPtr->fix.line_length; | |
436 | else | |
437 | return fPtr->var.xres_virtual * fPtr->var.bits_per_pixel / 8; | |
438 | } | |
439 | ||
440 | int | |
441 | fbdevHWGetType(ScrnInfoPtr pScrn) | |
442 | { | |
443 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
444 | ||
445 | return fPtr->fix.type; | |
446 | } | |
447 | ||
448 | int | |
449 | fbdevHWGetVidmem(ScrnInfoPtr pScrn) | |
450 | { | |
451 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
452 | ||
453 | return fPtr->fix.smem_len; | |
454 | } | |
455 | ||
456 | static Bool | |
457 | fbdevHWSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool check) | |
458 | { | |
459 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
460 | struct fb_var_screeninfo req_var = fPtr->var, set_var; | |
461 | ||
462 | xfree2fbdev_fblayout(pScrn, &req_var); | |
463 | xfree2fbdev_timing(mode, &req_var); | |
464 | ||
465 | #if DEBUG | |
466 | print_xfree_mode("init", mode); | |
467 | print_fbdev_mode("init", &req_var); | |
468 | #endif | |
469 | ||
470 | set_var = req_var; | |
471 | ||
472 | if (check) | |
473 | set_var.activate = FB_ACTIVATE_TEST; | |
474 | ||
475 | if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&set_var))) { | |
476 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
477 | "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); | |
478 | return FALSE; | |
479 | } | |
480 | ||
481 | if (!fbdev_modes_equal(&set_var, &req_var)) { | |
482 | if (!check) | |
483 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
484 | "FBIOPUT_VSCREENINFO succeeded but modified " "mode\n"); | |
485 | #if DEBUG | |
486 | print_fbdev_mode("returned", &set_var); | |
487 | #endif | |
488 | return FALSE; | |
489 | } | |
490 | ||
491 | if (!check) | |
492 | fPtr->var = set_var; | |
493 | ||
494 | return TRUE; | |
495 | } | |
496 | ||
497 | void | |
498 | fbdevHWSetVideoModes(ScrnInfoPtr pScrn) | |
499 | { | |
500 | char **modename; | |
501 | DisplayModePtr mode, this, last = pScrn->modes; | |
502 | ||
503 | if (NULL == pScrn->display->modes) | |
504 | return; | |
505 | ||
506 | pScrn->virtualX = pScrn->display->virtualX; | |
507 | pScrn->virtualY = pScrn->display->virtualY; | |
508 | ||
509 | for (modename = pScrn->display->modes; *modename != NULL; modename++) { | |
510 | for (mode = pScrn->monitor->Modes; mode != NULL; mode = mode->next) { | |
511 | if (0 == strcmp(mode->name, *modename)) { | |
512 | if (fbdevHWSetMode(pScrn, mode, TRUE)) | |
513 | break; | |
514 | ||
515 | xf86DrvMsg(pScrn->scrnIndex, X_INFO, | |
516 | "\tmode \"%s\" test failed\n", *modename); | |
517 | } | |
518 | } | |
519 | ||
520 | if (NULL == mode) { | |
521 | xf86DrvMsg(pScrn->scrnIndex, X_INFO, | |
522 | "\tmode \"%s\" not found\n", *modename); | |
523 | continue; | |
524 | } | |
525 | ||
526 | xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\tmode \"%s\" ok\n", *modename); | |
527 | ||
528 | if (pScrn->virtualX < mode->HDisplay) | |
529 | pScrn->virtualX = mode->HDisplay; | |
530 | if (pScrn->virtualY < mode->VDisplay) | |
531 | pScrn->virtualY = mode->VDisplay; | |
532 | ||
533 | if (NULL == pScrn->modes) { | |
534 | this = pScrn->modes = xf86DuplicateMode(mode); | |
535 | this->next = this; | |
536 | this->prev = this; | |
537 | } | |
538 | else { | |
539 | this = xf86DuplicateMode(mode); | |
540 | this->next = pScrn->modes; | |
541 | this->prev = last; | |
542 | last->next = this; | |
543 | pScrn->modes->prev = this; | |
544 | } | |
545 | last = this; | |
546 | } | |
547 | } | |
548 | ||
549 | DisplayModePtr | |
550 | fbdevHWGetBuildinMode(ScrnInfoPtr pScrn) | |
551 | { | |
552 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
553 | ||
554 | return &fPtr->buildin; | |
555 | } | |
556 | ||
557 | void | |
558 | fbdevHWUseBuildinMode(ScrnInfoPtr pScrn) | |
559 | { | |
560 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
561 | ||
562 | pScrn->modes = &fPtr->buildin; | |
563 | pScrn->virtualX = pScrn->display->virtualX; | |
564 | pScrn->virtualY = pScrn->display->virtualY; | |
565 | if (pScrn->virtualX < fPtr->buildin.HDisplay) | |
566 | pScrn->virtualX = fPtr->buildin.HDisplay; | |
567 | if (pScrn->virtualY < fPtr->buildin.VDisplay) | |
568 | pScrn->virtualY = fPtr->buildin.VDisplay; | |
569 | } | |
570 | ||
571 | /* -------------------------------------------------------------------- */ | |
572 | ||
573 | static void | |
574 | calculateFbmem_len(fbdevHWPtr fPtr) | |
575 | { | |
576 | fPtr->fboff = (unsigned long) fPtr->fix.smem_start & ~PAGE_MASK; | |
577 | fPtr->fbmem_len = (fPtr->fboff + fPtr->fix.smem_len + ~PAGE_MASK) & | |
578 | PAGE_MASK; | |
579 | } | |
580 | ||
581 | void * | |
582 | fbdevHWMapVidmem(ScrnInfoPtr pScrn) | |
583 | { | |
584 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
585 | ||
586 | if (NULL == fPtr->fbmem) { | |
587 | calculateFbmem_len(fPtr); | |
588 | fPtr->fbmem = mmap(NULL, fPtr->fbmem_len, PROT_READ | PROT_WRITE, | |
589 | MAP_SHARED, fPtr->fd, 0); | |
590 | if (-1 == (long) fPtr->fbmem) { | |
591 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
592 | "mmap fbmem: %s\n", strerror(errno)); | |
593 | fPtr->fbmem = NULL; | |
594 | } | |
595 | else { | |
596 | /* Perhaps we'd better add fboff to fbmem and return 0 in | |
597 | fbdevHWLinearOffset()? Of course we then need to mask | |
598 | fPtr->fbmem with PAGE_MASK in fbdevHWUnmapVidmem() as | |
599 | well. [geert] */ | |
600 | } | |
601 | } | |
602 | pScrn->memPhysBase = | |
603 | (unsigned long) fPtr->fix.smem_start & (unsigned long) (PAGE_MASK); | |
604 | pScrn->fbOffset = | |
605 | (unsigned long) fPtr->fix.smem_start & (unsigned long) (~PAGE_MASK); | |
606 | return fPtr->fbmem; | |
607 | } | |
608 | ||
609 | int | |
610 | fbdevHWLinearOffset(ScrnInfoPtr pScrn) | |
611 | { | |
612 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
613 | ||
614 | return fPtr->fboff; | |
615 | } | |
616 | ||
617 | Bool | |
618 | fbdevHWUnmapVidmem(ScrnInfoPtr pScrn) | |
619 | { | |
620 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
621 | ||
622 | if (NULL != fPtr->fbmem) { | |
623 | if (-1 == munmap(fPtr->fbmem, fPtr->fbmem_len)) | |
624 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
625 | "munmap fbmem: %s\n", strerror(errno)); | |
626 | fPtr->fbmem = NULL; | |
627 | } | |
628 | return TRUE; | |
629 | } | |
630 | ||
631 | void * | |
632 | fbdevHWMapMMIO(ScrnInfoPtr pScrn) | |
633 | { | |
634 | unsigned int mmio_off; | |
635 | ||
636 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
637 | ||
638 | if (NULL == fPtr->mmio) { | |
639 | /* tell the kernel not to use accels to speed up console scrolling */ | |
640 | fPtr->var.accel_flags = 0; | |
641 | if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->var))) { | |
642 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
643 | "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); | |
644 | return FALSE; | |
645 | } | |
646 | mmio_off = (unsigned long) fPtr->fix.mmio_start & ~PAGE_MASK; | |
647 | fPtr->mmio_len = (mmio_off + fPtr->fix.mmio_len + ~PAGE_MASK) & | |
648 | PAGE_MASK; | |
649 | if (NULL == fPtr->fbmem) | |
650 | calculateFbmem_len(fPtr); | |
651 | fPtr->mmio = mmap(NULL, fPtr->mmio_len, PROT_READ | PROT_WRITE, | |
652 | MAP_SHARED, fPtr->fd, fPtr->fbmem_len); | |
653 | if (-1 == (long) fPtr->mmio) { | |
654 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
655 | "mmap mmio: %s\n", strerror(errno)); | |
656 | fPtr->mmio = NULL; | |
657 | } | |
658 | else | |
659 | fPtr->mmio += mmio_off; | |
660 | } | |
661 | return fPtr->mmio; | |
662 | } | |
663 | ||
664 | Bool | |
665 | fbdevHWUnmapMMIO(ScrnInfoPtr pScrn) | |
666 | { | |
667 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
668 | ||
669 | if (NULL != fPtr->mmio) { | |
670 | if (-1 == | |
671 | munmap((void *) ((unsigned long) fPtr->mmio & PAGE_MASK), | |
672 | fPtr->mmio_len)) | |
673 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "munmap mmio: %s\n", | |
674 | strerror(errno)); | |
675 | fPtr->mmio = NULL; | |
676 | /* FIXME: restore var.accel_flags [geert] */ | |
677 | } | |
678 | return TRUE; | |
679 | } | |
680 | ||
681 | /* -------------------------------------------------------------------- */ | |
682 | ||
683 | Bool | |
684 | fbdevHWModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) | |
685 | { | |
686 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
687 | ||
688 | pScrn->vtSema = TRUE; | |
689 | ||
690 | /* set */ | |
691 | if (!fbdevHWSetMode(pScrn, mode, FALSE)) | |
692 | return FALSE; | |
693 | ||
694 | /* read back */ | |
695 | if (0 != ioctl(fPtr->fd, FBIOGET_FSCREENINFO, (void *) (&fPtr->fix))) { | |
696 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
697 | "FBIOGET_FSCREENINFO: %s\n", strerror(errno)); | |
698 | return FALSE; | |
699 | } | |
700 | if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->var))) { | |
701 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
702 | "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); | |
703 | return FALSE; | |
704 | } | |
705 | ||
706 | if (pScrn->defaultVisual == TrueColor || | |
707 | pScrn->defaultVisual == DirectColor) { | |
708 | /* XXX: This is a hack, but it should be a NOP for all the setups that | |
709 | * worked before and actually seems to fix some others... | |
710 | */ | |
711 | pScrn->offset.red = fPtr->var.red.offset; | |
712 | pScrn->offset.green = fPtr->var.green.offset; | |
713 | pScrn->offset.blue = fPtr->var.blue.offset; | |
714 | pScrn->mask.red = | |
715 | ((1 << fPtr->var.red.length) - 1) << fPtr->var.red.offset; | |
716 | pScrn->mask.green = | |
717 | ((1 << fPtr->var.green.length) - 1) << fPtr->var.green.offset; | |
718 | pScrn->mask.blue = | |
719 | ((1 << fPtr->var.blue.length) - 1) << fPtr->var.blue.offset; | |
720 | } | |
721 | ||
722 | return TRUE; | |
723 | } | |
724 | ||
725 | /* -------------------------------------------------------------------- */ | |
726 | /* video mode save/restore */ | |
727 | void | |
728 | fbdevHWSave(ScrnInfoPtr pScrn) | |
729 | { | |
730 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
731 | ||
732 | if (0 != ioctl(fPtr->fd, FBIOGET_VSCREENINFO, (void *) (&fPtr->saved_var))) | |
733 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
734 | "FBIOGET_VSCREENINFO: %s\n", strerror(errno)); | |
735 | } | |
736 | ||
737 | void | |
738 | fbdevHWRestore(ScrnInfoPtr pScrn) | |
739 | { | |
740 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
741 | ||
742 | if (0 != ioctl(fPtr->fd, FBIOPUT_VSCREENINFO, (void *) (&fPtr->saved_var))) | |
743 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
744 | "FBIOPUT_VSCREENINFO: %s\n", strerror(errno)); | |
745 | } | |
746 | ||
747 | /* -------------------------------------------------------------------- */ | |
748 | /* callback for xf86HandleColormaps */ | |
749 | ||
750 | void | |
751 | fbdevHWLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, | |
752 | LOCO * colors, VisualPtr pVisual) | |
753 | { | |
754 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
755 | struct fb_cmap cmap; | |
756 | unsigned short red, green, blue; | |
757 | int i; | |
758 | ||
759 | cmap.len = 1; | |
760 | cmap.red = &red; | |
761 | cmap.green = &green; | |
762 | cmap.blue = &blue; | |
763 | cmap.transp = NULL; | |
764 | for (i = 0; i < numColors; i++) { | |
765 | cmap.start = indices[i]; | |
766 | red = (colors[indices[i]].red << 8) | colors[indices[i]].red; | |
767 | green = (colors[indices[i]].green << 8) | colors[indices[i]].green; | |
768 | blue = (colors[indices[i]].blue << 8) | colors[indices[i]].blue; | |
769 | if (-1 == ioctl(fPtr->fd, FBIOPUTCMAP, (void *) &cmap)) | |
770 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
771 | "FBIOPUTCMAP: %s\n", strerror(errno)); | |
772 | } | |
773 | } | |
774 | ||
775 | /* -------------------------------------------------------------------- */ | |
776 | /* these can be hooked directly into ScrnInfoRec */ | |
777 | ||
778 | ModeStatus | |
779 | fbdevHWValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode, Bool verbose, int flags) | |
780 | { | |
781 | if (!fbdevHWSetMode(pScrn, mode, TRUE)) | |
782 | return MODE_BAD; | |
783 | ||
784 | return MODE_OK; | |
785 | } | |
786 | ||
787 | Bool | |
788 | fbdevHWSwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode) | |
789 | { | |
790 | if (!fbdevHWSetMode(pScrn, mode, FALSE)) | |
791 | return FALSE; | |
792 | ||
793 | return TRUE; | |
794 | } | |
795 | ||
796 | void | |
797 | fbdevHWAdjustFrame(ScrnInfoPtr pScrn, int x, int y) | |
798 | { | |
799 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
800 | ||
801 | if (x < 0 || x + fPtr->var.xres > fPtr->var.xres_virtual || | |
802 | y < 0 || y + fPtr->var.yres > fPtr->var.yres_virtual) | |
803 | return; | |
804 | ||
805 | fPtr->var.xoffset = x; | |
806 | fPtr->var.yoffset = y; | |
807 | if (-1 == ioctl(fPtr->fd, FBIOPAN_DISPLAY, (void *) &fPtr->var)) | |
808 | xf86DrvMsgVerb(pScrn->scrnIndex, X_WARNING, 5, | |
809 | "FBIOPAN_DISPLAY: %s\n", strerror(errno)); | |
810 | } | |
811 | ||
812 | Bool | |
813 | fbdevHWEnterVT(ScrnInfoPtr pScrn) | |
814 | { | |
815 | if (!fbdevHWModeInit(pScrn, pScrn->currentMode)) | |
816 | return FALSE; | |
817 | fbdevHWAdjustFrame(pScrn, pScrn->frameX0, pScrn->frameY0); | |
818 | return TRUE; | |
819 | } | |
820 | ||
821 | void | |
822 | fbdevHWLeaveVT(ScrnInfoPtr pScrn) | |
823 | { | |
824 | fbdevHWRestore(pScrn); | |
825 | } | |
826 | ||
827 | void | |
828 | fbdevHWDPMSSet(ScrnInfoPtr pScrn, int mode, int flags) | |
829 | { | |
830 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
831 | unsigned long fbmode; | |
832 | ||
833 | if (!pScrn->vtSema) | |
834 | return; | |
835 | ||
836 | switch (mode) { | |
837 | case DPMSModeOn: | |
838 | fbmode = 0; | |
839 | break; | |
840 | case DPMSModeStandby: | |
841 | fbmode = 2; | |
842 | break; | |
843 | case DPMSModeSuspend: | |
844 | fbmode = 3; | |
845 | break; | |
846 | case DPMSModeOff: | |
847 | fbmode = 4; | |
848 | break; | |
849 | default: | |
850 | return; | |
851 | } | |
852 | ||
853 | if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) fbmode)) | |
854 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
855 | "FBIOBLANK: %s\n", strerror(errno)); | |
856 | } | |
857 | ||
858 | Bool | |
859 | fbdevHWSaveScreen(ScreenPtr pScreen, int mode) | |
860 | { | |
861 | ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); | |
862 | fbdevHWPtr fPtr = FBDEVHWPTR(pScrn); | |
863 | unsigned long unblank; | |
864 | ||
865 | if (!pScrn->vtSema) | |
866 | return TRUE; | |
867 | ||
868 | unblank = xf86IsUnblank(mode); | |
869 | ||
870 | if (-1 == ioctl(fPtr->fd, FBIOBLANK, (void *) (1 - unblank))) { | |
871 | xf86DrvMsg(pScrn->scrnIndex, X_ERROR, | |
872 | "FBIOBLANK: %s\n", strerror(errno)); | |
873 | return FALSE; | |
874 | } | |
875 | ||
876 | return TRUE; | |
877 | } | |
878 | ||
879 | xf86SwitchModeProc * | |
880 | fbdevHWSwitchModeWeak(void) | |
881 | { | |
882 | return fbdevHWSwitchMode; | |
883 | } | |
884 | ||
885 | xf86AdjustFrameProc * | |
886 | fbdevHWAdjustFrameWeak(void) | |
887 | { | |
888 | return fbdevHWAdjustFrame; | |
889 | } | |
890 | ||
891 | xf86EnterVTProc * | |
892 | fbdevHWEnterVTWeak(void) | |
893 | { | |
894 | return fbdevHWEnterVT; | |
895 | } | |
896 | ||
897 | xf86LeaveVTProc * | |
898 | fbdevHWLeaveVTWeak(void) | |
899 | { | |
900 | return fbdevHWLeaveVT; | |
901 | } | |
902 | ||
903 | xf86ValidModeProc * | |
904 | fbdevHWValidModeWeak(void) | |
905 | { | |
906 | return fbdevHWValidMode; | |
907 | } | |
908 | ||
909 | xf86DPMSSetProc * | |
910 | fbdevHWDPMSSetWeak(void) | |
911 | { | |
912 | return fbdevHWDPMSSet; | |
913 | } | |
914 | ||
915 | xf86LoadPaletteProc * | |
916 | fbdevHWLoadPaletteWeak(void) | |
917 | { | |
918 | return fbdevHWLoadPalette; | |
919 | } | |
920 | ||
921 | SaveScreenProcPtr | |
922 | fbdevHWSaveScreenWeak(void) | |
923 | { | |
924 | return fbdevHWSaveScreen; | |
925 | } |