/*
* drivers/sbus/char/bpp.c
*
* Copyright (c) 1995 Picture Elements
* Stephen Williams (steve@icarus.com)
* Gus Baldauf (gbaldauf@ix.netcom.com)
*
* Linux/SPARC port by Peter Zaitcev.
* Integration into SPARC tree by Tom Dyas.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/major.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#if defined(__i386__)
# include <asm/system.h>
#endif
#if defined(__sparc__)
# include <linux/init.h>
# include <linux/delay.h> /* udelay() */
# include <asm/oplib.h> /* OpenProm Library */
# include <asm/sbus.h>
#endif
#include <asm/bpp.h>
#define BPP_PROBE_CODE 0x55
#define BPP_DELAY 100
static const unsigned BPP_MAJOR = LP_MAJOR;
static const char* dev_name = "bpp";
/* When switching from compatibility to a mode where I can read, try
the following mode first. */
/* const unsigned char DEFAULT_ECP = 0x10; */
static const unsigned char DEFAULT_ECP = 0x30;
static const unsigned char DEFAULT_NIBBLE = 0x00;
/*
* These are 1284 time constraints, in units of jiffies.
*/
static const unsigned long TIME_PSetup = 1;
static const unsigned long TIME_PResponse = 6;
static const unsigned long TIME_IDLE_LIMIT = 2000;
/*
* One instance per supported subdevice...
*/
# define BPP_NO 3
enum IEEE_Mode { COMPATIBILITY, NIBBLE, ECP, ECP_RLE, EPP };
struct inst {
unsigned present : 1; /* True if the hardware exists */
unsigned enhanced : 1; /* True if the hardware in "enhanced" */
unsigned opened : 1; /* True if the device is opened already */
unsigned run_flag : 1; /* True if waiting for a repeate byte */
unsigned char direction; /* 0 --> out, 0x20 --> IN */
unsigned char pp_state; /* State of host controlled pins. */
enum IEEE_Mode mode;
unsigned char run_length;
unsigned char repeat_byte;
};
static struct inst instances[BPP_NO];
#if defined(__i386__)
static const unsigned short base_addrs[BPP_NO] = { 0x278, 0x378, 0x3bc };
/*
* These are for data access.
* Control lines accesses are hidden in set_bits() and get_bits().
* The exception is the probe procedure, which is system-dependent.
*/
#define bpp_outb_p(data, base) outb_p((data), (base))
#define bpp_inb(base) inb(base)
#define bpp_inb_p(base) inb_p(base)
/*
* This method takes the pin values mask and sets the hardware pins to
* the requested value: 1 == high voltage, 0 == low voltage. This
* burries the annoying PC bit inversion and preserves the direction
* flag.
*/
static void set_pins(unsigned short pins, unsigned minor)
{
unsigned char bits = instances[minor].direction; /* == 0x20 */
if (! (pins & BPP_PP_nStrobe)) bits |= 1;
if (! (pins & BPP_PP_nAutoFd)) bits |= 2;
if ( pins & BPP_PP_nInit) bits |= 4;
if (! (pins & BPP_PP_nSelectIn)) bits |= 8;
instances[minor].pp_state = bits;
outb_p(bits, base_addrs[minor]+2);
}
static unsigned short get_pins(unsigned minor)
{
unsigned short bits = 0;
unsigned value = instances[minor].pp_state;
if (! (value & 0x01)) bits |= BPP_PP_nStrobe;
if (! (value & 0x02)) bits |= BPP_PP_nAutoFd;
if (value & 0x04) bits |= BPP_PP_nInit;
if (! (value & 0x08)) bits |= BPP_PP_nSelectIn;
value = inb_p(base_addrs[minor]+1);
if (value & 0x08) bits |= BPP_GP_nFault;
if (value & 0x10) bits |= BPP_GP_Select;
if (value & 0x20) bits |= BPP_GP_PError;
if (value & 0x40) bits |= BPP_GP_nAck;
if (! (value & 0x80)) bits |= BPP_GP_Busy;
return bits;
}
#endif /* __i386__ */
#if defined(__sparc__)
/*
* Register block
*/
/* DMA registers */
#define BPP_CSR 0x00
#define BPP_ADDR 0x04
#define BPP_BCNT 0x08
#define BPP_TST_CSR 0x0C
/* Parallel Port registers */
#define BPP_HCR 0x10
#define BPP_OCR 0x12
#define BPP_DR 0x14
#def