📄 bpp.c
字号:
/* * 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 <linux/devfs_fs_kernel.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 100static 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 3enum 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; /* These members manage timeouts for programmed delays */ wait_queue_head_t wait_queue; struct timer_list timer_list;};static struct inst instances[BPP_NO];#if defined(__i386__)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#define BPP_TCR 0x15#define BPP_OR 0x16#define BPP_IR 0x17#define BPP_ICR 0x18#define BPP_SIZE 0x1A/* BPP_CSR. Bits of type RW1 are cleared with writting '1'. */#define P_DEV_ID_MASK 0xf0000000 /* R */#define P_DEV_ID_ZEBRA 0x40000000#define P_DEV_ID_L64854 0xa0000000 /* == NCR 89C100+89C105. Pity. */#define P_NA_LOADED 0x08000000 /* R NA wirtten but was not used */#define P_A_LOADED 0x04000000 /* R */#define P_DMA_ON 0x02000000 /* R DMA is not disabled */#define P_EN_NEXT 0x01000000 /* RW */#define P_TCI_DIS 0x00800000 /* RW TCI forbidden from interrupts */#define P_DIAG 0x00100000 /* RW Disables draining and resetting of P-FIFO on loading of P_ADDR*/#define P_BURST_SIZE 0x000c0000 /* RW SBus burst size */#define P_BURST_8 0x00000000#define P_BURST_4 0x00040000#define P_BURST_1 0x00080000 /* "No burst" write */#define P_TC 0x00004000 /* RW1 Term Count, can be cleared when P_EN_NEXT=1 */#define P_EN_CNT 0x00002000 /* RW */#define P_EN_DMA 0x00000200 /* RW */#define P_WRITE 0x00000100 /* R DMA dir, 1=to ram, 0=to port */#define P_RESET 0x00000080 /* RW */#define P_SLAVE_ERR 0x00000040 /* RW1 Access size error */#define P_INVALIDATE 0x00000020 /* W Drop P-FIFO */#define P_INT_EN 0x00000010 /* RW OK to P_INT_PEND||P_ERR_PEND */#define P_DRAINING 0x0000000c /* R P-FIFO is draining to memory */#define P_ERR_PEND 0x00000002 /* R */#define P_INT_PEND 0x00000001 /* R *//* BPP_HCR. Time is in increments of SBus clock. */#define P_HCR_TEST 0x8000 /* Allows buried counters to be read */#define P_HCR_DSW 0x7f00 /* Data strobe width (in ticks) */#define P_HCR_DDS 0x007f /* Data setup before strobe (in ticks) *//* BPP_OCR. */#define P_OCR_MEM_CLR 0x8000#define P_OCR_DATA_SRC 0x4000 /* ) */#define P_OCR_DS_DSEL 0x2000 /* ) Bidirectional */#define P_OCR_BUSY_DSEL 0x1000 /* ) selects */#define P_OCR_ACK_DSEL 0x0800 /* ) */#define P_OCR_EN_DIAG 0x0400#define P_OCR_BUSY_OP 0x0200 /* Busy operation */#define P_OCR_ACK_OP 0x0100 /* Ack operation */#define P_OCR_SRST 0x0080 /* Reset state machines. Not selfcleaning. */#define P_OCR_IDLE 0x0008 /* PP data transfer state machine is idle */#define P_OCR_V_ILCK 0x0002 /* Versatec faded. Zebra only. */#define P_OCR_EN_VER 0x0001 /* Enable Versatec (0 - enable). Zebra only. *//* BPP_TCR */#define P_TCR_DIR 0x08#define P_TCR_BUSY 0x04#define P_TCR_ACK 0x02#define P_TCR_DS 0x01 /* Strobe *//* BPP_OR */#define P_OR_V3 0x20 /* ) */#define P_OR_V2 0x10 /* ) on Zebra only */#define P_OR_V1 0x08 /* ) */#define P_OR_INIT 0x04#define P_OR_AFXN 0x02 /* Auto Feed */#define P_OR_SLCT_IN 0x01/* BPP_IR */#define P_IR_PE 0x04#define P_IR_SLCT 0x02#define P_IR_ERR 0x01/* BPP_ICR */#define P_DS_IRQ 0x8000 /* RW1 */#define P_ACK_IRQ 0x4000 /* RW1 */#define P_BUSY_IRQ 0x2000 /* RW1 */#define P_PE_IRQ 0x1000 /* RW1 */#define P_SLCT_IRQ 0x0800 /* RW1 */#define P_ERR_IRQ 0x0400 /* RW1 */#define P_DS_IRQ_EN 0x0200 /* RW Always on rising edge */#define P_ACK_IRQ_EN 0x0100 /* RW Always on rising edge */#define P_BUSY_IRP 0x0080 /* RW 1= rising edge */#define P_BUSY_IRQ_EN 0x0040 /* RW */#define P_PE_IRP 0x0020 /* RW 1= rising edge */#define P_PE_IRQ_EN 0x0010 /* RW */#define P_SLCT_IRP 0x0008 /* RW 1= rising edge */#define P_SLCT_IRQ_EN 0x0004 /* RW */#define P_ERR_IRP 0x0002 /* RW1 1= rising edge */#define P_ERR_IRQ_EN 0x0001 /* RW */unsigned long base_addrs[BPP_NO];#define bpp_outb_p(data, base) sbus_writeb(data, (base) + BPP_DR)#define bpp_inb_p(base) sbus_readb((base) + BPP_DR)#define bpp_inb(base) sbus_readb((base) + BPP_DR)static void set_pins(unsigned short pins, unsigned minor){ unsigned long base = base_addrs[minor]; unsigned char bits_tcr = 0, bits_or = 0; if (instances[minor].direction & 0x20) bits_tcr |= P_TCR_DIR; if ( pins & BPP_PP_nStrobe) bits_tcr |= P_TCR_DS; if ( pins & BPP_PP_nAutoFd) bits_or |= P_OR_AFXN; if (! (pins & BPP_PP_nInit)) bits_or |= P_OR_INIT; if (! (pins & BPP_PP_nSelectIn)) bits_or |= P_OR_SLCT_IN; sbus_writeb(bits_or, base + BPP_OR); sbus_writeb(bits_tcr, base + BPP_TCR);}/* * i386 people read output pins from a software image. * We may get them back from hardware. * Again, inversion of pins must he buried here. */static unsigned short get_pins(unsigned minor){ unsigned long base = base_addrs[minor]; unsigned short bits = 0; unsigned value_tcr = sbus_readb(base + BPP_TCR); unsigned value_ir = sbus_readb(base + BPP_IR); unsigned value_or = sbus_readb(base + BPP_OR); if (value_tcr & P_TCR_DS) bits |= BPP_PP_nStrobe; if (value_or & P_OR_AFXN) bits |= BPP_PP_nAutoFd; if (! (value_or & P_OR_INIT)) bits |= BPP_PP_nInit; if (! (value_or & P_OR_SLCT_IN)) bits |= BPP_PP_nSelectIn; if (value_ir & P_IR_ERR) bits |= BPP_GP_nFault; if (! (value_ir & P_IR_SLCT)) bits |= BPP_GP_Select; if (! (value_ir & P_IR_PE)) bits |= BPP_GP_PError; if (! (value_tcr & P_TCR_ACK)) bits |= BPP_GP_nAck; if (value_tcr & P_TCR_BUSY) bits |= BPP_GP_Busy; return bits;}#endif /* __sparc__ */static void bpp_wake_up(unsigned long val){ wake_up(&instances[val].wait_queue); }static void snooze(unsigned long snooze_time, unsigned minor){ init_timer(&instances[minor].timer_list); instances[minor].timer_list.expires = jiffies + snooze_time + 1; instances[minor].timer_list.data = minor; add_timer(&instances[minor].timer_list); sleep_on (&instances[minor].wait_queue);}static int wait_for(unsigned short set, unsigned short clr, unsigned long delay, unsigned minor){ unsigned short pins = get_pins(minor); unsigned long extime = 0; /* * Try a real fast scan for the first jiffy, in case the device * responds real good. The first while loop guesses an expire * time accounting for possible wraparound of jiffies. */ while (time_after_eq(jiffies, extime)) extime = jiffies + 1; while ( (time_before(jiffies, extime)) && (((pins & set) != set) || ((pins & clr) != 0)) ) { pins = get_pins(minor); } delay -= 1; /* * If my delay expired or the pins are still not where I want * them, then resort to using the timer and greatly reduce my * sample rate. If the peripheral is going to be slow, this will * give the CPU up to some more worthy process. */ while ( delay && (((pins & set) != set) || ((pins & clr) != 0)) ) { snooze(1, minor); pins = get_pins(minor); delay -= 1; } if (delay == 0) return -1; else return pins;}/* * Return ZERO(0) If the negotiation succeeds, an errno otherwise. An * errno means something broke, and I do not yet know how to fix it. */static int negotiate(unsigned char mode, unsigned minor){ int rc; unsigned short pins = get_pins(minor); if (pins & BPP_PP_nSelectIn) return -EIO; /* Event 0: Write the mode to the data lines */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -