Test Application with DRM or Simple FB

Souce Code는 다음과 같다.

#include	<stdio.h>
#include	<stdint.h>
#include	<string.h>		/* for memset */
#include	<unistd.h>		/* for open/close .. */
#include	<fcntl.h>		/* for O_RDWR */
#include	<sys/ioctl.h>	/* for ioctl */
#include	<sys/mman.h>	/* for mmap */
#include	<linux/fb.h>	/* for fb_var_screeninfo, FBIOGET_VSCREENINFO */

#include	"drm.h"	/* /home/stephanos/VI/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/drm -> check Makefile */
#include	"drm_mode.h"

#define	DEFAULT_FRAME_BUFFER_FILE	"/dev/fb0"
#define	DEV_LCD_DRM					"/dev/dri/card0"


#define	MAXIMUM_NUMBER_OF_CONNECTORS				10
#define	MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER	20

typedef	struct
{
	void *		pBuffer;
	uint32_t	ByteSizeOfBuffer;
	uint32_t	ScreenWidth;
	uint32_t	ScreenHeight;
} FrameBuffer_t;





typedef	struct
{
	uint64_t	pFB_ID[MAXIMUM_NUMBER_OF_CONNECTORS];
	uint64_t	pCRTC_ID[MAXIMUM_NUMBER_OF_CONNECTORS];
	uint64_t	pCONNECTOR_ID[MAXIMUM_NUMBER_OF_CONNECTORS];
	uint64_t	pENCODER_ID[MAXIMUM_NUMBER_OF_CONNECTORS];
} DRMResourceBuffer_t;

typedef	struct
{
	struct	drm_mode_modeinfo	pMode[MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER];
	uint64_t					pProps[MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER];
	uint64_t					PPropValue[MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER];
	uint64_t					pEncoder[MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER];
} DRMConnectorResourceBuffer_t;

typedef	struct
{
	struct	drm_mode_create_dumb	Create;
	struct	drm_mode_map_dumb		Map;
	struct	drm_mode_fb_cmd			Cmd;
} DRMdumbBuffer_t;





typedef	struct
{
	int							Device;

	void *						pFrameBuffer;

	struct	fb_var_screeninfo	var;
	struct	fb_fix_screeninfo	fix;
} FrameBufferContext_t;



void	drm_draw_pixel(	FrameBuffer_t *pFrameBuffer,
						uint32_t X,
						uint32_t Y,
						uint32_t Color/*(b << 16) | (g << 8) | (r << 0)*/)
{
	if ( pFrameBuffer != (FrameBuffer_t *)0 )
	{
		if ((pFrameBuffer->ScreenWidth > X)
		 &&	(pFrameBuffer->ScreenHeight > Y))
		{
			*(((uint32_t*)pFrameBuffer->pBuffer ) + Y * pFrameBuffer->ScreenWidth + X) = Color;
		}
	}
}

void	drm_draw_test_pattern(FrameBuffer_t *pFrameBuffer)
{
	uint32_t	x;
	uint32_t	y;
	uint32_t	h;
	uint32_t	w;

	h = pFrameBuffer->ScreenHeight;
	w = pFrameBuffer->ScreenWidth;
	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			if (x < 20 && y < 20)
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xffffff);
			}
			else if (x < 20 && (y > 20 && y < h - 20))
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xff);
			}
			else if (y < 20 && (x > 20 && x < w - 20))
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xff00);
			}
			else if (x > w - 20 && (y > 20 && y < h - 20))
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xff0000);
			}
			else if (y > h - 20 && (x > 20 && x < w - 20))
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xffff00);
			}
			else if (x == 20 || x == w - 20 ||
					y == 20 || y == h - 20)
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xffffff);
			}
			else if (x == y || w - x == h - y)
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0xff00ff);
			}
			else if (w - x == y || x == h - y)
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0x00ffff);
			}

			else if (x > 20 && y > 20 && x < w - 20 && y < h - 20)
			{
				int t = x * 3 / w;
				unsigned r = 0, g = 0, b = 0;
				unsigned c;
				if (t == 0)
				{
					b = (y % 256);
				}
				else if (t == 1)
				{
					g = (y % 256);
				}
				else if (t == 2)
				{
					r = (y % 256);
				}
				c = (b << 16) | (g << 8) | (r << 0);
				drm_draw_pixel(pFrameBuffer, x, y, c);
			}
			else
			{
				drm_draw_pixel(pFrameBuffer, x, y, 0);
			}
		}
	}
}

