#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	<linux/input.h>
#include	<poll.h>

#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	DEV_LCD_FB					"/dev/fb0"
#define	DEV_LCD_DRM					"/dev/dri/card0"

#define	DEV_LCD_BACKLIGHT			"/sys/class/backlight/backlight/brightness"
#define	DEV_KEY_MATRIX				"/dev/input/event0"

#define	POLL_IMMEDIATE								0


#define	MAXIMUM_NUMBER_OF_CONNECTORS				10
#define	MAXIMUM_NUMBER_OF_CONNECTOR_RESOURCE_BUFFER	20

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

typedef	struct
{
	int							Device;
	struct	fb_var_screeninfo	var;
	struct	fb_fix_screeninfo	fix;
} FrameBufferContext_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;

/*	Color
RGB Value   : ARGB8888 = (a << 24) | (b << 16) | (g << 8) | (r << 0)
Color Index : Index of Color
*/
void	frame_buffer_draw_pixel(FrameBuffer_t *pFrameBuffer,
								uint32_t X,
								uint32_t Y,
								uint32_t Color)
{
	void *	pTarget;

	if ( pFrameBuffer != (FrameBuffer_t *)0 )
	{
		if ( ( pFrameBuffer->ScreenWidth > X )
		 &&	( pFrameBuffer->ScreenHeight > Y ) )
		{
			switch ( pFrameBuffer->BitsPerPixel )
			{
			case	24:	/* RGB888 */
				pTarget = (void *)(pFrameBuffer->pBuffer + (Y * pFrameBuffer->ScreenWidth + X) * 3);
				*((unsigned char *)pTarget)     = (uint8_t)((Color >> 0) & 0x000000FF);
				*((unsigned char *)pTarget + 1) = (uint8_t)((Color >> 8) & 0x000000FF);
				*((unsigned char *)pTarget + 2) = (uint8_t)((Color >> 16) & 0x000000FF);
				break;

			case	16:	/* RGB565 */
				pTarget = (void *)(pFrameBuffer->pBuffer + (Y * pFrameBuffer->ScreenWidth + X) * 2);
				*((unsigned short *)pTarget) = (uint16_t)((Color & 0x0000001F) + ((Color >> 5) & 0x0000002F) + ((Color >> 11) & 0x0000001F));
				break;

			case	8:	/* Color Index */
				pTarget = (void *)(pFrameBuffer->pBuffer + Y * pFrameBuffer->ScreenWidth + X);
				*((uint8_t *)pTarget) = (uint8_t)(Color & 0x000000FF);
				break;

			case	32:	/* ARGB8888 */
			default:
				*(((uint32_t*)pFrameBuffer->pBuffer ) + Y * pFrameBuffer->ScreenWidth + X) = Color;
				break;
			}
		}
	}
}

void	frame_buffer_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)
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xffffff);
			}
			else if (x < 20 && (y > 20 && y < h - 20))
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xff);
			}
			else if (y < 20 && (x > 20 && x < w - 20))
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xff00);
			}
			else if (x > w - 20 && (y > 20 && y < h - 20))
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xff0000);
			}
			else if (y > h - 20 && (x > 20 && x < w - 20))
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xffff00);
			}
			else if (x == 20 || x == w - 20 ||
					y == 20 || y == h - 20)
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xffffff);
			}
			else if (x == y || w - x == h - y)
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0xff00ff);
			}
			else if (w - x == y || x == h - y)
			{
				frame_buffer_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);
				frame_buffer_draw_pixel(pFrameBuffer, x, y, c);
			}
			else
			{
				frame_buffer_draw_pixel(pFrameBuffer, x, y, 0);
			}
		}
	}
}

void	frame_buffer_clear_screen(FrameBuffer_t *pFrameBuffer)
{
	memset(pFrameBuffer->pBuffer, 0, pFrameBuffer->ByteSizeOfBuffer);
}



