/*
Copyright (C) 2002 Pedro Zorzenon Neto <pzn@vztech.com.br>

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.

Do not forget to visit Free Software Foundation site: http://fsf.org

$Id: parport.c,v 1.2 2003/06/30 17:20:25 pzn Exp $
*/
#include "common.h"
#include "parport.h"
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>

#ifdef __linux__
#  include <sys/io.h>
#  include <unistd.h>
#  include <sys/types.h>
#endif

#ifdef __dos__
#  include <dos.h>
#endif

#include "mcdelay.h"

parport_t * parport_init (long int base_address) {
  parport_t * self;

  self=malloc(sizeof(parport_t));
  assert(self!=NULL);
  self->base_address=base_address;
  self->last_write=~0;
#ifdef __linux__
  if (geteuid()!=0) {
    fprintf(stderr,"ERROR: this programs needs root permisions to access parallel port. Please use root user to run or setuid bit.\n");
    abort();
  }
  ioperm(self->base_address,3,1);
#endif
  return self;
}

void parport_destroy (parport_t * self) {
  if (self!=NULL) {
#ifdef __linux__
    ioperm(self->base_address,3,0);
#endif
    free(self);
  }
}

int parport_readbit (parport_t * self, int bit) {
  int i;
  i=parport_readbyte (self);
  if (i & (0x01<<bit))
    return 1;
  return 0;
}
unsigned int parport_readbyte (parport_t * self) {
#ifdef __linux__
  return (unsigned int) inb(self->base_address+1);
#endif
#ifdef __dos__
  return (unsigned int) inportb (self->base_address+1);
#endif
}

void parport_writebit (parport_t * self, int bit, unsigned value) {
  int i;
  i=self->last_write;
  if (value) {
    i|=(0x01<<bit);
  } else {
    i&=~(0x01<<bit);
  }
  parport_writebyte (self, i);
}

void parport_writebyte (parport_t * self, unsigned int value) {
#ifdef __linux__
  if ((value&0xFF) != (self->last_write&0xFF))
    outb(value&0xFF,self->base_address);
  if ((value&0xF00) != (self->last_write&0xF00))
      outb((value>>8)&0x0F,self->base_address+2);
#endif
#ifdef __dos__
  if ((value&0xFF) != (self->last_write&0xFF))
    outportb(self->base_address,value&0xFF);
  if ((value&0xF00) != (self->last_write&0xF00))
    outportb(self->base_address+2,(value>>8)&0x0F);
#endif
  self->last_write=value;
}

#ifdef TEST
int main() {
    parport_t * pp;
    unsigned int i, j;
    pp=parport_init(0x378);
    i=parport_readbyte(pp);
    j=0; if (i & PARPORT_ERROR) j=1;
    printf("status ERROR    %d\n",j);
    j=0; if (i & PARPORT_SELECTIN) j=1;
    printf("status SELECTIN %d\n",j);
    j=0; if (i & PARPORT_PAPEROUT) j=1;
    printf("status PAPEROUT %d\n",j);
    j=0; if (i & PARPORT_ACK) j=1;
    printf("status ACK      %d\n",j);
    j=0; if (i & PARPORT_BUSY) j=1;
    printf("status BUSY     %d\n",j);

    parport_destroy(pp);
    return 0;
}
#endif