void	drm_fill_screen(FrameBuffer_t *pFrameBuffer,
						uint32_t Color/*(b << 16) | (g << 8) | (r << 0)*/)
{
	uint32_t	X;
	uint32_t	Y;

	if ( pFrameBuffer != (FrameBuffer_t *)0 )
	{
		for (Y = 0; Y < pFrameBuffer->ScreenHeight; Y++)
		{
			for (X = 0; X < pFrameBuffer->ScreenWidth; X++)
			{
				*(((uint32_t*)pFrameBuffer->pBuffer ) + Y * pFrameBuffer->ScreenWidth + X) = Color;
			}
		}
	}
}


void	fb_draw_pixel(	FrameBufferContext_t *pFrameBufferContext,
					uint32_t X,
					uint32_t Y,
					uint32_t Color)
{
	void *	pFrameBuffer;

	pFrameBuffer = pFrameBufferContext->pFrameBuffer;
	if (pFrameBufferContext->var.bits_per_pixel == 8)
	{
		unsigned char *		p;

		pFrameBuffer += pFrameBufferContext->fix.line_length * Y;
		p = pFrameBuffer;
		p += X;

		*p = (unsigned char)Color;
	}
	else if (pFrameBufferContext->var.bits_per_pixel == 16)
	{
		unsigned short *	p;

		pFrameBuffer += pFrameBufferContext->fix.line_length * Y;
		p = pFrameBuffer;
		p += X;

		*p = (unsigned short)(((((Color >> 16) & 0xff) * 32 / 256) << 11) | ((((Color >> 8) & 0xff) * 64 / 256) << 5) | ((((Color >> 0) & 0xff) * 32 / 256) << 0));
	}
	else if (pFrameBufferContext->var.bits_per_pixel == 24)
	{
		unsigned char *		p;

		p = (unsigned char *)pFrameBuffer + pFrameBufferContext->fix.line_length * Y + 3 * X;

		*p++ = (unsigned char)Color;
		*p++ = (unsigned char)(Color >> 8);
		*p = (unsigned char)(Color >> 16);
	}
	else
	{
		uint32_t *		p;

		pFrameBuffer += pFrameBufferContext->fix.line_length * Y;
		p = pFrameBuffer;
		p += X;

		*p = Color;
	}
}


void	fill_screen(FrameBufferContext_t *pFrameBufferContext)
{
	uint32_t	x;
	uint32_t	y;
	uint32_t	h;
	uint32_t	w;

	h = pFrameBufferContext->var.yres;
	w = pFrameBufferContext->var.xres;
	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			if (x < 20 && y < 20)
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xffffff);
			}
			else if (x < 20 && (y > 20 && y < h - 20))
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xff);
			}
			else if (y < 20 && (x > 20 && x < w - 20))
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xff00);
			}
			else if (x > w - 20 && (y > 20 && y < h - 20))
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xff0000);
			}
			else if (y > h - 20 && (x > 20 && x < w - 20))
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xffff00);
			}
			else if (x == 20 || x == w - 20 ||
					y == 20 || y == h - 20)
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xffffff);
			}
			else if (x == y || w - x == h - y)
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0xff00ff);
			}
			else if (w - x == y || x == h - y)
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0x00ffff);
			}

			else if (x > 20 && y > 20 && x < w - 20 && y < h - 20)
			{
				int t = x * 3 / w;
				unsigned r = 0, g = 0, b = 0;
				unsigned c;
				if (pFrameBufferContext->var.bits_per_pixel == 16)
				{
					if (t == 0)
					{
						b = (y % 32) * 256 / 32;
					}
					else if (t == 1)
					{
						g = (y % 64) * 256 / 64;
					}
					else if (t == 2)
					{
						r = (y % 32) * 256 / 32;
					}
				}
				else
				{
					if (t == 0)
					{
						b = (y % 256);
					}
					else if (t == 1)
					{
						g = (y % 256);
					}
					else if (t == 2)
					{
						r = (y % 256);
					}
				}
				c = (b << 16) | (g << 8) | (r << 0);
				fb_draw_pixel(pFrameBufferContext, x, y, c);
			}
			else
			{
				fb_draw_pixel(pFrameBufferContext, x, y, 0);
			}
		}
	}
}


