162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Low-level parallel-port routines for 8255-based PC-style hardware. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Authors: Phil Blundell <philb@gnu.org> 562306a36Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> 662306a36Sopenharmony_ci * Jose Renau <renau@acm.org> 762306a36Sopenharmony_ci * David Campbell 862306a36Sopenharmony_ci * Andrea Arcangeli 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Cleaned up include files - Russell King <linux@arm.uk.linux.org> 1362306a36Sopenharmony_ci * DMA support - Bert De Jonghe <bert@sophis.be> 1462306a36Sopenharmony_ci * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 1562306a36Sopenharmony_ci * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 1662306a36Sopenharmony_ci * Various hacks, Fred Barnes, 04/2001 1762306a36Sopenharmony_ci * Updated probing logic - Adam Belay <ambx1@neo.rr.com> 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* This driver should work with any hardware that is broadly compatible 2162306a36Sopenharmony_ci * with that in the IBM PC. This applies to the majority of integrated 2262306a36Sopenharmony_ci * I/O chipsets that are commonly available. The expected register 2362306a36Sopenharmony_ci * layout is: 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * base+0 data 2662306a36Sopenharmony_ci * base+1 status 2762306a36Sopenharmony_ci * base+2 control 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * In addition, there are some optional registers: 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * base+3 EPP address 3262306a36Sopenharmony_ci * base+4 EPP data 3362306a36Sopenharmony_ci * base+0x400 ECP config A 3462306a36Sopenharmony_ci * base+0x401 ECP config B 3562306a36Sopenharmony_ci * base+0x402 ECP control 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * All registers are 8 bits wide and read/write. If your hardware differs 3862306a36Sopenharmony_ci * only in register addresses (eg because your registers are on 32-bit 3962306a36Sopenharmony_ci * word boundaries) then you can alter the constants in parport_pc.h to 4062306a36Sopenharmony_ci * accommodate this. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * Note that the ECP registers may not start at offset 0x400 for PCI cards, 4362306a36Sopenharmony_ci * but rather will start at port->base_hi. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <linux/module.h> 4762306a36Sopenharmony_ci#include <linux/init.h> 4862306a36Sopenharmony_ci#include <linux/sched/signal.h> 4962306a36Sopenharmony_ci#include <linux/delay.h> 5062306a36Sopenharmony_ci#include <linux/errno.h> 5162306a36Sopenharmony_ci#include <linux/interrupt.h> 5262306a36Sopenharmony_ci#include <linux/ioport.h> 5362306a36Sopenharmony_ci#include <linux/kernel.h> 5462306a36Sopenharmony_ci#include <linux/slab.h> 5562306a36Sopenharmony_ci#include <linux/dma-mapping.h> 5662306a36Sopenharmony_ci#include <linux/pci.h> 5762306a36Sopenharmony_ci#include <linux/pnp.h> 5862306a36Sopenharmony_ci#include <linux/platform_device.h> 5962306a36Sopenharmony_ci#include <linux/sysctl.h> 6062306a36Sopenharmony_ci#include <linux/io.h> 6162306a36Sopenharmony_ci#include <linux/uaccess.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include <asm/dma.h> 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#include <linux/parport.h> 6662306a36Sopenharmony_ci#include <linux/parport_pc.h> 6762306a36Sopenharmony_ci#include <linux/via.h> 6862306a36Sopenharmony_ci#include <asm/parport.h> 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define PARPORT_PC_MAX_PORTS PARPORT_MAX 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#ifdef CONFIG_ISA_DMA_API 7362306a36Sopenharmony_ci#define HAS_DMA 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* ECR modes */ 7762306a36Sopenharmony_ci#define ECR_SPP 00 7862306a36Sopenharmony_ci#define ECR_PS2 01 7962306a36Sopenharmony_ci#define ECR_PPF 02 8062306a36Sopenharmony_ci#define ECR_ECP 03 8162306a36Sopenharmony_ci#define ECR_EPP 04 8262306a36Sopenharmony_ci#define ECR_VND 05 8362306a36Sopenharmony_ci#define ECR_TST 06 8462306a36Sopenharmony_ci#define ECR_CNF 07 8562306a36Sopenharmony_ci#define ECR_MODE_MASK 0xe0 8662306a36Sopenharmony_ci#define ECR_WRITE(p, v) frob_econtrol((p), 0xff, (v)) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#undef DEBUG 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define NR_SUPERIOS 3 9162306a36Sopenharmony_cistatic struct superio_struct { /* For Super-IO chips autodetection */ 9262306a36Sopenharmony_ci int io; 9362306a36Sopenharmony_ci int irq; 9462306a36Sopenharmony_ci int dma; 9562306a36Sopenharmony_ci} superios[NR_SUPERIOS] = { {0,},}; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic int user_specified; 9862306a36Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ 9962306a36Sopenharmony_ci (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) 10062306a36Sopenharmony_cistatic int verbose_probing; 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_cistatic int pci_registered_parport; 10362306a36Sopenharmony_cistatic int pnp_registered_parport; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* frob_control, but for ECR */ 10662306a36Sopenharmony_cistatic void frob_econtrol(struct parport *pb, unsigned char m, 10762306a36Sopenharmony_ci unsigned char v) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci const struct parport_pc_private *priv = pb->physport->private_data; 11062306a36Sopenharmony_ci unsigned char ecr_writable = priv->ecr_writable; 11162306a36Sopenharmony_ci unsigned char ectr = 0; 11262306a36Sopenharmony_ci unsigned char new; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (m != 0xff) 11562306a36Sopenharmony_ci ectr = inb(ECONTROL(pb)); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci new = (ectr & ~m) ^ v; 11862306a36Sopenharmony_ci if (ecr_writable) 11962306a36Sopenharmony_ci /* All known users of the ECR mask require bit 0 to be set. */ 12062306a36Sopenharmony_ci new = (new & ecr_writable) | 1; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n", m, v, ectr, new); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci outb(new, ECONTROL(pb)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline void frob_set_mode(struct parport *p, int mode) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci frob_econtrol(p, ECR_MODE_MASK, mode << 5); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 13362306a36Sopenharmony_ci/* Safely change the mode bits in the ECR 13462306a36Sopenharmony_ci Returns: 13562306a36Sopenharmony_ci 0 : Success 13662306a36Sopenharmony_ci -EBUSY: Could not drain FIFO in some finite amount of time, 13762306a36Sopenharmony_ci mode not changed! 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_cistatic int change_mode(struct parport *p, int m) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci const struct parport_pc_private *priv = p->physport->private_data; 14262306a36Sopenharmony_ci unsigned char oecr; 14362306a36Sopenharmony_ci int mode; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci pr_debug("parport change_mode ECP-ISA to mode 0x%02x\n", m); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!priv->ecr) { 14862306a36Sopenharmony_ci printk(KERN_DEBUG "change_mode: but there's no ECR!\n"); 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Bits <7:5> contain the mode. */ 15362306a36Sopenharmony_ci oecr = inb(ECONTROL(p)); 15462306a36Sopenharmony_ci mode = (oecr >> 5) & 0x7; 15562306a36Sopenharmony_ci if (mode == m) 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (mode >= 2 && !(priv->ctr & 0x20)) { 15962306a36Sopenharmony_ci /* This mode resets the FIFO, so we may 16062306a36Sopenharmony_ci * have to wait for it to drain first. */ 16162306a36Sopenharmony_ci unsigned long expire = jiffies + p->physport->cad->timeout; 16262306a36Sopenharmony_ci int counter; 16362306a36Sopenharmony_ci switch (mode) { 16462306a36Sopenharmony_ci case ECR_PPF: /* Parallel Port FIFO mode */ 16562306a36Sopenharmony_ci case ECR_ECP: /* ECP Parallel Port mode */ 16662306a36Sopenharmony_ci /* Busy wait for 200us */ 16762306a36Sopenharmony_ci for (counter = 0; counter < 40; counter++) { 16862306a36Sopenharmony_ci if (inb(ECONTROL(p)) & 0x01) 16962306a36Sopenharmony_ci break; 17062306a36Sopenharmony_ci if (signal_pending(current)) 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci udelay(5); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* Poll slowly. */ 17662306a36Sopenharmony_ci while (!(inb(ECONTROL(p)) & 0x01)) { 17762306a36Sopenharmony_ci if (time_after_eq(jiffies, expire)) 17862306a36Sopenharmony_ci /* The FIFO is stuck. */ 17962306a36Sopenharmony_ci return -EBUSY; 18062306a36Sopenharmony_ci schedule_timeout_interruptible( 18162306a36Sopenharmony_ci msecs_to_jiffies(10)); 18262306a36Sopenharmony_ci if (signal_pending(current)) 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (mode >= 2 && m >= 2) { 18962306a36Sopenharmony_ci /* We have to go through mode 001 */ 19062306a36Sopenharmony_ci oecr &= ~(7 << 5); 19162306a36Sopenharmony_ci oecr |= ECR_PS2 << 5; 19262306a36Sopenharmony_ci ECR_WRITE(p, oecr); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Set the mode. */ 19662306a36Sopenharmony_ci oecr &= ~(7 << 5); 19762306a36Sopenharmony_ci oecr |= m << 5; 19862306a36Sopenharmony_ci ECR_WRITE(p, oecr); 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci#endif /* FIFO support */ 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 20462306a36Sopenharmony_ci * Clear TIMEOUT BIT in EPP MODE 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * This is also used in SPP detection. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_cistatic int clear_epp_timeout(struct parport *pb) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci unsigned char r; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (!(parport_pc_read_status(pb) & 0x01)) 21362306a36Sopenharmony_ci return 1; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* To clear timeout some chips require double read */ 21662306a36Sopenharmony_ci parport_pc_read_status(pb); 21762306a36Sopenharmony_ci r = parport_pc_read_status(pb); 21862306a36Sopenharmony_ci outb(r | 0x01, STATUS(pb)); /* Some reset by writing 1 */ 21962306a36Sopenharmony_ci outb(r & 0xfe, STATUS(pb)); /* Others by writing 0 */ 22062306a36Sopenharmony_ci r = parport_pc_read_status(pb); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return !(r & 0x01); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/* 22662306a36Sopenharmony_ci * Access functions. 22762306a36Sopenharmony_ci * 22862306a36Sopenharmony_ci * Most of these aren't static because they may be used by the 22962306a36Sopenharmony_ci * parport_xxx_yyy macros. extern __inline__ versions of several 23062306a36Sopenharmony_ci * of these are in parport_pc.h. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void parport_pc_init_state(struct pardevice *dev, 23462306a36Sopenharmony_ci struct parport_state *s) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci s->u.pc.ctr = 0xc; 23762306a36Sopenharmony_ci if (dev->irq_func && 23862306a36Sopenharmony_ci dev->port->irq != PARPORT_IRQ_NONE) 23962306a36Sopenharmony_ci /* Set ackIntEn */ 24062306a36Sopenharmony_ci s->u.pc.ctr |= 0x10; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24; 24362306a36Sopenharmony_ci * D.Gruszka VScom */ 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void parport_pc_save_state(struct parport *p, struct parport_state *s) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci const struct parport_pc_private *priv = p->physport->private_data; 24962306a36Sopenharmony_ci s->u.pc.ctr = priv->ctr; 25062306a36Sopenharmony_ci if (priv->ecr) 25162306a36Sopenharmony_ci s->u.pc.ecr = inb(ECONTROL(p)); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic void parport_pc_restore_state(struct parport *p, 25562306a36Sopenharmony_ci struct parport_state *s) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct parport_pc_private *priv = p->physport->private_data; 25862306a36Sopenharmony_ci register unsigned char c = s->u.pc.ctr & priv->ctr_writable; 25962306a36Sopenharmony_ci outb(c, CONTROL(p)); 26062306a36Sopenharmony_ci priv->ctr = c; 26162306a36Sopenharmony_ci if (priv->ecr) 26262306a36Sopenharmony_ci ECR_WRITE(p, s->u.pc.ecr); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 26662306a36Sopenharmony_cistatic size_t parport_pc_epp_read_data(struct parport *port, void *buf, 26762306a36Sopenharmony_ci size_t length, int flags) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci size_t got = 0; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (flags & PARPORT_W91284PIC) { 27262306a36Sopenharmony_ci unsigned char status; 27362306a36Sopenharmony_ci size_t left = length; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* use knowledge about data lines..: 27662306a36Sopenharmony_ci * nFault is 0 if there is at least 1 byte in the Warp's FIFO 27762306a36Sopenharmony_ci * pError is 1 if there are 16 bytes in the Warp's FIFO 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci status = inb(STATUS(port)); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci while (!(status & 0x08) && got < length) { 28262306a36Sopenharmony_ci if (left >= 16 && (status & 0x20) && !(status & 0x08)) { 28362306a36Sopenharmony_ci /* can grab 16 bytes from warp fifo */ 28462306a36Sopenharmony_ci if (!((long)buf & 0x03)) 28562306a36Sopenharmony_ci insl(EPPDATA(port), buf, 4); 28662306a36Sopenharmony_ci else 28762306a36Sopenharmony_ci insb(EPPDATA(port), buf, 16); 28862306a36Sopenharmony_ci buf += 16; 28962306a36Sopenharmony_ci got += 16; 29062306a36Sopenharmony_ci left -= 16; 29162306a36Sopenharmony_ci } else { 29262306a36Sopenharmony_ci /* grab single byte from the warp fifo */ 29362306a36Sopenharmony_ci *((char *)buf) = inb(EPPDATA(port)); 29462306a36Sopenharmony_ci buf++; 29562306a36Sopenharmony_ci got++; 29662306a36Sopenharmony_ci left--; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci status = inb(STATUS(port)); 29962306a36Sopenharmony_ci if (status & 0x01) { 30062306a36Sopenharmony_ci /* EPP timeout should never occur... */ 30162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: EPP timeout occurred while talking to w91284pic (should not have done)\n", 30262306a36Sopenharmony_ci port->name); 30362306a36Sopenharmony_ci clear_epp_timeout(port); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci return got; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci if ((length > 1) && ((flags & PARPORT_EPP_FAST_32) 30962306a36Sopenharmony_ci || flags & PARPORT_EPP_FAST_16 31062306a36Sopenharmony_ci || flags & PARPORT_EPP_FAST_8)) { 31162306a36Sopenharmony_ci if ((flags & PARPORT_EPP_FAST_32) 31262306a36Sopenharmony_ci && !(((long)buf | length) & 0x03)) 31362306a36Sopenharmony_ci insl(EPPDATA(port), buf, (length >> 2)); 31462306a36Sopenharmony_ci else if ((flags & PARPORT_EPP_FAST_16) 31562306a36Sopenharmony_ci && !(((long)buf | length) & 0x01)) 31662306a36Sopenharmony_ci insw(EPPDATA(port), buf, length >> 1); 31762306a36Sopenharmony_ci else 31862306a36Sopenharmony_ci insb(EPPDATA(port), buf, length); 31962306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 32062306a36Sopenharmony_ci clear_epp_timeout(port); 32162306a36Sopenharmony_ci return -EIO; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci return length; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci for (; got < length; got++) { 32662306a36Sopenharmony_ci *((char *)buf) = inb(EPPDATA(port)); 32762306a36Sopenharmony_ci buf++; 32862306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 32962306a36Sopenharmony_ci /* EPP timeout */ 33062306a36Sopenharmony_ci clear_epp_timeout(port); 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci return got; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic size_t parport_pc_epp_write_data(struct parport *port, const void *buf, 33962306a36Sopenharmony_ci size_t length, int flags) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci size_t written = 0; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if ((length > 1) && ((flags & PARPORT_EPP_FAST_32) 34462306a36Sopenharmony_ci || flags & PARPORT_EPP_FAST_16 34562306a36Sopenharmony_ci || flags & PARPORT_EPP_FAST_8)) { 34662306a36Sopenharmony_ci if ((flags & PARPORT_EPP_FAST_32) 34762306a36Sopenharmony_ci && !(((long)buf | length) & 0x03)) 34862306a36Sopenharmony_ci outsl(EPPDATA(port), buf, (length >> 2)); 34962306a36Sopenharmony_ci else if ((flags & PARPORT_EPP_FAST_16) 35062306a36Sopenharmony_ci && !(((long)buf | length) & 0x01)) 35162306a36Sopenharmony_ci outsw(EPPDATA(port), buf, length >> 1); 35262306a36Sopenharmony_ci else 35362306a36Sopenharmony_ci outsb(EPPDATA(port), buf, length); 35462306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 35562306a36Sopenharmony_ci clear_epp_timeout(port); 35662306a36Sopenharmony_ci return -EIO; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci return length; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci for (; written < length; written++) { 36162306a36Sopenharmony_ci outb(*((char *)buf), EPPDATA(port)); 36262306a36Sopenharmony_ci buf++; 36362306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 36462306a36Sopenharmony_ci clear_epp_timeout(port); 36562306a36Sopenharmony_ci break; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci return written; 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic size_t parport_pc_epp_read_addr(struct parport *port, void *buf, 37362306a36Sopenharmony_ci size_t length, int flags) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci size_t got = 0; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 37862306a36Sopenharmony_ci insb(EPPADDR(port), buf, length); 37962306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 38062306a36Sopenharmony_ci clear_epp_timeout(port); 38162306a36Sopenharmony_ci return -EIO; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci return length; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci for (; got < length; got++) { 38662306a36Sopenharmony_ci *((char *)buf) = inb(EPPADDR(port)); 38762306a36Sopenharmony_ci buf++; 38862306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 38962306a36Sopenharmony_ci clear_epp_timeout(port); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return got; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic size_t parport_pc_epp_write_addr(struct parport *port, 39862306a36Sopenharmony_ci const void *buf, size_t length, 39962306a36Sopenharmony_ci int flags) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci size_t written = 0; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 40462306a36Sopenharmony_ci outsb(EPPADDR(port), buf, length); 40562306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 40662306a36Sopenharmony_ci clear_epp_timeout(port); 40762306a36Sopenharmony_ci return -EIO; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci return length; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci for (; written < length; written++) { 41262306a36Sopenharmony_ci outb(*((char *)buf), EPPADDR(port)); 41362306a36Sopenharmony_ci buf++; 41462306a36Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 41562306a36Sopenharmony_ci clear_epp_timeout(port); 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return written; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic size_t parport_pc_ecpepp_read_data(struct parport *port, void *buf, 42462306a36Sopenharmony_ci size_t length, int flags) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci size_t got; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci frob_set_mode(port, ECR_EPP); 42962306a36Sopenharmony_ci parport_pc_data_reverse(port); 43062306a36Sopenharmony_ci parport_pc_write_control(port, 0x4); 43162306a36Sopenharmony_ci got = parport_pc_epp_read_data(port, buf, length, flags); 43262306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return got; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic size_t parport_pc_ecpepp_write_data(struct parport *port, 43862306a36Sopenharmony_ci const void *buf, size_t length, 43962306a36Sopenharmony_ci int flags) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci size_t written; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci frob_set_mode(port, ECR_EPP); 44462306a36Sopenharmony_ci parport_pc_write_control(port, 0x4); 44562306a36Sopenharmony_ci parport_pc_data_forward(port); 44662306a36Sopenharmony_ci written = parport_pc_epp_write_data(port, buf, length, flags); 44762306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return written; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic size_t parport_pc_ecpepp_read_addr(struct parport *port, void *buf, 45362306a36Sopenharmony_ci size_t length, int flags) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci size_t got; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci frob_set_mode(port, ECR_EPP); 45862306a36Sopenharmony_ci parport_pc_data_reverse(port); 45962306a36Sopenharmony_ci parport_pc_write_control(port, 0x4); 46062306a36Sopenharmony_ci got = parport_pc_epp_read_addr(port, buf, length, flags); 46162306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return got; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic size_t parport_pc_ecpepp_write_addr(struct parport *port, 46762306a36Sopenharmony_ci const void *buf, size_t length, 46862306a36Sopenharmony_ci int flags) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci size_t written; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci frob_set_mode(port, ECR_EPP); 47362306a36Sopenharmony_ci parport_pc_write_control(port, 0x4); 47462306a36Sopenharmony_ci parport_pc_data_forward(port); 47562306a36Sopenharmony_ci written = parport_pc_epp_write_addr(port, buf, length, flags); 47662306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci return written; 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ci#endif /* IEEE 1284 support */ 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 48362306a36Sopenharmony_cistatic size_t parport_pc_fifo_write_block_pio(struct parport *port, 48462306a36Sopenharmony_ci const void *buf, size_t length) 48562306a36Sopenharmony_ci{ 48662306a36Sopenharmony_ci int ret = 0; 48762306a36Sopenharmony_ci const unsigned char *bufp = buf; 48862306a36Sopenharmony_ci size_t left = length; 48962306a36Sopenharmony_ci unsigned long expire = jiffies + port->physport->cad->timeout; 49062306a36Sopenharmony_ci const unsigned long fifo = FIFO(port); 49162306a36Sopenharmony_ci int poll_for = 8; /* 80 usecs */ 49262306a36Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 49362306a36Sopenharmony_ci const int fifo_depth = priv->fifo_depth; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci port = port->physport; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* We don't want to be interrupted every character. */ 49862306a36Sopenharmony_ci parport_pc_disable_irq(port); 49962306a36Sopenharmony_ci /* set nErrIntrEn and serviceIntr */ 50062306a36Sopenharmony_ci frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Forward mode. */ 50362306a36Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci while (left) { 50662306a36Sopenharmony_ci unsigned char byte; 50762306a36Sopenharmony_ci unsigned char ecrval = inb(ECONTROL(port)); 50862306a36Sopenharmony_ci int i = 0; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (need_resched() && time_before(jiffies, expire)) 51162306a36Sopenharmony_ci /* Can't yield the port. */ 51262306a36Sopenharmony_ci schedule(); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Anyone else waiting for the port? */ 51562306a36Sopenharmony_ci if (port->waithead) { 51662306a36Sopenharmony_ci printk(KERN_DEBUG "Somebody wants the port\n"); 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (ecrval & 0x02) { 52162306a36Sopenharmony_ci /* FIFO is full. Wait for interrupt. */ 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* Clear serviceIntr */ 52462306a36Sopenharmony_ci ECR_WRITE(port, ecrval & ~(1<<2)); 52562306a36Sopenharmony_cifalse_alarm: 52662306a36Sopenharmony_ci ret = parport_wait_event(port, HZ); 52762306a36Sopenharmony_ci if (ret < 0) 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci ret = 0; 53062306a36Sopenharmony_ci if (!time_before(jiffies, expire)) { 53162306a36Sopenharmony_ci /* Timed out. */ 53262306a36Sopenharmony_ci printk(KERN_DEBUG "FIFO write timed out\n"); 53362306a36Sopenharmony_ci break; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci ecrval = inb(ECONTROL(port)); 53662306a36Sopenharmony_ci if (!(ecrval & (1<<2))) { 53762306a36Sopenharmony_ci if (need_resched() && 53862306a36Sopenharmony_ci time_before(jiffies, expire)) 53962306a36Sopenharmony_ci schedule(); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci goto false_alarm; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci continue; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Can't fail now. */ 54862306a36Sopenharmony_ci expire = jiffies + port->cad->timeout; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_cipoll: 55162306a36Sopenharmony_ci if (signal_pending(current)) 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (ecrval & 0x01) { 55562306a36Sopenharmony_ci /* FIFO is empty. Blast it full. */ 55662306a36Sopenharmony_ci const int n = left < fifo_depth ? left : fifo_depth; 55762306a36Sopenharmony_ci outsb(fifo, bufp, n); 55862306a36Sopenharmony_ci bufp += n; 55962306a36Sopenharmony_ci left -= n; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* Adjust the poll time. */ 56262306a36Sopenharmony_ci if (i < (poll_for - 2)) 56362306a36Sopenharmony_ci poll_for--; 56462306a36Sopenharmony_ci continue; 56562306a36Sopenharmony_ci } else if (i++ < poll_for) { 56662306a36Sopenharmony_ci udelay(10); 56762306a36Sopenharmony_ci ecrval = inb(ECONTROL(port)); 56862306a36Sopenharmony_ci goto poll; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* Half-full(call me an optimist) */ 57262306a36Sopenharmony_ci byte = *bufp++; 57362306a36Sopenharmony_ci outb(byte, fifo); 57462306a36Sopenharmony_ci left--; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci dump_parport_state("leave fifo_write_block_pio", port); 57762306a36Sopenharmony_ci return length - left; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci#ifdef HAS_DMA 58162306a36Sopenharmony_cistatic size_t parport_pc_fifo_write_block_dma(struct parport *port, 58262306a36Sopenharmony_ci const void *buf, size_t length) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci int ret = 0; 58562306a36Sopenharmony_ci unsigned long dmaflag; 58662306a36Sopenharmony_ci size_t left = length; 58762306a36Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 58862306a36Sopenharmony_ci struct device *dev = port->physport->dev; 58962306a36Sopenharmony_ci dma_addr_t dma_addr, dma_handle; 59062306a36Sopenharmony_ci size_t maxlen = 0x10000; /* max 64k per DMA transfer */ 59162306a36Sopenharmony_ci unsigned long start = (unsigned long) buf; 59262306a36Sopenharmony_ci unsigned long end = (unsigned long) buf + length - 1; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci dump_parport_state("enter fifo_write_block_dma", port); 59562306a36Sopenharmony_ci if (end < MAX_DMA_ADDRESS) { 59662306a36Sopenharmony_ci /* If it would cross a 64k boundary, cap it at the end. */ 59762306a36Sopenharmony_ci if ((start ^ end) & ~0xffffUL) 59862306a36Sopenharmony_ci maxlen = 0x10000 - (start & 0xffff); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length, 60162306a36Sopenharmony_ci DMA_TO_DEVICE); 60262306a36Sopenharmony_ci } else { 60362306a36Sopenharmony_ci /* above 16 MB we use a bounce buffer as ISA-DMA 60462306a36Sopenharmony_ci is not possible */ 60562306a36Sopenharmony_ci maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ 60662306a36Sopenharmony_ci dma_addr = priv->dma_handle; 60762306a36Sopenharmony_ci dma_handle = 0; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci port = port->physport; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* We don't want to be interrupted every character. */ 61362306a36Sopenharmony_ci parport_pc_disable_irq(port); 61462306a36Sopenharmony_ci /* set nErrIntrEn and serviceIntr */ 61562306a36Sopenharmony_ci frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Forward mode. */ 61862306a36Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci while (left) { 62162306a36Sopenharmony_ci unsigned long expire = jiffies + port->physport->cad->timeout; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci size_t count = left; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (count > maxlen) 62662306a36Sopenharmony_ci count = maxlen; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (!dma_handle) /* bounce buffer ! */ 62962306a36Sopenharmony_ci memcpy(priv->dma_buf, buf, count); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci dmaflag = claim_dma_lock(); 63262306a36Sopenharmony_ci disable_dma(port->dma); 63362306a36Sopenharmony_ci clear_dma_ff(port->dma); 63462306a36Sopenharmony_ci set_dma_mode(port->dma, DMA_MODE_WRITE); 63562306a36Sopenharmony_ci set_dma_addr(port->dma, dma_addr); 63662306a36Sopenharmony_ci set_dma_count(port->dma, count); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Set DMA mode */ 63962306a36Sopenharmony_ci frob_econtrol(port, 1<<3, 1<<3); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Clear serviceIntr */ 64262306a36Sopenharmony_ci frob_econtrol(port, 1<<2, 0); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci enable_dma(port->dma); 64562306a36Sopenharmony_ci release_dma_lock(dmaflag); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* assume DMA will be successful */ 64862306a36Sopenharmony_ci left -= count; 64962306a36Sopenharmony_ci buf += count; 65062306a36Sopenharmony_ci if (dma_handle) 65162306a36Sopenharmony_ci dma_addr += count; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* Wait for interrupt. */ 65462306a36Sopenharmony_cifalse_alarm: 65562306a36Sopenharmony_ci ret = parport_wait_event(port, HZ); 65662306a36Sopenharmony_ci if (ret < 0) 65762306a36Sopenharmony_ci break; 65862306a36Sopenharmony_ci ret = 0; 65962306a36Sopenharmony_ci if (!time_before(jiffies, expire)) { 66062306a36Sopenharmony_ci /* Timed out. */ 66162306a36Sopenharmony_ci printk(KERN_DEBUG "DMA write timed out\n"); 66262306a36Sopenharmony_ci break; 66362306a36Sopenharmony_ci } 66462306a36Sopenharmony_ci /* Is serviceIntr set? */ 66562306a36Sopenharmony_ci if (!(inb(ECONTROL(port)) & (1<<2))) { 66662306a36Sopenharmony_ci cond_resched(); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci goto false_alarm; 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci dmaflag = claim_dma_lock(); 67262306a36Sopenharmony_ci disable_dma(port->dma); 67362306a36Sopenharmony_ci clear_dma_ff(port->dma); 67462306a36Sopenharmony_ci count = get_dma_residue(port->dma); 67562306a36Sopenharmony_ci release_dma_lock(dmaflag); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci cond_resched(); /* Can't yield the port. */ 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* Anyone else waiting for the port? */ 68062306a36Sopenharmony_ci if (port->waithead) { 68162306a36Sopenharmony_ci printk(KERN_DEBUG "Somebody wants the port\n"); 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* update for possible DMA residue ! */ 68662306a36Sopenharmony_ci buf -= count; 68762306a36Sopenharmony_ci left += count; 68862306a36Sopenharmony_ci if (dma_handle) 68962306a36Sopenharmony_ci dma_addr -= count; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Maybe got here through break, so adjust for DMA residue! */ 69362306a36Sopenharmony_ci dmaflag = claim_dma_lock(); 69462306a36Sopenharmony_ci disable_dma(port->dma); 69562306a36Sopenharmony_ci clear_dma_ff(port->dma); 69662306a36Sopenharmony_ci left += get_dma_residue(port->dma); 69762306a36Sopenharmony_ci release_dma_lock(dmaflag); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Turn off DMA mode */ 70062306a36Sopenharmony_ci frob_econtrol(port, 1<<3, 0); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (dma_handle) 70362306a36Sopenharmony_ci dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci dump_parport_state("leave fifo_write_block_dma", port); 70662306a36Sopenharmony_ci return length - left; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci#endif 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic inline size_t parport_pc_fifo_write_block(struct parport *port, 71162306a36Sopenharmony_ci const void *buf, size_t length) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci#ifdef HAS_DMA 71462306a36Sopenharmony_ci if (port->dma != PARPORT_DMA_NONE) 71562306a36Sopenharmony_ci return parport_pc_fifo_write_block_dma(port, buf, length); 71662306a36Sopenharmony_ci#endif 71762306a36Sopenharmony_ci return parport_pc_fifo_write_block_pio(port, buf, length); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/* Parallel Port FIFO mode (ECP chipsets) */ 72162306a36Sopenharmony_cistatic size_t parport_pc_compat_write_block_pio(struct parport *port, 72262306a36Sopenharmony_ci const void *buf, size_t length, 72362306a36Sopenharmony_ci int flags) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci size_t written; 72662306a36Sopenharmony_ci int r; 72762306a36Sopenharmony_ci unsigned long expire; 72862306a36Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Special case: a timeout of zero means we cannot call schedule(). 73162306a36Sopenharmony_ci * Also if O_NONBLOCK is set then use the default implementation. */ 73262306a36Sopenharmony_ci if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) 73362306a36Sopenharmony_ci return parport_ieee1284_write_compat(port, buf, 73462306a36Sopenharmony_ci length, flags); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Set up parallel port FIFO mode.*/ 73762306a36Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 73862306a36Sopenharmony_ci parport_pc_frob_control(port, PARPORT_CONTROL_STROBE, 0); 73962306a36Sopenharmony_ci r = change_mode(port, ECR_PPF); /* Parallel port FIFO */ 74062306a36Sopenharmony_ci if (r) 74162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", 74262306a36Sopenharmony_ci port->name); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* Write the data to the FIFO. */ 74762306a36Sopenharmony_ci written = parport_pc_fifo_write_block(port, buf, length); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* Finish up. */ 75062306a36Sopenharmony_ci /* For some hardware we don't want to touch the mode until 75162306a36Sopenharmony_ci * the FIFO is empty, so allow 4 seconds for each position 75262306a36Sopenharmony_ci * in the fifo. 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci expire = jiffies + (priv->fifo_depth * HZ * 4); 75562306a36Sopenharmony_ci do { 75662306a36Sopenharmony_ci /* Wait for the FIFO to empty */ 75762306a36Sopenharmony_ci r = change_mode(port, ECR_PS2); 75862306a36Sopenharmony_ci if (r != -EBUSY) 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci } while (time_before(jiffies, expire)); 76162306a36Sopenharmony_ci if (r == -EBUSY) { 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Prevent further data transfer. */ 76662306a36Sopenharmony_ci frob_set_mode(port, ECR_TST); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci /* Adjust for the contents of the FIFO. */ 76962306a36Sopenharmony_ci for (written -= priv->fifo_depth; ; written++) { 77062306a36Sopenharmony_ci if (inb(ECONTROL(port)) & 0x2) { 77162306a36Sopenharmony_ci /* Full up. */ 77262306a36Sopenharmony_ci break; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci outb(0, FIFO(port)); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Reset the FIFO and return to PS2 mode. */ 77862306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci r = parport_wait_peripheral(port, 78262306a36Sopenharmony_ci PARPORT_STATUS_BUSY, 78362306a36Sopenharmony_ci PARPORT_STATUS_BUSY); 78462306a36Sopenharmony_ci if (r) 78562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: BUSY timeout (%d) in compat_write_block_pio\n", 78662306a36Sopenharmony_ci port->name, r); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return written; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* ECP */ 79462306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 79562306a36Sopenharmony_cistatic size_t parport_pc_ecp_write_block_pio(struct parport *port, 79662306a36Sopenharmony_ci const void *buf, size_t length, 79762306a36Sopenharmony_ci int flags) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci size_t written; 80062306a36Sopenharmony_ci int r; 80162306a36Sopenharmony_ci unsigned long expire; 80262306a36Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* Special case: a timeout of zero means we cannot call schedule(). 80562306a36Sopenharmony_ci * Also if O_NONBLOCK is set then use the default implementation. */ 80662306a36Sopenharmony_ci if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) 80762306a36Sopenharmony_ci return parport_ieee1284_ecp_write_data(port, buf, 80862306a36Sopenharmony_ci length, flags); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Switch to forward mode if necessary. */ 81162306a36Sopenharmony_ci if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { 81262306a36Sopenharmony_ci /* Event 47: Set nInit high. */ 81362306a36Sopenharmony_ci parport_frob_control(port, 81462306a36Sopenharmony_ci PARPORT_CONTROL_INIT 81562306a36Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 81662306a36Sopenharmony_ci PARPORT_CONTROL_INIT 81762306a36Sopenharmony_ci | PARPORT_CONTROL_AUTOFD); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* Event 49: PError goes high. */ 82062306a36Sopenharmony_ci r = parport_wait_peripheral(port, 82162306a36Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 82262306a36Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 82362306a36Sopenharmony_ci if (r) { 82462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PError timeout (%d) in ecp_write_block_pio\n", 82562306a36Sopenharmony_ci port->name, r); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci /* Set up ECP parallel port mode.*/ 83062306a36Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 83162306a36Sopenharmony_ci parport_pc_frob_control(port, 83262306a36Sopenharmony_ci PARPORT_CONTROL_STROBE | 83362306a36Sopenharmony_ci PARPORT_CONTROL_AUTOFD, 83462306a36Sopenharmony_ci 0); 83562306a36Sopenharmony_ci r = change_mode(port, ECR_ECP); /* ECP FIFO */ 83662306a36Sopenharmony_ci if (r) 83762306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", 83862306a36Sopenharmony_ci port->name); 83962306a36Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci /* Write the data to the FIFO. */ 84262306a36Sopenharmony_ci written = parport_pc_fifo_write_block(port, buf, length); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* Finish up. */ 84562306a36Sopenharmony_ci /* For some hardware we don't want to touch the mode until 84662306a36Sopenharmony_ci * the FIFO is empty, so allow 4 seconds for each position 84762306a36Sopenharmony_ci * in the fifo. 84862306a36Sopenharmony_ci */ 84962306a36Sopenharmony_ci expire = jiffies + (priv->fifo_depth * (HZ * 4)); 85062306a36Sopenharmony_ci do { 85162306a36Sopenharmony_ci /* Wait for the FIFO to empty */ 85262306a36Sopenharmony_ci r = change_mode(port, ECR_PS2); 85362306a36Sopenharmony_ci if (r != -EBUSY) 85462306a36Sopenharmony_ci break; 85562306a36Sopenharmony_ci } while (time_before(jiffies, expire)); 85662306a36Sopenharmony_ci if (r == -EBUSY) { 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Prevent further data transfer. */ 86162306a36Sopenharmony_ci frob_set_mode(port, ECR_TST); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Adjust for the contents of the FIFO. */ 86462306a36Sopenharmony_ci for (written -= priv->fifo_depth; ; written++) { 86562306a36Sopenharmony_ci if (inb(ECONTROL(port)) & 0x2) { 86662306a36Sopenharmony_ci /* Full up. */ 86762306a36Sopenharmony_ci break; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci outb(0, FIFO(port)); 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci /* Reset the FIFO and return to PS2 mode. */ 87362306a36Sopenharmony_ci frob_set_mode(port, ECR_PS2); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* Host transfer recovery. */ 87662306a36Sopenharmony_ci parport_pc_data_reverse(port); /* Must be in PS2 mode */ 87762306a36Sopenharmony_ci udelay(5); 87862306a36Sopenharmony_ci parport_frob_control(port, PARPORT_CONTROL_INIT, 0); 87962306a36Sopenharmony_ci r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0); 88062306a36Sopenharmony_ci if (r) 88162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PE,1 timeout (%d) in ecp_write_block_pio\n", 88262306a36Sopenharmony_ci port->name, r); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci parport_frob_control(port, 88562306a36Sopenharmony_ci PARPORT_CONTROL_INIT, 88662306a36Sopenharmony_ci PARPORT_CONTROL_INIT); 88762306a36Sopenharmony_ci r = parport_wait_peripheral(port, 88862306a36Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 88962306a36Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 89062306a36Sopenharmony_ci if (r) 89162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: PE,2 timeout (%d) in ecp_write_block_pio\n", 89262306a36Sopenharmony_ci port->name, r); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci r = parport_wait_peripheral(port, 89662306a36Sopenharmony_ci PARPORT_STATUS_BUSY, 89762306a36Sopenharmony_ci PARPORT_STATUS_BUSY); 89862306a36Sopenharmony_ci if (r) 89962306a36Sopenharmony_ci printk(KERN_DEBUG "%s: BUSY timeout (%d) in ecp_write_block_pio\n", 90062306a36Sopenharmony_ci port->name, r); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci return written; 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci#endif /* IEEE 1284 support */ 90762306a36Sopenharmony_ci#endif /* Allowed to use FIFO/DMA */ 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci/* 91162306a36Sopenharmony_ci * ****************************************** 91262306a36Sopenharmony_ci * INITIALISATION AND MODULE STUFF BELOW HERE 91362306a36Sopenharmony_ci * ****************************************** 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci/* GCC is not inlining extern inline function later overwritten to non-inline, 91762306a36Sopenharmony_ci so we use outlined_ variants here. */ 91862306a36Sopenharmony_cistatic const struct parport_operations parport_pc_ops = { 91962306a36Sopenharmony_ci .write_data = parport_pc_write_data, 92062306a36Sopenharmony_ci .read_data = parport_pc_read_data, 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci .write_control = parport_pc_write_control, 92362306a36Sopenharmony_ci .read_control = parport_pc_read_control, 92462306a36Sopenharmony_ci .frob_control = parport_pc_frob_control, 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci .read_status = parport_pc_read_status, 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci .enable_irq = parport_pc_enable_irq, 92962306a36Sopenharmony_ci .disable_irq = parport_pc_disable_irq, 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci .data_forward = parport_pc_data_forward, 93262306a36Sopenharmony_ci .data_reverse = parport_pc_data_reverse, 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci .init_state = parport_pc_init_state, 93562306a36Sopenharmony_ci .save_state = parport_pc_save_state, 93662306a36Sopenharmony_ci .restore_state = parport_pc_restore_state, 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci .epp_write_data = parport_ieee1284_epp_write_data, 93962306a36Sopenharmony_ci .epp_read_data = parport_ieee1284_epp_read_data, 94062306a36Sopenharmony_ci .epp_write_addr = parport_ieee1284_epp_write_addr, 94162306a36Sopenharmony_ci .epp_read_addr = parport_ieee1284_epp_read_addr, 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci .ecp_write_data = parport_ieee1284_ecp_write_data, 94462306a36Sopenharmony_ci .ecp_read_data = parport_ieee1284_ecp_read_data, 94562306a36Sopenharmony_ci .ecp_write_addr = parport_ieee1284_ecp_write_addr, 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci .compat_write_data = parport_ieee1284_write_compat, 94862306a36Sopenharmony_ci .nibble_read_data = parport_ieee1284_read_nibble, 94962306a36Sopenharmony_ci .byte_read_data = parport_ieee1284_read_byte, 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci .owner = THIS_MODULE, 95262306a36Sopenharmony_ci}; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_SUPERIO 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic struct superio_struct *find_free_superio(void) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci int i; 95962306a36Sopenharmony_ci for (i = 0; i < NR_SUPERIOS; i++) 96062306a36Sopenharmony_ci if (superios[i].io == 0) 96162306a36Sopenharmony_ci return &superios[i]; 96262306a36Sopenharmony_ci return NULL; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci/* Super-IO chipset detection, Winbond, SMSC */ 96762306a36Sopenharmony_cistatic void show_parconfig_smsc37c669(int io, int key) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci int cr1, cr4, cra, cr23, cr26, cr27; 97062306a36Sopenharmony_ci struct superio_struct *s; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci static const char *const modes[] = { 97362306a36Sopenharmony_ci "SPP and Bidirectional (PS/2)", 97462306a36Sopenharmony_ci "EPP and SPP", 97562306a36Sopenharmony_ci "ECP", 97662306a36Sopenharmony_ci "ECP and EPP" }; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci outb(key, io); 97962306a36Sopenharmony_ci outb(key, io); 98062306a36Sopenharmony_ci outb(1, io); 98162306a36Sopenharmony_ci cr1 = inb(io + 1); 98262306a36Sopenharmony_ci outb(4, io); 98362306a36Sopenharmony_ci cr4 = inb(io + 1); 98462306a36Sopenharmony_ci outb(0x0a, io); 98562306a36Sopenharmony_ci cra = inb(io + 1); 98662306a36Sopenharmony_ci outb(0x23, io); 98762306a36Sopenharmony_ci cr23 = inb(io + 1); 98862306a36Sopenharmony_ci outb(0x26, io); 98962306a36Sopenharmony_ci cr26 = inb(io + 1); 99062306a36Sopenharmony_ci outb(0x27, io); 99162306a36Sopenharmony_ci cr27 = inb(io + 1); 99262306a36Sopenharmony_ci outb(0xaa, io); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (verbose_probing) { 99562306a36Sopenharmony_ci pr_info("SMSC 37c669 LPT Config: cr_1=0x%02x, 4=0x%02x, A=0x%2x, 23=0x%02x, 26=0x%02x, 27=0x%02x\n", 99662306a36Sopenharmony_ci cr1, cr4, cra, cr23, cr26, cr27); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* The documentation calls DMA and IRQ-Lines by letters, so 99962306a36Sopenharmony_ci the board maker can/will wire them 100062306a36Sopenharmony_ci appropriately/randomly... G=reserved H=IDE-irq, */ 100162306a36Sopenharmony_ci pr_info("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, fifo threshold=%d\n", 100262306a36Sopenharmony_ci cr23 * 4, 100362306a36Sopenharmony_ci (cr27 & 0x0f) ? 'A' - 1 + (cr27 & 0x0f) : '-', 100462306a36Sopenharmony_ci (cr26 & 0x0f) ? 'A' - 1 + (cr26 & 0x0f) : '-', 100562306a36Sopenharmony_ci cra & 0x0f); 100662306a36Sopenharmony_ci pr_info("SMSC LPT Config: enabled=%s power=%s\n", 100762306a36Sopenharmony_ci (cr23 * 4 >= 0x100) ? "yes" : "no", 100862306a36Sopenharmony_ci (cr1 & 4) ? "yes" : "no"); 100962306a36Sopenharmony_ci pr_info("SMSC LPT Config: Port mode=%s, EPP version =%s\n", 101062306a36Sopenharmony_ci (cr1 & 0x08) ? "Standard mode only (SPP)" 101162306a36Sopenharmony_ci : modes[cr4 & 0x03], 101262306a36Sopenharmony_ci (cr4 & 0x40) ? "1.7" : "1.9"); 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* Heuristics ! BIOS setup for this mainboard device limits 101662306a36Sopenharmony_ci the choices to standard settings, i.e. io-address and IRQ 101762306a36Sopenharmony_ci are related, however DMA can be 1 or 3, assume DMA_A=DMA1, 101862306a36Sopenharmony_ci DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */ 101962306a36Sopenharmony_ci if (cr23 * 4 >= 0x100) { /* if active */ 102062306a36Sopenharmony_ci s = find_free_superio(); 102162306a36Sopenharmony_ci if (s == NULL) 102262306a36Sopenharmony_ci pr_info("Super-IO: too many chips!\n"); 102362306a36Sopenharmony_ci else { 102462306a36Sopenharmony_ci int d; 102562306a36Sopenharmony_ci switch (cr23 * 4) { 102662306a36Sopenharmony_ci case 0x3bc: 102762306a36Sopenharmony_ci s->io = 0x3bc; 102862306a36Sopenharmony_ci s->irq = 7; 102962306a36Sopenharmony_ci break; 103062306a36Sopenharmony_ci case 0x378: 103162306a36Sopenharmony_ci s->io = 0x378; 103262306a36Sopenharmony_ci s->irq = 7; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci case 0x278: 103562306a36Sopenharmony_ci s->io = 0x278; 103662306a36Sopenharmony_ci s->irq = 5; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci d = (cr26 & 0x0f); 103962306a36Sopenharmony_ci if (d == 1 || d == 3) 104062306a36Sopenharmony_ci s->dma = d; 104162306a36Sopenharmony_ci else 104262306a36Sopenharmony_ci s->dma = PARPORT_DMA_NONE; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic void show_parconfig_winbond(int io, int key) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci int cr30, cr60, cr61, cr70, cr74, crf0; 105162306a36Sopenharmony_ci struct superio_struct *s; 105262306a36Sopenharmony_ci static const char *const modes[] = { 105362306a36Sopenharmony_ci "Standard (SPP) and Bidirectional(PS/2)", /* 0 */ 105462306a36Sopenharmony_ci "EPP-1.9 and SPP", 105562306a36Sopenharmony_ci "ECP", 105662306a36Sopenharmony_ci "ECP and EPP-1.9", 105762306a36Sopenharmony_ci "Standard (SPP)", 105862306a36Sopenharmony_ci "EPP-1.7 and SPP", /* 5 */ 105962306a36Sopenharmony_ci "undefined!", 106062306a36Sopenharmony_ci "ECP and EPP-1.7" }; 106162306a36Sopenharmony_ci static char *const irqtypes[] = { 106262306a36Sopenharmony_ci "pulsed low, high-Z", 106362306a36Sopenharmony_ci "follows nACK" }; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* The registers are called compatible-PnP because the 106662306a36Sopenharmony_ci register layout is modelled after ISA-PnP, the access 106762306a36Sopenharmony_ci method is just another ... */ 106862306a36Sopenharmony_ci outb(key, io); 106962306a36Sopenharmony_ci outb(key, io); 107062306a36Sopenharmony_ci outb(0x07, io); /* Register 7: Select Logical Device */ 107162306a36Sopenharmony_ci outb(0x01, io + 1); /* LD1 is Parallel Port */ 107262306a36Sopenharmony_ci outb(0x30, io); 107362306a36Sopenharmony_ci cr30 = inb(io + 1); 107462306a36Sopenharmony_ci outb(0x60, io); 107562306a36Sopenharmony_ci cr60 = inb(io + 1); 107662306a36Sopenharmony_ci outb(0x61, io); 107762306a36Sopenharmony_ci cr61 = inb(io + 1); 107862306a36Sopenharmony_ci outb(0x70, io); 107962306a36Sopenharmony_ci cr70 = inb(io + 1); 108062306a36Sopenharmony_ci outb(0x74, io); 108162306a36Sopenharmony_ci cr74 = inb(io + 1); 108262306a36Sopenharmony_ci outb(0xf0, io); 108362306a36Sopenharmony_ci crf0 = inb(io + 1); 108462306a36Sopenharmony_ci outb(0xaa, io); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (verbose_probing) { 108762306a36Sopenharmony_ci pr_info("Winbond LPT Config: cr_30=%02x 60,61=%02x%02x 70=%02x 74=%02x, f0=%02x\n", 108862306a36Sopenharmony_ci cr30, cr60, cr61, cr70, cr74, crf0); 108962306a36Sopenharmony_ci pr_info("Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 109062306a36Sopenharmony_ci (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f); 109162306a36Sopenharmony_ci if ((cr74 & 0x07) > 3) 109262306a36Sopenharmony_ci pr_cont("dma=none\n"); 109362306a36Sopenharmony_ci else 109462306a36Sopenharmony_ci pr_cont("dma=%d\n", cr74 & 0x07); 109562306a36Sopenharmony_ci pr_info("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", 109662306a36Sopenharmony_ci irqtypes[crf0 >> 7], (crf0 >> 3) & 0x0f); 109762306a36Sopenharmony_ci pr_info("Winbond LPT Config: Port mode=%s\n", 109862306a36Sopenharmony_ci modes[crf0 & 0x07]); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci if (cr30 & 0x01) { /* the settings can be interrogated later ... */ 110262306a36Sopenharmony_ci s = find_free_superio(); 110362306a36Sopenharmony_ci if (s == NULL) 110462306a36Sopenharmony_ci pr_info("Super-IO: too many chips!\n"); 110562306a36Sopenharmony_ci else { 110662306a36Sopenharmony_ci s->io = (cr60 << 8) | cr61; 110762306a36Sopenharmony_ci s->irq = cr70 & 0x0f; 110862306a36Sopenharmony_ci s->dma = (((cr74 & 0x07) > 3) ? 110962306a36Sopenharmony_ci PARPORT_DMA_NONE : (cr74 & 0x07)); 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic void decode_winbond(int efer, int key, int devid, int devrev, int oldid) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci const char *type = "unknown"; 111762306a36Sopenharmony_ci int id, progif = 2; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci if (devid == devrev) 112062306a36Sopenharmony_ci /* simple heuristics, we happened to read some 112162306a36Sopenharmony_ci non-winbond register */ 112262306a36Sopenharmony_ci return; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci id = (devid << 8) | devrev; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci /* Values are from public data sheets pdf files, I can just 112762306a36Sopenharmony_ci confirm 83977TF is correct :-) */ 112862306a36Sopenharmony_ci if (id == 0x9771) 112962306a36Sopenharmony_ci type = "83977F/AF"; 113062306a36Sopenharmony_ci else if (id == 0x9773) 113162306a36Sopenharmony_ci type = "83977TF / SMSC 97w33x/97w34x"; 113262306a36Sopenharmony_ci else if (id == 0x9774) 113362306a36Sopenharmony_ci type = "83977ATF"; 113462306a36Sopenharmony_ci else if ((id & ~0x0f) == 0x5270) 113562306a36Sopenharmony_ci type = "83977CTF / SMSC 97w36x"; 113662306a36Sopenharmony_ci else if ((id & ~0x0f) == 0x52f0) 113762306a36Sopenharmony_ci type = "83977EF / SMSC 97w35x"; 113862306a36Sopenharmony_ci else if ((id & ~0x0f) == 0x5210) 113962306a36Sopenharmony_ci type = "83627"; 114062306a36Sopenharmony_ci else if ((id & ~0x0f) == 0x6010) 114162306a36Sopenharmony_ci type = "83697HF"; 114262306a36Sopenharmony_ci else if ((oldid & 0x0f) == 0x0a) { 114362306a36Sopenharmony_ci type = "83877F"; 114462306a36Sopenharmony_ci progif = 1; 114562306a36Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0b) { 114662306a36Sopenharmony_ci type = "83877AF"; 114762306a36Sopenharmony_ci progif = 1; 114862306a36Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0c) { 114962306a36Sopenharmony_ci type = "83877TF"; 115062306a36Sopenharmony_ci progif = 1; 115162306a36Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0d) { 115262306a36Sopenharmony_ci type = "83877ATF"; 115362306a36Sopenharmony_ci progif = 1; 115462306a36Sopenharmony_ci } else 115562306a36Sopenharmony_ci progif = 0; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if (verbose_probing) 115862306a36Sopenharmony_ci pr_info("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x oldid=%02x type=%s\n", 115962306a36Sopenharmony_ci efer, key, devid, devrev, oldid, type); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (progif == 2) 116262306a36Sopenharmony_ci show_parconfig_winbond(efer, key); 116362306a36Sopenharmony_ci} 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cistatic void decode_smsc(int efer, int key, int devid, int devrev) 116662306a36Sopenharmony_ci{ 116762306a36Sopenharmony_ci const char *type = "unknown"; 116862306a36Sopenharmony_ci void (*func)(int io, int key); 116962306a36Sopenharmony_ci int id; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci if (devid == devrev) 117262306a36Sopenharmony_ci /* simple heuristics, we happened to read some 117362306a36Sopenharmony_ci non-smsc register */ 117462306a36Sopenharmony_ci return; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci func = NULL; 117762306a36Sopenharmony_ci id = (devid << 8) | devrev; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (id == 0x0302) { 118062306a36Sopenharmony_ci type = "37c669"; 118162306a36Sopenharmony_ci func = show_parconfig_smsc37c669; 118262306a36Sopenharmony_ci } else if (id == 0x6582) 118362306a36Sopenharmony_ci type = "37c665IR"; 118462306a36Sopenharmony_ci else if (devid == 0x65) 118562306a36Sopenharmony_ci type = "37c665GT"; 118662306a36Sopenharmony_ci else if (devid == 0x66) 118762306a36Sopenharmony_ci type = "37c666GT"; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci if (verbose_probing) 119062306a36Sopenharmony_ci pr_info("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x type=%s\n", 119162306a36Sopenharmony_ci efer, key, devid, devrev, type); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (func) 119462306a36Sopenharmony_ci func(efer, key); 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic void winbond_check(int io, int key) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci int origval, devid, devrev, oldid, x_devid, x_devrev, x_oldid; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (!request_region(io, 3, __func__)) 120362306a36Sopenharmony_ci return; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci origval = inb(io); /* Save original value */ 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci /* First probe without key */ 120862306a36Sopenharmony_ci outb(0x20, io); 120962306a36Sopenharmony_ci x_devid = inb(io + 1); 121062306a36Sopenharmony_ci outb(0x21, io); 121162306a36Sopenharmony_ci x_devrev = inb(io + 1); 121262306a36Sopenharmony_ci outb(0x09, io); 121362306a36Sopenharmony_ci x_oldid = inb(io + 1); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci outb(key, io); 121662306a36Sopenharmony_ci outb(key, io); /* Write Magic Sequence to EFER, extended 121762306a36Sopenharmony_ci function enable register */ 121862306a36Sopenharmony_ci outb(0x20, io); /* Write EFIR, extended function index register */ 121962306a36Sopenharmony_ci devid = inb(io + 1); /* Read EFDR, extended function data register */ 122062306a36Sopenharmony_ci outb(0x21, io); 122162306a36Sopenharmony_ci devrev = inb(io + 1); 122262306a36Sopenharmony_ci outb(0x09, io); 122362306a36Sopenharmony_ci oldid = inb(io + 1); 122462306a36Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci outb(origval, io); /* in case we poked some entirely different hardware */ 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) 122962306a36Sopenharmony_ci goto out; /* protection against false positives */ 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci decode_winbond(io, key, devid, devrev, oldid); 123262306a36Sopenharmony_ciout: 123362306a36Sopenharmony_ci release_region(io, 3); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic void winbond_check2(int io, int key) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci int origval[3], devid, devrev, oldid, x_devid, x_devrev, x_oldid; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (!request_region(io, 3, __func__)) 124162306a36Sopenharmony_ci return; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci origval[0] = inb(io); /* Save original values */ 124462306a36Sopenharmony_ci origval[1] = inb(io + 1); 124562306a36Sopenharmony_ci origval[2] = inb(io + 2); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci /* First probe without the key */ 124862306a36Sopenharmony_ci outb(0x20, io + 2); 124962306a36Sopenharmony_ci x_devid = inb(io + 2); 125062306a36Sopenharmony_ci outb(0x21, io + 1); 125162306a36Sopenharmony_ci x_devrev = inb(io + 2); 125262306a36Sopenharmony_ci outb(0x09, io + 1); 125362306a36Sopenharmony_ci x_oldid = inb(io + 2); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci outb(key, io); /* Write Magic Byte to EFER, extended 125662306a36Sopenharmony_ci function enable register */ 125762306a36Sopenharmony_ci outb(0x20, io + 2); /* Write EFIR, extended function index register */ 125862306a36Sopenharmony_ci devid = inb(io + 2); /* Read EFDR, extended function data register */ 125962306a36Sopenharmony_ci outb(0x21, io + 1); 126062306a36Sopenharmony_ci devrev = inb(io + 2); 126162306a36Sopenharmony_ci outb(0x09, io + 1); 126262306a36Sopenharmony_ci oldid = inb(io + 2); 126362306a36Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci outb(origval[0], io); /* in case we poked some entirely different hardware */ 126662306a36Sopenharmony_ci outb(origval[1], io + 1); 126762306a36Sopenharmony_ci outb(origval[2], io + 2); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (x_devid == devid && x_devrev == devrev && x_oldid == oldid) 127062306a36Sopenharmony_ci goto out; /* protection against false positives */ 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci decode_winbond(io, key, devid, devrev, oldid); 127362306a36Sopenharmony_ciout: 127462306a36Sopenharmony_ci release_region(io, 3); 127562306a36Sopenharmony_ci} 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_cistatic void smsc_check(int io, int key) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci int origval, id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (!request_region(io, 3, __func__)) 128262306a36Sopenharmony_ci return; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci origval = inb(io); /* Save original value */ 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci /* First probe without the key */ 128762306a36Sopenharmony_ci outb(0x0d, io); 128862306a36Sopenharmony_ci x_oldid = inb(io + 1); 128962306a36Sopenharmony_ci outb(0x0e, io); 129062306a36Sopenharmony_ci x_oldrev = inb(io + 1); 129162306a36Sopenharmony_ci outb(0x20, io); 129262306a36Sopenharmony_ci x_id = inb(io + 1); 129362306a36Sopenharmony_ci outb(0x21, io); 129462306a36Sopenharmony_ci x_rev = inb(io + 1); 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci outb(key, io); 129762306a36Sopenharmony_ci outb(key, io); /* Write Magic Sequence to EFER, extended 129862306a36Sopenharmony_ci function enable register */ 129962306a36Sopenharmony_ci outb(0x0d, io); /* Write EFIR, extended function index register */ 130062306a36Sopenharmony_ci oldid = inb(io + 1); /* Read EFDR, extended function data register */ 130162306a36Sopenharmony_ci outb(0x0e, io); 130262306a36Sopenharmony_ci oldrev = inb(io + 1); 130362306a36Sopenharmony_ci outb(0x20, io); 130462306a36Sopenharmony_ci id = inb(io + 1); 130562306a36Sopenharmony_ci outb(0x21, io); 130662306a36Sopenharmony_ci rev = inb(io + 1); 130762306a36Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci outb(origval, io); /* in case we poked some entirely different hardware */ 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (x_id == id && x_oldrev == oldrev && 131262306a36Sopenharmony_ci x_oldid == oldid && x_rev == rev) 131362306a36Sopenharmony_ci goto out; /* protection against false positives */ 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci decode_smsc(io, key, oldid, oldrev); 131662306a36Sopenharmony_ciout: 131762306a36Sopenharmony_ci release_region(io, 3); 131862306a36Sopenharmony_ci} 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_cistatic void detect_and_report_winbond(void) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci if (verbose_probing) 132462306a36Sopenharmony_ci printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n"); 132562306a36Sopenharmony_ci winbond_check(0x3f0, 0x87); 132662306a36Sopenharmony_ci winbond_check(0x370, 0x87); 132762306a36Sopenharmony_ci winbond_check(0x2e , 0x87); 132862306a36Sopenharmony_ci winbond_check(0x4e , 0x87); 132962306a36Sopenharmony_ci winbond_check(0x3f0, 0x86); 133062306a36Sopenharmony_ci winbond_check2(0x250, 0x88); 133162306a36Sopenharmony_ci winbond_check2(0x250, 0x89); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic void detect_and_report_smsc(void) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci if (verbose_probing) 133762306a36Sopenharmony_ci printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n"); 133862306a36Sopenharmony_ci smsc_check(0x3f0, 0x55); 133962306a36Sopenharmony_ci smsc_check(0x370, 0x55); 134062306a36Sopenharmony_ci smsc_check(0x3f0, 0x44); 134162306a36Sopenharmony_ci smsc_check(0x370, 0x44); 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic void detect_and_report_it87(void) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci u16 dev; 134762306a36Sopenharmony_ci u8 origval, r; 134862306a36Sopenharmony_ci if (verbose_probing) 134962306a36Sopenharmony_ci printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n"); 135062306a36Sopenharmony_ci if (!request_muxed_region(0x2e, 2, __func__)) 135162306a36Sopenharmony_ci return; 135262306a36Sopenharmony_ci origval = inb(0x2e); /* Save original value */ 135362306a36Sopenharmony_ci outb(0x87, 0x2e); 135462306a36Sopenharmony_ci outb(0x01, 0x2e); 135562306a36Sopenharmony_ci outb(0x55, 0x2e); 135662306a36Sopenharmony_ci outb(0x55, 0x2e); 135762306a36Sopenharmony_ci outb(0x20, 0x2e); 135862306a36Sopenharmony_ci dev = inb(0x2f) << 8; 135962306a36Sopenharmony_ci outb(0x21, 0x2e); 136062306a36Sopenharmony_ci dev |= inb(0x2f); 136162306a36Sopenharmony_ci if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 || 136262306a36Sopenharmony_ci dev == 0x8716 || dev == 0x8718 || dev == 0x8726) { 136362306a36Sopenharmony_ci pr_info("IT%04X SuperIO detected\n", dev); 136462306a36Sopenharmony_ci outb(0x07, 0x2E); /* Parallel Port */ 136562306a36Sopenharmony_ci outb(0x03, 0x2F); 136662306a36Sopenharmony_ci outb(0xF0, 0x2E); /* BOOT 0x80 off */ 136762306a36Sopenharmony_ci r = inb(0x2f); 136862306a36Sopenharmony_ci outb(0xF0, 0x2E); 136962306a36Sopenharmony_ci outb(r | 8, 0x2F); 137062306a36Sopenharmony_ci outb(0x02, 0x2E); /* Lock */ 137162306a36Sopenharmony_ci outb(0x02, 0x2F); 137262306a36Sopenharmony_ci } else { 137362306a36Sopenharmony_ci outb(origval, 0x2e); /* Oops, sorry to disturb */ 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci release_region(0x2e, 2); 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci#endif /* CONFIG_PARPORT_PC_SUPERIO */ 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic struct superio_struct *find_superio(struct parport *p) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci int i; 138262306a36Sopenharmony_ci for (i = 0; i < NR_SUPERIOS; i++) 138362306a36Sopenharmony_ci if (superios[i].io == p->base) 138462306a36Sopenharmony_ci return &superios[i]; 138562306a36Sopenharmony_ci return NULL; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic int get_superio_dma(struct parport *p) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct superio_struct *s = find_superio(p); 139162306a36Sopenharmony_ci if (s) 139262306a36Sopenharmony_ci return s->dma; 139362306a36Sopenharmony_ci return PARPORT_DMA_NONE; 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic int get_superio_irq(struct parport *p) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci struct superio_struct *s = find_superio(p); 139962306a36Sopenharmony_ci if (s) 140062306a36Sopenharmony_ci return s->irq; 140162306a36Sopenharmony_ci return PARPORT_IRQ_NONE; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci/* --- Mode detection ------------------------------------- */ 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci/* 140862306a36Sopenharmony_ci * Checks for port existence, all ports support SPP MODE 140962306a36Sopenharmony_ci * Returns: 141062306a36Sopenharmony_ci * 0 : No parallel port at this address 141162306a36Sopenharmony_ci * PARPORT_MODE_PCSPP : SPP port detected 141262306a36Sopenharmony_ci * (if the user specified an ioport himself, 141362306a36Sopenharmony_ci * this shall always be the case!) 141462306a36Sopenharmony_ci * 141562306a36Sopenharmony_ci */ 141662306a36Sopenharmony_cistatic int parport_SPP_supported(struct parport *pb) 141762306a36Sopenharmony_ci{ 141862306a36Sopenharmony_ci unsigned char r, w; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci /* 142162306a36Sopenharmony_ci * first clear an eventually pending EPP timeout 142262306a36Sopenharmony_ci * I (sailer@ife.ee.ethz.ch) have an SMSC chipset 142362306a36Sopenharmony_ci * that does not even respond to SPP cycles if an EPP 142462306a36Sopenharmony_ci * timeout is pending 142562306a36Sopenharmony_ci */ 142662306a36Sopenharmony_ci clear_epp_timeout(pb); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* Do a simple read-write test to make sure the port exists. */ 142962306a36Sopenharmony_ci w = 0xc; 143062306a36Sopenharmony_ci outb(w, CONTROL(pb)); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* Is there a control register that we can read from? Some 143362306a36Sopenharmony_ci * ports don't allow reads, so read_control just returns a 143462306a36Sopenharmony_ci * software copy. Some ports _do_ allow reads, so bypass the 143562306a36Sopenharmony_ci * software copy here. In addition, some bits aren't 143662306a36Sopenharmony_ci * writable. */ 143762306a36Sopenharmony_ci r = inb(CONTROL(pb)); 143862306a36Sopenharmony_ci if ((r & 0xf) == w) { 143962306a36Sopenharmony_ci w = 0xe; 144062306a36Sopenharmony_ci outb(w, CONTROL(pb)); 144162306a36Sopenharmony_ci r = inb(CONTROL(pb)); 144262306a36Sopenharmony_ci outb(0xc, CONTROL(pb)); 144362306a36Sopenharmony_ci if ((r & 0xf) == w) 144462306a36Sopenharmony_ci return PARPORT_MODE_PCSPP; 144562306a36Sopenharmony_ci } 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (user_specified) 144862306a36Sopenharmony_ci /* That didn't work, but the user thinks there's a 144962306a36Sopenharmony_ci * port here. */ 145062306a36Sopenharmony_ci pr_info("parport 0x%lx (WARNING): CTR: wrote 0x%02x, read 0x%02x\n", 145162306a36Sopenharmony_ci pb->base, w, r); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* Try the data register. The data lines aren't tri-stated at 145462306a36Sopenharmony_ci * this stage, so we expect back what we wrote. */ 145562306a36Sopenharmony_ci w = 0xaa; 145662306a36Sopenharmony_ci parport_pc_write_data(pb, w); 145762306a36Sopenharmony_ci r = parport_pc_read_data(pb); 145862306a36Sopenharmony_ci if (r == w) { 145962306a36Sopenharmony_ci w = 0x55; 146062306a36Sopenharmony_ci parport_pc_write_data(pb, w); 146162306a36Sopenharmony_ci r = parport_pc_read_data(pb); 146262306a36Sopenharmony_ci if (r == w) 146362306a36Sopenharmony_ci return PARPORT_MODE_PCSPP; 146462306a36Sopenharmony_ci } 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (user_specified) { 146762306a36Sopenharmony_ci /* Didn't work, but the user is convinced this is the 146862306a36Sopenharmony_ci * place. */ 146962306a36Sopenharmony_ci pr_info("parport 0x%lx (WARNING): DATA: wrote 0x%02x, read 0x%02x\n", 147062306a36Sopenharmony_ci pb->base, w, r); 147162306a36Sopenharmony_ci pr_info("parport 0x%lx: You gave this address, but there is probably no parallel port there!\n", 147262306a36Sopenharmony_ci pb->base); 147362306a36Sopenharmony_ci } 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* It's possible that we can't read the control register or 147662306a36Sopenharmony_ci * the data register. In that case just believe the user. */ 147762306a36Sopenharmony_ci if (user_specified) 147862306a36Sopenharmony_ci return PARPORT_MODE_PCSPP; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return 0; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci/* Check for ECR 148462306a36Sopenharmony_ci * 148562306a36Sopenharmony_ci * Old style XT ports alias io ports every 0x400, hence accessing ECR 148662306a36Sopenharmony_ci * on these cards actually accesses the CTR. 148762306a36Sopenharmony_ci * 148862306a36Sopenharmony_ci * Modern cards don't do this but reading from ECR will return 0xff 148962306a36Sopenharmony_ci * regardless of what is written here if the card does NOT support 149062306a36Sopenharmony_ci * ECP. 149162306a36Sopenharmony_ci * 149262306a36Sopenharmony_ci * We first check to see if ECR is the same as CTR. If not, the low 149362306a36Sopenharmony_ci * two bits of ECR aren't writable, so we check by writing ECR and 149462306a36Sopenharmony_ci * reading it back to see if it's what we expect. 149562306a36Sopenharmony_ci */ 149662306a36Sopenharmony_cistatic int parport_ECR_present(struct parport *pb) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 149962306a36Sopenharmony_ci unsigned char r = 0xc; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci if (!priv->ecr_writable) { 150262306a36Sopenharmony_ci outb(r, CONTROL(pb)); 150362306a36Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) { 150462306a36Sopenharmony_ci outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */ 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci r = inb(CONTROL(pb)); 150762306a36Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2)) 150862306a36Sopenharmony_ci /* Sure that no ECR register exists */ 150962306a36Sopenharmony_ci goto no_reg; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x3) != 0x1) 151362306a36Sopenharmony_ci goto no_reg; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci ECR_WRITE(pb, 0x34); 151662306a36Sopenharmony_ci if (inb(ECONTROL(pb)) != 0x35) 151762306a36Sopenharmony_ci goto no_reg; 151862306a36Sopenharmony_ci } 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci priv->ecr = 1; 152162306a36Sopenharmony_ci outb(0xc, CONTROL(pb)); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci /* Go to mode 000 */ 152462306a36Sopenharmony_ci frob_set_mode(pb, ECR_SPP); 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci return 1; 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci no_reg: 152962306a36Sopenharmony_ci outb(0xc, CONTROL(pb)); 153062306a36Sopenharmony_ci return 0; 153162306a36Sopenharmony_ci} 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 153462306a36Sopenharmony_ci/* Detect PS/2 support. 153562306a36Sopenharmony_ci * 153662306a36Sopenharmony_ci * Bit 5 (0x20) sets the PS/2 data direction; setting this high 153762306a36Sopenharmony_ci * allows us to read data from the data lines. In theory we would get back 153862306a36Sopenharmony_ci * 0xff but any peripheral attached to the port may drag some or all of the 153962306a36Sopenharmony_ci * lines down to zero. So if we get back anything that isn't the contents 154062306a36Sopenharmony_ci * of the data register we deem PS/2 support to be present. 154162306a36Sopenharmony_ci * 154262306a36Sopenharmony_ci * Some SPP ports have "half PS/2" ability - you can't turn off the line 154362306a36Sopenharmony_ci * drivers, but an external peripheral with sufficiently beefy drivers of 154462306a36Sopenharmony_ci * its own can overpower them and assert its own levels onto the bus, from 154562306a36Sopenharmony_ci * where they can then be read back as normal. Ports with this property 154662306a36Sopenharmony_ci * and the right type of device attached are likely to fail the SPP test, 154762306a36Sopenharmony_ci * (as they will appear to have stuck bits) and so the fact that they might 154862306a36Sopenharmony_ci * be misdetected here is rather academic. 154962306a36Sopenharmony_ci */ 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic int parport_PS2_supported(struct parport *pb) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci int ok = 0; 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci clear_epp_timeout(pb); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci /* try to tri-state the buffer */ 155862306a36Sopenharmony_ci parport_pc_data_reverse(pb); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci parport_pc_write_data(pb, 0x55); 156162306a36Sopenharmony_ci if (parport_pc_read_data(pb) != 0x55) 156262306a36Sopenharmony_ci ok++; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci parport_pc_write_data(pb, 0xaa); 156562306a36Sopenharmony_ci if (parport_pc_read_data(pb) != 0xaa) 156662306a36Sopenharmony_ci ok++; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci /* cancel input mode */ 156962306a36Sopenharmony_ci parport_pc_data_forward(pb); 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (ok) { 157262306a36Sopenharmony_ci pb->modes |= PARPORT_MODE_TRISTATE; 157362306a36Sopenharmony_ci } else { 157462306a36Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 157562306a36Sopenharmony_ci priv->ctr_writable &= ~0x20; 157662306a36Sopenharmony_ci } 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci return ok; 157962306a36Sopenharmony_ci} 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 158262306a36Sopenharmony_cistatic int parport_ECP_supported(struct parport *pb) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci int i; 158562306a36Sopenharmony_ci int config, configb; 158662306a36Sopenharmony_ci int pword; 158762306a36Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 158862306a36Sopenharmony_ci /* Translate ECP intrLine to ISA irq value */ 158962306a36Sopenharmony_ci static const int intrline[] = { 0, 7, 9, 10, 11, 14, 15, 5 }; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci /* If there is no ECR, we have no hope of supporting ECP. */ 159262306a36Sopenharmony_ci if (!priv->ecr) 159362306a36Sopenharmony_ci return 0; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* Find out FIFO depth */ 159662306a36Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 159762306a36Sopenharmony_ci ECR_WRITE(pb, ECR_TST << 5); /* TEST FIFO */ 159862306a36Sopenharmony_ci for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02); i++) 159962306a36Sopenharmony_ci outb(0xaa, FIFO(pb)); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* 160262306a36Sopenharmony_ci * Using LGS chipset it uses ECR register, but 160362306a36Sopenharmony_ci * it doesn't support ECP or FIFO MODE 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci if (i == 1024) { 160662306a36Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); 160762306a36Sopenharmony_ci return 0; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci priv->fifo_depth = i; 161162306a36Sopenharmony_ci if (verbose_probing) 161262306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci /* Find out writeIntrThreshold */ 161562306a36Sopenharmony_ci frob_econtrol(pb, 1<<2, 1<<2); 161662306a36Sopenharmony_ci frob_econtrol(pb, 1<<2, 0); 161762306a36Sopenharmony_ci for (i = 1; i <= priv->fifo_depth; i++) { 161862306a36Sopenharmony_ci inb(FIFO(pb)); 161962306a36Sopenharmony_ci udelay(50); 162062306a36Sopenharmony_ci if (inb(ECONTROL(pb)) & (1<<2)) 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci if (i <= priv->fifo_depth) { 162562306a36Sopenharmony_ci if (verbose_probing) 162662306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n", 162762306a36Sopenharmony_ci pb->base, i); 162862306a36Sopenharmony_ci } else 162962306a36Sopenharmony_ci /* Number of bytes we know we can write if we get an 163062306a36Sopenharmony_ci interrupt. */ 163162306a36Sopenharmony_ci i = 0; 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci priv->writeIntrThreshold = i; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci /* Find out readIntrThreshold */ 163662306a36Sopenharmony_ci frob_set_mode(pb, ECR_PS2); /* Reset FIFO and enable PS2 */ 163762306a36Sopenharmony_ci parport_pc_data_reverse(pb); /* Must be in PS2 mode */ 163862306a36Sopenharmony_ci frob_set_mode(pb, ECR_TST); /* Test FIFO */ 163962306a36Sopenharmony_ci frob_econtrol(pb, 1<<2, 1<<2); 164062306a36Sopenharmony_ci frob_econtrol(pb, 1<<2, 0); 164162306a36Sopenharmony_ci for (i = 1; i <= priv->fifo_depth; i++) { 164262306a36Sopenharmony_ci outb(0xaa, FIFO(pb)); 164362306a36Sopenharmony_ci if (inb(ECONTROL(pb)) & (1<<2)) 164462306a36Sopenharmony_ci break; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci if (i <= priv->fifo_depth) { 164862306a36Sopenharmony_ci if (verbose_probing) 164962306a36Sopenharmony_ci pr_info("0x%lx: readIntrThreshold is %d\n", 165062306a36Sopenharmony_ci pb->base, i); 165162306a36Sopenharmony_ci } else 165262306a36Sopenharmony_ci /* Number of bytes we can read if we get an interrupt. */ 165362306a36Sopenharmony_ci i = 0; 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci priv->readIntrThreshold = i; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 165862306a36Sopenharmony_ci ECR_WRITE(pb, 0xf4); /* Configuration mode */ 165962306a36Sopenharmony_ci config = inb(CONFIGA(pb)); 166062306a36Sopenharmony_ci pword = (config >> 4) & 0x7; 166162306a36Sopenharmony_ci switch (pword) { 166262306a36Sopenharmony_ci case 0: 166362306a36Sopenharmony_ci pword = 2; 166462306a36Sopenharmony_ci pr_warn("0x%lx: Unsupported pword size!\n", pb->base); 166562306a36Sopenharmony_ci break; 166662306a36Sopenharmony_ci case 2: 166762306a36Sopenharmony_ci pword = 4; 166862306a36Sopenharmony_ci pr_warn("0x%lx: Unsupported pword size!\n", pb->base); 166962306a36Sopenharmony_ci break; 167062306a36Sopenharmony_ci default: 167162306a36Sopenharmony_ci pr_warn("0x%lx: Unknown implementation ID\n", pb->base); 167262306a36Sopenharmony_ci fallthrough; /* Assume 1 */ 167362306a36Sopenharmony_ci case 1: 167462306a36Sopenharmony_ci pword = 1; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci priv->pword = pword; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (verbose_probing) { 167962306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: PWord is %d bits\n", 168062306a36Sopenharmony_ci pb->base, 8 * pword); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", 168362306a36Sopenharmony_ci pb->base, config & 0x80 ? "Level" : "Pulses"); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci configb = inb(CONFIGB(pb)); 168662306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", 168762306a36Sopenharmony_ci pb->base, config, configb); 168862306a36Sopenharmony_ci printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); 168962306a36Sopenharmony_ci if ((configb >> 3) & 0x07) 169062306a36Sopenharmony_ci pr_cont("%d", intrline[(configb >> 3) & 0x07]); 169162306a36Sopenharmony_ci else 169262306a36Sopenharmony_ci pr_cont("<none or set by other means>"); 169362306a36Sopenharmony_ci pr_cont(" dma="); 169462306a36Sopenharmony_ci if ((configb & 0x03) == 0x00) 169562306a36Sopenharmony_ci pr_cont("<none or set by other means>\n"); 169662306a36Sopenharmony_ci else 169762306a36Sopenharmony_ci pr_cont("%d\n", configb & 0x07); 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* Go back to mode 000 */ 170162306a36Sopenharmony_ci frob_set_mode(pb, ECR_SPP); 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci return 1; 170462306a36Sopenharmony_ci} 170562306a36Sopenharmony_ci#endif 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci#ifdef CONFIG_X86_32 170862306a36Sopenharmony_cistatic int intel_bug_present_check_epp(struct parport *pb) 170962306a36Sopenharmony_ci{ 171062306a36Sopenharmony_ci const struct parport_pc_private *priv = pb->private_data; 171162306a36Sopenharmony_ci int bug_present = 0; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci if (priv->ecr) { 171462306a36Sopenharmony_ci /* store value of ECR */ 171562306a36Sopenharmony_ci unsigned char ecr = inb(ECONTROL(pb)); 171662306a36Sopenharmony_ci unsigned char i; 171762306a36Sopenharmony_ci for (i = 0x00; i < 0x80; i += 0x20) { 171862306a36Sopenharmony_ci ECR_WRITE(pb, i); 171962306a36Sopenharmony_ci if (clear_epp_timeout(pb)) { 172062306a36Sopenharmony_ci /* Phony EPP in ECP. */ 172162306a36Sopenharmony_ci bug_present = 1; 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci /* return ECR into the inital state */ 172662306a36Sopenharmony_ci ECR_WRITE(pb, ecr); 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci return bug_present; 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_cistatic int intel_bug_present(struct parport *pb) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci/* Check whether the device is legacy, not PCI or PCMCIA. Only legacy is known to be affected. */ 173462306a36Sopenharmony_ci if (pb->dev != NULL) { 173562306a36Sopenharmony_ci return 0; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci return intel_bug_present_check_epp(pb); 173962306a36Sopenharmony_ci} 174062306a36Sopenharmony_ci#else 174162306a36Sopenharmony_cistatic int intel_bug_present(struct parport *pb) 174262306a36Sopenharmony_ci{ 174362306a36Sopenharmony_ci return 0; 174462306a36Sopenharmony_ci} 174562306a36Sopenharmony_ci#endif /* CONFIG_X86_32 */ 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_cistatic int parport_ECPPS2_supported(struct parport *pb) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci const struct parport_pc_private *priv = pb->private_data; 175062306a36Sopenharmony_ci int result; 175162306a36Sopenharmony_ci unsigned char oecr; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci if (!priv->ecr) 175462306a36Sopenharmony_ci return 0; 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci oecr = inb(ECONTROL(pb)); 175762306a36Sopenharmony_ci ECR_WRITE(pb, ECR_PS2 << 5); 175862306a36Sopenharmony_ci result = parport_PS2_supported(pb); 175962306a36Sopenharmony_ci ECR_WRITE(pb, oecr); 176062306a36Sopenharmony_ci return result; 176162306a36Sopenharmony_ci} 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci/* EPP mode detection */ 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic int parport_EPP_supported(struct parport *pb) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci /* 176862306a36Sopenharmony_ci * Theory: 176962306a36Sopenharmony_ci * Bit 0 of STR is the EPP timeout bit, this bit is 0 177062306a36Sopenharmony_ci * when EPP is possible and is set high when an EPP timeout 177162306a36Sopenharmony_ci * occurs (EPP uses the HALT line to stop the CPU while it does 177262306a36Sopenharmony_ci * the byte transfer, an EPP timeout occurs if the attached 177362306a36Sopenharmony_ci * device fails to respond after 10 micro seconds). 177462306a36Sopenharmony_ci * 177562306a36Sopenharmony_ci * This bit is cleared by either reading it (National Semi) 177662306a36Sopenharmony_ci * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? 177762306a36Sopenharmony_ci * This bit is always high in non EPP modes. 177862306a36Sopenharmony_ci */ 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci /* If EPP timeout bit clear then EPP available */ 178162306a36Sopenharmony_ci if (!clear_epp_timeout(pb)) 178262306a36Sopenharmony_ci return 0; /* No way to clear timeout */ 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* Check for Intel bug. */ 178562306a36Sopenharmony_ci if (intel_bug_present(pb)) 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci pb->modes |= PARPORT_MODE_EPP; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci /* Set up access functions to use EPP hardware. */ 179162306a36Sopenharmony_ci pb->ops->epp_read_data = parport_pc_epp_read_data; 179262306a36Sopenharmony_ci pb->ops->epp_write_data = parport_pc_epp_write_data; 179362306a36Sopenharmony_ci pb->ops->epp_read_addr = parport_pc_epp_read_addr; 179462306a36Sopenharmony_ci pb->ops->epp_write_addr = parport_pc_epp_write_addr; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci return 1; 179762306a36Sopenharmony_ci} 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_cistatic int parport_ECPEPP_supported(struct parport *pb) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 180262306a36Sopenharmony_ci int result; 180362306a36Sopenharmony_ci unsigned char oecr; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci if (!priv->ecr) 180662306a36Sopenharmony_ci return 0; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci oecr = inb(ECONTROL(pb)); 180962306a36Sopenharmony_ci /* Search for SMC style EPP+ECP mode */ 181062306a36Sopenharmony_ci ECR_WRITE(pb, 0x80); 181162306a36Sopenharmony_ci outb(0x04, CONTROL(pb)); 181262306a36Sopenharmony_ci result = parport_EPP_supported(pb); 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci ECR_WRITE(pb, oecr); 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (result) { 181762306a36Sopenharmony_ci /* Set up access functions to use ECP+EPP hardware. */ 181862306a36Sopenharmony_ci pb->ops->epp_read_data = parport_pc_ecpepp_read_data; 181962306a36Sopenharmony_ci pb->ops->epp_write_data = parport_pc_ecpepp_write_data; 182062306a36Sopenharmony_ci pb->ops->epp_read_addr = parport_pc_ecpepp_read_addr; 182162306a36Sopenharmony_ci pb->ops->epp_write_addr = parport_pc_ecpepp_write_addr; 182262306a36Sopenharmony_ci } 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return result; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci#else /* No IEEE 1284 support */ 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_ci/* Don't bother probing for modes we know we won't use. */ 183062306a36Sopenharmony_cistatic int parport_PS2_supported(struct parport *pb) { return 0; } 183162306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 183262306a36Sopenharmony_cistatic int parport_ECP_supported(struct parport *pb) 183362306a36Sopenharmony_ci{ 183462306a36Sopenharmony_ci return 0; 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci#endif 183762306a36Sopenharmony_cistatic int parport_EPP_supported(struct parport *pb) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci return 0; 184062306a36Sopenharmony_ci} 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_cistatic int parport_ECPEPP_supported(struct parport *pb) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci return 0; 184562306a36Sopenharmony_ci} 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_cistatic int parport_ECPPS2_supported(struct parport *pb) 184862306a36Sopenharmony_ci{ 184962306a36Sopenharmony_ci return 0; 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci#endif /* No IEEE 1284 support */ 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci/* --- IRQ detection -------------------------------------- */ 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci/* Only if supports ECP mode */ 185762306a36Sopenharmony_cistatic int programmable_irq_support(struct parport *pb) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci int irq, intrLine; 186062306a36Sopenharmony_ci unsigned char oecr = inb(ECONTROL(pb)); 186162306a36Sopenharmony_ci static const int lookup[8] = { 186262306a36Sopenharmony_ci PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 186362306a36Sopenharmony_ci }; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci ECR_WRITE(pb, ECR_CNF << 5); /* Configuration MODE */ 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci intrLine = (inb(CONFIGB(pb)) >> 3) & 0x07; 186862306a36Sopenharmony_ci irq = lookup[intrLine]; 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci ECR_WRITE(pb, oecr); 187162306a36Sopenharmony_ci return irq; 187262306a36Sopenharmony_ci} 187362306a36Sopenharmony_ci 187462306a36Sopenharmony_cistatic int irq_probe_ECP(struct parport *pb) 187562306a36Sopenharmony_ci{ 187662306a36Sopenharmony_ci int i; 187762306a36Sopenharmony_ci unsigned long irqs; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci irqs = probe_irq_on(); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 188262306a36Sopenharmony_ci ECR_WRITE(pb, (ECR_TST << 5) | 0x04); 188362306a36Sopenharmony_ci ECR_WRITE(pb, ECR_TST << 5); 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci /* If Full FIFO sure that writeIntrThreshold is generated */ 188662306a36Sopenharmony_ci for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02) ; i++) 188762306a36Sopenharmony_ci outb(0xaa, FIFO(pb)); 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci pb->irq = probe_irq_off(irqs); 189062306a36Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (pb->irq <= 0) 189362306a36Sopenharmony_ci pb->irq = PARPORT_IRQ_NONE; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci return pb->irq; 189662306a36Sopenharmony_ci} 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci/* 189962306a36Sopenharmony_ci * This detection seems that only works in National Semiconductors 190062306a36Sopenharmony_ci * This doesn't work in SMC, LGS, and Winbond 190162306a36Sopenharmony_ci */ 190262306a36Sopenharmony_cistatic int irq_probe_EPP(struct parport *pb) 190362306a36Sopenharmony_ci{ 190462306a36Sopenharmony_ci#ifndef ADVANCED_DETECT 190562306a36Sopenharmony_ci return PARPORT_IRQ_NONE; 190662306a36Sopenharmony_ci#else 190762306a36Sopenharmony_ci int irqs; 190862306a36Sopenharmony_ci unsigned char oecr; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 191162306a36Sopenharmony_ci oecr = inb(ECONTROL(pb)); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci irqs = probe_irq_on(); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 191662306a36Sopenharmony_ci frob_econtrol(pb, 0x10, 0x10); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci clear_epp_timeout(pb); 191962306a36Sopenharmony_ci parport_pc_frob_control(pb, 0x20, 0x20); 192062306a36Sopenharmony_ci parport_pc_frob_control(pb, 0x10, 0x10); 192162306a36Sopenharmony_ci clear_epp_timeout(pb); 192262306a36Sopenharmony_ci 192362306a36Sopenharmony_ci /* Device isn't expecting an EPP read 192462306a36Sopenharmony_ci * and generates an IRQ. 192562306a36Sopenharmony_ci */ 192662306a36Sopenharmony_ci parport_pc_read_epp(pb); 192762306a36Sopenharmony_ci udelay(20); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci pb->irq = probe_irq_off(irqs); 193062306a36Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 193162306a36Sopenharmony_ci ECR_WRITE(pb, oecr); 193262306a36Sopenharmony_ci parport_pc_write_control(pb, 0xc); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci if (pb->irq <= 0) 193562306a36Sopenharmony_ci pb->irq = PARPORT_IRQ_NONE; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci return pb->irq; 193862306a36Sopenharmony_ci#endif /* Advanced detection */ 193962306a36Sopenharmony_ci} 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_cistatic int irq_probe_SPP(struct parport *pb) 194262306a36Sopenharmony_ci{ 194362306a36Sopenharmony_ci /* Don't even try to do this. */ 194462306a36Sopenharmony_ci return PARPORT_IRQ_NONE; 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci/* We will attempt to share interrupt requests since other devices 194862306a36Sopenharmony_ci * such as sound cards and network cards seem to like using the 194962306a36Sopenharmony_ci * printer IRQs. 195062306a36Sopenharmony_ci * 195162306a36Sopenharmony_ci * When ECP is available we can autoprobe for IRQs. 195262306a36Sopenharmony_ci * NOTE: If we can autoprobe it, we can register the IRQ. 195362306a36Sopenharmony_ci */ 195462306a36Sopenharmony_cistatic int parport_irq_probe(struct parport *pb) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (priv->ecr) { 195962306a36Sopenharmony_ci pb->irq = programmable_irq_support(pb); 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 196262306a36Sopenharmony_ci pb->irq = irq_probe_ECP(pb); 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr && 196662306a36Sopenharmony_ci (pb->modes & PARPORT_MODE_EPP)) 196762306a36Sopenharmony_ci pb->irq = irq_probe_EPP(pb); 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci clear_epp_timeout(pb); 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) 197262306a36Sopenharmony_ci pb->irq = irq_probe_EPP(pb); 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci clear_epp_timeout(pb); 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 197762306a36Sopenharmony_ci pb->irq = irq_probe_SPP(pb); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 198062306a36Sopenharmony_ci pb->irq = get_superio_irq(pb); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci return pb->irq; 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci/* --- DMA detection -------------------------------------- */ 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci/* Only if chipset conforms to ECP ISA Interface Standard */ 198862306a36Sopenharmony_cistatic int programmable_dma_support(struct parport *p) 198962306a36Sopenharmony_ci{ 199062306a36Sopenharmony_ci unsigned char oecr = inb(ECONTROL(p)); 199162306a36Sopenharmony_ci int dma; 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci frob_set_mode(p, ECR_CNF); 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci dma = inb(CONFIGB(p)) & 0x07; 199662306a36Sopenharmony_ci /* 000: Indicates jumpered 8-bit DMA if read-only. 199762306a36Sopenharmony_ci 100: Indicates jumpered 16-bit DMA if read-only. */ 199862306a36Sopenharmony_ci if ((dma & 0x03) == 0) 199962306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci ECR_WRITE(p, oecr); 200262306a36Sopenharmony_ci return dma; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_cistatic int parport_dma_probe(struct parport *p) 200662306a36Sopenharmony_ci{ 200762306a36Sopenharmony_ci const struct parport_pc_private *priv = p->private_data; 200862306a36Sopenharmony_ci if (priv->ecr) /* ask ECP chipset first */ 200962306a36Sopenharmony_ci p->dma = programmable_dma_support(p); 201062306a36Sopenharmony_ci if (p->dma == PARPORT_DMA_NONE) { 201162306a36Sopenharmony_ci /* ask known Super-IO chips proper, although these 201262306a36Sopenharmony_ci claim ECP compatible, some don't report their DMA 201362306a36Sopenharmony_ci conforming to ECP standards */ 201462306a36Sopenharmony_ci p->dma = get_superio_dma(p); 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci return p->dma; 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci/* --- Initialisation code -------------------------------- */ 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_cistatic LIST_HEAD(ports_list); 202362306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ports_lock); 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_cistatic struct parport *__parport_pc_probe_port(unsigned long int base, 202662306a36Sopenharmony_ci unsigned long int base_hi, 202762306a36Sopenharmony_ci int irq, int dma, 202862306a36Sopenharmony_ci struct device *dev, 202962306a36Sopenharmony_ci int irqflags, 203062306a36Sopenharmony_ci unsigned int mode_mask, 203162306a36Sopenharmony_ci unsigned char ecr_writable) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci struct parport_pc_private *priv; 203462306a36Sopenharmony_ci struct parport_operations *ops; 203562306a36Sopenharmony_ci struct parport *p; 203662306a36Sopenharmony_ci int probedirq = PARPORT_IRQ_NONE; 203762306a36Sopenharmony_ci struct resource *base_res; 203862306a36Sopenharmony_ci struct resource *ECR_res = NULL; 203962306a36Sopenharmony_ci struct resource *EPP_res = NULL; 204062306a36Sopenharmony_ci struct platform_device *pdev = NULL; 204162306a36Sopenharmony_ci int ret; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci if (!dev) { 204462306a36Sopenharmony_ci /* We need a physical device to attach to, but none was 204562306a36Sopenharmony_ci * provided. Create our own. */ 204662306a36Sopenharmony_ci pdev = platform_device_register_simple("parport_pc", 204762306a36Sopenharmony_ci base, NULL, 0); 204862306a36Sopenharmony_ci if (IS_ERR(pdev)) 204962306a36Sopenharmony_ci return NULL; 205062306a36Sopenharmony_ci dev = &pdev->dev; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(24)); 205362306a36Sopenharmony_ci if (ret) { 205462306a36Sopenharmony_ci dev_err(dev, "Unable to set coherent dma mask: disabling DMA\n"); 205562306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 205662306a36Sopenharmony_ci } 205762306a36Sopenharmony_ci } 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); 206062306a36Sopenharmony_ci if (!ops) 206162306a36Sopenharmony_ci goto out1; 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci priv = kmalloc(sizeof(struct parport_pc_private), GFP_KERNEL); 206462306a36Sopenharmony_ci if (!priv) 206562306a36Sopenharmony_ci goto out2; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci /* a misnomer, actually - it's allocate and reserve parport number */ 206862306a36Sopenharmony_ci p = parport_register_port(base, irq, dma, ops); 206962306a36Sopenharmony_ci if (!p) 207062306a36Sopenharmony_ci goto out3; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci base_res = request_region(base, 3, p->name); 207362306a36Sopenharmony_ci if (!base_res) 207462306a36Sopenharmony_ci goto out4; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci memcpy(ops, &parport_pc_ops, sizeof(struct parport_operations)); 207762306a36Sopenharmony_ci priv->ctr = 0xc; 207862306a36Sopenharmony_ci priv->ctr_writable = ~0x10; 207962306a36Sopenharmony_ci priv->ecr = 0; 208062306a36Sopenharmony_ci priv->ecr_writable = ecr_writable; 208162306a36Sopenharmony_ci priv->fifo_depth = 0; 208262306a36Sopenharmony_ci priv->dma_buf = NULL; 208362306a36Sopenharmony_ci priv->dma_handle = 0; 208462306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->list); 208562306a36Sopenharmony_ci priv->port = p; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci p->dev = dev; 208862306a36Sopenharmony_ci p->base_hi = base_hi; 208962306a36Sopenharmony_ci p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; 209062306a36Sopenharmony_ci p->private_data = priv; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci if (base_hi) { 209362306a36Sopenharmony_ci ECR_res = request_region(base_hi, 3, p->name); 209462306a36Sopenharmony_ci if (ECR_res) 209562306a36Sopenharmony_ci parport_ECR_present(p); 209662306a36Sopenharmony_ci } 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci if (base != 0x3bc) { 209962306a36Sopenharmony_ci EPP_res = request_region(base+0x3, 5, p->name); 210062306a36Sopenharmony_ci if (EPP_res) 210162306a36Sopenharmony_ci if (!parport_EPP_supported(p)) 210262306a36Sopenharmony_ci parport_ECPEPP_supported(p); 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci if (!parport_SPP_supported(p)) 210562306a36Sopenharmony_ci /* No port. */ 210662306a36Sopenharmony_ci goto out5; 210762306a36Sopenharmony_ci if (priv->ecr) 210862306a36Sopenharmony_ci parport_ECPPS2_supported(p); 210962306a36Sopenharmony_ci else 211062306a36Sopenharmony_ci parport_PS2_supported(p); 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci p->size = (p->modes & PARPORT_MODE_EPP) ? 8 : 3; 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci pr_info("%s: PC-style at 0x%lx", p->name, p->base); 211562306a36Sopenharmony_ci if (p->base_hi && priv->ecr) 211662306a36Sopenharmony_ci pr_cont(" (0x%lx)", p->base_hi); 211762306a36Sopenharmony_ci if (p->irq == PARPORT_IRQ_AUTO) { 211862306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 211962306a36Sopenharmony_ci parport_irq_probe(p); 212062306a36Sopenharmony_ci } else if (p->irq == PARPORT_IRQ_PROBEONLY) { 212162306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 212262306a36Sopenharmony_ci parport_irq_probe(p); 212362306a36Sopenharmony_ci probedirq = p->irq; 212462306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 212762306a36Sopenharmony_ci pr_cont(", irq %d", p->irq); 212862306a36Sopenharmony_ci priv->ctr_writable |= 0x10; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci if (p->dma == PARPORT_DMA_AUTO) { 213162306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 213262306a36Sopenharmony_ci parport_dma_probe(p); 213362306a36Sopenharmony_ci } 213462306a36Sopenharmony_ci } 213562306a36Sopenharmony_ci if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq 213662306a36Sopenharmony_ci is mandatory (see above) */ 213762306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 214062306a36Sopenharmony_ci if (parport_ECP_supported(p) && 214162306a36Sopenharmony_ci p->dma != PARPORT_DMA_NOFIFO && 214262306a36Sopenharmony_ci priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) { 214362306a36Sopenharmony_ci p->modes |= PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; 214462306a36Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) 214562306a36Sopenharmony_ci p->modes |= PARPORT_MODE_DMA; 214662306a36Sopenharmony_ci } else 214762306a36Sopenharmony_ci /* We can't use the DMA channel after all. */ 214862306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 214962306a36Sopenharmony_ci#endif /* Allowed to use FIFO/DMA */ 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ci p->modes &= ~mode_mask; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 215462306a36Sopenharmony_ci if ((p->modes & PARPORT_MODE_COMPAT) != 0) 215562306a36Sopenharmony_ci p->ops->compat_write_data = parport_pc_compat_write_block_pio; 215662306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 215762306a36Sopenharmony_ci if ((p->modes & PARPORT_MODE_ECP) != 0) 215862306a36Sopenharmony_ci p->ops->ecp_write_data = parport_pc_ecp_write_block_pio; 215962306a36Sopenharmony_ci#endif 216062306a36Sopenharmony_ci if ((p->modes & (PARPORT_MODE_ECP | PARPORT_MODE_COMPAT)) != 0) { 216162306a36Sopenharmony_ci if ((p->modes & PARPORT_MODE_DMA) != 0) 216262306a36Sopenharmony_ci pr_cont(", dma %d", p->dma); 216362306a36Sopenharmony_ci else 216462306a36Sopenharmony_ci pr_cont(", using FIFO"); 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci#endif /* Allowed to use FIFO/DMA */ 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci pr_cont(" ["); 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci#define printmode(x) \ 217162306a36Sopenharmony_cido { \ 217262306a36Sopenharmony_ci if (p->modes & PARPORT_MODE_##x) \ 217362306a36Sopenharmony_ci pr_cont("%s%s", f++ ? "," : "", #x); \ 217462306a36Sopenharmony_ci} while (0) 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci { 217762306a36Sopenharmony_ci int f = 0; 217862306a36Sopenharmony_ci printmode(PCSPP); 217962306a36Sopenharmony_ci printmode(TRISTATE); 218062306a36Sopenharmony_ci printmode(COMPAT); 218162306a36Sopenharmony_ci printmode(EPP); 218262306a36Sopenharmony_ci printmode(ECP); 218362306a36Sopenharmony_ci printmode(DMA); 218462306a36Sopenharmony_ci } 218562306a36Sopenharmony_ci#undef printmode 218662306a36Sopenharmony_ci#ifndef CONFIG_PARPORT_1284 218762306a36Sopenharmony_ci pr_cont("(,...)"); 218862306a36Sopenharmony_ci#endif /* CONFIG_PARPORT_1284 */ 218962306a36Sopenharmony_ci pr_cont("]\n"); 219062306a36Sopenharmony_ci if (probedirq != PARPORT_IRQ_NONE) 219162306a36Sopenharmony_ci pr_info("%s: irq %d detected\n", p->name, probedirq); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci /* If No ECP release the ports grabbed above. */ 219462306a36Sopenharmony_ci if (ECR_res && (p->modes & PARPORT_MODE_ECP) == 0) { 219562306a36Sopenharmony_ci release_region(base_hi, 3); 219662306a36Sopenharmony_ci ECR_res = NULL; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci /* Likewise for EEP ports */ 219962306a36Sopenharmony_ci if (EPP_res && (p->modes & PARPORT_MODE_EPP) == 0) { 220062306a36Sopenharmony_ci release_region(base+3, 5); 220162306a36Sopenharmony_ci EPP_res = NULL; 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 220462306a36Sopenharmony_ci if (request_irq(p->irq, parport_irq_handler, 220562306a36Sopenharmony_ci irqflags, p->name, p)) { 220662306a36Sopenharmony_ci pr_warn("%s: irq %d in use, resorting to polled operation\n", 220762306a36Sopenharmony_ci p->name, p->irq); 220862306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 220962306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 221362306a36Sopenharmony_ci#ifdef HAS_DMA 221462306a36Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) { 221562306a36Sopenharmony_ci if (request_dma(p->dma, p->name)) { 221662306a36Sopenharmony_ci pr_warn("%s: dma %d in use, resorting to PIO operation\n", 221762306a36Sopenharmony_ci p->name, p->dma); 221862306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 221962306a36Sopenharmony_ci } else { 222062306a36Sopenharmony_ci priv->dma_buf = 222162306a36Sopenharmony_ci dma_alloc_coherent(dev, 222262306a36Sopenharmony_ci PAGE_SIZE, 222362306a36Sopenharmony_ci &priv->dma_handle, 222462306a36Sopenharmony_ci GFP_KERNEL); 222562306a36Sopenharmony_ci if (!priv->dma_buf) { 222662306a36Sopenharmony_ci pr_warn("%s: cannot get buffer for DMA, resorting to PIO operation\n", 222762306a36Sopenharmony_ci p->name); 222862306a36Sopenharmony_ci free_dma(p->dma); 222962306a36Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci#endif 223462306a36Sopenharmony_ci#endif 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci /* Done probing. Now put the port into a sensible start-up state. */ 223862306a36Sopenharmony_ci if (priv->ecr) 223962306a36Sopenharmony_ci /* 224062306a36Sopenharmony_ci * Put the ECP detected port in PS2 mode. 224162306a36Sopenharmony_ci * Do this also for ports that have ECR but don't do ECP. 224262306a36Sopenharmony_ci */ 224362306a36Sopenharmony_ci ECR_WRITE(p, 0x34); 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci parport_pc_write_data(p, 0); 224662306a36Sopenharmony_ci parport_pc_data_forward(p); 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci /* Now that we've told the sharing engine about the port, and 224962306a36Sopenharmony_ci found out its characteristics, let the high-level drivers 225062306a36Sopenharmony_ci know about it. */ 225162306a36Sopenharmony_ci spin_lock(&ports_lock); 225262306a36Sopenharmony_ci list_add(&priv->list, &ports_list); 225362306a36Sopenharmony_ci spin_unlock(&ports_lock); 225462306a36Sopenharmony_ci parport_announce_port(p); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci return p; 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ciout5: 225962306a36Sopenharmony_ci if (ECR_res) 226062306a36Sopenharmony_ci release_region(base_hi, 3); 226162306a36Sopenharmony_ci if (EPP_res) 226262306a36Sopenharmony_ci release_region(base+0x3, 5); 226362306a36Sopenharmony_ci release_region(base, 3); 226462306a36Sopenharmony_ciout4: 226562306a36Sopenharmony_ci parport_del_port(p); 226662306a36Sopenharmony_ciout3: 226762306a36Sopenharmony_ci kfree(priv); 226862306a36Sopenharmony_ciout2: 226962306a36Sopenharmony_ci kfree(ops); 227062306a36Sopenharmony_ciout1: 227162306a36Sopenharmony_ci if (pdev) 227262306a36Sopenharmony_ci platform_device_unregister(pdev); 227362306a36Sopenharmony_ci return NULL; 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_cistruct parport *parport_pc_probe_port(unsigned long int base, 227762306a36Sopenharmony_ci unsigned long int base_hi, 227862306a36Sopenharmony_ci int irq, int dma, 227962306a36Sopenharmony_ci struct device *dev, 228062306a36Sopenharmony_ci int irqflags) 228162306a36Sopenharmony_ci{ 228262306a36Sopenharmony_ci return __parport_pc_probe_port(base, base_hi, irq, dma, 228362306a36Sopenharmony_ci dev, irqflags, 0, 0); 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ciEXPORT_SYMBOL(parport_pc_probe_port); 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_civoid parport_pc_unregister_port(struct parport *p) 228862306a36Sopenharmony_ci{ 228962306a36Sopenharmony_ci struct parport_pc_private *priv = p->private_data; 229062306a36Sopenharmony_ci struct parport_operations *ops = p->ops; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci parport_remove_port(p); 229362306a36Sopenharmony_ci spin_lock(&ports_lock); 229462306a36Sopenharmony_ci list_del_init(&priv->list); 229562306a36Sopenharmony_ci spin_unlock(&ports_lock); 229662306a36Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) 229762306a36Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) 229862306a36Sopenharmony_ci free_dma(p->dma); 229962306a36Sopenharmony_ci#endif 230062306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) 230162306a36Sopenharmony_ci free_irq(p->irq, p); 230262306a36Sopenharmony_ci release_region(p->base, 3); 230362306a36Sopenharmony_ci if (p->size > 3) 230462306a36Sopenharmony_ci release_region(p->base + 3, p->size - 3); 230562306a36Sopenharmony_ci if (p->modes & PARPORT_MODE_ECP) 230662306a36Sopenharmony_ci release_region(p->base_hi, 3); 230762306a36Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) 230862306a36Sopenharmony_ci if (priv->dma_buf) 230962306a36Sopenharmony_ci dma_free_coherent(p->physport->dev, PAGE_SIZE, 231062306a36Sopenharmony_ci priv->dma_buf, 231162306a36Sopenharmony_ci priv->dma_handle); 231262306a36Sopenharmony_ci#endif 231362306a36Sopenharmony_ci kfree(p->private_data); 231462306a36Sopenharmony_ci parport_del_port(p); 231562306a36Sopenharmony_ci kfree(ops); /* hope no-one cached it */ 231662306a36Sopenharmony_ci} 231762306a36Sopenharmony_ciEXPORT_SYMBOL(parport_pc_unregister_port); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci#ifdef CONFIG_PCI 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci/* ITE support maintained by Rich Liu <richliu@poorman.org> */ 232262306a36Sopenharmony_cistatic int sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, int autodma, 232362306a36Sopenharmony_ci const struct parport_pc_via_data *via) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; 232662306a36Sopenharmony_ci u32 ite8872set; 232762306a36Sopenharmony_ci u32 ite8872_lpt, ite8872_lpthi; 232862306a36Sopenharmony_ci u8 ite8872_irq, type; 232962306a36Sopenharmony_ci int irq; 233062306a36Sopenharmony_ci int i; 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci pr_debug("sio_ite_8872_probe()\n"); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci /* make sure which one chip */ 233562306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 233662306a36Sopenharmony_ci if (request_region(inta_addr[i], 32, "it887x")) { 233762306a36Sopenharmony_ci int test; 233862306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x60, 233962306a36Sopenharmony_ci 0xe5000000 | inta_addr[i]); 234062306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x78, 234162306a36Sopenharmony_ci 0x00000000 | inta_addr[i]); 234262306a36Sopenharmony_ci test = inb(inta_addr[i]); 234362306a36Sopenharmony_ci if (test != 0xff) 234462306a36Sopenharmony_ci break; 234562306a36Sopenharmony_ci release_region(inta_addr[i], 32); 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci if (i >= 5) { 234962306a36Sopenharmony_ci pr_info("parport_pc: cannot find ITE8872 INTA\n"); 235062306a36Sopenharmony_ci return 0; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci type = inb(inta_addr[i] + 0x18); 235462306a36Sopenharmony_ci type &= 0x0f; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci switch (type) { 235762306a36Sopenharmony_ci case 0x2: 235862306a36Sopenharmony_ci pr_info("parport_pc: ITE8871 found (1P)\n"); 235962306a36Sopenharmony_ci ite8872set = 0x64200000; 236062306a36Sopenharmony_ci break; 236162306a36Sopenharmony_ci case 0xa: 236262306a36Sopenharmony_ci pr_info("parport_pc: ITE8875 found (1P)\n"); 236362306a36Sopenharmony_ci ite8872set = 0x64200000; 236462306a36Sopenharmony_ci break; 236562306a36Sopenharmony_ci case 0xe: 236662306a36Sopenharmony_ci pr_info("parport_pc: ITE8872 found (2S1P)\n"); 236762306a36Sopenharmony_ci ite8872set = 0x64e00000; 236862306a36Sopenharmony_ci break; 236962306a36Sopenharmony_ci case 0x6: 237062306a36Sopenharmony_ci pr_info("parport_pc: ITE8873 found (1S)\n"); 237162306a36Sopenharmony_ci release_region(inta_addr[i], 32); 237262306a36Sopenharmony_ci return 0; 237362306a36Sopenharmony_ci case 0x8: 237462306a36Sopenharmony_ci pr_info("parport_pc: ITE8874 found (2S)\n"); 237562306a36Sopenharmony_ci release_region(inta_addr[i], 32); 237662306a36Sopenharmony_ci return 0; 237762306a36Sopenharmony_ci default: 237862306a36Sopenharmony_ci pr_info("parport_pc: unknown ITE887x\n"); 237962306a36Sopenharmony_ci pr_info("parport_pc: please mail 'lspci -nvv' output to Rich.Liu@ite.com.tw\n"); 238062306a36Sopenharmony_ci release_region(inta_addr[i], 32); 238162306a36Sopenharmony_ci return 0; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci pci_read_config_byte(pdev, 0x3c, &ite8872_irq); 238562306a36Sopenharmony_ci pci_read_config_dword(pdev, 0x1c, &ite8872_lpt); 238662306a36Sopenharmony_ci ite8872_lpt &= 0x0000ff00; 238762306a36Sopenharmony_ci pci_read_config_dword(pdev, 0x20, &ite8872_lpthi); 238862306a36Sopenharmony_ci ite8872_lpthi &= 0x0000ff00; 238962306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x6c, 0xe3000000 | ite8872_lpt); 239062306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x70, 0xe3000000 | ite8872_lpthi); 239162306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt); 239262306a36Sopenharmony_ci /* SET SPP&EPP , Parallel Port NO DMA , Enable All Function */ 239362306a36Sopenharmony_ci /* SET Parallel IRQ */ 239462306a36Sopenharmony_ci pci_write_config_dword(pdev, 0x9c, 239562306a36Sopenharmony_ci ite8872set | (ite8872_irq * 0x11111)); 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci pr_debug("ITE887x: The IRQ is %d\n", ite8872_irq); 239862306a36Sopenharmony_ci pr_debug("ITE887x: The PARALLEL I/O port is 0x%x\n", ite8872_lpt); 239962306a36Sopenharmony_ci pr_debug("ITE887x: The PARALLEL I/O porthi is 0x%x\n", ite8872_lpthi); 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci /* Let the user (or defaults) steer us away from interrupts */ 240262306a36Sopenharmony_ci irq = ite8872_irq; 240362306a36Sopenharmony_ci if (autoirq != PARPORT_IRQ_AUTO) 240462306a36Sopenharmony_ci irq = PARPORT_IRQ_NONE; 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci /* 240762306a36Sopenharmony_ci * Release the resource so that parport_pc_probe_port can get it. 240862306a36Sopenharmony_ci */ 240962306a36Sopenharmony_ci release_region(inta_addr[i], 32); 241062306a36Sopenharmony_ci if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, 241162306a36Sopenharmony_ci irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { 241262306a36Sopenharmony_ci pr_info("parport_pc: ITE 8872 parallel port: io=0x%X", 241362306a36Sopenharmony_ci ite8872_lpt); 241462306a36Sopenharmony_ci if (irq != PARPORT_IRQ_NONE) 241562306a36Sopenharmony_ci pr_cont(", irq=%d", irq); 241662306a36Sopenharmony_ci pr_cont("\n"); 241762306a36Sopenharmony_ci return 1; 241862306a36Sopenharmony_ci } 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci return 0; 242162306a36Sopenharmony_ci} 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci/* VIA 8231 support by Pavel Fedin <sonic_amiga@rambler.ru> 242462306a36Sopenharmony_ci based on VIA 686a support code by Jeff Garzik <jgarzik@pobox.com> */ 242562306a36Sopenharmony_cistatic int parport_init_mode; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci/* Data for two known VIA chips */ 242862306a36Sopenharmony_cistatic struct parport_pc_via_data via_686a_data = { 242962306a36Sopenharmony_ci 0x51, 243062306a36Sopenharmony_ci 0x50, 243162306a36Sopenharmony_ci 0x85, 243262306a36Sopenharmony_ci 0x02, 243362306a36Sopenharmony_ci 0xE2, 243462306a36Sopenharmony_ci 0xF0, 243562306a36Sopenharmony_ci 0xE6 243662306a36Sopenharmony_ci}; 243762306a36Sopenharmony_cistatic struct parport_pc_via_data via_8231_data = { 243862306a36Sopenharmony_ci 0x45, 243962306a36Sopenharmony_ci 0x44, 244062306a36Sopenharmony_ci 0x50, 244162306a36Sopenharmony_ci 0x04, 244262306a36Sopenharmony_ci 0xF2, 244362306a36Sopenharmony_ci 0xFA, 244462306a36Sopenharmony_ci 0xF6 244562306a36Sopenharmony_ci}; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_cistatic int sio_via_probe(struct pci_dev *pdev, int autoirq, int autodma, 244862306a36Sopenharmony_ci const struct parport_pc_via_data *via) 244962306a36Sopenharmony_ci{ 245062306a36Sopenharmony_ci u8 tmp, tmp2, siofunc; 245162306a36Sopenharmony_ci u8 ppcontrol = 0; 245262306a36Sopenharmony_ci int dma, irq; 245362306a36Sopenharmony_ci unsigned port1, port2; 245462306a36Sopenharmony_ci unsigned have_epp = 0; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: VIA 686A/8231 detected\n"); 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci switch (parport_init_mode) { 245962306a36Sopenharmony_ci case 1: 246062306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting SPP mode\n"); 246162306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_SPP; 246262306a36Sopenharmony_ci break; 246362306a36Sopenharmony_ci case 2: 246462306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n"); 246562306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_SPP; 246662306a36Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 246762306a36Sopenharmony_ci break; 246862306a36Sopenharmony_ci case 3: 246962306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting EPP mode\n"); 247062306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_EPP; 247162306a36Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 247262306a36Sopenharmony_ci have_epp = 1; 247362306a36Sopenharmony_ci break; 247462306a36Sopenharmony_ci case 4: 247562306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting ECP mode\n"); 247662306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_ECP; 247762306a36Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 247862306a36Sopenharmony_ci break; 247962306a36Sopenharmony_ci case 5: 248062306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n"); 248162306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_ECP; 248262306a36Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP; 248362306a36Sopenharmony_ci have_epp = 1; 248462306a36Sopenharmony_ci break; 248562306a36Sopenharmony_ci default: 248662306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: probing current configuration\n"); 248762306a36Sopenharmony_ci siofunc = VIA_FUNCTION_PROBE; 248862306a36Sopenharmony_ci break; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci /* 249162306a36Sopenharmony_ci * unlock super i/o configuration 249262306a36Sopenharmony_ci */ 249362306a36Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_superio_config_reg, &tmp); 249462306a36Sopenharmony_ci tmp |= via->via_pci_superio_config_data; 249562306a36Sopenharmony_ci pci_write_config_byte(pdev, via->via_pci_superio_config_reg, tmp); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci /* Bits 1-0: Parallel Port Mode / Enable */ 249862306a36Sopenharmony_ci outb(via->viacfg_function, VIA_CONFIG_INDEX); 249962306a36Sopenharmony_ci tmp = inb(VIA_CONFIG_DATA); 250062306a36Sopenharmony_ci /* Bit 5: EPP+ECP enable; bit 7: PS/2 bidirectional port enable */ 250162306a36Sopenharmony_ci outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); 250262306a36Sopenharmony_ci tmp2 = inb(VIA_CONFIG_DATA); 250362306a36Sopenharmony_ci if (siofunc == VIA_FUNCTION_PROBE) { 250462306a36Sopenharmony_ci siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE; 250562306a36Sopenharmony_ci ppcontrol = tmp2; 250662306a36Sopenharmony_ci } else { 250762306a36Sopenharmony_ci tmp &= ~VIA_FUNCTION_PARPORT_DISABLE; 250862306a36Sopenharmony_ci tmp |= siofunc; 250962306a36Sopenharmony_ci outb(via->viacfg_function, VIA_CONFIG_INDEX); 251062306a36Sopenharmony_ci outb(tmp, VIA_CONFIG_DATA); 251162306a36Sopenharmony_ci tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP); 251262306a36Sopenharmony_ci tmp2 |= ppcontrol; 251362306a36Sopenharmony_ci outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); 251462306a36Sopenharmony_ci outb(tmp2, VIA_CONFIG_DATA); 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci /* Parallel Port I/O Base Address, bits 9-2 */ 251862306a36Sopenharmony_ci outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); 251962306a36Sopenharmony_ci port1 = inb(VIA_CONFIG_DATA) << 2; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n", 252262306a36Sopenharmony_ci port1); 252362306a36Sopenharmony_ci if (port1 == 0x3BC && have_epp) { 252462306a36Sopenharmony_ci outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); 252562306a36Sopenharmony_ci outb((0x378 >> 2), VIA_CONFIG_DATA); 252662306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc: Parallel port base changed to 0x378\n"); 252762306a36Sopenharmony_ci port1 = 0x378; 252862306a36Sopenharmony_ci } 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci /* 253162306a36Sopenharmony_ci * lock super i/o configuration 253262306a36Sopenharmony_ci */ 253362306a36Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_superio_config_reg, &tmp); 253462306a36Sopenharmony_ci tmp &= ~via->via_pci_superio_config_data; 253562306a36Sopenharmony_ci pci_write_config_byte(pdev, via->via_pci_superio_config_reg, tmp); 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (siofunc == VIA_FUNCTION_PARPORT_DISABLE) { 253862306a36Sopenharmony_ci pr_info("parport_pc: VIA parallel port disabled in BIOS\n"); 253962306a36Sopenharmony_ci return 0; 254062306a36Sopenharmony_ci } 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci /* Bits 7-4: PnP Routing for Parallel Port IRQ */ 254362306a36Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_parport_irq_reg, &tmp); 254462306a36Sopenharmony_ci irq = ((tmp & VIA_IRQCONTROL_PARALLEL) >> 4); 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci if (siofunc == VIA_FUNCTION_PARPORT_ECP) { 254762306a36Sopenharmony_ci /* Bits 3-2: PnP Routing for Parallel Port DMA */ 254862306a36Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp); 254962306a36Sopenharmony_ci dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2); 255062306a36Sopenharmony_ci } else 255162306a36Sopenharmony_ci /* if ECP not enabled, DMA is not enabled, assumed 255262306a36Sopenharmony_ci bogus 'dma' value */ 255362306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci /* Let the user (or defaults) steer us away from interrupts and DMA */ 255662306a36Sopenharmony_ci if (autoirq == PARPORT_IRQ_NONE) { 255762306a36Sopenharmony_ci irq = PARPORT_IRQ_NONE; 255862306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci if (autodma == PARPORT_DMA_NONE) 256162306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci switch (port1) { 256462306a36Sopenharmony_ci case 0x3bc: 256562306a36Sopenharmony_ci port2 = 0x7bc; break; 256662306a36Sopenharmony_ci case 0x378: 256762306a36Sopenharmony_ci port2 = 0x778; break; 256862306a36Sopenharmony_ci case 0x278: 256962306a36Sopenharmony_ci port2 = 0x678; break; 257062306a36Sopenharmony_ci default: 257162306a36Sopenharmony_ci pr_info("parport_pc: Weird VIA parport base 0x%X, ignoring\n", 257262306a36Sopenharmony_ci port1); 257362306a36Sopenharmony_ci return 0; 257462306a36Sopenharmony_ci } 257562306a36Sopenharmony_ci 257662306a36Sopenharmony_ci /* filter bogus IRQs */ 257762306a36Sopenharmony_ci switch (irq) { 257862306a36Sopenharmony_ci case 0: 257962306a36Sopenharmony_ci case 2: 258062306a36Sopenharmony_ci case 8: 258162306a36Sopenharmony_ci case 13: 258262306a36Sopenharmony_ci irq = PARPORT_IRQ_NONE; 258362306a36Sopenharmony_ci break; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci default: /* do nothing */ 258662306a36Sopenharmony_ci break; 258762306a36Sopenharmony_ci } 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci /* finally, do the probe with values obtained */ 259062306a36Sopenharmony_ci if (parport_pc_probe_port(port1, port2, irq, dma, &pdev->dev, 0)) { 259162306a36Sopenharmony_ci pr_info("parport_pc: VIA parallel port: io=0x%X", port1); 259262306a36Sopenharmony_ci if (irq != PARPORT_IRQ_NONE) 259362306a36Sopenharmony_ci pr_cont(", irq=%d", irq); 259462306a36Sopenharmony_ci if (dma != PARPORT_DMA_NONE) 259562306a36Sopenharmony_ci pr_cont(", dma=%d", dma); 259662306a36Sopenharmony_ci pr_cont("\n"); 259762306a36Sopenharmony_ci return 1; 259862306a36Sopenharmony_ci } 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci pr_warn("parport_pc: Strange, can't probe VIA parallel port: io=0x%X, irq=%d, dma=%d\n", 260162306a36Sopenharmony_ci port1, irq, dma); 260262306a36Sopenharmony_ci return 0; 260362306a36Sopenharmony_ci} 260462306a36Sopenharmony_ci 260562306a36Sopenharmony_ci 260662306a36Sopenharmony_cienum parport_pc_sio_types { 260762306a36Sopenharmony_ci sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ 260862306a36Sopenharmony_ci sio_via_8231, /* Via VT8231 south bridge integrated Super IO */ 260962306a36Sopenharmony_ci sio_ite_8872, 261062306a36Sopenharmony_ci last_sio 261162306a36Sopenharmony_ci}; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci/* each element directly indexed from enum list, above */ 261462306a36Sopenharmony_cistatic struct parport_pc_superio { 261562306a36Sopenharmony_ci int (*probe) (struct pci_dev *pdev, int autoirq, int autodma, 261662306a36Sopenharmony_ci const struct parport_pc_via_data *via); 261762306a36Sopenharmony_ci const struct parport_pc_via_data *via; 261862306a36Sopenharmony_ci} parport_pc_superio_info[] = { 261962306a36Sopenharmony_ci { sio_via_probe, &via_686a_data, }, 262062306a36Sopenharmony_ci { sio_via_probe, &via_8231_data, }, 262162306a36Sopenharmony_ci { sio_ite_8872_probe, NULL, }, 262262306a36Sopenharmony_ci}; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_cienum parport_pc_pci_cards { 262562306a36Sopenharmony_ci siig_1p_10x = last_sio, 262662306a36Sopenharmony_ci siig_2p_10x, 262762306a36Sopenharmony_ci siig_1p_20x, 262862306a36Sopenharmony_ci siig_2p_20x, 262962306a36Sopenharmony_ci lava_parallel, 263062306a36Sopenharmony_ci lava_parallel_dual_a, 263162306a36Sopenharmony_ci lava_parallel_dual_b, 263262306a36Sopenharmony_ci boca_ioppar, 263362306a36Sopenharmony_ci plx_9050, 263462306a36Sopenharmony_ci timedia_4006a, 263562306a36Sopenharmony_ci timedia_4014, 263662306a36Sopenharmony_ci timedia_4008a, 263762306a36Sopenharmony_ci timedia_4018, 263862306a36Sopenharmony_ci timedia_9018a, 263962306a36Sopenharmony_ci syba_2p_epp, 264062306a36Sopenharmony_ci syba_1p_ecp, 264162306a36Sopenharmony_ci titan_010l, 264262306a36Sopenharmony_ci avlab_1p, 264362306a36Sopenharmony_ci avlab_2p, 264462306a36Sopenharmony_ci oxsemi_952, 264562306a36Sopenharmony_ci oxsemi_954, 264662306a36Sopenharmony_ci oxsemi_840, 264762306a36Sopenharmony_ci oxsemi_pcie_pport, 264862306a36Sopenharmony_ci aks_0100, 264962306a36Sopenharmony_ci mobility_pp, 265062306a36Sopenharmony_ci netmos_9900, 265162306a36Sopenharmony_ci netmos_9705, 265262306a36Sopenharmony_ci netmos_9715, 265362306a36Sopenharmony_ci netmos_9755, 265462306a36Sopenharmony_ci netmos_9805, 265562306a36Sopenharmony_ci netmos_9815, 265662306a36Sopenharmony_ci netmos_9901, 265762306a36Sopenharmony_ci netmos_9865, 265862306a36Sopenharmony_ci asix_ax99100, 265962306a36Sopenharmony_ci quatech_sppxp100, 266062306a36Sopenharmony_ci wch_ch382l, 266162306a36Sopenharmony_ci brainboxes_uc146, 266262306a36Sopenharmony_ci brainboxes_px203, 266362306a36Sopenharmony_ci}; 266462306a36Sopenharmony_ci 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci/* each element directly indexed from enum list, above 266762306a36Sopenharmony_ci * (but offset by last_sio) */ 266862306a36Sopenharmony_cistatic struct parport_pc_pci { 266962306a36Sopenharmony_ci int numports; 267062306a36Sopenharmony_ci struct { /* BAR (base address registers) numbers in the config 267162306a36Sopenharmony_ci space header */ 267262306a36Sopenharmony_ci int lo; 267362306a36Sopenharmony_ci int hi; 267462306a36Sopenharmony_ci /* -1 if not there, >6 for offset-method (max BAR is 6) */ 267562306a36Sopenharmony_ci } addr[2]; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci /* Bit field of parport modes to exclude. */ 267862306a36Sopenharmony_ci unsigned int mode_mask; 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci /* If non-zero, sets the bitmask of writable ECR bits. In that 268162306a36Sopenharmony_ci * case additionally bit 0 will be forcibly set on writes. */ 268262306a36Sopenharmony_ci unsigned char ecr_writable; 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_ci /* If set, this is called immediately after pci_enable_device. 268562306a36Sopenharmony_ci * If it returns non-zero, no probing will take place and the 268662306a36Sopenharmony_ci * ports will not be used. */ 268762306a36Sopenharmony_ci int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci /* If set, this is called after probing for ports. If 'failed' 269062306a36Sopenharmony_ci * is non-zero we couldn't use any of the ports. */ 269162306a36Sopenharmony_ci void (*postinit_hook) (struct pci_dev *pdev, int failed); 269262306a36Sopenharmony_ci} cards[] = { 269362306a36Sopenharmony_ci /* siig_1p_10x */ { 1, { { 2, 3 }, } }, 269462306a36Sopenharmony_ci /* siig_2p_10x */ { 2, { { 2, 3 }, { 4, 5 }, } }, 269562306a36Sopenharmony_ci /* siig_1p_20x */ { 1, { { 0, 1 }, } }, 269662306a36Sopenharmony_ci /* siig_2p_20x */ { 2, { { 0, 1 }, { 2, 3 }, } }, 269762306a36Sopenharmony_ci /* lava_parallel */ { 1, { { 0, -1 }, } }, 269862306a36Sopenharmony_ci /* lava_parallel_dual_a */ { 1, { { 0, -1 }, } }, 269962306a36Sopenharmony_ci /* lava_parallel_dual_b */ { 1, { { 0, -1 }, } }, 270062306a36Sopenharmony_ci /* boca_ioppar */ { 1, { { 0, -1 }, } }, 270162306a36Sopenharmony_ci /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } }, 270262306a36Sopenharmony_ci /* timedia_4006a */ { 1, { { 0, -1 }, } }, 270362306a36Sopenharmony_ci /* timedia_4014 */ { 2, { { 0, -1 }, { 2, -1 }, } }, 270462306a36Sopenharmony_ci /* timedia_4008a */ { 1, { { 0, 1 }, } }, 270562306a36Sopenharmony_ci /* timedia_4018 */ { 2, { { 0, 1 }, { 2, 3 }, } }, 270662306a36Sopenharmony_ci /* timedia_9018a */ { 2, { { 0, 1 }, { 2, 3 }, } }, 270762306a36Sopenharmony_ci /* SYBA uses fixed offsets in 270862306a36Sopenharmony_ci a 1K io window */ 270962306a36Sopenharmony_ci /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, 271062306a36Sopenharmony_ci /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } }, 271162306a36Sopenharmony_ci /* titan_010l */ { 1, { { 3, -1 }, } }, 271262306a36Sopenharmony_ci /* avlab_1p */ { 1, { { 0, 1}, } }, 271362306a36Sopenharmony_ci /* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} }, 271462306a36Sopenharmony_ci /* The Oxford Semi cards are unusual: older variants of 954 don't 271562306a36Sopenharmony_ci * support ECP, and 840 locks up if you write 1 to bit 2! None 271662306a36Sopenharmony_ci * implement nFault or service interrupts and all require 00001 271762306a36Sopenharmony_ci * bit pattern to be used for bits 4:0 with ECR writes. */ 271862306a36Sopenharmony_ci /* oxsemi_952 */ { 1, { { 0, 1 }, }, 271962306a36Sopenharmony_ci PARPORT_MODE_COMPAT, ECR_MODE_MASK }, 272062306a36Sopenharmony_ci /* oxsemi_954 */ { 1, { { 0, 1 }, }, 272162306a36Sopenharmony_ci PARPORT_MODE_ECP | 272262306a36Sopenharmony_ci PARPORT_MODE_COMPAT, ECR_MODE_MASK }, 272362306a36Sopenharmony_ci /* oxsemi_840 */ { 1, { { 0, 1 }, }, 272462306a36Sopenharmony_ci PARPORT_MODE_COMPAT, ECR_MODE_MASK }, 272562306a36Sopenharmony_ci /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, }, 272662306a36Sopenharmony_ci PARPORT_MODE_COMPAT, ECR_MODE_MASK }, 272762306a36Sopenharmony_ci /* aks_0100 */ { 1, { { 0, -1 }, } }, 272862306a36Sopenharmony_ci /* mobility_pp */ { 1, { { 0, 1 }, } }, 272962306a36Sopenharmony_ci /* netmos_9900 */ { 1, { { 0, -1 }, } }, 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci /* The netmos entries below are untested */ 273262306a36Sopenharmony_ci /* netmos_9705 */ { 1, { { 0, -1 }, } }, 273362306a36Sopenharmony_ci /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, 273462306a36Sopenharmony_ci /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, 273562306a36Sopenharmony_ci /* netmos_9805 */ { 1, { { 0, 1 }, } }, 273662306a36Sopenharmony_ci /* netmos_9815 */ { 2, { { 0, 1 }, { 2, 3 }, } }, 273762306a36Sopenharmony_ci /* netmos_9901 */ { 1, { { 0, -1 }, } }, 273862306a36Sopenharmony_ci /* netmos_9865 */ { 1, { { 0, -1 }, } }, 273962306a36Sopenharmony_ci /* asix_ax99100 */ { 1, { { 0, 1 }, } }, 274062306a36Sopenharmony_ci /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, 274162306a36Sopenharmony_ci /* wch_ch382l */ { 1, { { 2, -1 }, } }, 274262306a36Sopenharmony_ci /* brainboxes_uc146 */ { 1, { { 3, -1 }, } }, 274362306a36Sopenharmony_ci /* brainboxes_px203 */ { 1, { { 0, -1 }, } }, 274462306a36Sopenharmony_ci}; 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_cistatic const struct pci_device_id parport_pc_pci_tbl[] = { 274762306a36Sopenharmony_ci /* Super-IO onboard chips */ 274862306a36Sopenharmony_ci { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, 274962306a36Sopenharmony_ci { 0x1106, 0x8231, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_8231 }, 275062306a36Sopenharmony_ci { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872, 275162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_ite_8872 }, 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci /* PCI cards */ 275462306a36Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 275562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x }, 275662306a36Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 275762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x }, 275862306a36Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 275962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x }, 276062306a36Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 276162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x }, 276262306a36Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 276362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel }, 276462306a36Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 276562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_a }, 276662306a36Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 276762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_b }, 276862306a36Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, 276962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar }, 277062306a36Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, 277162306a36Sopenharmony_ci PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0, 0, plx_9050 }, 277262306a36Sopenharmony_ci /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/ 277362306a36Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0101, 0, 0, timedia_4006a }, 277462306a36Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0102, 0, 0, timedia_4014 }, 277562306a36Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0103, 0, 0, timedia_4008a }, 277662306a36Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0104, 0, 0, timedia_4018 }, 277762306a36Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x9018, 0, 0, timedia_9018a }, 277862306a36Sopenharmony_ci { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_2P_EPP, 277962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp }, 278062306a36Sopenharmony_ci { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_1P_ECP, 278162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp }, 278262306a36Sopenharmony_ci { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L, 278362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l }, 278462306a36Sopenharmony_ci /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ 278562306a36Sopenharmony_ci /* AFAVLAB_TK9902 */ 278662306a36Sopenharmony_ci { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, 278762306a36Sopenharmony_ci { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p}, 278862306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952PP, 278962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 }, 279062306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, 279162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 }, 279262306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, 279362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_840 }, 279462306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840, 279562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 279662306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840_G, 279762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 279862306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0, 279962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 280062306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0_G, 280162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 280262306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1, 280362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 280462306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_G, 280562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 280662306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_U, 280762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 280862306a36Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU, 280962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 281062306a36Sopenharmony_ci { PCI_VENDOR_ID_AKS, PCI_DEVICE_ID_AKS_ALADDINCARD, 281162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, aks_0100 }, 281262306a36Sopenharmony_ci { 0x14f2, 0x0121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, mobility_pp }, 281362306a36Sopenharmony_ci /* NetMos communication controllers */ 281462306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, 281562306a36Sopenharmony_ci 0xA000, 0x2000, 0, 0, netmos_9900 }, 281662306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705, 281762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 }, 281862306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715, 281962306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 }, 282062306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755, 282162306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 }, 282262306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9805, 282362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 }, 282462306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815, 282562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, 282662306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 282762306a36Sopenharmony_ci 0xA000, 0x2000, 0, 0, netmos_9901 }, 282862306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, 282962306a36Sopenharmony_ci 0xA000, 0x1000, 0, 0, netmos_9865 }, 283062306a36Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, 283162306a36Sopenharmony_ci 0xA000, 0x2000, 0, 0, netmos_9865 }, 283262306a36Sopenharmony_ci /* ASIX AX99100 PCIe to Multi I/O Controller */ 283362306a36Sopenharmony_ci { PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_AX99100, 283462306a36Sopenharmony_ci 0xA000, 0x2000, 0, 0, asix_ax99100 }, 283562306a36Sopenharmony_ci /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ 283662306a36Sopenharmony_ci { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, 283762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, 283862306a36Sopenharmony_ci /* WCH CH382L PCI-E single parallel port card */ 283962306a36Sopenharmony_ci { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l }, 284062306a36Sopenharmony_ci /* Brainboxes IX-500/550 */ 284162306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x402a, 284262306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 284362306a36Sopenharmony_ci /* Brainboxes UC-146/UC-157 */ 284462306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x0be1, 284562306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc146 }, 284662306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x0be2, 284762306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc146 }, 284862306a36Sopenharmony_ci /* Brainboxes PX-146/PX-257 */ 284962306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x401c, 285062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 285162306a36Sopenharmony_ci /* Brainboxes PX-203 */ 285262306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x4007, 285362306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_px203 }, 285462306a36Sopenharmony_ci /* Brainboxes PX-475 */ 285562306a36Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x401f, 285662306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 285762306a36Sopenharmony_ci { 0, } /* terminate list */ 285862306a36Sopenharmony_ci}; 285962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_cistruct pci_parport_data { 286262306a36Sopenharmony_ci int num; 286362306a36Sopenharmony_ci struct parport *ports[2]; 286462306a36Sopenharmony_ci}; 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_cistatic int parport_pc_pci_probe(struct pci_dev *dev, 286762306a36Sopenharmony_ci const struct pci_device_id *id) 286862306a36Sopenharmony_ci{ 286962306a36Sopenharmony_ci int err, count, n, i = id->driver_data; 287062306a36Sopenharmony_ci struct pci_parport_data *data; 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci if (i < last_sio) 287362306a36Sopenharmony_ci /* This is an onboard Super-IO and has already been probed */ 287462306a36Sopenharmony_ci return 0; 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci /* This is a PCI card */ 287762306a36Sopenharmony_ci i -= last_sio; 287862306a36Sopenharmony_ci count = 0; 287962306a36Sopenharmony_ci err = pci_enable_device(dev); 288062306a36Sopenharmony_ci if (err) 288162306a36Sopenharmony_ci return err; 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci data = kmalloc(sizeof(struct pci_parport_data), GFP_KERNEL); 288462306a36Sopenharmony_ci if (!data) 288562306a36Sopenharmony_ci return -ENOMEM; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci if (cards[i].preinit_hook && 288862306a36Sopenharmony_ci cards[i].preinit_hook(dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) { 288962306a36Sopenharmony_ci kfree(data); 289062306a36Sopenharmony_ci return -ENODEV; 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci 289362306a36Sopenharmony_ci for (n = 0; n < cards[i].numports; n++) { 289462306a36Sopenharmony_ci int lo = cards[i].addr[n].lo; 289562306a36Sopenharmony_ci int hi = cards[i].addr[n].hi; 289662306a36Sopenharmony_ci int irq; 289762306a36Sopenharmony_ci unsigned long io_lo, io_hi; 289862306a36Sopenharmony_ci io_lo = pci_resource_start(dev, lo); 289962306a36Sopenharmony_ci io_hi = 0; 290062306a36Sopenharmony_ci if ((hi >= 0) && (hi <= 6)) 290162306a36Sopenharmony_ci io_hi = pci_resource_start(dev, hi); 290262306a36Sopenharmony_ci else if (hi > 6) 290362306a36Sopenharmony_ci io_lo += hi; /* Reinterpret the meaning of 290462306a36Sopenharmony_ci "hi" as an offset (see SYBA 290562306a36Sopenharmony_ci def.) */ 290662306a36Sopenharmony_ci /* TODO: test if sharing interrupts works */ 290762306a36Sopenharmony_ci irq = dev->irq; 290862306a36Sopenharmony_ci if (irq == IRQ_NONE) { 290962306a36Sopenharmony_ci printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx)\n", 291062306a36Sopenharmony_ci id->vendor, id->device, io_lo, io_hi); 291162306a36Sopenharmony_ci irq = PARPORT_IRQ_NONE; 291262306a36Sopenharmony_ci } else { 291362306a36Sopenharmony_ci printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx), IRQ %d\n", 291462306a36Sopenharmony_ci id->vendor, id->device, io_lo, io_hi, irq); 291562306a36Sopenharmony_ci } 291662306a36Sopenharmony_ci data->ports[count] = 291762306a36Sopenharmony_ci __parport_pc_probe_port(io_lo, io_hi, irq, 291862306a36Sopenharmony_ci PARPORT_DMA_NONE, &dev->dev, 291962306a36Sopenharmony_ci IRQF_SHARED, 292062306a36Sopenharmony_ci cards[i].mode_mask, 292162306a36Sopenharmony_ci cards[i].ecr_writable); 292262306a36Sopenharmony_ci if (data->ports[count]) 292362306a36Sopenharmony_ci count++; 292462306a36Sopenharmony_ci } 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci data->num = count; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci if (cards[i].postinit_hook) 292962306a36Sopenharmony_ci cards[i].postinit_hook(dev, count == 0); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci if (count) { 293262306a36Sopenharmony_ci pci_set_drvdata(dev, data); 293362306a36Sopenharmony_ci return 0; 293462306a36Sopenharmony_ci } 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci kfree(data); 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci return -ENODEV; 293962306a36Sopenharmony_ci} 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_cistatic void parport_pc_pci_remove(struct pci_dev *dev) 294262306a36Sopenharmony_ci{ 294362306a36Sopenharmony_ci struct pci_parport_data *data = pci_get_drvdata(dev); 294462306a36Sopenharmony_ci int i; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci if (data) { 294762306a36Sopenharmony_ci for (i = data->num - 1; i >= 0; i--) 294862306a36Sopenharmony_ci parport_pc_unregister_port(data->ports[i]); 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci kfree(data); 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci} 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_cistatic struct pci_driver parport_pc_pci_driver = { 295562306a36Sopenharmony_ci .name = "parport_pc", 295662306a36Sopenharmony_ci .id_table = parport_pc_pci_tbl, 295762306a36Sopenharmony_ci .probe = parport_pc_pci_probe, 295862306a36Sopenharmony_ci .remove = parport_pc_pci_remove, 295962306a36Sopenharmony_ci}; 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_cistatic int __init parport_pc_init_superio(int autoirq, int autodma) 296262306a36Sopenharmony_ci{ 296362306a36Sopenharmony_ci const struct pci_device_id *id; 296462306a36Sopenharmony_ci struct pci_dev *pdev = NULL; 296562306a36Sopenharmony_ci int ret = 0; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci for_each_pci_dev(pdev) { 296862306a36Sopenharmony_ci id = pci_match_id(parport_pc_pci_tbl, pdev); 296962306a36Sopenharmony_ci if (id == NULL || id->driver_data >= last_sio) 297062306a36Sopenharmony_ci continue; 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_ci if (parport_pc_superio_info[id->driver_data].probe( 297362306a36Sopenharmony_ci pdev, autoirq, autodma, 297462306a36Sopenharmony_ci parport_pc_superio_info[id->driver_data].via)) { 297562306a36Sopenharmony_ci ret++; 297662306a36Sopenharmony_ci } 297762306a36Sopenharmony_ci } 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci return ret; /* number of devices found */ 298062306a36Sopenharmony_ci} 298162306a36Sopenharmony_ci#else 298262306a36Sopenharmony_cistatic struct pci_driver parport_pc_pci_driver; 298362306a36Sopenharmony_cistatic int __init parport_pc_init_superio(int autoirq, int autodma) 298462306a36Sopenharmony_ci{ 298562306a36Sopenharmony_ci return 0; 298662306a36Sopenharmony_ci} 298762306a36Sopenharmony_ci#endif /* CONFIG_PCI */ 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci#ifdef CONFIG_PNP 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_cistatic const struct pnp_device_id parport_pc_pnp_tbl[] = { 299262306a36Sopenharmony_ci /* Standard LPT Printer Port */ 299362306a36Sopenharmony_ci {.id = "PNP0400", .driver_data = 0}, 299462306a36Sopenharmony_ci /* ECP Printer Port */ 299562306a36Sopenharmony_ci {.id = "PNP0401", .driver_data = 0}, 299662306a36Sopenharmony_ci { } 299762306a36Sopenharmony_ci}; 299862306a36Sopenharmony_ci 299962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pnp, parport_pc_pnp_tbl); 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_cistatic int parport_pc_pnp_probe(struct pnp_dev *dev, 300262306a36Sopenharmony_ci const struct pnp_device_id *id) 300362306a36Sopenharmony_ci{ 300462306a36Sopenharmony_ci struct parport *pdata; 300562306a36Sopenharmony_ci unsigned long io_lo, io_hi; 300662306a36Sopenharmony_ci int dma, irq; 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci if (pnp_port_valid(dev, 0) && 300962306a36Sopenharmony_ci !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { 301062306a36Sopenharmony_ci io_lo = pnp_port_start(dev, 0); 301162306a36Sopenharmony_ci } else 301262306a36Sopenharmony_ci return -EINVAL; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci if (pnp_port_valid(dev, 1) && 301562306a36Sopenharmony_ci !(pnp_port_flags(dev, 1) & IORESOURCE_DISABLED)) { 301662306a36Sopenharmony_ci io_hi = pnp_port_start(dev, 1); 301762306a36Sopenharmony_ci } else 301862306a36Sopenharmony_ci io_hi = 0; 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci if (pnp_irq_valid(dev, 0) && 302162306a36Sopenharmony_ci !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) { 302262306a36Sopenharmony_ci irq = pnp_irq(dev, 0); 302362306a36Sopenharmony_ci } else 302462306a36Sopenharmony_ci irq = PARPORT_IRQ_NONE; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci if (pnp_dma_valid(dev, 0) && 302762306a36Sopenharmony_ci !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) { 302862306a36Sopenharmony_ci dma = pnp_dma(dev, 0); 302962306a36Sopenharmony_ci } else 303062306a36Sopenharmony_ci dma = PARPORT_DMA_NONE; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci dev_info(&dev->dev, "reported by %s\n", dev->protocol->name); 303362306a36Sopenharmony_ci pdata = parport_pc_probe_port(io_lo, io_hi, irq, dma, &dev->dev, 0); 303462306a36Sopenharmony_ci if (pdata == NULL) 303562306a36Sopenharmony_ci return -ENODEV; 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci pnp_set_drvdata(dev, pdata); 303862306a36Sopenharmony_ci return 0; 303962306a36Sopenharmony_ci} 304062306a36Sopenharmony_ci 304162306a36Sopenharmony_cistatic void parport_pc_pnp_remove(struct pnp_dev *dev) 304262306a36Sopenharmony_ci{ 304362306a36Sopenharmony_ci struct parport *pdata = (struct parport *)pnp_get_drvdata(dev); 304462306a36Sopenharmony_ci if (!pdata) 304562306a36Sopenharmony_ci return; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci parport_pc_unregister_port(pdata); 304862306a36Sopenharmony_ci} 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci/* we only need the pnp layer to activate the device, at least for now */ 305162306a36Sopenharmony_cistatic struct pnp_driver parport_pc_pnp_driver = { 305262306a36Sopenharmony_ci .name = "parport_pc", 305362306a36Sopenharmony_ci .id_table = parport_pc_pnp_tbl, 305462306a36Sopenharmony_ci .probe = parport_pc_pnp_probe, 305562306a36Sopenharmony_ci .remove = parport_pc_pnp_remove, 305662306a36Sopenharmony_ci}; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci#else 305962306a36Sopenharmony_cistatic struct pnp_driver parport_pc_pnp_driver; 306062306a36Sopenharmony_ci#endif /* CONFIG_PNP */ 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_cistatic int parport_pc_platform_probe(struct platform_device *pdev) 306362306a36Sopenharmony_ci{ 306462306a36Sopenharmony_ci /* Always succeed, the actual probing is done in 306562306a36Sopenharmony_ci * parport_pc_probe_port(). */ 306662306a36Sopenharmony_ci return 0; 306762306a36Sopenharmony_ci} 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_cistatic struct platform_driver parport_pc_platform_driver = { 307062306a36Sopenharmony_ci .driver = { 307162306a36Sopenharmony_ci .name = "parport_pc", 307262306a36Sopenharmony_ci }, 307362306a36Sopenharmony_ci .probe = parport_pc_platform_probe, 307462306a36Sopenharmony_ci}; 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci/* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ 307762306a36Sopenharmony_cistatic int __attribute__((unused)) 307862306a36Sopenharmony_ciparport_pc_find_isa_ports(int autoirq, int autodma) 307962306a36Sopenharmony_ci{ 308062306a36Sopenharmony_ci int count = 0; 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL, 0)) 308362306a36Sopenharmony_ci count++; 308462306a36Sopenharmony_ci if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL, 0)) 308562306a36Sopenharmony_ci count++; 308662306a36Sopenharmony_ci if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL, 0)) 308762306a36Sopenharmony_ci count++; 308862306a36Sopenharmony_ci 308962306a36Sopenharmony_ci return count; 309062306a36Sopenharmony_ci} 309162306a36Sopenharmony_ci 309262306a36Sopenharmony_ci/* This function is called by parport_pc_init if the user didn't 309362306a36Sopenharmony_ci * specify any ports to probe. Its job is to find some ports. Order 309462306a36Sopenharmony_ci * is important here -- we want ISA ports to be registered first, 309562306a36Sopenharmony_ci * followed by PCI cards (for least surprise), but before that we want 309662306a36Sopenharmony_ci * to do chipset-specific tests for some onboard ports that we know 309762306a36Sopenharmony_ci * about. 309862306a36Sopenharmony_ci * 309962306a36Sopenharmony_ci * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY 310062306a36Sopenharmony_ci * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO 310162306a36Sopenharmony_ci */ 310262306a36Sopenharmony_cistatic void __init parport_pc_find_ports(int autoirq, int autodma) 310362306a36Sopenharmony_ci{ 310462306a36Sopenharmony_ci int count = 0, err; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_SUPERIO 310762306a36Sopenharmony_ci detect_and_report_it87(); 310862306a36Sopenharmony_ci detect_and_report_winbond(); 310962306a36Sopenharmony_ci detect_and_report_smsc(); 311062306a36Sopenharmony_ci#endif 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci /* Onboard SuperIO chipsets that show themselves on the PCI bus. */ 311362306a36Sopenharmony_ci count += parport_pc_init_superio(autoirq, autodma); 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci /* PnP ports, skip detection if SuperIO already found them */ 311662306a36Sopenharmony_ci if (!count) { 311762306a36Sopenharmony_ci err = pnp_register_driver(&parport_pc_pnp_driver); 311862306a36Sopenharmony_ci if (!err) 311962306a36Sopenharmony_ci pnp_registered_parport = 1; 312062306a36Sopenharmony_ci } 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci /* ISA ports and whatever (see asm/parport.h). */ 312362306a36Sopenharmony_ci parport_pc_find_nonpci_ports(autoirq, autodma); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci err = pci_register_driver(&parport_pc_pci_driver); 312662306a36Sopenharmony_ci if (!err) 312762306a36Sopenharmony_ci pci_registered_parport = 1; 312862306a36Sopenharmony_ci} 312962306a36Sopenharmony_ci 313062306a36Sopenharmony_ci/* 313162306a36Sopenharmony_ci * Piles of crap below pretend to be a parser for module and kernel 313262306a36Sopenharmony_ci * parameters. Say "thank you" to whoever had come up with that 313362306a36Sopenharmony_ci * syntax and keep in mind that code below is a cleaned up version. 313462306a36Sopenharmony_ci */ 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_cistatic int __initdata io[PARPORT_PC_MAX_PORTS+1] = { 313762306a36Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS] = 0 313862306a36Sopenharmony_ci}; 313962306a36Sopenharmony_cistatic int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] = { 314062306a36Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO 314162306a36Sopenharmony_ci}; 314262306a36Sopenharmony_cistatic int __initdata dmaval[PARPORT_PC_MAX_PORTS] = { 314362306a36Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE 314462306a36Sopenharmony_ci}; 314562306a36Sopenharmony_cistatic int __initdata irqval[PARPORT_PC_MAX_PORTS] = { 314662306a36Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY 314762306a36Sopenharmony_ci}; 314862306a36Sopenharmony_ci 314962306a36Sopenharmony_cistatic int __init parport_parse_param(const char *s, int *val, 315062306a36Sopenharmony_ci int automatic, int none, int nofifo) 315162306a36Sopenharmony_ci{ 315262306a36Sopenharmony_ci if (!s) 315362306a36Sopenharmony_ci return 0; 315462306a36Sopenharmony_ci if (!strncmp(s, "auto", 4)) 315562306a36Sopenharmony_ci *val = automatic; 315662306a36Sopenharmony_ci else if (!strncmp(s, "none", 4)) 315762306a36Sopenharmony_ci *val = none; 315862306a36Sopenharmony_ci else if (nofifo && !strncmp(s, "nofifo", 6)) 315962306a36Sopenharmony_ci *val = nofifo; 316062306a36Sopenharmony_ci else { 316162306a36Sopenharmony_ci char *ep; 316262306a36Sopenharmony_ci unsigned long r = simple_strtoul(s, &ep, 0); 316362306a36Sopenharmony_ci if (ep != s) 316462306a36Sopenharmony_ci *val = r; 316562306a36Sopenharmony_ci else { 316662306a36Sopenharmony_ci pr_err("parport: bad specifier `%s'\n", s); 316762306a36Sopenharmony_ci return -1; 316862306a36Sopenharmony_ci } 316962306a36Sopenharmony_ci } 317062306a36Sopenharmony_ci return 0; 317162306a36Sopenharmony_ci} 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_cistatic int __init parport_parse_irq(const char *irqstr, int *val) 317462306a36Sopenharmony_ci{ 317562306a36Sopenharmony_ci return parport_parse_param(irqstr, val, PARPORT_IRQ_AUTO, 317662306a36Sopenharmony_ci PARPORT_IRQ_NONE, 0); 317762306a36Sopenharmony_ci} 317862306a36Sopenharmony_ci 317962306a36Sopenharmony_cistatic int __init parport_parse_dma(const char *dmastr, int *val) 318062306a36Sopenharmony_ci{ 318162306a36Sopenharmony_ci return parport_parse_param(dmastr, val, PARPORT_DMA_AUTO, 318262306a36Sopenharmony_ci PARPORT_DMA_NONE, PARPORT_DMA_NOFIFO); 318362306a36Sopenharmony_ci} 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci#ifdef CONFIG_PCI 318662306a36Sopenharmony_cistatic int __init parport_init_mode_setup(char *str) 318762306a36Sopenharmony_ci{ 318862306a36Sopenharmony_ci printk(KERN_DEBUG "parport_pc.c: Specified parameter parport_init_mode=%s\n", 318962306a36Sopenharmony_ci str); 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci if (!strcmp(str, "spp")) 319262306a36Sopenharmony_ci parport_init_mode = 1; 319362306a36Sopenharmony_ci if (!strcmp(str, "ps2")) 319462306a36Sopenharmony_ci parport_init_mode = 2; 319562306a36Sopenharmony_ci if (!strcmp(str, "epp")) 319662306a36Sopenharmony_ci parport_init_mode = 3; 319762306a36Sopenharmony_ci if (!strcmp(str, "ecp")) 319862306a36Sopenharmony_ci parport_init_mode = 4; 319962306a36Sopenharmony_ci if (!strcmp(str, "ecpepp")) 320062306a36Sopenharmony_ci parport_init_mode = 5; 320162306a36Sopenharmony_ci return 1; 320262306a36Sopenharmony_ci} 320362306a36Sopenharmony_ci#endif 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci#ifdef MODULE 320662306a36Sopenharmony_cistatic char *irq[PARPORT_PC_MAX_PORTS]; 320762306a36Sopenharmony_cistatic char *dma[PARPORT_PC_MAX_PORTS]; 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ciMODULE_PARM_DESC(io, "Base I/O address (SPP regs)"); 321062306a36Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0); 321162306a36Sopenharmony_ciMODULE_PARM_DESC(io_hi, "Base I/O address (ECR)"); 321262306a36Sopenharmony_cimodule_param_hw_array(io_hi, int, ioport, NULL, 0); 321362306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ line"); 321462306a36Sopenharmony_cimodule_param_hw_array(irq, charp, irq, NULL, 0); 321562306a36Sopenharmony_ciMODULE_PARM_DESC(dma, "DMA channel"); 321662306a36Sopenharmony_cimodule_param_hw_array(dma, charp, dma, NULL, 0); 321762306a36Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ 321862306a36Sopenharmony_ci (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) 321962306a36Sopenharmony_ciMODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); 322062306a36Sopenharmony_cimodule_param(verbose_probing, int, 0644); 322162306a36Sopenharmony_ci#endif 322262306a36Sopenharmony_ci#ifdef CONFIG_PCI 322362306a36Sopenharmony_cistatic char *init_mode; 322462306a36Sopenharmony_ciMODULE_PARM_DESC(init_mode, 322562306a36Sopenharmony_ci "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)"); 322662306a36Sopenharmony_cimodule_param(init_mode, charp, 0); 322762306a36Sopenharmony_ci#endif 322862306a36Sopenharmony_ci 322962306a36Sopenharmony_cistatic int __init parse_parport_params(void) 323062306a36Sopenharmony_ci{ 323162306a36Sopenharmony_ci unsigned int i; 323262306a36Sopenharmony_ci int val; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci#ifdef CONFIG_PCI 323562306a36Sopenharmony_ci if (init_mode) 323662306a36Sopenharmony_ci parport_init_mode_setup(init_mode); 323762306a36Sopenharmony_ci#endif 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_ci for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++) { 324062306a36Sopenharmony_ci if (parport_parse_irq(irq[i], &val)) 324162306a36Sopenharmony_ci return 1; 324262306a36Sopenharmony_ci irqval[i] = val; 324362306a36Sopenharmony_ci if (parport_parse_dma(dma[i], &val)) 324462306a36Sopenharmony_ci return 1; 324562306a36Sopenharmony_ci dmaval[i] = val; 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci if (!io[0]) { 324862306a36Sopenharmony_ci /* The user can make us use any IRQs or DMAs we find. */ 324962306a36Sopenharmony_ci if (irq[0] && !parport_parse_irq(irq[0], &val)) 325062306a36Sopenharmony_ci switch (val) { 325162306a36Sopenharmony_ci case PARPORT_IRQ_NONE: 325262306a36Sopenharmony_ci case PARPORT_IRQ_AUTO: 325362306a36Sopenharmony_ci irqval[0] = val; 325462306a36Sopenharmony_ci break; 325562306a36Sopenharmony_ci default: 325662306a36Sopenharmony_ci pr_warn("parport_pc: irq specified without base address. Use 'io=' to specify one\n"); 325762306a36Sopenharmony_ci } 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci if (dma[0] && !parport_parse_dma(dma[0], &val)) 326062306a36Sopenharmony_ci switch (val) { 326162306a36Sopenharmony_ci case PARPORT_DMA_NONE: 326262306a36Sopenharmony_ci case PARPORT_DMA_AUTO: 326362306a36Sopenharmony_ci dmaval[0] = val; 326462306a36Sopenharmony_ci break; 326562306a36Sopenharmony_ci default: 326662306a36Sopenharmony_ci pr_warn("parport_pc: dma specified without base address. Use 'io=' to specify one\n"); 326762306a36Sopenharmony_ci } 326862306a36Sopenharmony_ci } 326962306a36Sopenharmony_ci return 0; 327062306a36Sopenharmony_ci} 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci#else 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_cistatic int parport_setup_ptr __initdata; 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci/* 327762306a36Sopenharmony_ci * Acceptable parameters: 327862306a36Sopenharmony_ci * 327962306a36Sopenharmony_ci * parport=0 328062306a36Sopenharmony_ci * parport=auto 328162306a36Sopenharmony_ci * parport=0xBASE[,IRQ[,DMA]] 328262306a36Sopenharmony_ci * 328362306a36Sopenharmony_ci * IRQ/DMA may be numeric or 'auto' or 'none' 328462306a36Sopenharmony_ci */ 328562306a36Sopenharmony_cistatic int __init parport_setup(char *str) 328662306a36Sopenharmony_ci{ 328762306a36Sopenharmony_ci char *endptr; 328862306a36Sopenharmony_ci char *sep; 328962306a36Sopenharmony_ci int val; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci if (!str || !*str || (*str == '0' && !*(str+1))) { 329262306a36Sopenharmony_ci /* Disable parport if "parport=0" in cmdline */ 329362306a36Sopenharmony_ci io[0] = PARPORT_DISABLE; 329462306a36Sopenharmony_ci return 1; 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci if (!strncmp(str, "auto", 4)) { 329862306a36Sopenharmony_ci irqval[0] = PARPORT_IRQ_AUTO; 329962306a36Sopenharmony_ci dmaval[0] = PARPORT_DMA_AUTO; 330062306a36Sopenharmony_ci return 1; 330162306a36Sopenharmony_ci } 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_ci val = simple_strtoul(str, &endptr, 0); 330462306a36Sopenharmony_ci if (endptr == str) { 330562306a36Sopenharmony_ci pr_warn("parport=%s not understood\n", str); 330662306a36Sopenharmony_ci return 1; 330762306a36Sopenharmony_ci } 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci if (parport_setup_ptr == PARPORT_PC_MAX_PORTS) { 331062306a36Sopenharmony_ci pr_err("parport=%s ignored, too many ports\n", str); 331162306a36Sopenharmony_ci return 1; 331262306a36Sopenharmony_ci } 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci io[parport_setup_ptr] = val; 331562306a36Sopenharmony_ci irqval[parport_setup_ptr] = PARPORT_IRQ_NONE; 331662306a36Sopenharmony_ci dmaval[parport_setup_ptr] = PARPORT_DMA_NONE; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci sep = strchr(str, ','); 331962306a36Sopenharmony_ci if (sep++) { 332062306a36Sopenharmony_ci if (parport_parse_irq(sep, &val)) 332162306a36Sopenharmony_ci return 1; 332262306a36Sopenharmony_ci irqval[parport_setup_ptr] = val; 332362306a36Sopenharmony_ci sep = strchr(sep, ','); 332462306a36Sopenharmony_ci if (sep++) { 332562306a36Sopenharmony_ci if (parport_parse_dma(sep, &val)) 332662306a36Sopenharmony_ci return 1; 332762306a36Sopenharmony_ci dmaval[parport_setup_ptr] = val; 332862306a36Sopenharmony_ci } 332962306a36Sopenharmony_ci } 333062306a36Sopenharmony_ci parport_setup_ptr++; 333162306a36Sopenharmony_ci return 1; 333262306a36Sopenharmony_ci} 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_cistatic int __init parse_parport_params(void) 333562306a36Sopenharmony_ci{ 333662306a36Sopenharmony_ci return io[0] == PARPORT_DISABLE; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ci__setup("parport=", parport_setup); 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_ci/* 334262306a36Sopenharmony_ci * Acceptable parameters: 334362306a36Sopenharmony_ci * 334462306a36Sopenharmony_ci * parport_init_mode=[spp|ps2|epp|ecp|ecpepp] 334562306a36Sopenharmony_ci */ 334662306a36Sopenharmony_ci#ifdef CONFIG_PCI 334762306a36Sopenharmony_ci__setup("parport_init_mode=", parport_init_mode_setup); 334862306a36Sopenharmony_ci#endif 334962306a36Sopenharmony_ci#endif 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci/* "Parser" ends here */ 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_cistatic int __init parport_pc_init(void) 335462306a36Sopenharmony_ci{ 335562306a36Sopenharmony_ci int err; 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci if (parse_parport_params()) 335862306a36Sopenharmony_ci return -EINVAL; 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci err = platform_driver_register(&parport_pc_platform_driver); 336162306a36Sopenharmony_ci if (err) 336262306a36Sopenharmony_ci return err; 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci if (io[0]) { 336562306a36Sopenharmony_ci int i; 336662306a36Sopenharmony_ci /* Only probe the ports we were given. */ 336762306a36Sopenharmony_ci user_specified = 1; 336862306a36Sopenharmony_ci for (i = 0; i < PARPORT_PC_MAX_PORTS; i++) { 336962306a36Sopenharmony_ci if (!io[i]) 337062306a36Sopenharmony_ci break; 337162306a36Sopenharmony_ci if (io_hi[i] == PARPORT_IOHI_AUTO) 337262306a36Sopenharmony_ci io_hi[i] = 0x400 + io[i]; 337362306a36Sopenharmony_ci parport_pc_probe_port(io[i], io_hi[i], 337462306a36Sopenharmony_ci irqval[i], dmaval[i], NULL, 0); 337562306a36Sopenharmony_ci } 337662306a36Sopenharmony_ci } else 337762306a36Sopenharmony_ci parport_pc_find_ports(irqval[0], dmaval[0]); 337862306a36Sopenharmony_ci 337962306a36Sopenharmony_ci return 0; 338062306a36Sopenharmony_ci} 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_cistatic void __exit parport_pc_exit(void) 338362306a36Sopenharmony_ci{ 338462306a36Sopenharmony_ci if (pci_registered_parport) 338562306a36Sopenharmony_ci pci_unregister_driver(&parport_pc_pci_driver); 338662306a36Sopenharmony_ci if (pnp_registered_parport) 338762306a36Sopenharmony_ci pnp_unregister_driver(&parport_pc_pnp_driver); 338862306a36Sopenharmony_ci platform_driver_unregister(&parport_pc_platform_driver); 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci while (!list_empty(&ports_list)) { 339162306a36Sopenharmony_ci struct parport_pc_private *priv; 339262306a36Sopenharmony_ci struct parport *port; 339362306a36Sopenharmony_ci struct device *dev; 339462306a36Sopenharmony_ci priv = list_entry(ports_list.next, 339562306a36Sopenharmony_ci struct parport_pc_private, list); 339662306a36Sopenharmony_ci port = priv->port; 339762306a36Sopenharmony_ci dev = port->dev; 339862306a36Sopenharmony_ci parport_pc_unregister_port(port); 339962306a36Sopenharmony_ci if (dev && dev->bus == &platform_bus_type) 340062306a36Sopenharmony_ci platform_device_unregister(to_platform_device(dev)); 340162306a36Sopenharmony_ci } 340262306a36Sopenharmony_ci} 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ciMODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); 340562306a36Sopenharmony_ciMODULE_DESCRIPTION("PC-style parallel port driver"); 340662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 340762306a36Sopenharmony_cimodule_init(parport_pc_init) 340862306a36Sopenharmony_cimodule_exit(parport_pc_exit) 3409