int		fb_open_device_mode(FrameBufferContext_t *pFrameBufferContext, int BitPerPixel)
{
	pFrameBufferContext->Device = open(DEV_LCD_FB, O_RDWR);
	if(pFrameBufferContext->Device < 0)
	{
		printf("Faile to open : %s \n", DEV_LCD_FB);
		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		fb_open_device(FrameBufferContext_t *pFrameBufferContext, int BitPerPixel)
{
	if ( BitPerPixel != 8 )
	{
		if ( fb_open_device_mode(pFrameBufferContext, 8) != 0 )
		{
			printf("Faile to open with 8bit: %s \n", DEV_LCD_FB);
			return	-1;
		}
		close(pFrameBufferContext->Device);
	}

	if ( fb_open_device_mode(pFrameBufferContext, BitPerPixel) != 0 )
	{
		printf("Faile to open with 24bit: %s \n", DEV_LCD_FB);
		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;
}

void	fb_test(void)
{
	FrameBufferContext_t	FrameBufferContext;
	FrameBuffer_t			FrameBuffer;

	FrameBuffer.BitsPerPixel = 24;
	printf("Opening frame buffer device `%s'\n", DEV_LCD_FB);
	if ( fb_open_device(&FrameBufferContext, FrameBuffer.BitsPerPixel) != 0 )
	{
		printf("Fail to Device Open\n");
		return;
	}
	FrameBuffer.ScreenHeight = FrameBufferContext.var.yres_virtual;
	FrameBuffer.ScreenWidth = FrameBufferContext.var.xres_virtual;
	FrameBuffer.ByteSizeOfBuffer = FrameBuffer.ScreenHeight * FrameBuffer.ScreenWidth * (FrameBuffer.BitsPerPixel / 8);
	FrameBuffer.pBuffer = mmap(0,
								FrameBuffer.ByteSizeOfBuffer,
								PROT_WRITE | PROT_READ,
								MAP_SHARED,
								FrameBufferContext.Device,
								0);

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

	printf("Display Test Pattern !\n");
	frame_buffer_test_pattern(&FrameBuffer);

	sleep(3);
/* End of... */
	printf("Clear Test Pattern !\n");
	frame_buffer_clear_screen(&FrameBuffer);
	munmap(	FrameBuffer.pBuffer,
			FrameBuffer.ByteSizeOfBuffer);

	close(FrameBufferContext.Device);
}


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;
}

int		drm_get_frame_buffer(FrameBuffer_t *pFrameBuffer,
								int Device,
								int BitsPerPixel,
								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 = BitsPerPixel;
			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->BitsPerPixel = BitsPerPixel;
			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;

			//	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;
}

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");

//		drmModeRmFB(fd, devp->fb_id);
//		memset( &dreq, 0, sizeof(dreq) );
//		dreq.handle = devp->handle;
//		drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq);

			return	0;
		}
	}

	return	-1;
}


/*
	drmGetCap() -> make error!!
	drmModeGetResources()
		-> ioctl(.., DRM_IOCTL_MODE_GETRESOURCES, ..)
	drmModeGetConnector()
		-> ioctl(.., DRM_IOCTL_MODE_GETCONNECTOR, ..)
	drmModeGetEncoder()
		-> ioctl(.., DRM_IOCTL_MODE_GETENCODER, ..)
	drmIoctl(.., DRM_IOCTL_MODE_CREATE_DUMB, ..)
		-> ioctl(.., DRM_IOCTL_MODE_CREATE_DUMB, ..)
	drmModeAddFB(.., width, height, DEPTH, BPP, pitch, handle, ..)
		-> ioctl(.., DRM_IOCTL_MODE_ADDFB, ..)
	drmIoctl(.., DRM_IOCTL_MODE_MAP_DUMB, ..)
		-> ioctl(.., DRM_IOCTL_MODE_MAP_DUMB, ..)
	drmModeSetCrtc(.., .., .., .., .., .., .., ..)
		-> ioctl(.., DRM_IOCTL_MODE_SETCRTC, ..)
*/
void	drm_test(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, 32/*BitsPerPixel*/, &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 < 2; j++)
		{
			for (ConnectorIndex = 0; ConnectorIndex < Resource.count_connectors; ConnectorIndex++)
			{
				frame_buffer_test_pattern(&pFrameBuffer[ConnectorIndex]);
				sleep(2);
				frame_buffer_clear_screen(&pFrameBuffer[ConnectorIndex]);
			}
		}