void	clear_area(	FrameBufferContext_t *pFrameBufferContext,
					uint32_t X,
					uint32_t Y,
					uint32_t W,
					uint32_t H)
{
	uint32_t	AddressOffsetForH;
	uint32_t	CountForH;
	unsigned char *	pFrameBuffer;

	pFrameBuffer = (unsigned char *)pFrameBufferContext->pFrameBuffer;

	for (CountForH = 0; CountForH < H; CountForH++)
	{
		AddressOffsetForH = (X + pFrameBufferContext->var.xoffset) * (pFrameBufferContext->var.bits_per_pixel / 8)
			+ (Y + CountForH + pFrameBufferContext->var.yoffset) * pFrameBufferContext->fix.line_length;

		memset(pFrameBuffer + AddressOffsetForH, 0, W * pFrameBufferContext->var.bits_per_pixel / 8);
	}
}


int	device_open_mode(FrameBufferContext_t *pFrameBufferContext, int BitPerPixel)
{
	pFrameBufferContext->Device = open(DEFAULT_FRAME_BUFFER_FILE, O_RDWR);
	if(pFrameBufferContext->Device < 0)
	{
		printf("Faile to open : %s \n", DEFAULT_FRAME_BUFFER_FILE);
		return	-1;
	}

	if(ioctl(pFrameBufferContext->Device, FBIOGET_VSCREENINFO, &pFrameBufferContext->var) < 0)
	{
		printf("fbdev ioctl(VSCREENINFO)\n");
		close(pFrameBufferContext->Device);
		return	-1;
	}

	if(ioctl(pFrameBufferContext->Device, FBIOGET_FSCREENINFO, &pFrameBufferContext->fix) < 0)
	{
		printf("fbdev ioctl(FSCREENINFO)\n");
		close(pFrameBufferContext->Device);
		return	-1;
	}

	if(pFrameBufferContext->var.bits_per_pixel != BitPerPixel)
	{
		pFrameBufferContext->var.bits_per_pixel = BitPerPixel;
		if(ioctl(pFrameBufferContext->Device, FBIOPUT_VSCREENINFO, &pFrameBufferContext->var) < 0)
		{
			printf("fbdev ioctl(PUT)\n");
			close(pFrameBufferContext->Device);
			return	-1;
		}
	}

	return	0;
}


int	device_open(FrameBufferContext_t *pFrameBufferContext)
{
	if(device_open_mode(pFrameBufferContext, 8) != 0)
	{
		printf("Faile to open with 8bit: %s \n", DEFAULT_FRAME_BUFFER_FILE);
		return	-1;
	}
	close(pFrameBufferContext->Device);

	if(device_open_mode(pFrameBufferContext, 24) != 0)
	{
		printf("Faile to open with 24bit: %s \n", DEFAULT_FRAME_BUFFER_FILE);
		return	-1;
	}

	printf("x-resolution : %d\n", pFrameBufferContext->var.xres);
	printf("y-resolution : %d\n", pFrameBufferContext->var.yres);
	printf("x-resolution(virtual) : %d\n", pFrameBufferContext->var.xres_virtual);
	printf("y-resolution(virtual) : %d\n", pFrameBufferContext->var.yres_virtual);
	printf("bpp : %d\n", pFrameBufferContext->var.bits_per_pixel);
	printf("length of frame buffer memory : %d\n", pFrameBufferContext->fix.smem_len);

	return	0;
}

