본문 바로가기

Programming/Linux_Kernel

frame buffer 이야기 (2)

원문 : http://kelp.or.kr/korweblog/stories.php?story=02/11/09/8670820


글쓴이 : holelee (2002년 11월 09일 오후 10:31) 읽은수: 13,703 [ 임베디드강좌/이규명 인쇄용 페이지 ]
== 시작하기에 앞서
이 글에 있는 모든 내용은 글쓴이가 가지고 있는 ATI mach 64(2MB) 그래픽 카드가 달려있고 RedHat 8.0이 설치된 PC(또는 Permedia2(8MB) 그래픽 카드가 달려 있는 RedHat 7.3이 설치된 PC)에서 제대로 동작하지만 이 글에 있는 모든 내용이 정확하다고 말씀 드릴 수 없습니다. 이 글에 있는 내용을 따라 했을 때 혹 생길 지 모르는 모든 문제에 대해서 글쓴이는 책임을 지지 않습니다. 글의 내용 중에 잘못된 내용이 있거나 질문할 것이 있으면 위쪽의 “holelee”를 누르고 메일을 보내기 바랍니다.

== 시작하기 전에
전 글에서 frame buffer driver를 올리는 방법을 알아봤습니다. 이번 글에서는 frame buffer driver가 올라가 있는 시스템에서 frame buffer driver가 올라가 있는 상태에서 frame buffer device의 기본적인 정보를 살펴볼 수 있는 프로그램을 작성해보도록 하겠습니다. 우선 frame buffer device special 파일을 보도록 하죠. 다음과 같이 shell 상에 입력합니다.
$ ls –l /dev/fb
lrwxrwxrwx 1 root root 3 9월 8 03:15 /dev/fb -> fb0
다음과 같은 결과를 보입니다.(이 결과는 RedHat 7.3의 결과입니다.)
$ ls –l /dev/fb0
crw------- 1 root root 29, 0 4월 11 2002 /dev/fb0
결과를 보면 /dev/fb는 /dev/fb0의 symbolic link이고 /dev/fb0는 root만 쓰고 읽을 수 있는 character device임을 알 수 있습니다.(물론 permission은 바꿀 수 있습니다. 그러나 그냥 root만 읽고 쓸 수 있도록 놔두도록 하죠. 대신 /dev/fb를 여는 모든 프로그램은 root 권한이 있을 때만 수행해야 합니다.)

== fb_var_screeninfo, fb_fix_screeninfo
이제 직접 소스코드를 만날 차례입니다.
===============================
1 /*
2 * fbinfo.c : Frame buffer information viewer
3 *
4 * Copyright(C) 2002 holelee
5 *
6 */


7 #include <stdio.h>
8 #include <stdlib.h> /* for exit */
9 #include <unistd.h> /* for open/close .. */
10 #include <fcntl.h> /* for O_RDWR */
11 #include <sys/ioctl.h> /* for ioctl */
12 #include <linux/fb.h> /* for fb_var_screeninfo, FBIOGET_VSCREENINFO */


13 #define FBDEVFILE "/dev/fb"


14 int main()
15 {
16 int fbfd;
17 int ret;
18 struct fb_var_screeninfo fbvar;
19 struct fb_fix_screeninfo fbfix;


20 fbfd = open(FBDEVFILE, O_RDWR);
21 if(fbfd < 0)
22 {
23 perror("fbdev open");
24 exit(1);
25 }


26 ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar);
27 if(ret < 0)
28 {
29 perror("fbdev ioctl(FSCREENINFO)");
30 exit(1);
31 }


32 ret = ioctl(fbfd, FBIOGET_FSCREENINFO, &fbfix);
33 if(ret < 0)
34 {
35 perror("fbdev ioctl(FSCREENINFO)");
36 exit(1);
37 }


38 printf("x-resolution : %d\n", fbvar.xres);
39 printf("y-resolution : %d\n", fbvar.yres);
40 printf("x-resolution(virtual) : %d\n", fbvar.xres_virtual);
41 printf("y-resolution(virtual) : %d\n", fbvar.yres_virtual);
42 printf("bpp : %d\n", fbvar.bits_per_pixel);