//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");
	}
	else
	{
		printf("DRM open Fail !\n");
	}
}


int	bright_set(const uint8_t Brightness)
{
	FILE *	pDeviceFile;
	char	pString[10] = {0};
	int		StringLength;

	pDeviceFile = fopen(DEV_LCD_BACKLIGHT, "w+");
	if ( pDeviceFile == (FILE *)0 )
	{
		printf("failed to open back light device : %s\n", DEV_LCD_BACKLIGHT);
		return	-1;
	}

	sprintf(pString, "%d", Brightness);
	StringLength = (int)strlen(pString);

	if ( fwrite(pString, StringLength, 1, pDeviceFile) < 0 )
	{
		return	-1;
	}

	fclose(pDeviceFile);

	return	0;
}

int bright_get(uint8_t *pBrightness)
{
	FILE *	pDeviceFile;
	char	pCommand[128] = {0};
	char	pString[10] = {0};

	char buf[10] = {0};
	int level = 0;

	if ( pBrightness == (uint8_t *)0 )
	{
		printf("bright_get : Input Parameter error\n");
		return	-1;
	}

	sprintf(pCommand, "cat %s", DEV_LCD_BACKLIGHT);
	pDeviceFile = popen(pCommand, "r");
	if ( pDeviceFile == (FILE *)0 )
	{
		return	-1;
	}

	while( fgets(pString, 10, pDeviceFile) );
	*pBrightness = (uint8_t)strtoul(pString, NULL, 10);

	fclose(pDeviceFile);

	return	0;
}



int		key_matrix_initialize(void)
{
	int	Device;

//	Device = 0;
	Device = open(DEV_KEY_MATRIX, O_RDONLY);

	if ( Device < 0 )
	{
		printf("failed to open - %s\n", DEV_KEY_MATRIX);
	}

	return	Device;
}

int		key_matrix_close(int DeviceFileDescriptor)
{
	if ( DeviceFileDescriptor < 0 )
	{
		return	-1;
	}

	close(DeviceFileDescriptor);
	return	0;
}

void	key_matrix_flush(int DeviceFileDescriptor)
{

#define	BUFFER_MAX	100
	char			pBuffer[BUFFER_MAX];
	struct	pollfd	Event;
	int				Result;

	Event.fd = DeviceFileDescriptor;
	Event.events = POLLIN;

	while(1)
	{
		if ( (Result = poll( (struct pollfd *)&Event, 1, POLL_IMMEDIATE)) < 0 )
		{
			return ;
		}
		else
		{
			if ( Result == 0 )
			{
				printf("time out\n");
				return ;
			}
			else
			{
				Result = read(DeviceFileDescriptor, pBuffer, BUFFER_MAX);
			}
		}
	}
}