static	int	test_simple_fb_style(void)
{
	FrameBufferContext_t	FrameBufferContext;
	int						Error;

	printf("Opening frame buffer device `%s'\n", DEFAULT_FRAME_BUFFER_FILE);

	if(device_open(&FrameBufferContext) != 0)
	{
		printf("Fail to Device Open\n");
		return	0;
	}

	FrameBufferContext.pFrameBuffer = mmap(0,
			FrameBufferContext.var.yres_virtual * FrameBufferContext.fix.line_length,
			PROT_WRITE | PROT_READ,
			MAP_SHARED,
			FrameBufferContext.Device,
			0);

	if(FrameBufferContext.pFrameBuffer == MAP_FAILED)
	{
		printf("Frame buffer MAP fail !\n");
		close(FrameBufferContext.Device);
		return	0;
	}

/* Display pattern to screen */
	fill_screen(&FrameBufferContext);

/* End of... */
	munmap(	FrameBufferContext.pFrameBuffer,
			FrameBufferContext.var.yres_virtual * FrameBufferContext.fix.line_length);

	close(FrameBufferContext.Device);

	return	0;
}





static	int	drm_open(void)
{
	int			Device;
	int			Flags;
	uint64_t	HasDumbBuffer;

	Device = -1;
	if ( access(DEV_LCD_DRM, F_OK) )
	{
		printf("no device - %s\n", DEV_LCD_DRM);
		return	0;
	}

	if ( (Device = open(DEV_LCD_DRM, O_RDWR)) <= 0 )
	{
		printf("Faile to open : %s \n", DEV_LCD_DRM);
		return	0;
	}

	//	set FD_CLOEXEC flag
	Flags = fcntl(Device, F_GETFD);
	if (Flags < 0)
	{
		printf("Faile to read Flags \n");
		close(Device);
		return	0;
	}
	if ( fcntl(Device, F_SETFD, Flags | FD_CLOEXEC) < 0 )
	{
		printf("Faile to set Falsgs FD_CLOEXEC \n");
		close(Device);
		return	0;
	}

	return	Device;
}


