/* grfconfig.c
 *

NAME
    grfconfig - show and configure graphics device parameters

SYNOPSIS
    grfconfig [-d dev] [-l] [file] 

DESCRIPTION
    grfconfig is used to add/show monitor definitions in the internal
    database of a 'grf' driver.  The monitor definitions are taken
    from a file which has lines in the format:

    num clock wid hi dep hbs hss hse hbe ht vbs vss vse vbe vt

    grfconfig takes the following arguments:

    -d	    	Add/Show monitor database entries for the device
		specified. (ie. -d /dev/grf3)

    -l 	    	List the current monitor database.  The database
		for the specfied device will be listed after
		any modes are loaded from a definition file.

    -v	    	WHen listing the monitor database, list the
		real monitor entries as well as the user-friendly
		description.

    A filename which contains monitor definitions.  

CAVEATS

    Currently only grf_cl (grf3) supports a monitor database, and it
    only supports a maximu of 8 entries. (mode num 1-8).  

 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/ioctl.h>

#include <grfioctl.h>

extern char *optarg;
extern int optind;

/*
 * Yes, this code is really hacky.  I'll fix it sometime when I
 * feel really motivated. :-)
 */
int
main(ac,av)
int ac;
char **av;
{
	FILE *fp;
	char *conffile;
	char *grfdev, *cmd;
	struct grfvideo_mode gfvm, *gv;
	int x,y,grffd,dolist,verbose;
	char buf[350],c;

	gv = &gfvm;
	cmd = av[0];
	conffile = 0;
	grfdev = 0;
	dolist = 0;
	verbose = 0;


	while((c = getopt(ac, av, "d:lv")) != -1) {
		switch(c) {
		case 'd':
			grfdev = optarg;
			break;
		case 'l':
			dolist = 1;
			break;
		case 'v':
			verbose = 1;
			break;
		default:
			printf ("%s [-d dev] [-l] [-v] [file]\n", cmd);
			return(0);
		}
	}
	ac -= optind;
	av += optind;

	if (ac == 1)
		conffile = *av;

	if ((grffd = open(grfdev, O_RDWR)) < 0) {
		printf("%s: can't open grf device.\n", cmd);
		return(1);
	}

	if (!conffile) goto skip1;  /* yes, nasty..but I'm tired */

	if (fp = fopen(conffile, "r")) {
		while (fgets(buf, 300, fp)) {
			if (buf[0] == '#')
				continue;
			x = sscanf(buf, "%d %d %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd %hd",
				&y,
				&gv->pixel_clock,
				&gv->disp_width,
				&gv->disp_height,
				&gv->depth,
				&gv->hblank_start,
				&gv->hsync_start,
				&gv->hsync_stop,
				&gv->hblank_stop,
				&gv->htotal,
				&gv->vblank_start,
				&gv->vsync_start,
				&gv->vsync_stop,
				&gv->vblank_stop,
				&gv->vtotal
				);
			gv->mode_num = y;
			gv->mode_descr[0] = 0;
			if (x == 15) {
				if (ioctl(grffd, GRFIOCSETMON, (char *)gv) < 0)
					printf("%s: ioctl failed\n",cmd);
			} else {
				printf("%s: bad monitor definition\n", cmd);
			} 
				
		}
		fclose(fp);
	} else {
		printf("%s: Cannot open configuration file.\n",cmd);
		close(grffd);
		return(1);
	}

skip1:
	if (dolist) {
		ioctl(grffd, GRFGETNUMVM, &y);
		y++;
		for (x=1;x<y;x++) {
			gv->mode_num = x;
			if (ioctl(grffd, GRFGETVMODE, gv) >= 0) {
				printf("%d: %dx%dx%d\t%d.%dkHz @ %dHz %s\n",
				gv->mode_num,
				gv->disp_width,
				gv->disp_height,
				gv->depth,
				gv->pixel_clock / (gv->htotal*8000),
				(gv->pixel_clock / (gv->htotal*800)) % 10,
				gv->pixel_clock / (gv->htotal*gv->vtotal*8),
				gv->vblank_start + 100 < gv->disp_height ?
				  "I" :
				  (gv->vblank_start - 100) > gv->disp_height ?
				  "SD" :
				  "NI"
				);
			    
				if (verbose) {
				printf("%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
				gv->mode_num,
				gv->pixel_clock,
				gv->disp_width,
				gv->disp_height,
				gv->depth,
				gv->hblank_start,
				gv->hsync_start,
				gv->hsync_stop,
				gv->hblank_stop,
				gv->htotal,
				gv->vblank_start,
				gv->vsync_start,
				gv->vsync_stop,
				gv->vblank_stop,
				gv->vtotal
				);
				}
			}
		}
	}
    
	close(grffd);
	return(0);
}
