Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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.