static	int	drm_get_frame_buffer(FrameBuffer_t *pFrameBuffer,
								int Device,
								uint64_t * pConnectorID)
{
	struct	drm_mode_get_connector	ConnectorResource = {0};
	DRMConnectorResourceBuffer_t	DRMConnectorResourceBuffer = {0};
	DRMdumbBuffer_t					DRMdumbBuffer = {0};
	struct	drm_mode_get_encoder	Encoder = {0};
	struct	drm_mode_crtc			CRTC = {0};

	if ((pFrameBuffer != (FrameBuffer_t *)0)
	 &&	(pConnectorID != (uint64_t * )0) )
	{
		//	get connector resource counts
		ConnectorResource.connector_id = *pConnectorID;
		ioctl(Device, DRM_IOCTL_MODE_GETCONNECTOR, &ConnectorResource);

		//	get connector resources
		ConnectorResource.modes_ptr = (uint64_t)DRMConnectorResourceBuffer.pMode;
		ConnectorResource.props_ptr = (uint64_t)DRMConnectorResourceBuffer.pProps;
		ConnectorResource.prop_values_ptr = (uint64_t)DRMConnectorResourceBuffer.PPropValue;
		ConnectorResource.encoders_ptr = (uint64_t)DRMConnectorResourceBuffer.pEncoder;
		ioctl(Device, DRM_IOCTL_MODE_GETCONNECTOR, &ConnectorResource);

		//	Check if the connector is OK to use (connected to something)
		if ((ConnectorResource.count_encoders > 0)
		 &&	(ConnectorResource.count_modes > 0)
		 && (ConnectorResource.encoder_id != 0)
		 && (ConnectorResource.connection != 0)	)
		{
			//	Creating a dumb buffer
			//	If we create the buffer later, we can get the size of the screen first.
			//	This must be a valid mode, so it's probably best to do this after we find a valid crtc with modes.
			DRMdumbBuffer.Create.width = DRMConnectorResourceBuffer.pMode[0].hdisplay;
			DRMdumbBuffer.Create.height = DRMConnectorResourceBuffer.pMode[0].vdisplay;
			DRMdumbBuffer.Create.bpp = 32;
			DRMdumbBuffer.Create.flags = 0;	/* must be zero */
			DRMdumbBuffer.Create.pitch = 0;
			DRMdumbBuffer.Create.size = 0;
			DRMdumbBuffer.Create.handle = 0;
			if(ioctl(Device, DRM_IOCTL_MODE_CREATE_DUMB, &DRMdumbBuffer.Create) < 0)
			{
				printf("Fail to create dumb buffer\n");
			};

			DRMdumbBuffer.Cmd.width=DRMdumbBuffer.Create.width;
			DRMdumbBuffer.Cmd.height=DRMdumbBuffer.Create.height;
			DRMdumbBuffer.Cmd.bpp=DRMdumbBuffer.Create.bpp;
			DRMdumbBuffer.Cmd.pitch=DRMdumbBuffer.Create.pitch;
			DRMdumbBuffer.Cmd.depth=24;
			DRMdumbBuffer.Cmd.handle=DRMdumbBuffer.Create.handle;
			ioctl(Device,DRM_IOCTL_MODE_ADDFB,&DRMdumbBuffer.Cmd);

			DRMdumbBuffer.Map.handle=DRMdumbBuffer.Create.handle;
			ioctl(Device,DRM_IOCTL_MODE_MAP_DUMB,&DRMdumbBuffer.Map);

			pFrameBuffer->pBuffer = mmap(0, DRMdumbBuffer.Create.size, PROT_READ | PROT_WRITE, MAP_SHARED, Device, DRMdumbBuffer.Map.offset);
			pFrameBuffer->ByteSizeOfBuffer = DRMdumbBuffer.Create.size;
			pFrameBuffer->ScreenWidth = DRMdumbBuffer.Create.width;
			pFrameBuffer->ScreenHeight = DRMdumbBuffer.Create.height;

//		drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);

			//	Kernel Mode Setting (KMS)
			printf("Connection %d : mode: %d, prop: %d, enc: %d\n",
					ConnectorResource.connection,
					ConnectorResource.count_modes,
					ConnectorResource.count_props,
					ConnectorResource.count_encoders);
			printf("modes: %dx%d Frame Buffer Address: 0x%X Frame Buffer Byte Size: 0x%X(%d) \n",
					DRMConnectorResourceBuffer.pMode[0].hdisplay,
					DRMConnectorResourceBuffer.pMode[0].vdisplay,
					pFrameBuffer->pBuffer,
					pFrameBuffer->ByteSizeOfBuffer, pFrameBuffer->ByteSizeOfBuffer);

			//	get encoder
			Encoder.encoder_id = ConnectorResource.encoder_id;
			ioctl(Device, DRM_IOCTL_MODE_GETENCODER, &Encoder);

			CRTC.crtc_id = Encoder.crtc_id;
			ioctl(Device, DRM_IOCTL_MODE_GETCRTC, &CRTC);

			CRTC.fb_id = DRMdumbBuffer.Cmd.fb_id;
			CRTC.set_connectors_ptr = (uint64_t)pConnectorID;
			CRTC.count_connectors = 1;
			CRTC.mode = DRMConnectorResourceBuffer.pMode[0];
			CRTC.mode_valid = 1;
			ioctl(Device, DRM_IOCTL_MODE_SETCRTC, &CRTC);

			return	0;
		}
		else
		{
			printf("Not connected\n");
		}
	}

	return	-1;
}


static	int	drm_free_frame_buffer(FrameBuffer_t *pFrameBuffer)
{
	if (pFrameBuffer != (FrameBuffer_t *)0)
	{
		if (pFrameBuffer->ByteSizeOfBuffer != 0)
		{
			munmap(	pFrameBuffer->pBuffer, pFrameBuffer->ByteSizeOfBuffer );
			printf("Free Frame Buffer\n");

			return	0;
		}
	}

	return	-1;
}