43 printf("length of frame buffer memory : %d\n", fbfix.smem_len);


44 close(fbfd);
45 exit(0);
46 return 0;
47 }
===============================
이 것을 모두 타이핑하고 컴파일하여 수행해 보시기 바랍니다.
우선 수행 중에 생길 수 있는 에러 메시지는 다음과 같습니다.
(1) fbdev open: Permission denied
=> root 권한이 없어서 생기는 메시지입니다.
(2) fbdev open: No such device
=> frame buffer driver가 제대로 올라가지 않아서 생기는 에러 메시지입니다.
혹 fbdev ioctl…어쩌구 하는 에러 메시지가 나온다면 그것은 frame buffer driver가 정상적인 동작을 하지 않아서 그런 것 같습니다.

수행시키면 다음과 같은 결과를 볼 수 있습니다.
x-resolution : 640
y-resolution : 480
x-resolution(virtual) : 640
y-resolution(virtual) : 480
bpp : 8
length of frame buffer memory : 8388608
(이 결과는 RedHat 7.3 Permedia2 8MB 그래픽 카드가 있는 시스템에서 보여주는 결과입니다.)
화면 해상도는 640x480이고 가상화면 해상도도 640x480입니다. 픽셀당 bits 수는 8이고 frame buffer memory의 크기는 8MB라고 해석할 수 있습니다. 가장 중요한 정보는 해상도하고 bpp정보입니다. 가상화면을 쓰는 경우가 있는지 모르겠지만 가상화면 정보는 혹시나 해서 출력해 보았고 Frame buffer memory 크기도 크게 중요한 부분은 아닙니다.

헤더 파일들을 간략히 살펴보면 unstd.h는 open/close 시스템 콜이 선언되어 있기 때문에 include한 것이고, fcntl.h는 open의 argument인 O_RDWR이 #define인 되어 있을 겁니다. Sys/ioctl.h는 ioctl 시스템 콜이 선언되어 있는 파일입니다. linux/fb.h가 제일 중요한 include 파일인데요, 이 내부에 fb_var_screeninfo 구조체, fb_fix_screeninfo 구조체, FBIOGET_VSCREENINFO, FBIOGET_FSCREENINFO 등이 정의되어 있습니다.

소스코드가 너무 짧기 때문에 설명할 내용도 없습니다. 단지 fb_var_screeninfo 정보를 얻어오기 위해 FBIOGET_VSCREENINFO ioctl을 이용하고 fb_fix_screeninfo 정보를 얻어오기 위해 FBIOGET_FSCREENINFO ioctl을 이용한다고 기억하시면 됩니다.

fb_fix_screeninfo는 frame buffer상에 고정(fix)된 정보입니다. fb_var_screeninfo는 frame buffer상에서 바꿀 수 있는 정보입니다. 즉 fb_var_screeninfo 안에 있는 정보, 예를 들어 해상도나 bpp는 사용자의 요구에 의해서 바꿀 수도 있습니다. 각각의 정의는 linux/fb.h에 있고 구조체의 멤버에 대해서 짤막한 설명이 들어 있으므로 살펴보시기 바랍니다.

== 16bpp로 바꾸기
다음의 소스코드를 살펴보도록 하죠.
===============================
1 /*
2 * fb16bpp.c : Change bpp of frame buffer to 16
3 *
4 * Copyright(C) 2002 holelee
5 *
6 */


7 #include <stdio.h>
8 #include <stdlib.h> /* for exit */
9 #include <unistd.h> /* for open/close .. */
10 #include <fcntl.h> /* for O_RDONLY */
11 #include <sys/ioctl.h> /* for ioctl */
12 #include <linux/fb.h> /* for fb_var_screeninfo, FBIOGET_VSCREENINFO */


13 #define FBDEVFILE "/dev/fb"


