/*
Softwareroutinen zur Ansteuerung eines LCD Displays am Paralellport eines PCs

Anschluss des Modules am ParPort:

ParPort		Beschreibung	LCDModul	LCD-Pin
18-25		GND				GND			1 -|
							R/W			5 -|-- Brücke
			+5V				Vcc			2
1			-STROBE			EN			6
2			D0				D0			7
3			D1				D1			8
4			D2				D2			9
5			D3				D3			10
6			D4				D4			11
7			D5				D5			12
8			D6				D6			13
9			D7				D7			14
14			Autofeed		RS			4

Kontrast Pin3 auf Masse sorgt für vollen Kontrast.
GND und +5V können mit einem Pfostenstecker (2Pin) von einem freien
Floppy Stromanschluss besorgt werden.

Das an die Funktion mylcdprint übergebene Array of Char muss immer mit einem
Unterstrich ('_') abgeschlossen werden. Kann aber auch sehr einfach abgeändert werden,
z.B. auf Ascii-0.

*/

#include <stdio.h>
#include <unistd.h>
#include <asm/io.h>

#define LP_DATA 0x378		// Datenport von lp1
#define LP_CONTROL 0x378+2	// CONTROL-Port von lp1

// +++++++++++++++++++ Begin der Funktion initlcd() zur Initialisierung des LCDs ++++++++++++++++++
// LCD initialisieren für 8Bit Modus

void initlcd()
{
	/* begin funktion set */
  	set_command();
  	outb(0x38, LP_DATA); /* 00111000 */
	cycle_enable();

	/* begin display on */
	outb(0x0e, LP_DATA); /* 00001110 */
	cycle_enable();

	/* begin entry mode */
	outb(0x06, LP_DATA); /* 00000110 */
	cycle_enable();
  
	/* begin clear display */
	outb(0x01, LP_DATA); /* 00000001 */
	cycle_enable();
	return;
}


/* ++++++++++ Beginn der Funktionen printret2() und printret2() und hidecr() zur positionierung des Cursors im Display +++++++ */
int printret1(void)
{
	/* Cursor auf Position 00 im display */
	set_command();
	outb(0x80, LP_DATA);
	cycle_enable();
	return 0;
}

int printret2(void)
{
	/* Cursor auf Position 40 im display */
	set_command();
	outb(0xc0, LP_DATA);
	cycle_enable();
	return 0;
}

int hidecr(void)
{
  /* Cursor auf Position 62 im display */
	set_command();
	outb(0xd4, LP_DATA);
	cycle_enable();
	return 0;
}


/* +++++++++++++++++++++ Beginn der Funktion mylcdprint() ++++++++++++++++++++++++++ */
void mylcdprint (char *ausgabetext)
{
	int zeiger = 0;
	set_data();
	while ( ausgabetext[zeiger] != '_' )
	{
		outb(ausgabetext[zeiger], LP_DATA);
		cycle_enable();
		zeiger++;
	}
}

int cycle_enable(void)
{
	outb((inb(LP_CONTROL) & 0xfe), LP_CONTROL);	// SET Enable to 0 (negiert) (ControlBit0)
	micro_sleep(1500);
	outb( inb(LP_CONTROL) | 0x01, LP_CONTROL);	// Clear Enable to 1 (negiert)
	return 0;
}

int set_data(void)
{
	outb(0x00, LP_DATA);
	outb( inb(LP_CONTROL) | 0x01, LP_CONTROL);	// Clear Enable (negiert)
	outb((inb(LP_CONTROL) & 0xfd), LP_CONTROL);	// SET RS to 0 (negiert) (ControlBit0)
	return 0;
}

int set_command(void)
{
	outb(0x00, LP_DATA);
	outb( inb(LP_CONTROL) | 0x01, LP_CONTROL);	// Clear Enable (negiert)
	outb((inb(LP_CONTROL) | 0x02), LP_CONTROL);	// Clear RS to 1 (negiert) (ControlBit0)
	return 0;
}

int micro_sleep(int usec)
{
	while(usec > 0)
	{
		inb(LP_DATA);
		usec--;
	}
	return 0;
}