static	int	test_drm_style(void)
{
	int							Device;
	uint32_t					ConnectorIndex;
	uint32_t					Color;
	struct	drm_mode_card_res	Resource = {0};
	DRMResourceBuffer_t			DRMResourceBuffer = {0};

	Device = drm_open();
	if ( Device != 0 )
	{
		FrameBuffer_t	pFrameBuffer[MAXIMUM_NUMBER_OF_CONNECTORS];

		printf("DRM opened !\n");

		//	Kernel Mode Setting (KMS)
		//	Become the "master" of the DRI device
		ioctl(Device, DRM_IOCTL_SET_MASTER, 0);
		printf("DRM DRM_IOCTL_SET_MASTER\n");

		//	Get resource counts
		ioctl(Device, DRM_IOCTL_MODE_GETRESOURCES, &Resource);
		Resource.fb_id_ptr = (uint64_t)DRMResourceBuffer.pFB_ID;
		Resource.crtc_id_ptr = (uint64_t)DRMResourceBuffer.pCRTC_ID;
		Resource.connector_id_ptr = (uint64_t)DRMResourceBuffer.pCONNECTOR_ID;
		Resource.encoder_id_ptr = (uint64_t)DRMResourceBuffer.pENCODER_ID;

		//	Get resource IDs
		ioctl(Device, DRM_IOCTL_MODE_GETRESOURCES, &Resource);
		printf("Get Resource ID fb: %d, crtc: %d, conn: %d, enc: %d\n",
				Resource.count_fbs,
				Resource.count_crtcs,
				Resource.count_connectors,
				Resource.count_encoders);

		//	Loop though all available connectors
		for (ConnectorIndex = 0; ConnectorIndex < Resource.count_connectors; ConnectorIndex++)
		{
			drm_get_frame_buffer(&pFrameBuffer[ConnectorIndex], Device, &DRMResourceBuffer.pCONNECTOR_ID[ConnectorIndex]);
		}

		//	Stop being the "master" of the DRI device
		ioctl(Device, DRM_IOCTL_DROP_MASTER, 0);
		printf("DRM DRM_IOCTL_DROP_MASTER\n");


		int	j;
		for (j = 0; j < 100; j++)
		{
			for (ConnectorIndex = 0; ConnectorIndex < Resource.count_connectors; ConnectorIndex++)
			{
				drm_fill_screen(&pFrameBuffer[ConnectorIndex], 0x00000000);
				usleep(100000);
				Color = (rand() % 0x00ffffff) & 0x00ff00ff;
				drm_fill_screen(&pFrameBuffer[ConnectorIndex], Color);
				usleep(100000);
				for (uint32_t k = 0; k <255; k++)
				{
					drm_fill_screen(&pFrameBuffer[ConnectorIndex], (Color | (k << 24)));
				}
				drm_draw_test_pattern(&pFrameBuffer[ConnectorIndex]);
				usleep(100000);
			}
		}

//DRM_IOCTL_MODE_DESTROY_DUMB

		for (ConnectorIndex = 0; ConnectorIndex < Resource.count_connectors; ConnectorIndex++)
		{
			drm_free_frame_buffer(&pFrameBuffer[ConnectorIndex]);
		}

		close(Device);
		printf("DRM closed !\n");
	}

}


int	main()
{
	printf("Test Symple FB Style\n");
	test_simple_fb_style();

	printf("Test DRM Style\n");
	test_drm_style();

	return	0;
}

test_app_002.zip

아래와 같이 컴파일 한다.

stephanos@stephanos-VirtualBox:~/VI/App$ /home/stephanos/VI/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc -I$/home/stephanos/VI/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/include/drm -o test test.c

test_app_000.jpg

NFS에 위에서 만들어진 test를 복사한다. Target Board를 NFS로 부팅한다.

로그인 후 아래와 같이 실행한다.

test_app_001.jpg