#if !defined(__KERNEL__)
#include <sys/io.h>
#include <errno.h>
#else
#include <asm/io.h>
#endif
#include "hal_parport.h"
int ioaddr = 0x378;
int ioaddr_hi = 0;
int epp_wide = 1;
int watchdog = 1;
struct hal_parport_t portdata;
RTAPI_MP_INT(ioaddr, "Address of parallel port where pluto-p is attached");
RTAPI_MP_INT(ioaddr_hi,
"Secondary address of parallel port (0 to use ioaddr+0x400)");
RTAPI_MP_INT(epp_wide, "Use 16- and 32-bit EPP transfers with hardware EPP");
RTAPI_MP_INT(watchdog,
"Enable hardware watchdog to tristate outputs if EMC crashes");
#ifndef llabs
static int64_t llabs(int64_t l) { if(l < 0) return -l; return l; }
#endif
static inline int64_t extend(int64_t old, int newlow, int nbits) {
int64_t mask = (1<<nbits) - 1;
int64_t maxdelta = mask / 2;
int64_t oldhigh = old & ~mask;
int64_t oldlow = old & mask;
int64_t candidate1, candidate2;
candidate1 = oldhigh | newlow;
if(oldlow < newlow) candidate2 = candidate1 - (1<<nbits);
else candidate2 = candidate1 + (1<<nbits);
if (llabs(old-candidate1) > maxdelta)
return candidate2;
else
return candidate1;
}
static inline void EPP_DIR_WRITE(void) { }
static inline void EPP_DIR_READ(void) { }
static inline void EPP_ADDR(int w) {
outb(w, ioaddr+3);
}
static inline void EPP_WRITE(int w) {
outb(w, ioaddr+4);
}
static inline int EPP_READ(void) {
return inb(ioaddr+4);
}
static inline __u32 read32(void) {
unsigned char a, b, c, d;
if(epp_wide)
return inl(ioaddr+4);
a = EPP_READ();
b = EPP_READ();
c = EPP_READ();
d = EPP_READ();
return a + (b<<8) + (c<<16) + (d<<24);
}
static inline void write32(long w) {
if(epp_wide) {
outl(w, ioaddr+4);
return;
}
EPP_WRITE(w);
EPP_WRITE(w >> 8);
EPP_WRITE(w >> 16);
EPP_WRITE(w >> 24);
}
static inline void write16(int w) {
if(epp_wide) {
outw(w, ioaddr+4);
return;
}
EPP_WRITE(w & 0xff);
EPP_WRITE(w >> 8);
}
#define FIRMWARE_SIZE 19895
static void pluto_program(unsigned char firmware[FIRMWARE_SIZE]) {
int byte, bit;
int i;
rtapi_print_msg(RTAPI_MSG_INFO, "uploading firmware\n");
for(i=0; i<4; i++) outb(0, ioaddr+2);
for(i=0; i<20; i++) outb(4, ioaddr+2);
for(byte = 0; byte < FIRMWARE_SIZE; byte++) {
for(bit = 0; bit < 8; bit++) {
int v = firmware[byte] & (1<<bit);
if(v) outb(0xff, ioaddr); else outb(0, ioaddr);
outb(0|4, ioaddr+2);
outb(1|4, ioaddr+2);
outb(0|4, ioaddr+2);
}
}
rtapi_print_msg(RTAPI_MSG_INFO, "done\n");
}
static void pluto_clear_error_register(void) {
int r = inb(ioaddr+1);
outb (r | 0x01, ioaddr+1);
outb (r & 0xfe, ioaddr+1);
}
static void pluto_cleanup(void) {
hal_parport_release(&portdata);
}
static int pluto_setup(unsigned char *firmware) {
int retval = hal_parport_get(comp_id, &portdata, ioaddr, ioaddr_hi,
PARPORT_MODE_EPP);
int status;
if(retval < 0)
return retval;
ioaddr = portdata.base;
ioaddr_hi = portdata.base_hi;
outb(4, ioaddr + 2); if(ioaddr_hi != -1)
outb(0, ioaddr_hi + 0x2); pluto_program(firmware);
if(ioaddr_hi != -1) {
outb(0x80, ioaddr_hi + 0x2); }
pluto_clear_error_register();
EPP_ADDR(0);
EPP_DIR_READ();
EPP_READ();
status = inb(ioaddr+1) & 1;
if(status) {
rtapi_print_msg(RTAPI_MSG_ERR, "Failed to communicate with pluto-servo board after programming firmware.\n");
return -EIO;
}
return 0;
}