int	main()
{
	uint8_t				Brightness;
	int					KeyDeviceFileDescriptor;
	struct	pollfd		Event;
	struct	input_event	Input;
	int					InputData;
	int					Result;


	if ( bright_get(&Brightness) != 0 )
	{
		printf("Fail to bright_get()\n");
	}
	else
	{
		printf("Brightness == %d\n", Brightness);
	}
	Brightness = 7;	/* */
	if( bright_set(Brightness) != 0 )
	{
		printf("Fail to bright_set(0)\n");
	}

	KeyDeviceFileDescriptor = key_matrix_initialize();
	if ( KeyDeviceFileDescriptor < 0 )
	{
		printf("Key Initialize Fail\n");
		return	-1;
	}
	key_matrix_flush(KeyDeviceFileDescriptor);

	do
	{
		Result = poll( (struct pollfd *)&Event, 1, POLL_IMMEDIATE);
		if ( Result > 0 )
		{
			Result = read(KeyDeviceFileDescriptor, &Input, sizeof(struct input_event));
			if ( Result != 0 )
			{
				Result = 0;
				switch(Input.type)
				{
				case	EV_SYN:
					switch (Input.code)
					{
					case	SYN_REPORT:
						printf("EV_SYN code : SYN_REPORT, value : %x\n", Input.value);
						break;
					case	SYN_CONFIG:
						printf("EV_SYN code : SYN_CONFIG, value : %x\n", Input.value);
						break;
					case	SYN_MT_REPORT:
						printf("EV_SYN code : SYN_MT_REPORT, value : %x\n", Input.value);
						break;
					case	SYN_DROPPED:
						printf("EV_SYN code : SYN_DROPPED, value : %x\n", Input.value);
						break;
					default:
						printf("EV_SYN code : %x, value : %x\n", Input.code, Input.value);
						break;
					}
					break;
				case	EV_KEY:
					switch (Input.code)
					{
					case	KEY_RESERVED:
						printf("EV_KEY code : KEY_RESERVED %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_ESC:
						printf("EV_KEY code : KEY_ESC %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_1:
						printf("EV_KEY code : KEY_1 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_2:
						printf("EV_KEY code : KEY_2 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_3:
						printf("EV_KEY code : KEY_3 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_4:
						printf("EV_KEY code : KEY_4 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_5:
						printf("EV_KEY code : KEY_5 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_6:
						printf("EV_KEY code : KEY_6 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_7:
						printf("EV_KEY code : KEY_7 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_8:
						printf("EV_KEY code : KEY_8 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_9:
						printf("EV_KEY code : KEY_9 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_0:
						printf("EV_KEY code : KEY_0 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_BACKSPACE:
						printf("EV_KEY code : KEY_BACKSPACE %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_ENTER:
						printf("EV_KEY code : KEY_ENTER %x, value : %x\n", Input.code, Input.value);
if(Input.value == 0)
{	/* Key Released */
	Result = 1;	/* Exit */
}
						break;
					case	KEY_F1:
						printf("EV_KEY code : KEY_F1 %x, value : %x\n", Input.code, Input.value);
if(Input.value == 0)
{	/* Key Released */
	printf("Test Symple FB Style\n");
	fb_test();
}
						break;
					case	KEY_F2:
						printf("EV_KEY code : KEY_F2 %x, value : %x\n", Input.code, Input.value);
if(Input.value == 0)
{	/* Key Released */
	printf("Test DRM Style\n");
	drm_test();
}
						break;
					case	KEY_F3:
						printf("EV_KEY code : KEY_F3 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_F4:
						printf("EV_KEY code : KEY_F4 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_F5:
						printf("EV_KEY code : KEY_F5 %x, value : %x\n", Input.code, Input.value);
						break;
					case	KEY_F6:
						printf("EV_KEY code : KEY_F6 %x, value : %x\n", Input.code, Input.value);
if(Input.value == 0)
{	/* Key Released */
	if( Brightness != 7 )
	{
		Brightness ++;
		if( bright_set(Brightness) != 0 )
		{
			printf("Fail to bright_set\n");
		}
		printf("bright -\n");
	}
}
						break;
					case	KEY_F7:
						printf("EV_KEY code : KEY_F7 %x, value : %x\n", Input.code, Input.value);
if(Input.value == 0)
{	/* Key Released */
	if( Brightness != 0 )
	{
		Brightness --;
		if( bright_set(Brightness) != 0 )
		{
			printf("Fail to bright_set\n");
		}
		printf("bright +\n");
	}
}
						break;
					default:
						break;
					}
					break;
				case	EV_REL:
					switch (Input.code)
					{
					case	REL_X:
						printf("EV_REL code : REL_X %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_Y:
						printf("EV_REL code : REL_Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_Z:
						printf("EV_REL code : REL_Z %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_RX:
						printf("EV_REL code : REL_RX %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_RY:
						printf("EV_REL code : REL_RY %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_RZ:
						printf("EV_REL code : REL_RZ %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_HWHEEL:
						printf("EV_REL code : REL_HWHEEL %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_DIAL:
						printf("EV_REL code : REL_DIAL %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_WHEEL:
						printf("EV_REL code : REL_WHEEL %x, value : %x\n", Input.code, Input.value);
						break;
					case	REL_MISC:
						printf("EV_REL code : REL_MISC %x, value : %x\n", Input.code, Input.value);
						break;
					default:
						printf("EV_REL code : %x, value : %x\n", Input.code, Input.value);
						break;
					}
					break;
				case	EV_ABS:
					switch (Input.code)
					{
					case	ABS_X:
						printf("EV_ABS code : ABS_X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_Y:
						printf("EV_ABS code : ABS_Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_Z:
						printf("EV_ABS code : ABS_Z %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_RX:
						printf("EV_ABS code : ABS_RX %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_RY:
						printf("EV_ABS code : ABS_RY %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_RZ:
						printf("EV_ABS code : ABS_RZ %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_THROTTLE:
						printf("EV_ABS code : ABS_THROTTLE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_RUDDER:
						printf("EV_ABS code : ABS_RUDDER %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_WHEEL:
						printf("EV_ABS code : ABS_WHEEL %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_GAS:
						printf("EV_ABS code : ABS_GAS %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_BRAKE:
						printf("EV_ABS code : ABS_BRAKE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT0X:
						printf("EV_ABS code : ABS_HAT0X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT0Y:
						printf("EV_ABS code : ABS_HAT0Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT1X:
						printf("EV_ABS code : ABS_HAT1X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT1Y:
						printf("EV_ABS code : ABS_HAT1Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT2X:
						printf("EV_ABS code : ABS_HAT2X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT2Y:
						printf("EV_ABS code : ABS_HAT2Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT3X:
						printf("EV_ABS code : ABS_HAT3X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_HAT3Y:
						printf("EV_ABS code : ABS_HAT3Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_PRESSURE:
						printf("EV_ABS code : ABS_PRESSURE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_DISTANCE:
						printf("EV_ABS code : ABS_DISTANCE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_TILT_X:
						printf("EV_ABS code : ABS_TILT_X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_TILT_Y:
						printf("EV_ABS code : ABS_TILT_Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_TOOL_WIDTH:
						printf("EV_ABS code : ABS_TOOL_WIDTH %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_VOLUME:
						printf("EV_ABS code : ABS_VOLUME %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MISC:
						printf("EV_ABS code : ABS_MISC %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_SLOT:	/* MT slot being modified */
						printf("EV_ABS code : ABS_MT_SLOT %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TOUCH_MAJOR:	/* Major axis of touching ellipse */
						printf("EV_ABS code : ABS_MT_TOUCH_MAJOR %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TOUCH_MINOR:	/* Minor axis (omit if circular) */
						printf("EV_ABS code : ABS_MT_TOUCH_MINOR %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_WIDTH_MAJOR:	/* Major axis of approaching ellipse */
						printf("EV_ABS code : ABS_MT_WIDTH_MAJOR %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_WIDTH_MINOR:	/* Minor axis (omit if circular) */
						printf("EV_ABS code : ABS_MT_WIDTH_MINOR %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_ORIENTATION:	/* Ellipse orientation */
						printf("EV_ABS code : ABS_MT_ORIENTATION %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_POSITION_X:	/* Center X touch position */
						printf("EV_ABS code : ABS_MT_POSITION_X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_POSITION_Y:	/* Center Y touch position */
						printf("EV_ABS code : ABS_MT_POSITION_Y %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TOOL_TYPE:	/* Type of touching device */
						printf("EV_ABS code : ABS_MT_TOOL_TYPE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_BLOB_ID:	/* Group a set of packets as a blob */
						printf("EV_ABS code : ABS_MT_BLOB_ID %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TRACKING_ID:	/* Unique ID of initiated contact */
						printf("EV_ABS code : ABS_MT_TRACKING_ID %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_PRESSURE:	/* Pressure on contact area */
						printf("EV_ABS code : ABS_MT_PRESSURE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_DISTANCE:	/* Contact hover distance */
						printf("EV_ABS code : ABS_MT_DISTANCE %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TOOL_X:	/* Center X tool position */
						printf("EV_ABS code : ABS_MT_TOOL_X %x, value : %x\n", Input.code, Input.value);
						break;
					case	ABS_MT_TOOL_Y:	/* Center Y tool position */
						printf("EV_ABS code : ABS_MT_TOOL_Y %x, value : %x\n", Input.code, Input.value);
						break;
					default:
						printf("EV_ABS code : %x, value : %x\n", Input.code, Input.value);
						break;
					}
					break;
				case	EV_MSC:
					switch (Input.code)
					{
					case	MSC_SERIAL:
						printf("EV_MSC code : MSC_SERIAL %x, value : %x\n", Input.code, Input.value);
						break;
					case	MSC_PULSELED:
						printf("EV_MSC code : MSC_PULSELED %x, value : %x\n", Input.code, Input.value);
						break;
					case	MSC_GESTURE:
						printf("EV_MSC code : MSC_GESTURE %x, value : %x\n", Input.code, Input.value);
						break;
					case	MSC_RAW:
						printf("EV_MSC code : MSC_RAW %x, value : %x\n", Input.code, Input.value);
						break;
					case	MSC_SCAN:
						printf("EV_MSC code : MSC_SCAN %x, value : %x\n", Input.code, Input.value);
						break;
					case	MSC_TIMESTAMP:
						printf("EV_MSC code : MSC_TIMESTAMP %x, value : %x\n", Input.code, Input.value);
						break;
					default:
						printf("EV_MSC code : %x, value : %x\n", Input.code, Input.value);
						break;
					}
					break;
				case	EV_SW:
				case	EV_LED:
				case	EV_SND:
				case	EV_REP:
				case	EV_FF:
				case	EV_PWR:
				case	EV_FF_STATUS:
				default:
					printf("type : %x, code: %x, value: %x\n", Input.type, Input.code, Input.value);
					break;
				}
			}
			else
			{
				Result = 0;
			}
		}
		else if ( Result == 0 )
		{
			/* Time-Out */
			;
		}
	} while ( Result <= 0 );

	key_matrix_close(KeyDeviceFileDescriptor);

	return	0;
}
/*
# modetest
trying to open device 'i915'...failed
trying to open device 'amdgpu'...failed
trying to open device 'radeon'...failed
trying to open device 'nouveau'...failed
trying to open device 'vmwgfx'...failed
trying to open device 'omapdrm'...failed
trying to open device 'exynos'...failed
trying to open device 'tilcdc'...failed
trying to open device 'msm'...failed
trying to open device 'sti'...failed
trying to open device 'tegra'...failed
trying to open device 'imx-drm'...failed
trying to open device 'rockchip'...failed
trying to open device 'atmel-hlcdc'...done
Encoders:
id      crtc    type    possible crtcs  possible clones
23      31      none    0x00000001      0x00000000

Connectors:
id      encoder status          name            size (mm)       modes   encoders
24      23      connected       unknown-1       49x65           1       23
  modes:
        name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
  240x320 70 240 250 270 280 320 322 326 328 6549 flags: phsync, pvsync; type: preferred, driver
  props:
        1 EDID:
                flags: immutable blob
                blobs:

                value:
        2 DPMS:
                flags: enum
                enums: On=0 Standby=1 Suspend=2 Off=3
                value: 0

CRTCs:
id      fb      pos     size
31      34      (0,0)   (240x320)
  240x320 70 240 250 270 280 320 322 326 328 6549 flags: phsync, pvsync; type: preferred, driver
  props:

Planes:
id      crtc    fb      CRTC x,y        x,y     gamma size      possible crtcs
27      31      34      0,0             0,0     0               0x00000001
  formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
  props:
        5 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 1
        26 rotation:
                flags: bitmask
                values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
                value: 1
28      0       0       0,0             0,0     0               0x00000001
  formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
  props:
        5 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 0
        25 alpha:
                flags: range
                values: 0 255
                value: 255
        26 rotation:
                flags: bitmask
                values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
                value: 1
29      0       0       0,0             0,0     0               0x00000001
  formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24
  props:
        5 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 0
        25 alpha:
                flags: range
                values: 0 255
                value: 255
        26 rotation:
                flags: bitmask
                values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
                value: 1
30      0       0       0,0             0,0     0               0x00000001
  formats: XR12 AR12 RA12 AR15 RG16 RG24 XR24 AR24 RA24 AYUV YUYV UYVY YVYU VYUY NV21 NV61 YU16 YU12
  props:
        5 type:
                flags: immutable enum
                enums: Overlay=0 Primary=1 Cursor=2
                value: 0
        25 alpha:
                flags: range
                values: 0 255
                value: 255
        26 rotation:
                flags: bitmask
                values: rotate-0=0x1 rotate-90=0x2 rotate-180=0x4 rotate-270=0x8
                value: 1

Frame buffers:
id      size    pitch

*/

