1 /*
2 * Set the framebuffer parameters for bttv.
3 * tries to ask the X-Server if $DISPLAY is set,
4 * otherwise it checks /dev/fb0
5 *
6 * (c) 1998-2001 Gerd Knorr <kraxel@bytesex.org>
7 *
8 * Security checks by okir@caldera.de
9 */
10 #include "config.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <strings.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <time.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/stat.h>
24 #include <linux/vt.h>
25 #include <linux/fb.h>
26 #ifdef HAVE_GETOPT_H
27 # include <getopt.h>
28 #endif
29
30 #ifndef X_DISPLAY_MISSING
31 # include <X11/Xlib.h>
32 # include <X11/Xutil.h>
33 # ifdef HAVE_LIBXXF86DGA
34 # include <X11/extensions/xf86dga.h>
35 # endif
36 #endif
37
38 #include "videodev.h"
39 #include "videodev2.h"
40
41 struct DISPLAYINFO {
42 int width; /* visible display width (pixels) */
43 int height; /* visible display height (pixels) */
44 int depth; /* color depth */
45 int bpp; /* bit per pixel */
46 int bpl; /* bytes per scanline */
47 unsigned char *base;
48 };
49
50 int verbose = 1;
51 int yuv = 0;
52 int v4l1 = 1;
53 int v4l2 = 1;
54 int user_bpp = 0;
55 int user_shift = 0;
56 void *user_base = NULL;
57 char *display = NULL;
58 char *fbdev = NULL;
59 char *videodev = "/dev/video0";
60
61 /* ---------------------------------------------------------------- */
62 /* this is required for MkLinux */
63
64 #ifdef __powerpc__
65 struct vc_mode {
66 int height;
67 int width;
68 int depth;
69 int pitch;
70 int mode;
71 char name[32];
72 unsigned long fb_address;
73 unsigned long cmap_adr_address;
74 unsigned long cmap_data_address;
75 unsigned long disp_reg_address;
76 };
77
78 #define VC_GETMODE 0x7667
79 #define VC_SETMODE 0x7668
80 #define VC_INQMODE 0x7669
81
82 #define VC_SETCMAP 0x766a
83 #define VC_GETCMAP 0x766b
84
85 static int
86 is_mklinux(void)
87 {
88 int fd;
89 if(-1 == (fd = open("/proc/osfmach3", O_RDONLY)))
90 return 0;
91 close(fd);
92 return 1;
93 }
94
95 static void
96 displayinfo_mklinux(struct DISPLAYINFO *d)
97 {
98 struct vc_mode mode;
99 int fd;
100
101 if (verbose)
102 fprintf(stderr,"v4l-conf: using mklinux console driver\n");
103
104 if (-1 == (fd = open("/dev/console",O_RDWR|O_NDELAY))) {
105 fprintf(stderr,"open console: %s\n",strerror(errno));
106 exit(1);
107 }
108 if (-1 == ioctl(fd, VC_GETMODE, (unsigned long)&mode)) {
109 perror("ioctl VC_GETMODE");
110 exit(1);
111 }
112 close(fd);
113 d->width = mode.width;
114 d->height = mode.height;
115 d->bpp = mode.depth;
116 d->bpl = mode.pitch;
117 d->base = (void*)mode.fb_address;
118 }
119 #endif
120
121 /* ---------------------------------------------------------------- */
122
123 #ifndef major
124 # define major(dev) (((dev) >> 8) & 0xff)
125 #endif
126
127 static int
128 dev_open(const char *device, int major)
129 {
130 struct stat stb;
131 int fd;
132
133 if (strncmp(device, "/dev/", 5)) {
134 fprintf(stderr, "error: %s is not a /dev file\n", device);
135 exit(1);
136 }
137
138 /* open & check v4l device */
139 if (-1 == (fd = open(device,O_RDWR))) {
140 fprintf(stderr, "can't open %s: %s\n", device, strerror(errno));
141 exit(1);
142 }
143
144 if (-1 == fstat(fd,&stb)) {
145 fprintf(stderr, "fstat(%s): %s\n", device, strerror(errno));
146 exit(1);
147 }
148 if (!S_ISCHR(stb.st_mode) || (major(stb.st_rdev) != major)) {
149 fprintf(stderr, "%s: wrong device\n", device);
150 exit(1);
151 }
152 return fd;
153 }
154
155 static void real_user(void)
156 {
157 if (-1 == seteuid(getuid())) {
158 perror("seteuid(user)");
159 exit(1);
160 }
161 }
162
163 static void root_user(void)
164 {
165 if (-1 == seteuid(0)) {
166 perror("seteuid(root)");
167 exit(1);
168 }
169 }
170
171 /* ---------------------------------------------------------------- */
172 /* get mode info */
173
174 #ifndef X_DISPLAY_MISSING
175 static void
176 displayinfo_x11(Display *dpy, struct DISPLAYINFO *d)
177 {
178 Window root;
179 XVisualInfo *info, template;
180 XPixmapFormatValues *pf;
181 XWindowAttributes wts;
182 int found,v,i,n;
183
184 if (verbose)
185 fprintf(stderr,"v4l-conf: using X11 display %s\n",display);
186
187 /* take size from root window */
188 root = DefaultRootWindow(dpy);
189 XGetWindowAttributes(dpy, root, &wts);
190 d->width = wts.width;
191 d->height = wts.height;
192
193 /* look for a usable visual */
194 template.screen = XDefaultScreen(dpy);
195 info = XGetVisualInfo(dpy, VisualScreenMask,&template,&found);
196 v = -1;
197 for (i = 0; v == -1 && i < found; i++)
198 if (info[i].class == TrueColor && info[i].depth >= 15)
199 v = i;
200 for (i = 0; v == -1 && i < found; i++)
201 if (info[i].class == StaticGray && info[i].depth == 8)
202 v = i;
203 if (-1 == v) {
204 fprintf(stderr,"x11: no approximate visual available\n");
205 exit(1);
206 }
207
208 /* get depth + bpp (heuristic) */
209 pf = XListPixmapFormats(dpy,&n);
210 for (i = 0; i < n; i++) {
211 if (pf[i].depth == info[v].depth) {
212 d->depth = pf[i].depth;
213 d->bpp = pf[i].bits_per_pixel;
214 d->bpl = d->bpp * d->width / 8;
215 break;
216 }
217 }
218 if (0 == d->bpp) {
219 fprintf(stderr,"x11: can't detect framebuffer depth\n");
220 exit(1);
221 }
222 }
223
224 static void
225 displayinfo_dga(Display *dpy, struct DISPLAYINFO *d)
226 {
227 #ifdef HAVE_LIBXXF86DGA
228 int width,bar,foo,major,minor,flags=0;
229 void *base = NULL;
230
231 if (!XF86DGAQueryExtension(dpy,&foo,&bar)) {
232 fprintf(stderr,"WARNING: Your X-Server has no DGA support.\n");
233 return;
234 }
235 XF86DGAQueryVersion(dpy,&major,&minor);
236 if (verbose)
237 fprintf(stderr,"dga: version %d.%d\n",major,minor);
238 XF86DGAQueryDirectVideo(dpy,XDefaultScreen(dpy),&flags);
239 if (!(flags & XF86DGADirectPresent)) {
240 fprintf(stderr,"WARNING: No DGA support available for this display.\n");
241 return;
242 }
243 XF86DGAGetVideoLL(dpy,XDefaultScreen(dpy),(void*)&base,&width,&foo,&bar);
244 d->bpl = width * d->bpp/8;
245 d->base = base;
246 #else
247 fprintf(stderr,"WARNING: v4l-conf is compiled without DGA support.\n");
248 #endif
249 }
250 #endif
251
252 static void
253 displayinfo_fbdev(struct DISPLAYINFO *d)
254 {
255 struct fb_fix_screeninfo fix;
256 struct fb_var_screeninfo var;
257 struct fb_con2fbmap c2m;
258 struct vt_stat vstat;
259 int fd;
260
261 if (NULL == fbdev) {
262 if (-1 == (fd = open("/dev/tty",O_RDWR,0))) {
263 fprintf(stderr,"open /dev/tty: %s\n",strerror(errno));
264 exit(1);
265 }
266 if (-1 == ioctl(fd, VT_GETSTATE, &vstat)) {
267 perror("ioctl VT_GETSTATE");
268 exit(1);
269 }
270 close(fd);
271 c2m.console = vstat.v_active;
272 if (-1 == (fd = open("/dev/fb0",O_RDWR,0))) {
273 fprintf(stderr,"open /dev/fb0: %s\n",strerror(errno));
274 exit(1);
275 }
276 if (-1 == ioctl(fd, FBIOGET_CON2FBMAP, &c2m)) {
277 perror("ioctl FBIOGET_CON2FBMAP");
278 c2m.framebuffer = 0;
279 }
280 close(fd);
281 fprintf(stderr,"map: vt%02d => fb%d\n",c2m.console,c2m.framebuffer);
282 sprintf(fbdev=malloc(16),"/dev/fb%d",c2m.framebuffer);
283 }
284 if (verbose)
285 fprintf(stderr,"v4l-conf: using framebuffer device %s\n",fbdev);
286
287 /* Open frame buffer device, with security checks */
288 fd = dev_open(fbdev, 29 /* VIDEO_MAJOR */);
289 if (-1 == ioctl(fd,FBIOGET_FSCREENINFO,&fix)) {
290 perror("ioctl FBIOGET_FSCREENINFO");
291 exit(1);
292 }
293 if (-1 == ioctl(fd,FBIOGET_VSCREENINFO,&var)) {
294 perror("ioctl FBIOGET_VSCREENINFO");
295 exit(1);
296 }
297 if (fix.type != FB_TYPE_PACKED_PIXELS) {
298 fprintf(stderr,"can handle only packed pixel frame buffers\n");
299 exit(1);
300 }
301 close(fd);
302
303 d->width = var.xres_virtual;
304 d->height = var.yres_virtual;
305 d->bpp = var.bits_per_pixel;
306 d->bpl = fix.line_length;
307 d->base = (unsigned char*)fix.smem_start;
308
309 d->depth = d->bpp;
310 if (var.green.length == 5)
311 d->depth = 15;
312 }
313
314 /* ---------------------------------------------------------------- */
315 /* set mode info */
316
317 static int
318 displayinfo_v4l2(int fd, struct DISPLAYINFO *d)
319 {
320 struct v4l2_capability cap;
321 struct v4l2_framebuffer fb;
322
323 if (0 == v4l2) {
324 if (verbose)
325 fprintf(stderr,"skipping v4l2 (disabled on the cmd line)\n");
326 return -1;
327 }
328
329 if (-1 == ioctl(fd,VIDIOC_QUERYCAP,&cap)) {
330 if (verbose)
331 fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_QUERYCAP: %s\n",
332 videodev,strerror(errno));
333 return -1;
334 }
335 if (!(cap.capabilities & V4L2_CAP_VIDEO_OVERLAY)) {
336 fprintf(stderr,"%s [v4l2]: no overlay support\n",videodev);
337 exit(1);
338 }
339
340 /* read-modify-write v4l screen parameters */
341 if (-1 == ioctl(fd,VIDIOC_G_FBUF,&fb)) {
342 fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_G_FBUF: %s\n",
343 videodev,strerror(errno));
344 exit(1);
345 }
346
347 /* set values */
348 fb.fmt.width = d->width;
349 fb.fmt.height = d->height;
350 switch (d->bpp) {
351 case 8: fb.fmt.pixelformat = V4L2_PIX_FMT_HI240; break;
352 #if BYTE_ORDER == BIG_ENDIAN
353 case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555X; break;
354 case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565X; break;
355 case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB24; break;
356 case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB32; break;
357 #else
358 case 15: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB555; break;
359 case 16: fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565; break;
360 case 24: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR24; break;
361 case 32: fb.fmt.pixelformat = V4L2_PIX_FMT_BGR32; break;
362 #endif
363 }
364 if (yuv)
365 fb.fmt.pixelformat = V4L2_PIX_FMT_YUYV;
366 fb.fmt.bytesperline = d->bpl;
367 fb.fmt.sizeimage = fb.fmt.height * fb.fmt.bytesperline;
368 if (NULL != d->base)
369 fb.base = d->base;
370 if (NULL == fb.base)
371 fprintf(stderr,
372 "WARNING: couldn't find framebuffer base address, try manual\n"
373 " configuration (\"v4l-conf -a <addr>\")\n");
374
375 if (-1 == ioctl(fd,VIDIOC_S_FBUF,&fb)) {
376 fprintf(stderr,"%s [v4l2]: ioctl VIDIOC_S_FBUF: %s\n",
377 videodev,strerror(errno));
378 if (EPERM == errno && 0 != geteuid())
379 fprintf(stderr,
380 "v4l-conf: You should install me suid root, I need\n"
381 " root priviliges for the VIDIOC_S_FBUF ioctl.\n");
382 exit(1);
383 }
384 if (verbose)
385 fprintf(stderr,"%s [v4l2]: configuration done\n",videodev);
386 return 0;
387 }
388
389 static int
390 displayinfo_v4l(int fd, struct DISPLAYINFO *d)
391 {
392 struct video_capability capability;
393 struct video_buffer fbuf;
394
395 if (0 == v4l1) {
396 if (verbose)
397 fprintf(stderr,"skipping v4l (disabled on the cmd line)\n");
398 return -1;
399 }
400
401 if (-1 == ioctl(fd,VIDIOCGCAP,&capability)) {
402 fprintf(stderr,"%s [v4l]: ioctl VIDIOCGCAP: %s\n",
403 videodev,strerror(errno));
404 return -1;
405 }
406 if (!(capability.type & VID_TYPE_OVERLAY)) {
407 fprintf(stderr,"%s [v4l]: no overlay support\n",videodev);
408 exit(1);
409 }
410
411 /* read-modify-write v4l screen parameters */
412 if (-1 == ioctl(fd,VIDIOCGFBUF,&fbuf)) {
413 fprintf(stderr,"%s [v4l]: ioctl VIDIOCGFBUF: %s\n",
414 videodev,strerror(errno));
415 exit(1);
416 }
417
418 /* set values */
419 fbuf.width = d->width;
420 fbuf.height = d->height;
421 fbuf.depth = d->bpp;
422 fbuf.bytesperline = d->bpl;
423 if (NULL != d->base)
424 fbuf.base = d->base;
425 if (NULL == fbuf.base)
426 fprintf(stderr,
427 "WARNING: couldn't find framebuffer base address, try manual\n"
428 " configuration (\"v4l-conf -a <addr>\")\n");
429
430 /* XXX bttv confuses color depth and bits/pixel */
431 if (d->depth == 15)
432 fbuf.depth = 15;
433
434 if (-1 == ioctl(fd,VIDIOCSFBUF,&fbuf)) {
435 fprintf(stderr,"%s [v4l]: ioctl VIDIOCSFBUF: %s\n",
436 videodev,strerror(errno));
437 if (EPERM == errno && 0 != geteuid())
438 fprintf(stderr,
439 "v4l-conf: You should install me suid root, I need\n"
440 " root priviliges for the VIDIOCSFBUF ioctl.\n");
441 exit(1);
442 }
443 if (verbose)
444 fprintf(stderr,"%s [v4l]: configuration done\n",videodev);
445 return 0;
446 }
447
448 /* ---------------------------------------------------------------- */
449
450 int
451 main(int argc, char *argv[])
452 {
453 struct DISPLAYINFO d;
454 int fd,c,i,n;
455 char *h;
456 #ifndef X_DISPLAY_MISSING
457 Display *dpy;
458 #endif
459
460 /* we don't need root proviliges for now ... */
461 real_user();
462
463 /* Make sure fd's 0 1 2 are open, otherwise
464 * we might end up sending perror() messages to
465 * the `device' file */
466 for (i = 0; i < 3; i++) {
467 if (-1 == fcntl(i, F_GETFL, &n))
468 exit(1);
469 }
470
471 /* take defaults from environment */
472 if (NULL != (h = getenv("DISPLAY")))
473 display = h;
474 if (NULL != (h = getenv("FRAMEBUFFER")))
475 fbdev = h;
476
477 /* parse options */
478 for (;;) {
479 if (-1 == (c = getopt(argc, argv, "hyq12d:c:b:s:fa:")))
480 break;
481 switch (c) {
482 case 'q':
483 verbose = 0;
484 break;
485 case 'y':
486 yuv = 1;
487 break;
488 case '1':
489 v4l1 = 1;
490 v4l2 = 0;
491 break;
492 case '2':
493 v4l1 = 0;
494 v4l2 = 1;
495 break;
496 case 'd':
497 display = optarg;
498 break;
499 case 'c':
500 videodev = optarg;
501 break;
502 case 'b':
503 user_bpp = atoi(optarg);
504 break;
505 case 's':
506 user_shift = atoi(optarg);
507 if (user_shift < 0 || user_shift > 8192)
508 user_shift = 0;
509 break;
510 case 'f':
511 display = NULL;
512 break;
513 case 'a':
514 if (0 == getuid()) {
515 /* only root is allowed to set this, and it will work only
516 * if v4l-conf can't figure out the correct address itself.
517 * Useful for "post-install bttv ..." */
518 sscanf(optarg,"%p",&user_base);
519 } else {
520 fprintf(stderr,"only root is allowed to use the -a option\n");
521 exit(1);
522 }
523 break;
524 case 'h':
525 default:
526 fprintf(stderr,
527 "usage: %s [ options ] \n"
528 "\n"
529 "options:\n"
530 " -q quiet\n"
531 #ifndef X_DISPLAY_MISSING
532 " -d <dpy> X11 Display [%s]\n"
533 #endif
534 " -c <dev> video device [%s]\n"
535 " -b <n> displays color depth is <n> bpp\n"
536 " -s <n> shift display by <n> bytes\n"
537 " -f query frame buffer device for info\n"
538 " -a <addr> set framebuffer address to <addr>\n"
539 " (in hex, root only, successful autodetect\n"
540 " will overwrite this address)\n"
541 " -1 force v4l API\n"
542 " -2 force v4l2 API\n",
543 argv[0],
544 #ifndef X_DISPLAY_MISSING
545 display ? display : "none",
546 #endif
547 videodev);
548 exit(1);
549 }
550 }
551
552 /* figure out display parameters */
553 memset(&d,0,sizeof(struct DISPLAYINFO));
554 #ifdef __powerpc__
555 if (is_mklinux()) {
556 displayinfo_mklinux(&d);
557 } else
558 #endif
559 #ifndef X_DISPLAY_MISSING
560 if (NULL != display) {
561 /* using X11 */
562 if (display[0] != ':') {
563 fprintf(stderr,"WARNING: remote display `%s' not allowed, ",
564 display);
565 display = strchr(display,':');
566 if (NULL == display) {
567 fprintf(stderr,"exiting");
568 exit(1);
569 } else {
570 fprintf(stderr,"using `%s' instead\n",display);
571 }
572 }
573 if (NULL == (dpy = XOpenDisplay(display))) {
574 fprintf(stderr,"can't open x11 display %s\n",display);
575 exit(1);
576 }
577 displayinfo_x11(dpy,&d);
578 displayinfo_dga(dpy,&d);
579 } else
580 #endif
581 {
582 /* try framebuffer device */
583 displayinfo_fbdev(&d);
584 }
585
586 /* fixup struct displayinfo according to the given command line options */
587 if (user_base) {
588 if (NULL == d.base) {
589 fprintf(stderr,"using user provided base address %p\n",user_base);
590 d.base = user_base;
591 } else {
592 fprintf(stderr,"user provided base address %p ignored.\n",
593 user_base);
594 }
595 }
596 if (d.base)
597 d.base += user_shift;
598 if ((user_bpp == 24 || user_bpp == 32) &&
599 (d.bpp == 24 || d.bpp == 32)) {
600 d.bpp = user_bpp;
601 d.bpl = d.width * d.bpp/8;
602 }
603 if ((user_bpp == 15 || user_bpp == 16) &&
604 (d.depth == 15 || d.depth == 16))
605 d.depth = user_bpp;
606
607 if (verbose) {
608 fprintf(stderr,"mode: %dx%d, depth=%d, bpp=%d, bpl=%d, ",
609 d.width,d.height,d.depth,d.bpp,d.bpl);
610 if (NULL != d.base)
611 fprintf(stderr,"base=%p\n",d.base);
612 else
613 fprintf(stderr,"base=unknown\n");
614 }
615
616 /* Set the parameters (needs root) */
617 root_user();
618 fd = dev_open(videodev, 81 /* VIDEO_MAJOR */);
619 if (-1 == displayinfo_v4l2(fd,&d))
620 displayinfo_v4l(fd,&d);
621 close(fd);
622 return 0;
623 }
624
|
This page was automatically generated by the
LXR engine.
|