/* 
    Linux HD44780 LCD driver
    (C) 2003 Lifejunkie
    justinsanemsu@hotmail.com

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    Contact: huntjas2@msu.edu

    This is for an LCD hooked up "Winamp style"
*/

#include <stdio.h>
#include <time.h>
#include <sys/io.h>
#include <sched.h>

#define lpt_data	     0x0378 // lpt port data
#define lpt_control    0x037A // lpt port control


// wait for the lcd
inline void lcd_pause ( int usecs )
{
	struct timespec delay_time,remaining;

	delay_time.tv_sec = 0;
	delay_time.tv_nsec = usecs * 1000;
	while ( nanosleep(&delay_time,&remaining) == -1 )
	{
		delay_time.tv_sec  = remaining.tv_sec;
		delay_time.tv_nsec = remaining.tv_nsec;
	}
}


// send a command to the lcd
void inline lcd_command(unsigned char command)
{
	outb(command, lpt_data); //set data
	outb(0x02, lpt_control); // toggle strobe
	outb(0x03, lpt_control);
}

// send some data to the lcd
void inline lcd_data(char data)
{
	outb(data, lpt_data);    // set data
	outb(0x06, lpt_control); // toggle strobe
	outb(0x07, lpt_control);
	lcd_pause(80);		 // wait for the lcd
}

// send a raw string to the lcd
void lcd_string(char *str)
{
    while (*str)
        lcd_data(*str++);
}
		
// Cut a string to the max line size and skip a line
void lcd_string_pad40(char *data)
{
    int count = 0;
    char ch;

    // send the string
    while ((ch = data[count]) && (count < 20))
    {
	lcd_data(ch);
        count++;
    }

    // pad
    while(count < 40)
    {
       lcd_data(' ');
       count++;
    }
}

// Cut a string to the max line size and skip a line
void lcd_string_pad20(char *data)
{
    int count = 0;
    char ch;

    // send the string
    while ((ch = data[count]) && (count < 20))
    {
	lcd_data(ch);
        count++;
    }

    // pad
    while(count < 20)
    {
       lcd_data(' ');
       count++;
    }
}



// init the lcd
int lcd_init( void )
{
    // Raise the priority
    struct sched_param param;

    param.sched_priority=1;
    
    if (sched_setscheduler(0, SCHED_RR, &param) == -1) 
    {
	    printf("Unable to set priority\n");
	    return(-1);
    }
    
    // get permission to use the port
    ioperm(lpt_data, 3, 255);


    // 4 line 20 char init sequence
    lcd_command(0x38);
    lcd_pause(4000);

    lcd_command(0x0c);
    lcd_pause(4000);

    lcd_command(0x01);
    lcd_pause(4000);

    return(0);
}


