#include <unistd.h>
#include <sys/io.h>
#include <stdio.h>
#include <time.h>

#define IOBASE 0x378

#define TESTB(bit, word) (word & (1 << bit))
#define SETB(bit, word) (word |= (1 << bit))
#define UNSETB(bit, word) (word &= ~(1 << bit))

void msdelay(int ms) {
	usleep(1000 * ms);
}

void usage() {
	fprintf(stderr, "Commands:\n");
	fprintf(stderr, "\tq\t\tquit\n");
	fprintf(stderr, "\t?\t\tthis usage message\n");
	fprintf(stderr, "\tr\t\tRead status of port\n");
	fprintf(stderr, "\td <byte val>\tassign Data register\n");
	fprintf(stderr, "\tD <bit num>\ttoggle bit of Data register\n");
	fprintf(stderr, "\tc <byte val>\tassign Control register\n");
	fprintf(stderr, "\tC <bit num>\ttoggle bit of Control register\n");
}

void status() {
	int i;
	unsigned char d = inb(IOBASE);
	unsigned char c = inb(IOBASE+2);
	unsigned char s = inb(IOBASE+1);


	printf("D7 D6 D5 D4 D3 D2 D1 D0\n");
	for(i = 7; i > -1; i--) {
		printf(" %c ", (TESTB(i, d))?('1'):('0'));
	}
	printf("         (0x%.2X)\n\n", d);

	printf("/S7  S6  S5  S4  S3  S2  S1  S0\n");
	for(i = 7; i > -1; i--) {
		printf("  %c ", (TESTB(i, s))?('1'):('0'));
	}
	printf(" (0x%.2X)\n\n", s);

	printf(" C7  C6  C5  C4 /C3  C2 /C1 /C0\n");
	for(i = 7; i > -1; i--) {
		printf("  %c ", (TESTB(i, c))?('1'):('0'));
	}
	printf(" (0x%.2X)\n", c);
}

int main(int argc, char **argv) {
	int b, run = -1;
	char c;

	if(ioperm(IOBASE, 3, 1)) {
		perror("ioperm(1)");
		return -1;
	}

	fprintf(stderr, "parport> ");
	while(run) {
		if(scanf("%c", &c) < 1) break;
		switch(c) {
			case 'r':
			case 'R':
				status();
				break;
			case 'd':
				scanf("%i", &b);
				outb((0xff & b), IOBASE);
				break;
			case 'D':
				scanf("%i", &b);
				outb(0xff & (inb(IOBASE) ^ (1 << b)), IOBASE);
				break;
			case 'c':
				scanf("%i", &b);
				outb((0xff & b), IOBASE+2);
				break;
			case 'C':
				scanf("%i", &b);
				outb(0xff & (inb(IOBASE+2) ^ (1 << b)), IOBASE+2);
				break;
			case 'q':
				run = 0;
				continue;
			case '\n':
				break;
			case 'h':
			case '?':
			default:
				usage();
				break;
		}
		if(c != '\n') fprintf(stderr, "parport> ");
}
	fprintf(stderr, "\n");

	if(ioperm(IOBASE, 3, 0)) {
		perror("ioperm(0)");
		return -1;
	}
	return 0;
}