14 int main()
15 {
16 int fbfd;
17 int ret;
18 struct fb_var_screeninfo fbvar;


19 fbfd = open(FBDEVFILE, O_RDWR);
20 if(fbfd < 0)
21 {
22 perror("fbdev open");
23 exit(1);
24 }


25 ret = ioctl(fbfd, FBIOGET_VSCREENINFO, &fbvar);
26 if(ret < 0)
27 {
28 perror("fbdev ioctl(GET)");
29 exit(1);
30 }
31 fbvar.bits_per_pixel = 16;


32 ret = ioctl(fbfd, FBIOPUT_VSCREENINFO, &fbvar);
33 if(ret < 0)
34 {
35 perror("fbdev ioctl(PUT)");
36 exit(1);
37 }


38 close(fbfd);
39 exit(0);
40 return 0;
41 }
===============================
위의 소스코드는 fb_var_screeninfo를 읽어온 후에 bits_per_pixel 필드만 바꾼 후에 FBIOPUT_VSCREENINFO ioctl을 이용하여 kernel에 넘겨준 것입니다. 프로그램을 컴파일하여 수행할 때 혹시 생길 수 있는 에러 메시지는 위에서 언급된 두 가지 뿐 아니라 다음과 같은 메시지가 나올 수 있습니다.
fbdev ioctl(PUT): Invalid argument
이 메시지는 frame buffer device가 16 bpp로 바꿀 수 없다는 메시지입니다. 아무래도 하드웨어가 지원하는 해상도와 bpp에는 한계가 있을 수 있으므로 하드웨어에 따라서 달라집니다.
(RedHat 8.0 ATI mach 64 CT 2MB 시스템의 경우 에러가 나더군요. atyfb의 버그인 것으로 보입니다. fbinfo의 결과에서 yres_virtual이 엄청나게 이상한 값을 가지고 있고 따라서 그것을 다시 480으로 바꾼후에 FBIOPUT_VSCREENINFO를 해주면 문제가 해결됩니다.)
이 프로그램을 에러없이 수행하고 난 다음에 처음의 프로그램을 다시 수행하면 다음과 같은 결과를 볼 수 있습니다.
x-resolution : 640
y-resolution : 480
x-resolution(virtual) : 640
y-resolution(virtual) : 480
bpp : 16
length of frame buffer memory : 8388608
bpp가 제대로 바뀌었습니다. 나머지는 물론 변화가 없습니다. 이제 해상도를 800x600으로 바꾸는 프로그램도 작성할 수 있겠죠. 또 32bpp나 24bpp로 바꿀 수도 있겠죠.(단 하드웨어와 frame buffer driver가 지원만 한다면.)

== 마치며
이 이후부터 진행되는 모든 글에 있는 소스코드는 16bpp를 기준으로 작성할 예정입니다. 굳이 한정하는 이유는 모든 bpp를 지원할 수 있도록 하면 소스코드가 너무 길어지기도 하고 기타 등등의 이유가 있으므로 그렇게 하겠습니다. 요즘 PDA나 Handphone도 16bpp가 많이 있고 StrongARM에도 보통 16bpp LCD를 다는 추세이므로 16bpp가 크게 문제가 되리라 보지 않습니다. 다른 bpp의 경우는 모든 글이 완료되었을 때 각 bpp별 특성에 대해서 짤막한 글을 적도록 하겠습니다.
다음 글에서는 드뎌 “점찍기”를 해보도록 하겠습니다. 단 그것을 위한 준비로 이번 글에 있는 내용을 읽고 해상도는 관계 없이 frame buffer setting을 16bpp로 만들어 놓으시길 바랍니다.

== 참고 자료
fbset-2.1(http://home.tvd.be/cr26864/Linux/fbdev/)
=> 이 프로그램 컴파일 해서 수행해 보길 바랍니다.

'Programming > Linux_Kernel' 카테고리의 다른 글

frame buffer 이야기(4) (5)  (0) 2009.06.04
frame buffer 이야기 (3)  (0) 2009.06.04
frame buffer 이야기 (1)  (2) 2009.06.04
udev debuging 방법  (0) 2009.04.13
Linux kernel compile 시 stdio.h / stdlib.h 애러  (0) 2009.01.21