18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Low-level parallel-port routines for 8255-based PC-style hardware. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Authors: Phil Blundell <philb@gnu.org> 58c2ecf20Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> 68c2ecf20Sopenharmony_ci * Jose Renau <renau@acm.org> 78c2ecf20Sopenharmony_ci * David Campbell 88c2ecf20Sopenharmony_ci * Andrea Arcangeli 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * based on work by Grant Guenther <grant@torque.net> and Phil Blundell. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Cleaned up include files - Russell King <linux@arm.uk.linux.org> 138c2ecf20Sopenharmony_ci * DMA support - Bert De Jonghe <bert@sophis.be> 148c2ecf20Sopenharmony_ci * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999 158c2ecf20Sopenharmony_ci * More PCI support now conditional on CONFIG_PCI, 03/2001, Paul G. 168c2ecf20Sopenharmony_ci * Various hacks, Fred Barnes, 04/2001 178c2ecf20Sopenharmony_ci * Updated probing logic - Adam Belay <ambx1@neo.rr.com> 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* This driver should work with any hardware that is broadly compatible 218c2ecf20Sopenharmony_ci * with that in the IBM PC. This applies to the majority of integrated 228c2ecf20Sopenharmony_ci * I/O chipsets that are commonly available. The expected register 238c2ecf20Sopenharmony_ci * layout is: 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * base+0 data 268c2ecf20Sopenharmony_ci * base+1 status 278c2ecf20Sopenharmony_ci * base+2 control 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * In addition, there are some optional registers: 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * base+3 EPP address 328c2ecf20Sopenharmony_ci * base+4 EPP data 338c2ecf20Sopenharmony_ci * base+0x400 ECP config A 348c2ecf20Sopenharmony_ci * base+0x401 ECP config B 358c2ecf20Sopenharmony_ci * base+0x402 ECP control 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * All registers are 8 bits wide and read/write. If your hardware differs 388c2ecf20Sopenharmony_ci * only in register addresses (eg because your registers are on 32-bit 398c2ecf20Sopenharmony_ci * word boundaries) then you can alter the constants in parport_pc.h to 408c2ecf20Sopenharmony_ci * accommodate this. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Note that the ECP registers may not start at offset 0x400 for PCI cards, 438c2ecf20Sopenharmony_ci * but rather will start at port->base_hi. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#include <linux/module.h> 478c2ecf20Sopenharmony_ci#include <linux/init.h> 488c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 498c2ecf20Sopenharmony_ci#include <linux/delay.h> 508c2ecf20Sopenharmony_ci#include <linux/errno.h> 518c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 528c2ecf20Sopenharmony_ci#include <linux/ioport.h> 538c2ecf20Sopenharmony_ci#include <linux/kernel.h> 548c2ecf20Sopenharmony_ci#include <linux/slab.h> 558c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 568c2ecf20Sopenharmony_ci#include <linux/pci.h> 578c2ecf20Sopenharmony_ci#include <linux/pnp.h> 588c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 598c2ecf20Sopenharmony_ci#include <linux/sysctl.h> 608c2ecf20Sopenharmony_ci#include <linux/io.h> 618c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#include <asm/dma.h> 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include <linux/parport.h> 668c2ecf20Sopenharmony_ci#include <linux/parport_pc.h> 678c2ecf20Sopenharmony_ci#include <linux/via.h> 688c2ecf20Sopenharmony_ci#include <asm/parport.h> 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#define PARPORT_PC_MAX_PORTS PARPORT_MAX 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#ifdef CONFIG_ISA_DMA_API 738c2ecf20Sopenharmony_ci#define HAS_DMA 748c2ecf20Sopenharmony_ci#endif 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* ECR modes */ 778c2ecf20Sopenharmony_ci#define ECR_SPP 00 788c2ecf20Sopenharmony_ci#define ECR_PS2 01 798c2ecf20Sopenharmony_ci#define ECR_PPF 02 808c2ecf20Sopenharmony_ci#define ECR_ECP 03 818c2ecf20Sopenharmony_ci#define ECR_EPP 04 828c2ecf20Sopenharmony_ci#define ECR_VND 05 838c2ecf20Sopenharmony_ci#define ECR_TST 06 848c2ecf20Sopenharmony_ci#define ECR_CNF 07 858c2ecf20Sopenharmony_ci#define ECR_MODE_MASK 0xe0 868c2ecf20Sopenharmony_ci#define ECR_WRITE(p, v) frob_econtrol((p), 0xff, (v)) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#undef DEBUG 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define NR_SUPERIOS 3 918c2ecf20Sopenharmony_cistatic struct superio_struct { /* For Super-IO chips autodetection */ 928c2ecf20Sopenharmony_ci int io; 938c2ecf20Sopenharmony_ci int irq; 948c2ecf20Sopenharmony_ci int dma; 958c2ecf20Sopenharmony_ci} superios[NR_SUPERIOS] = { {0,},}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int user_specified; 988c2ecf20Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ 998c2ecf20Sopenharmony_ci (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) 1008c2ecf20Sopenharmony_cistatic int verbose_probing; 1018c2ecf20Sopenharmony_ci#endif 1028c2ecf20Sopenharmony_cistatic int pci_registered_parport; 1038c2ecf20Sopenharmony_cistatic int pnp_registered_parport; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/* frob_control, but for ECR */ 1068c2ecf20Sopenharmony_cistatic void frob_econtrol(struct parport *pb, unsigned char m, 1078c2ecf20Sopenharmony_ci unsigned char v) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci unsigned char ectr = 0; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (m != 0xff) 1128c2ecf20Sopenharmony_ci ectr = inb(ECONTROL(pb)); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci pr_debug("frob_econtrol(%02x,%02x): %02x -> %02x\n", 1158c2ecf20Sopenharmony_ci m, v, ectr, (ectr & ~m) ^ v); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci outb((ectr & ~m) ^ v, ECONTROL(pb)); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic inline void frob_set_mode(struct parport *p, int mode) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci frob_econtrol(p, ECR_MODE_MASK, mode << 5); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 1268c2ecf20Sopenharmony_ci/* Safely change the mode bits in the ECR 1278c2ecf20Sopenharmony_ci Returns: 1288c2ecf20Sopenharmony_ci 0 : Success 1298c2ecf20Sopenharmony_ci -EBUSY: Could not drain FIFO in some finite amount of time, 1308c2ecf20Sopenharmony_ci mode not changed! 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cistatic int change_mode(struct parport *p, int m) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = p->physport->private_data; 1358c2ecf20Sopenharmony_ci unsigned char oecr; 1368c2ecf20Sopenharmony_ci int mode; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci pr_debug("parport change_mode ECP-ISA to mode 0x%02x\n", m); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!priv->ecr) { 1418c2ecf20Sopenharmony_ci printk(KERN_DEBUG "change_mode: but there's no ECR!\n"); 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Bits <7:5> contain the mode. */ 1468c2ecf20Sopenharmony_ci oecr = inb(ECONTROL(p)); 1478c2ecf20Sopenharmony_ci mode = (oecr >> 5) & 0x7; 1488c2ecf20Sopenharmony_ci if (mode == m) 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (mode >= 2 && !(priv->ctr & 0x20)) { 1528c2ecf20Sopenharmony_ci /* This mode resets the FIFO, so we may 1538c2ecf20Sopenharmony_ci * have to wait for it to drain first. */ 1548c2ecf20Sopenharmony_ci unsigned long expire = jiffies + p->physport->cad->timeout; 1558c2ecf20Sopenharmony_ci int counter; 1568c2ecf20Sopenharmony_ci switch (mode) { 1578c2ecf20Sopenharmony_ci case ECR_PPF: /* Parallel Port FIFO mode */ 1588c2ecf20Sopenharmony_ci case ECR_ECP: /* ECP Parallel Port mode */ 1598c2ecf20Sopenharmony_ci /* Busy wait for 200us */ 1608c2ecf20Sopenharmony_ci for (counter = 0; counter < 40; counter++) { 1618c2ecf20Sopenharmony_ci if (inb(ECONTROL(p)) & 0x01) 1628c2ecf20Sopenharmony_ci break; 1638c2ecf20Sopenharmony_ci if (signal_pending(current)) 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci udelay(5); 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Poll slowly. */ 1698c2ecf20Sopenharmony_ci while (!(inb(ECONTROL(p)) & 0x01)) { 1708c2ecf20Sopenharmony_ci if (time_after_eq(jiffies, expire)) 1718c2ecf20Sopenharmony_ci /* The FIFO is stuck. */ 1728c2ecf20Sopenharmony_ci return -EBUSY; 1738c2ecf20Sopenharmony_ci schedule_timeout_interruptible( 1748c2ecf20Sopenharmony_ci msecs_to_jiffies(10)); 1758c2ecf20Sopenharmony_ci if (signal_pending(current)) 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (mode >= 2 && m >= 2) { 1828c2ecf20Sopenharmony_ci /* We have to go through mode 001 */ 1838c2ecf20Sopenharmony_ci oecr &= ~(7 << 5); 1848c2ecf20Sopenharmony_ci oecr |= ECR_PS2 << 5; 1858c2ecf20Sopenharmony_ci ECR_WRITE(p, oecr); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* Set the mode. */ 1898c2ecf20Sopenharmony_ci oecr &= ~(7 << 5); 1908c2ecf20Sopenharmony_ci oecr |= m << 5; 1918c2ecf20Sopenharmony_ci ECR_WRITE(p, oecr); 1928c2ecf20Sopenharmony_ci return 0; 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci#endif /* FIFO support */ 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/* 1978c2ecf20Sopenharmony_ci * Clear TIMEOUT BIT in EPP MODE 1988c2ecf20Sopenharmony_ci * 1998c2ecf20Sopenharmony_ci * This is also used in SPP detection. 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_cistatic int clear_epp_timeout(struct parport *pb) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci unsigned char r; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (!(parport_pc_read_status(pb) & 0x01)) 2068c2ecf20Sopenharmony_ci return 1; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* To clear timeout some chips require double read */ 2098c2ecf20Sopenharmony_ci parport_pc_read_status(pb); 2108c2ecf20Sopenharmony_ci r = parport_pc_read_status(pb); 2118c2ecf20Sopenharmony_ci outb(r | 0x01, STATUS(pb)); /* Some reset by writing 1 */ 2128c2ecf20Sopenharmony_ci outb(r & 0xfe, STATUS(pb)); /* Others by writing 0 */ 2138c2ecf20Sopenharmony_ci r = parport_pc_read_status(pb); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return !(r & 0x01); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* 2198c2ecf20Sopenharmony_ci * Access functions. 2208c2ecf20Sopenharmony_ci * 2218c2ecf20Sopenharmony_ci * Most of these aren't static because they may be used by the 2228c2ecf20Sopenharmony_ci * parport_xxx_yyy macros. extern __inline__ versions of several 2238c2ecf20Sopenharmony_ci * of these are in parport_pc.h. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic void parport_pc_init_state(struct pardevice *dev, 2278c2ecf20Sopenharmony_ci struct parport_state *s) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci s->u.pc.ctr = 0xc; 2308c2ecf20Sopenharmony_ci if (dev->irq_func && 2318c2ecf20Sopenharmony_ci dev->port->irq != PARPORT_IRQ_NONE) 2328c2ecf20Sopenharmony_ci /* Set ackIntEn */ 2338c2ecf20Sopenharmony_ci s->u.pc.ctr |= 0x10; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci s->u.pc.ecr = 0x34; /* NetMos chip can cause problems 0x24; 2368c2ecf20Sopenharmony_ci * D.Gruszka VScom */ 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic void parport_pc_save_state(struct parport *p, struct parport_state *s) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = p->physport->private_data; 2428c2ecf20Sopenharmony_ci s->u.pc.ctr = priv->ctr; 2438c2ecf20Sopenharmony_ci if (priv->ecr) 2448c2ecf20Sopenharmony_ci s->u.pc.ecr = inb(ECONTROL(p)); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic void parport_pc_restore_state(struct parport *p, 2488c2ecf20Sopenharmony_ci struct parport_state *s) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct parport_pc_private *priv = p->physport->private_data; 2518c2ecf20Sopenharmony_ci register unsigned char c = s->u.pc.ctr & priv->ctr_writable; 2528c2ecf20Sopenharmony_ci outb(c, CONTROL(p)); 2538c2ecf20Sopenharmony_ci priv->ctr = c; 2548c2ecf20Sopenharmony_ci if (priv->ecr) 2558c2ecf20Sopenharmony_ci ECR_WRITE(p, s->u.pc.ecr); 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 2598c2ecf20Sopenharmony_cistatic size_t parport_pc_epp_read_data(struct parport *port, void *buf, 2608c2ecf20Sopenharmony_ci size_t length, int flags) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci size_t got = 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (flags & PARPORT_W91284PIC) { 2658c2ecf20Sopenharmony_ci unsigned char status; 2668c2ecf20Sopenharmony_ci size_t left = length; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* use knowledge about data lines..: 2698c2ecf20Sopenharmony_ci * nFault is 0 if there is at least 1 byte in the Warp's FIFO 2708c2ecf20Sopenharmony_ci * pError is 1 if there are 16 bytes in the Warp's FIFO 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci status = inb(STATUS(port)); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci while (!(status & 0x08) && got < length) { 2758c2ecf20Sopenharmony_ci if (left >= 16 && (status & 0x20) && !(status & 0x08)) { 2768c2ecf20Sopenharmony_ci /* can grab 16 bytes from warp fifo */ 2778c2ecf20Sopenharmony_ci if (!((long)buf & 0x03)) 2788c2ecf20Sopenharmony_ci insl(EPPDATA(port), buf, 4); 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci insb(EPPDATA(port), buf, 16); 2818c2ecf20Sopenharmony_ci buf += 16; 2828c2ecf20Sopenharmony_ci got += 16; 2838c2ecf20Sopenharmony_ci left -= 16; 2848c2ecf20Sopenharmony_ci } else { 2858c2ecf20Sopenharmony_ci /* grab single byte from the warp fifo */ 2868c2ecf20Sopenharmony_ci *((char *)buf) = inb(EPPDATA(port)); 2878c2ecf20Sopenharmony_ci buf++; 2888c2ecf20Sopenharmony_ci got++; 2898c2ecf20Sopenharmony_ci left--; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci status = inb(STATUS(port)); 2928c2ecf20Sopenharmony_ci if (status & 0x01) { 2938c2ecf20Sopenharmony_ci /* EPP timeout should never occur... */ 2948c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: EPP timeout occurred while talking to w91284pic (should not have done)\n", 2958c2ecf20Sopenharmony_ci port->name); 2968c2ecf20Sopenharmony_ci clear_epp_timeout(port); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci return got; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 3028c2ecf20Sopenharmony_ci if (!(((long)buf | length) & 0x03)) 3038c2ecf20Sopenharmony_ci insl(EPPDATA(port), buf, (length >> 2)); 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci insb(EPPDATA(port), buf, length); 3068c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3078c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3088c2ecf20Sopenharmony_ci return -EIO; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci return length; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci for (; got < length; got++) { 3138c2ecf20Sopenharmony_ci *((char *)buf) = inb(EPPDATA(port)); 3148c2ecf20Sopenharmony_ci buf++; 3158c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3168c2ecf20Sopenharmony_ci /* EPP timeout */ 3178c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return got; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic size_t parport_pc_epp_write_data(struct parport *port, const void *buf, 3268c2ecf20Sopenharmony_ci size_t length, int flags) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci size_t written = 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 3318c2ecf20Sopenharmony_ci if (!(((long)buf | length) & 0x03)) 3328c2ecf20Sopenharmony_ci outsl(EPPDATA(port), buf, (length >> 2)); 3338c2ecf20Sopenharmony_ci else 3348c2ecf20Sopenharmony_ci outsb(EPPDATA(port), buf, length); 3358c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3368c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3378c2ecf20Sopenharmony_ci return -EIO; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci return length; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci for (; written < length; written++) { 3428c2ecf20Sopenharmony_ci outb(*((char *)buf), EPPDATA(port)); 3438c2ecf20Sopenharmony_ci buf++; 3448c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3458c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return written; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic size_t parport_pc_epp_read_addr(struct parport *port, void *buf, 3548c2ecf20Sopenharmony_ci size_t length, int flags) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci size_t got = 0; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 3598c2ecf20Sopenharmony_ci insb(EPPADDR(port), buf, length); 3608c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3618c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3628c2ecf20Sopenharmony_ci return -EIO; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci return length; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci for (; got < length; got++) { 3678c2ecf20Sopenharmony_ci *((char *)buf) = inb(EPPADDR(port)); 3688c2ecf20Sopenharmony_ci buf++; 3698c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3708c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci return got; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic size_t parport_pc_epp_write_addr(struct parport *port, 3798c2ecf20Sopenharmony_ci const void *buf, size_t length, 3808c2ecf20Sopenharmony_ci int flags) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci size_t written = 0; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if ((flags & PARPORT_EPP_FAST) && (length > 1)) { 3858c2ecf20Sopenharmony_ci outsb(EPPADDR(port), buf, length); 3868c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3878c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3888c2ecf20Sopenharmony_ci return -EIO; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci return length; 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci for (; written < length; written++) { 3938c2ecf20Sopenharmony_ci outb(*((char *)buf), EPPADDR(port)); 3948c2ecf20Sopenharmony_ci buf++; 3958c2ecf20Sopenharmony_ci if (inb(STATUS(port)) & 0x01) { 3968c2ecf20Sopenharmony_ci clear_epp_timeout(port); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return written; 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic size_t parport_pc_ecpepp_read_data(struct parport *port, void *buf, 4058c2ecf20Sopenharmony_ci size_t length, int flags) 4068c2ecf20Sopenharmony_ci{ 4078c2ecf20Sopenharmony_ci size_t got; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_EPP); 4108c2ecf20Sopenharmony_ci parport_pc_data_reverse(port); 4118c2ecf20Sopenharmony_ci parport_pc_write_control(port, 0x4); 4128c2ecf20Sopenharmony_ci got = parport_pc_epp_read_data(port, buf, length, flags); 4138c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci return got; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic size_t parport_pc_ecpepp_write_data(struct parport *port, 4198c2ecf20Sopenharmony_ci const void *buf, size_t length, 4208c2ecf20Sopenharmony_ci int flags) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci size_t written; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_EPP); 4258c2ecf20Sopenharmony_ci parport_pc_write_control(port, 0x4); 4268c2ecf20Sopenharmony_ci parport_pc_data_forward(port); 4278c2ecf20Sopenharmony_ci written = parport_pc_epp_write_data(port, buf, length, flags); 4288c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return written; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic size_t parport_pc_ecpepp_read_addr(struct parport *port, void *buf, 4348c2ecf20Sopenharmony_ci size_t length, int flags) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci size_t got; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_EPP); 4398c2ecf20Sopenharmony_ci parport_pc_data_reverse(port); 4408c2ecf20Sopenharmony_ci parport_pc_write_control(port, 0x4); 4418c2ecf20Sopenharmony_ci got = parport_pc_epp_read_addr(port, buf, length, flags); 4428c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return got; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic size_t parport_pc_ecpepp_write_addr(struct parport *port, 4488c2ecf20Sopenharmony_ci const void *buf, size_t length, 4498c2ecf20Sopenharmony_ci int flags) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci size_t written; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_EPP); 4548c2ecf20Sopenharmony_ci parport_pc_write_control(port, 0x4); 4558c2ecf20Sopenharmony_ci parport_pc_data_forward(port); 4568c2ecf20Sopenharmony_ci written = parport_pc_epp_write_addr(port, buf, length, flags); 4578c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return written; 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci#endif /* IEEE 1284 support */ 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 4648c2ecf20Sopenharmony_cistatic size_t parport_pc_fifo_write_block_pio(struct parport *port, 4658c2ecf20Sopenharmony_ci const void *buf, size_t length) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci int ret = 0; 4688c2ecf20Sopenharmony_ci const unsigned char *bufp = buf; 4698c2ecf20Sopenharmony_ci size_t left = length; 4708c2ecf20Sopenharmony_ci unsigned long expire = jiffies + port->physport->cad->timeout; 4718c2ecf20Sopenharmony_ci const unsigned long fifo = FIFO(port); 4728c2ecf20Sopenharmony_ci int poll_for = 8; /* 80 usecs */ 4738c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 4748c2ecf20Sopenharmony_ci const int fifo_depth = priv->fifo_depth; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci port = port->physport; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* We don't want to be interrupted every character. */ 4798c2ecf20Sopenharmony_ci parport_pc_disable_irq(port); 4808c2ecf20Sopenharmony_ci /* set nErrIntrEn and serviceIntr */ 4818c2ecf20Sopenharmony_ci frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci /* Forward mode. */ 4848c2ecf20Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci while (left) { 4878c2ecf20Sopenharmony_ci unsigned char byte; 4888c2ecf20Sopenharmony_ci unsigned char ecrval = inb(ECONTROL(port)); 4898c2ecf20Sopenharmony_ci int i = 0; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (need_resched() && time_before(jiffies, expire)) 4928c2ecf20Sopenharmony_ci /* Can't yield the port. */ 4938c2ecf20Sopenharmony_ci schedule(); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* Anyone else waiting for the port? */ 4968c2ecf20Sopenharmony_ci if (port->waithead) { 4978c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Somebody wants the port\n"); 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (ecrval & 0x02) { 5028c2ecf20Sopenharmony_ci /* FIFO is full. Wait for interrupt. */ 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* Clear serviceIntr */ 5058c2ecf20Sopenharmony_ci ECR_WRITE(port, ecrval & ~(1<<2)); 5068c2ecf20Sopenharmony_cifalse_alarm: 5078c2ecf20Sopenharmony_ci ret = parport_wait_event(port, HZ); 5088c2ecf20Sopenharmony_ci if (ret < 0) 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci ret = 0; 5118c2ecf20Sopenharmony_ci if (!time_before(jiffies, expire)) { 5128c2ecf20Sopenharmony_ci /* Timed out. */ 5138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "FIFO write timed out\n"); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci ecrval = inb(ECONTROL(port)); 5178c2ecf20Sopenharmony_ci if (!(ecrval & (1<<2))) { 5188c2ecf20Sopenharmony_ci if (need_resched() && 5198c2ecf20Sopenharmony_ci time_before(jiffies, expire)) 5208c2ecf20Sopenharmony_ci schedule(); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci goto false_alarm; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci continue; 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Can't fail now. */ 5298c2ecf20Sopenharmony_ci expire = jiffies + port->cad->timeout; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cipoll: 5328c2ecf20Sopenharmony_ci if (signal_pending(current)) 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (ecrval & 0x01) { 5368c2ecf20Sopenharmony_ci /* FIFO is empty. Blast it full. */ 5378c2ecf20Sopenharmony_ci const int n = left < fifo_depth ? left : fifo_depth; 5388c2ecf20Sopenharmony_ci outsb(fifo, bufp, n); 5398c2ecf20Sopenharmony_ci bufp += n; 5408c2ecf20Sopenharmony_ci left -= n; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* Adjust the poll time. */ 5438c2ecf20Sopenharmony_ci if (i < (poll_for - 2)) 5448c2ecf20Sopenharmony_ci poll_for--; 5458c2ecf20Sopenharmony_ci continue; 5468c2ecf20Sopenharmony_ci } else if (i++ < poll_for) { 5478c2ecf20Sopenharmony_ci udelay(10); 5488c2ecf20Sopenharmony_ci ecrval = inb(ECONTROL(port)); 5498c2ecf20Sopenharmony_ci goto poll; 5508c2ecf20Sopenharmony_ci } 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* Half-full(call me an optimist) */ 5538c2ecf20Sopenharmony_ci byte = *bufp++; 5548c2ecf20Sopenharmony_ci outb(byte, fifo); 5558c2ecf20Sopenharmony_ci left--; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci dump_parport_state("leave fifo_write_block_pio", port); 5588c2ecf20Sopenharmony_ci return length - left; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci#ifdef HAS_DMA 5628c2ecf20Sopenharmony_cistatic size_t parport_pc_fifo_write_block_dma(struct parport *port, 5638c2ecf20Sopenharmony_ci const void *buf, size_t length) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci int ret = 0; 5668c2ecf20Sopenharmony_ci unsigned long dmaflag; 5678c2ecf20Sopenharmony_ci size_t left = length; 5688c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 5698c2ecf20Sopenharmony_ci struct device *dev = port->physport->dev; 5708c2ecf20Sopenharmony_ci dma_addr_t dma_addr, dma_handle; 5718c2ecf20Sopenharmony_ci size_t maxlen = 0x10000; /* max 64k per DMA transfer */ 5728c2ecf20Sopenharmony_ci unsigned long start = (unsigned long) buf; 5738c2ecf20Sopenharmony_ci unsigned long end = (unsigned long) buf + length - 1; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci dump_parport_state("enter fifo_write_block_dma", port); 5768c2ecf20Sopenharmony_ci if (end < MAX_DMA_ADDRESS) { 5778c2ecf20Sopenharmony_ci /* If it would cross a 64k boundary, cap it at the end. */ 5788c2ecf20Sopenharmony_ci if ((start ^ end) & ~0xffffUL) 5798c2ecf20Sopenharmony_ci maxlen = 0x10000 - (start & 0xffff); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dma_addr = dma_handle = dma_map_single(dev, (void *)buf, length, 5828c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci /* above 16 MB we use a bounce buffer as ISA-DMA 5858c2ecf20Sopenharmony_ci is not possible */ 5868c2ecf20Sopenharmony_ci maxlen = PAGE_SIZE; /* sizeof(priv->dma_buf) */ 5878c2ecf20Sopenharmony_ci dma_addr = priv->dma_handle; 5888c2ecf20Sopenharmony_ci dma_handle = 0; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci port = port->physport; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci /* We don't want to be interrupted every character. */ 5948c2ecf20Sopenharmony_ci parport_pc_disable_irq(port); 5958c2ecf20Sopenharmony_ci /* set nErrIntrEn and serviceIntr */ 5968c2ecf20Sopenharmony_ci frob_econtrol(port, (1<<4) | (1<<2), (1<<4) | (1<<2)); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* Forward mode. */ 5998c2ecf20Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci while (left) { 6028c2ecf20Sopenharmony_ci unsigned long expire = jiffies + port->physport->cad->timeout; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci size_t count = left; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (count > maxlen) 6078c2ecf20Sopenharmony_ci count = maxlen; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!dma_handle) /* bounce buffer ! */ 6108c2ecf20Sopenharmony_ci memcpy(priv->dma_buf, buf, count); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci dmaflag = claim_dma_lock(); 6138c2ecf20Sopenharmony_ci disable_dma(port->dma); 6148c2ecf20Sopenharmony_ci clear_dma_ff(port->dma); 6158c2ecf20Sopenharmony_ci set_dma_mode(port->dma, DMA_MODE_WRITE); 6168c2ecf20Sopenharmony_ci set_dma_addr(port->dma, dma_addr); 6178c2ecf20Sopenharmony_ci set_dma_count(port->dma, count); 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* Set DMA mode */ 6208c2ecf20Sopenharmony_ci frob_econtrol(port, 1<<3, 1<<3); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Clear serviceIntr */ 6238c2ecf20Sopenharmony_ci frob_econtrol(port, 1<<2, 0); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci enable_dma(port->dma); 6268c2ecf20Sopenharmony_ci release_dma_lock(dmaflag); 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* assume DMA will be successful */ 6298c2ecf20Sopenharmony_ci left -= count; 6308c2ecf20Sopenharmony_ci buf += count; 6318c2ecf20Sopenharmony_ci if (dma_handle) 6328c2ecf20Sopenharmony_ci dma_addr += count; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* Wait for interrupt. */ 6358c2ecf20Sopenharmony_cifalse_alarm: 6368c2ecf20Sopenharmony_ci ret = parport_wait_event(port, HZ); 6378c2ecf20Sopenharmony_ci if (ret < 0) 6388c2ecf20Sopenharmony_ci break; 6398c2ecf20Sopenharmony_ci ret = 0; 6408c2ecf20Sopenharmony_ci if (!time_before(jiffies, expire)) { 6418c2ecf20Sopenharmony_ci /* Timed out. */ 6428c2ecf20Sopenharmony_ci printk(KERN_DEBUG "DMA write timed out\n"); 6438c2ecf20Sopenharmony_ci break; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci /* Is serviceIntr set? */ 6468c2ecf20Sopenharmony_ci if (!(inb(ECONTROL(port)) & (1<<2))) { 6478c2ecf20Sopenharmony_ci cond_resched(); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci goto false_alarm; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci dmaflag = claim_dma_lock(); 6538c2ecf20Sopenharmony_ci disable_dma(port->dma); 6548c2ecf20Sopenharmony_ci clear_dma_ff(port->dma); 6558c2ecf20Sopenharmony_ci count = get_dma_residue(port->dma); 6568c2ecf20Sopenharmony_ci release_dma_lock(dmaflag); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci cond_resched(); /* Can't yield the port. */ 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci /* Anyone else waiting for the port? */ 6618c2ecf20Sopenharmony_ci if (port->waithead) { 6628c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Somebody wants the port\n"); 6638c2ecf20Sopenharmony_ci break; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* update for possible DMA residue ! */ 6678c2ecf20Sopenharmony_ci buf -= count; 6688c2ecf20Sopenharmony_ci left += count; 6698c2ecf20Sopenharmony_ci if (dma_handle) 6708c2ecf20Sopenharmony_ci dma_addr -= count; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci /* Maybe got here through break, so adjust for DMA residue! */ 6748c2ecf20Sopenharmony_ci dmaflag = claim_dma_lock(); 6758c2ecf20Sopenharmony_ci disable_dma(port->dma); 6768c2ecf20Sopenharmony_ci clear_dma_ff(port->dma); 6778c2ecf20Sopenharmony_ci left += get_dma_residue(port->dma); 6788c2ecf20Sopenharmony_ci release_dma_lock(dmaflag); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* Turn off DMA mode */ 6818c2ecf20Sopenharmony_ci frob_econtrol(port, 1<<3, 0); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (dma_handle) 6848c2ecf20Sopenharmony_ci dma_unmap_single(dev, dma_handle, length, DMA_TO_DEVICE); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci dump_parport_state("leave fifo_write_block_dma", port); 6878c2ecf20Sopenharmony_ci return length - left; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci#endif 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic inline size_t parport_pc_fifo_write_block(struct parport *port, 6928c2ecf20Sopenharmony_ci const void *buf, size_t length) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci#ifdef HAS_DMA 6958c2ecf20Sopenharmony_ci if (port->dma != PARPORT_DMA_NONE) 6968c2ecf20Sopenharmony_ci return parport_pc_fifo_write_block_dma(port, buf, length); 6978c2ecf20Sopenharmony_ci#endif 6988c2ecf20Sopenharmony_ci return parport_pc_fifo_write_block_pio(port, buf, length); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/* Parallel Port FIFO mode (ECP chipsets) */ 7028c2ecf20Sopenharmony_cistatic size_t parport_pc_compat_write_block_pio(struct parport *port, 7038c2ecf20Sopenharmony_ci const void *buf, size_t length, 7048c2ecf20Sopenharmony_ci int flags) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci size_t written; 7078c2ecf20Sopenharmony_ci int r; 7088c2ecf20Sopenharmony_ci unsigned long expire; 7098c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci /* Special case: a timeout of zero means we cannot call schedule(). 7128c2ecf20Sopenharmony_ci * Also if O_NONBLOCK is set then use the default implementation. */ 7138c2ecf20Sopenharmony_ci if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) 7148c2ecf20Sopenharmony_ci return parport_ieee1284_write_compat(port, buf, 7158c2ecf20Sopenharmony_ci length, flags); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Set up parallel port FIFO mode.*/ 7188c2ecf20Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 7198c2ecf20Sopenharmony_ci parport_pc_frob_control(port, PARPORT_CONTROL_STROBE, 0); 7208c2ecf20Sopenharmony_ci r = change_mode(port, ECR_PPF); /* Parallel port FIFO */ 7218c2ecf20Sopenharmony_ci if (r) 7228c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Warning change_mode ECR_PPF failed\n", 7238c2ecf20Sopenharmony_ci port->name); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* Write the data to the FIFO. */ 7288c2ecf20Sopenharmony_ci written = parport_pc_fifo_write_block(port, buf, length); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* Finish up. */ 7318c2ecf20Sopenharmony_ci /* For some hardware we don't want to touch the mode until 7328c2ecf20Sopenharmony_ci * the FIFO is empty, so allow 4 seconds for each position 7338c2ecf20Sopenharmony_ci * in the fifo. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci expire = jiffies + (priv->fifo_depth * HZ * 4); 7368c2ecf20Sopenharmony_ci do { 7378c2ecf20Sopenharmony_ci /* Wait for the FIFO to empty */ 7388c2ecf20Sopenharmony_ci r = change_mode(port, ECR_PS2); 7398c2ecf20Sopenharmony_ci if (r != -EBUSY) 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci } while (time_before(jiffies, expire)); 7428c2ecf20Sopenharmony_ci if (r == -EBUSY) { 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci /* Prevent further data transfer. */ 7478c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_TST); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* Adjust for the contents of the FIFO. */ 7508c2ecf20Sopenharmony_ci for (written -= priv->fifo_depth; ; written++) { 7518c2ecf20Sopenharmony_ci if (inb(ECONTROL(port)) & 0x2) { 7528c2ecf20Sopenharmony_ci /* Full up. */ 7538c2ecf20Sopenharmony_ci break; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci outb(0, FIFO(port)); 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* Reset the FIFO and return to PS2 mode. */ 7598c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci r = parport_wait_peripheral(port, 7638c2ecf20Sopenharmony_ci PARPORT_STATUS_BUSY, 7648c2ecf20Sopenharmony_ci PARPORT_STATUS_BUSY); 7658c2ecf20Sopenharmony_ci if (r) 7668c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: BUSY timeout (%d) in compat_write_block_pio\n", 7678c2ecf20Sopenharmony_ci port->name, r); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return written; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/* ECP */ 7758c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 7768c2ecf20Sopenharmony_cistatic size_t parport_pc_ecp_write_block_pio(struct parport *port, 7778c2ecf20Sopenharmony_ci const void *buf, size_t length, 7788c2ecf20Sopenharmony_ci int flags) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci size_t written; 7818c2ecf20Sopenharmony_ci int r; 7828c2ecf20Sopenharmony_ci unsigned long expire; 7838c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = port->physport->private_data; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* Special case: a timeout of zero means we cannot call schedule(). 7868c2ecf20Sopenharmony_ci * Also if O_NONBLOCK is set then use the default implementation. */ 7878c2ecf20Sopenharmony_ci if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK) 7888c2ecf20Sopenharmony_ci return parport_ieee1284_ecp_write_data(port, buf, 7898c2ecf20Sopenharmony_ci length, flags); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci /* Switch to forward mode if necessary. */ 7928c2ecf20Sopenharmony_ci if (port->physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) { 7938c2ecf20Sopenharmony_ci /* Event 47: Set nInit high. */ 7948c2ecf20Sopenharmony_ci parport_frob_control(port, 7958c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT 7968c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD, 7978c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT 7988c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci /* Event 49: PError goes high. */ 8018c2ecf20Sopenharmony_ci r = parport_wait_peripheral(port, 8028c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 8038c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 8048c2ecf20Sopenharmony_ci if (r) { 8058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PError timeout (%d) in ecp_write_block_pio\n", 8068c2ecf20Sopenharmony_ci port->name, r); 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci /* Set up ECP parallel port mode.*/ 8118c2ecf20Sopenharmony_ci parport_pc_data_forward(port); /* Must be in PS2 mode */ 8128c2ecf20Sopenharmony_ci parport_pc_frob_control(port, 8138c2ecf20Sopenharmony_ci PARPORT_CONTROL_STROBE | 8148c2ecf20Sopenharmony_ci PARPORT_CONTROL_AUTOFD, 8158c2ecf20Sopenharmony_ci 0); 8168c2ecf20Sopenharmony_ci r = change_mode(port, ECR_ECP); /* ECP FIFO */ 8178c2ecf20Sopenharmony_ci if (r) 8188c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Warning change_mode ECR_ECP failed\n", 8198c2ecf20Sopenharmony_ci port->name); 8208c2ecf20Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* Write the data to the FIFO. */ 8238c2ecf20Sopenharmony_ci written = parport_pc_fifo_write_block(port, buf, length); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci /* Finish up. */ 8268c2ecf20Sopenharmony_ci /* For some hardware we don't want to touch the mode until 8278c2ecf20Sopenharmony_ci * the FIFO is empty, so allow 4 seconds for each position 8288c2ecf20Sopenharmony_ci * in the fifo. 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci expire = jiffies + (priv->fifo_depth * (HZ * 4)); 8318c2ecf20Sopenharmony_ci do { 8328c2ecf20Sopenharmony_ci /* Wait for the FIFO to empty */ 8338c2ecf20Sopenharmony_ci r = change_mode(port, ECR_PS2); 8348c2ecf20Sopenharmony_ci if (r != -EBUSY) 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci } while (time_before(jiffies, expire)); 8378c2ecf20Sopenharmony_ci if (r == -EBUSY) { 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: FIFO is stuck\n", port->name); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Prevent further data transfer. */ 8428c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_TST); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Adjust for the contents of the FIFO. */ 8458c2ecf20Sopenharmony_ci for (written -= priv->fifo_depth; ; written++) { 8468c2ecf20Sopenharmony_ci if (inb(ECONTROL(port)) & 0x2) { 8478c2ecf20Sopenharmony_ci /* Full up. */ 8488c2ecf20Sopenharmony_ci break; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci outb(0, FIFO(port)); 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* Reset the FIFO and return to PS2 mode. */ 8548c2ecf20Sopenharmony_ci frob_set_mode(port, ECR_PS2); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Host transfer recovery. */ 8578c2ecf20Sopenharmony_ci parport_pc_data_reverse(port); /* Must be in PS2 mode */ 8588c2ecf20Sopenharmony_ci udelay(5); 8598c2ecf20Sopenharmony_ci parport_frob_control(port, PARPORT_CONTROL_INIT, 0); 8608c2ecf20Sopenharmony_ci r = parport_wait_peripheral(port, PARPORT_STATUS_PAPEROUT, 0); 8618c2ecf20Sopenharmony_ci if (r) 8628c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PE,1 timeout (%d) in ecp_write_block_pio\n", 8638c2ecf20Sopenharmony_ci port->name, r); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci parport_frob_control(port, 8668c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT, 8678c2ecf20Sopenharmony_ci PARPORT_CONTROL_INIT); 8688c2ecf20Sopenharmony_ci r = parport_wait_peripheral(port, 8698c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT, 8708c2ecf20Sopenharmony_ci PARPORT_STATUS_PAPEROUT); 8718c2ecf20Sopenharmony_ci if (r) 8728c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: PE,2 timeout (%d) in ecp_write_block_pio\n", 8738c2ecf20Sopenharmony_ci port->name, r); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci r = parport_wait_peripheral(port, 8778c2ecf20Sopenharmony_ci PARPORT_STATUS_BUSY, 8788c2ecf20Sopenharmony_ci PARPORT_STATUS_BUSY); 8798c2ecf20Sopenharmony_ci if (r) 8808c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: BUSY timeout (%d) in ecp_write_block_pio\n", 8818c2ecf20Sopenharmony_ci port->name, r); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci port->physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci return written; 8868c2ecf20Sopenharmony_ci} 8878c2ecf20Sopenharmony_ci#endif /* IEEE 1284 support */ 8888c2ecf20Sopenharmony_ci#endif /* Allowed to use FIFO/DMA */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci/* 8928c2ecf20Sopenharmony_ci * ****************************************** 8938c2ecf20Sopenharmony_ci * INITIALISATION AND MODULE STUFF BELOW HERE 8948c2ecf20Sopenharmony_ci * ****************************************** 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci/* GCC is not inlining extern inline function later overwritten to non-inline, 8988c2ecf20Sopenharmony_ci so we use outlined_ variants here. */ 8998c2ecf20Sopenharmony_cistatic const struct parport_operations parport_pc_ops = { 9008c2ecf20Sopenharmony_ci .write_data = parport_pc_write_data, 9018c2ecf20Sopenharmony_ci .read_data = parport_pc_read_data, 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci .write_control = parport_pc_write_control, 9048c2ecf20Sopenharmony_ci .read_control = parport_pc_read_control, 9058c2ecf20Sopenharmony_ci .frob_control = parport_pc_frob_control, 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci .read_status = parport_pc_read_status, 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci .enable_irq = parport_pc_enable_irq, 9108c2ecf20Sopenharmony_ci .disable_irq = parport_pc_disable_irq, 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci .data_forward = parport_pc_data_forward, 9138c2ecf20Sopenharmony_ci .data_reverse = parport_pc_data_reverse, 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci .init_state = parport_pc_init_state, 9168c2ecf20Sopenharmony_ci .save_state = parport_pc_save_state, 9178c2ecf20Sopenharmony_ci .restore_state = parport_pc_restore_state, 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci .epp_write_data = parport_ieee1284_epp_write_data, 9208c2ecf20Sopenharmony_ci .epp_read_data = parport_ieee1284_epp_read_data, 9218c2ecf20Sopenharmony_ci .epp_write_addr = parport_ieee1284_epp_write_addr, 9228c2ecf20Sopenharmony_ci .epp_read_addr = parport_ieee1284_epp_read_addr, 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci .ecp_write_data = parport_ieee1284_ecp_write_data, 9258c2ecf20Sopenharmony_ci .ecp_read_data = parport_ieee1284_ecp_read_data, 9268c2ecf20Sopenharmony_ci .ecp_write_addr = parport_ieee1284_ecp_write_addr, 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci .compat_write_data = parport_ieee1284_write_compat, 9298c2ecf20Sopenharmony_ci .nibble_read_data = parport_ieee1284_read_nibble, 9308c2ecf20Sopenharmony_ci .byte_read_data = parport_ieee1284_read_byte, 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9338c2ecf20Sopenharmony_ci}; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_SUPERIO 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic struct superio_struct *find_free_superio(void) 9388c2ecf20Sopenharmony_ci{ 9398c2ecf20Sopenharmony_ci int i; 9408c2ecf20Sopenharmony_ci for (i = 0; i < NR_SUPERIOS; i++) 9418c2ecf20Sopenharmony_ci if (superios[i].io == 0) 9428c2ecf20Sopenharmony_ci return &superios[i]; 9438c2ecf20Sopenharmony_ci return NULL; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/* Super-IO chipset detection, Winbond, SMSC */ 9488c2ecf20Sopenharmony_cistatic void show_parconfig_smsc37c669(int io, int key) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci int cr1, cr4, cra, cr23, cr26, cr27; 9518c2ecf20Sopenharmony_ci struct superio_struct *s; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci static const char *const modes[] = { 9548c2ecf20Sopenharmony_ci "SPP and Bidirectional (PS/2)", 9558c2ecf20Sopenharmony_ci "EPP and SPP", 9568c2ecf20Sopenharmony_ci "ECP", 9578c2ecf20Sopenharmony_ci "ECP and EPP" }; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci outb(key, io); 9608c2ecf20Sopenharmony_ci outb(key, io); 9618c2ecf20Sopenharmony_ci outb(1, io); 9628c2ecf20Sopenharmony_ci cr1 = inb(io + 1); 9638c2ecf20Sopenharmony_ci outb(4, io); 9648c2ecf20Sopenharmony_ci cr4 = inb(io + 1); 9658c2ecf20Sopenharmony_ci outb(0x0a, io); 9668c2ecf20Sopenharmony_ci cra = inb(io + 1); 9678c2ecf20Sopenharmony_ci outb(0x23, io); 9688c2ecf20Sopenharmony_ci cr23 = inb(io + 1); 9698c2ecf20Sopenharmony_ci outb(0x26, io); 9708c2ecf20Sopenharmony_ci cr26 = inb(io + 1); 9718c2ecf20Sopenharmony_ci outb(0x27, io); 9728c2ecf20Sopenharmony_ci cr27 = inb(io + 1); 9738c2ecf20Sopenharmony_ci outb(0xaa, io); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (verbose_probing) { 9768c2ecf20Sopenharmony_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", 9778c2ecf20Sopenharmony_ci cr1, cr4, cra, cr23, cr26, cr27); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci /* The documentation calls DMA and IRQ-Lines by letters, so 9808c2ecf20Sopenharmony_ci the board maker can/will wire them 9818c2ecf20Sopenharmony_ci appropriately/randomly... G=reserved H=IDE-irq, */ 9828c2ecf20Sopenharmony_ci pr_info("SMSC LPT Config: io=0x%04x, irq=%c, dma=%c, fifo threshold=%d\n", 9838c2ecf20Sopenharmony_ci cr23 * 4, 9848c2ecf20Sopenharmony_ci (cr27 & 0x0f) ? 'A' - 1 + (cr27 & 0x0f) : '-', 9858c2ecf20Sopenharmony_ci (cr26 & 0x0f) ? 'A' - 1 + (cr26 & 0x0f) : '-', 9868c2ecf20Sopenharmony_ci cra & 0x0f); 9878c2ecf20Sopenharmony_ci pr_info("SMSC LPT Config: enabled=%s power=%s\n", 9888c2ecf20Sopenharmony_ci (cr23 * 4 >= 0x100) ? "yes" : "no", 9898c2ecf20Sopenharmony_ci (cr1 & 4) ? "yes" : "no"); 9908c2ecf20Sopenharmony_ci pr_info("SMSC LPT Config: Port mode=%s, EPP version =%s\n", 9918c2ecf20Sopenharmony_ci (cr1 & 0x08) ? "Standard mode only (SPP)" 9928c2ecf20Sopenharmony_ci : modes[cr4 & 0x03], 9938c2ecf20Sopenharmony_ci (cr4 & 0x40) ? "1.7" : "1.9"); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Heuristics ! BIOS setup for this mainboard device limits 9978c2ecf20Sopenharmony_ci the choices to standard settings, i.e. io-address and IRQ 9988c2ecf20Sopenharmony_ci are related, however DMA can be 1 or 3, assume DMA_A=DMA1, 9998c2ecf20Sopenharmony_ci DMA_C=DMA3 (this is true e.g. for TYAN 1564D Tomcat IV) */ 10008c2ecf20Sopenharmony_ci if (cr23 * 4 >= 0x100) { /* if active */ 10018c2ecf20Sopenharmony_ci s = find_free_superio(); 10028c2ecf20Sopenharmony_ci if (s == NULL) 10038c2ecf20Sopenharmony_ci pr_info("Super-IO: too many chips!\n"); 10048c2ecf20Sopenharmony_ci else { 10058c2ecf20Sopenharmony_ci int d; 10068c2ecf20Sopenharmony_ci switch (cr23 * 4) { 10078c2ecf20Sopenharmony_ci case 0x3bc: 10088c2ecf20Sopenharmony_ci s->io = 0x3bc; 10098c2ecf20Sopenharmony_ci s->irq = 7; 10108c2ecf20Sopenharmony_ci break; 10118c2ecf20Sopenharmony_ci case 0x378: 10128c2ecf20Sopenharmony_ci s->io = 0x378; 10138c2ecf20Sopenharmony_ci s->irq = 7; 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci case 0x278: 10168c2ecf20Sopenharmony_ci s->io = 0x278; 10178c2ecf20Sopenharmony_ci s->irq = 5; 10188c2ecf20Sopenharmony_ci } 10198c2ecf20Sopenharmony_ci d = (cr26 & 0x0f); 10208c2ecf20Sopenharmony_ci if (d == 1 || d == 3) 10218c2ecf20Sopenharmony_ci s->dma = d; 10228c2ecf20Sopenharmony_ci else 10238c2ecf20Sopenharmony_ci s->dma = PARPORT_DMA_NONE; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci} 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic void show_parconfig_winbond(int io, int key) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci int cr30, cr60, cr61, cr70, cr74, crf0; 10328c2ecf20Sopenharmony_ci struct superio_struct *s; 10338c2ecf20Sopenharmony_ci static const char *const modes[] = { 10348c2ecf20Sopenharmony_ci "Standard (SPP) and Bidirectional(PS/2)", /* 0 */ 10358c2ecf20Sopenharmony_ci "EPP-1.9 and SPP", 10368c2ecf20Sopenharmony_ci "ECP", 10378c2ecf20Sopenharmony_ci "ECP and EPP-1.9", 10388c2ecf20Sopenharmony_ci "Standard (SPP)", 10398c2ecf20Sopenharmony_ci "EPP-1.7 and SPP", /* 5 */ 10408c2ecf20Sopenharmony_ci "undefined!", 10418c2ecf20Sopenharmony_ci "ECP and EPP-1.7" }; 10428c2ecf20Sopenharmony_ci static char *const irqtypes[] = { 10438c2ecf20Sopenharmony_ci "pulsed low, high-Z", 10448c2ecf20Sopenharmony_ci "follows nACK" }; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* The registers are called compatible-PnP because the 10478c2ecf20Sopenharmony_ci register layout is modelled after ISA-PnP, the access 10488c2ecf20Sopenharmony_ci method is just another ... */ 10498c2ecf20Sopenharmony_ci outb(key, io); 10508c2ecf20Sopenharmony_ci outb(key, io); 10518c2ecf20Sopenharmony_ci outb(0x07, io); /* Register 7: Select Logical Device */ 10528c2ecf20Sopenharmony_ci outb(0x01, io + 1); /* LD1 is Parallel Port */ 10538c2ecf20Sopenharmony_ci outb(0x30, io); 10548c2ecf20Sopenharmony_ci cr30 = inb(io + 1); 10558c2ecf20Sopenharmony_ci outb(0x60, io); 10568c2ecf20Sopenharmony_ci cr60 = inb(io + 1); 10578c2ecf20Sopenharmony_ci outb(0x61, io); 10588c2ecf20Sopenharmony_ci cr61 = inb(io + 1); 10598c2ecf20Sopenharmony_ci outb(0x70, io); 10608c2ecf20Sopenharmony_ci cr70 = inb(io + 1); 10618c2ecf20Sopenharmony_ci outb(0x74, io); 10628c2ecf20Sopenharmony_ci cr74 = inb(io + 1); 10638c2ecf20Sopenharmony_ci outb(0xf0, io); 10648c2ecf20Sopenharmony_ci crf0 = inb(io + 1); 10658c2ecf20Sopenharmony_ci outb(0xaa, io); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (verbose_probing) { 10688c2ecf20Sopenharmony_ci pr_info("Winbond LPT Config: cr_30=%02x 60,61=%02x%02x 70=%02x 74=%02x, f0=%02x\n", 10698c2ecf20Sopenharmony_ci cr30, cr60, cr61, cr70, cr74, crf0); 10708c2ecf20Sopenharmony_ci pr_info("Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", 10718c2ecf20Sopenharmony_ci (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f); 10728c2ecf20Sopenharmony_ci if ((cr74 & 0x07) > 3) 10738c2ecf20Sopenharmony_ci pr_cont("dma=none\n"); 10748c2ecf20Sopenharmony_ci else 10758c2ecf20Sopenharmony_ci pr_cont("dma=%d\n", cr74 & 0x07); 10768c2ecf20Sopenharmony_ci pr_info("Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", 10778c2ecf20Sopenharmony_ci irqtypes[crf0 >> 7], (crf0 >> 3) & 0x0f); 10788c2ecf20Sopenharmony_ci pr_info("Winbond LPT Config: Port mode=%s\n", 10798c2ecf20Sopenharmony_ci modes[crf0 & 0x07]); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci if (cr30 & 0x01) { /* the settings can be interrogated later ... */ 10838c2ecf20Sopenharmony_ci s = find_free_superio(); 10848c2ecf20Sopenharmony_ci if (s == NULL) 10858c2ecf20Sopenharmony_ci pr_info("Super-IO: too many chips!\n"); 10868c2ecf20Sopenharmony_ci else { 10878c2ecf20Sopenharmony_ci s->io = (cr60 << 8) | cr61; 10888c2ecf20Sopenharmony_ci s->irq = cr70 & 0x0f; 10898c2ecf20Sopenharmony_ci s->dma = (((cr74 & 0x07) > 3) ? 10908c2ecf20Sopenharmony_ci PARPORT_DMA_NONE : (cr74 & 0x07)); 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci} 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_cistatic void decode_winbond(int efer, int key, int devid, int devrev, int oldid) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci const char *type = "unknown"; 10988c2ecf20Sopenharmony_ci int id, progif = 2; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci if (devid == devrev) 11018c2ecf20Sopenharmony_ci /* simple heuristics, we happened to read some 11028c2ecf20Sopenharmony_ci non-winbond register */ 11038c2ecf20Sopenharmony_ci return; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci id = (devid << 8) | devrev; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci /* Values are from public data sheets pdf files, I can just 11088c2ecf20Sopenharmony_ci confirm 83977TF is correct :-) */ 11098c2ecf20Sopenharmony_ci if (id == 0x9771) 11108c2ecf20Sopenharmony_ci type = "83977F/AF"; 11118c2ecf20Sopenharmony_ci else if (id == 0x9773) 11128c2ecf20Sopenharmony_ci type = "83977TF / SMSC 97w33x/97w34x"; 11138c2ecf20Sopenharmony_ci else if (id == 0x9774) 11148c2ecf20Sopenharmony_ci type = "83977ATF"; 11158c2ecf20Sopenharmony_ci else if ((id & ~0x0f) == 0x5270) 11168c2ecf20Sopenharmony_ci type = "83977CTF / SMSC 97w36x"; 11178c2ecf20Sopenharmony_ci else if ((id & ~0x0f) == 0x52f0) 11188c2ecf20Sopenharmony_ci type = "83977EF / SMSC 97w35x"; 11198c2ecf20Sopenharmony_ci else if ((id & ~0x0f) == 0x5210) 11208c2ecf20Sopenharmony_ci type = "83627"; 11218c2ecf20Sopenharmony_ci else if ((id & ~0x0f) == 0x6010) 11228c2ecf20Sopenharmony_ci type = "83697HF"; 11238c2ecf20Sopenharmony_ci else if ((oldid & 0x0f) == 0x0a) { 11248c2ecf20Sopenharmony_ci type = "83877F"; 11258c2ecf20Sopenharmony_ci progif = 1; 11268c2ecf20Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0b) { 11278c2ecf20Sopenharmony_ci type = "83877AF"; 11288c2ecf20Sopenharmony_ci progif = 1; 11298c2ecf20Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0c) { 11308c2ecf20Sopenharmony_ci type = "83877TF"; 11318c2ecf20Sopenharmony_ci progif = 1; 11328c2ecf20Sopenharmony_ci } else if ((oldid & 0x0f) == 0x0d) { 11338c2ecf20Sopenharmony_ci type = "83877ATF"; 11348c2ecf20Sopenharmony_ci progif = 1; 11358c2ecf20Sopenharmony_ci } else 11368c2ecf20Sopenharmony_ci progif = 0; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (verbose_probing) 11398c2ecf20Sopenharmony_ci pr_info("Winbond chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x oldid=%02x type=%s\n", 11408c2ecf20Sopenharmony_ci efer, key, devid, devrev, oldid, type); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (progif == 2) 11438c2ecf20Sopenharmony_ci show_parconfig_winbond(efer, key); 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic void decode_smsc(int efer, int key, int devid, int devrev) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci const char *type = "unknown"; 11498c2ecf20Sopenharmony_ci void (*func)(int io, int key); 11508c2ecf20Sopenharmony_ci int id; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci if (devid == devrev) 11538c2ecf20Sopenharmony_ci /* simple heuristics, we happened to read some 11548c2ecf20Sopenharmony_ci non-smsc register */ 11558c2ecf20Sopenharmony_ci return; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci func = NULL; 11588c2ecf20Sopenharmony_ci id = (devid << 8) | devrev; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci if (id == 0x0302) { 11618c2ecf20Sopenharmony_ci type = "37c669"; 11628c2ecf20Sopenharmony_ci func = show_parconfig_smsc37c669; 11638c2ecf20Sopenharmony_ci } else if (id == 0x6582) 11648c2ecf20Sopenharmony_ci type = "37c665IR"; 11658c2ecf20Sopenharmony_ci else if (devid == 0x65) 11668c2ecf20Sopenharmony_ci type = "37c665GT"; 11678c2ecf20Sopenharmony_ci else if (devid == 0x66) 11688c2ecf20Sopenharmony_ci type = "37c666GT"; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci if (verbose_probing) 11718c2ecf20Sopenharmony_ci pr_info("SMSC chip at EFER=0x%x key=0x%02x devid=%02x devrev=%02x type=%s\n", 11728c2ecf20Sopenharmony_ci efer, key, devid, devrev, type); 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (func) 11758c2ecf20Sopenharmony_ci func(efer, key); 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic void winbond_check(int io, int key) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci int origval, devid, devrev, oldid, x_devid, x_devrev, x_oldid; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci if (!request_region(io, 3, __func__)) 11848c2ecf20Sopenharmony_ci return; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci origval = inb(io); /* Save original value */ 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci /* First probe without key */ 11898c2ecf20Sopenharmony_ci outb(0x20, io); 11908c2ecf20Sopenharmony_ci x_devid = inb(io + 1); 11918c2ecf20Sopenharmony_ci outb(0x21, io); 11928c2ecf20Sopenharmony_ci x_devrev = inb(io + 1); 11938c2ecf20Sopenharmony_ci outb(0x09, io); 11948c2ecf20Sopenharmony_ci x_oldid = inb(io + 1); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci outb(key, io); 11978c2ecf20Sopenharmony_ci outb(key, io); /* Write Magic Sequence to EFER, extended 11988c2ecf20Sopenharmony_ci function enable register */ 11998c2ecf20Sopenharmony_ci outb(0x20, io); /* Write EFIR, extended function index register */ 12008c2ecf20Sopenharmony_ci devid = inb(io + 1); /* Read EFDR, extended function data register */ 12018c2ecf20Sopenharmony_ci outb(0x21, io); 12028c2ecf20Sopenharmony_ci devrev = inb(io + 1); 12038c2ecf20Sopenharmony_ci outb(0x09, io); 12048c2ecf20Sopenharmony_ci oldid = inb(io + 1); 12058c2ecf20Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci outb(origval, io); /* in case we poked some entirely different hardware */ 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci if ((x_devid == devid) && (x_devrev == devrev) && (x_oldid == oldid)) 12108c2ecf20Sopenharmony_ci goto out; /* protection against false positives */ 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci decode_winbond(io, key, devid, devrev, oldid); 12138c2ecf20Sopenharmony_ciout: 12148c2ecf20Sopenharmony_ci release_region(io, 3); 12158c2ecf20Sopenharmony_ci} 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_cistatic void winbond_check2(int io, int key) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci int origval[3], devid, devrev, oldid, x_devid, x_devrev, x_oldid; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci if (!request_region(io, 3, __func__)) 12228c2ecf20Sopenharmony_ci return; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci origval[0] = inb(io); /* Save original values */ 12258c2ecf20Sopenharmony_ci origval[1] = inb(io + 1); 12268c2ecf20Sopenharmony_ci origval[2] = inb(io + 2); 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci /* First probe without the key */ 12298c2ecf20Sopenharmony_ci outb(0x20, io + 2); 12308c2ecf20Sopenharmony_ci x_devid = inb(io + 2); 12318c2ecf20Sopenharmony_ci outb(0x21, io + 1); 12328c2ecf20Sopenharmony_ci x_devrev = inb(io + 2); 12338c2ecf20Sopenharmony_ci outb(0x09, io + 1); 12348c2ecf20Sopenharmony_ci x_oldid = inb(io + 2); 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci outb(key, io); /* Write Magic Byte to EFER, extended 12378c2ecf20Sopenharmony_ci function enable register */ 12388c2ecf20Sopenharmony_ci outb(0x20, io + 2); /* Write EFIR, extended function index register */ 12398c2ecf20Sopenharmony_ci devid = inb(io + 2); /* Read EFDR, extended function data register */ 12408c2ecf20Sopenharmony_ci outb(0x21, io + 1); 12418c2ecf20Sopenharmony_ci devrev = inb(io + 2); 12428c2ecf20Sopenharmony_ci outb(0x09, io + 1); 12438c2ecf20Sopenharmony_ci oldid = inb(io + 2); 12448c2ecf20Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci outb(origval[0], io); /* in case we poked some entirely different hardware */ 12478c2ecf20Sopenharmony_ci outb(origval[1], io + 1); 12488c2ecf20Sopenharmony_ci outb(origval[2], io + 2); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci if (x_devid == devid && x_devrev == devrev && x_oldid == oldid) 12518c2ecf20Sopenharmony_ci goto out; /* protection against false positives */ 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci decode_winbond(io, key, devid, devrev, oldid); 12548c2ecf20Sopenharmony_ciout: 12558c2ecf20Sopenharmony_ci release_region(io, 3); 12568c2ecf20Sopenharmony_ci} 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_cistatic void smsc_check(int io, int key) 12598c2ecf20Sopenharmony_ci{ 12608c2ecf20Sopenharmony_ci int origval, id, rev, oldid, oldrev, x_id, x_rev, x_oldid, x_oldrev; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci if (!request_region(io, 3, __func__)) 12638c2ecf20Sopenharmony_ci return; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci origval = inb(io); /* Save original value */ 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* First probe without the key */ 12688c2ecf20Sopenharmony_ci outb(0x0d, io); 12698c2ecf20Sopenharmony_ci x_oldid = inb(io + 1); 12708c2ecf20Sopenharmony_ci outb(0x0e, io); 12718c2ecf20Sopenharmony_ci x_oldrev = inb(io + 1); 12728c2ecf20Sopenharmony_ci outb(0x20, io); 12738c2ecf20Sopenharmony_ci x_id = inb(io + 1); 12748c2ecf20Sopenharmony_ci outb(0x21, io); 12758c2ecf20Sopenharmony_ci x_rev = inb(io + 1); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci outb(key, io); 12788c2ecf20Sopenharmony_ci outb(key, io); /* Write Magic Sequence to EFER, extended 12798c2ecf20Sopenharmony_ci function enable register */ 12808c2ecf20Sopenharmony_ci outb(0x0d, io); /* Write EFIR, extended function index register */ 12818c2ecf20Sopenharmony_ci oldid = inb(io + 1); /* Read EFDR, extended function data register */ 12828c2ecf20Sopenharmony_ci outb(0x0e, io); 12838c2ecf20Sopenharmony_ci oldrev = inb(io + 1); 12848c2ecf20Sopenharmony_ci outb(0x20, io); 12858c2ecf20Sopenharmony_ci id = inb(io + 1); 12868c2ecf20Sopenharmony_ci outb(0x21, io); 12878c2ecf20Sopenharmony_ci rev = inb(io + 1); 12888c2ecf20Sopenharmony_ci outb(0xaa, io); /* Magic Seal */ 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci outb(origval, io); /* in case we poked some entirely different hardware */ 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (x_id == id && x_oldrev == oldrev && 12938c2ecf20Sopenharmony_ci x_oldid == oldid && x_rev == rev) 12948c2ecf20Sopenharmony_ci goto out; /* protection against false positives */ 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci decode_smsc(io, key, oldid, oldrev); 12978c2ecf20Sopenharmony_ciout: 12988c2ecf20Sopenharmony_ci release_region(io, 3); 12998c2ecf20Sopenharmony_ci} 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic void detect_and_report_winbond(void) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci if (verbose_probing) 13058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "Winbond Super-IO detection, now testing ports 3F0,370,250,4E,2E ...\n"); 13068c2ecf20Sopenharmony_ci winbond_check(0x3f0, 0x87); 13078c2ecf20Sopenharmony_ci winbond_check(0x370, 0x87); 13088c2ecf20Sopenharmony_ci winbond_check(0x2e , 0x87); 13098c2ecf20Sopenharmony_ci winbond_check(0x4e , 0x87); 13108c2ecf20Sopenharmony_ci winbond_check(0x3f0, 0x86); 13118c2ecf20Sopenharmony_ci winbond_check2(0x250, 0x88); 13128c2ecf20Sopenharmony_ci winbond_check2(0x250, 0x89); 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic void detect_and_report_smsc(void) 13168c2ecf20Sopenharmony_ci{ 13178c2ecf20Sopenharmony_ci if (verbose_probing) 13188c2ecf20Sopenharmony_ci printk(KERN_DEBUG "SMSC Super-IO detection, now testing Ports 2F0, 370 ...\n"); 13198c2ecf20Sopenharmony_ci smsc_check(0x3f0, 0x55); 13208c2ecf20Sopenharmony_ci smsc_check(0x370, 0x55); 13218c2ecf20Sopenharmony_ci smsc_check(0x3f0, 0x44); 13228c2ecf20Sopenharmony_ci smsc_check(0x370, 0x44); 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic void detect_and_report_it87(void) 13268c2ecf20Sopenharmony_ci{ 13278c2ecf20Sopenharmony_ci u16 dev; 13288c2ecf20Sopenharmony_ci u8 origval, r; 13298c2ecf20Sopenharmony_ci if (verbose_probing) 13308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n"); 13318c2ecf20Sopenharmony_ci if (!request_muxed_region(0x2e, 2, __func__)) 13328c2ecf20Sopenharmony_ci return; 13338c2ecf20Sopenharmony_ci origval = inb(0x2e); /* Save original value */ 13348c2ecf20Sopenharmony_ci outb(0x87, 0x2e); 13358c2ecf20Sopenharmony_ci outb(0x01, 0x2e); 13368c2ecf20Sopenharmony_ci outb(0x55, 0x2e); 13378c2ecf20Sopenharmony_ci outb(0x55, 0x2e); 13388c2ecf20Sopenharmony_ci outb(0x20, 0x2e); 13398c2ecf20Sopenharmony_ci dev = inb(0x2f) << 8; 13408c2ecf20Sopenharmony_ci outb(0x21, 0x2e); 13418c2ecf20Sopenharmony_ci dev |= inb(0x2f); 13428c2ecf20Sopenharmony_ci if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 || 13438c2ecf20Sopenharmony_ci dev == 0x8716 || dev == 0x8718 || dev == 0x8726) { 13448c2ecf20Sopenharmony_ci pr_info("IT%04X SuperIO detected\n", dev); 13458c2ecf20Sopenharmony_ci outb(0x07, 0x2E); /* Parallel Port */ 13468c2ecf20Sopenharmony_ci outb(0x03, 0x2F); 13478c2ecf20Sopenharmony_ci outb(0xF0, 0x2E); /* BOOT 0x80 off */ 13488c2ecf20Sopenharmony_ci r = inb(0x2f); 13498c2ecf20Sopenharmony_ci outb(0xF0, 0x2E); 13508c2ecf20Sopenharmony_ci outb(r | 8, 0x2F); 13518c2ecf20Sopenharmony_ci outb(0x02, 0x2E); /* Lock */ 13528c2ecf20Sopenharmony_ci outb(0x02, 0x2F); 13538c2ecf20Sopenharmony_ci } else { 13548c2ecf20Sopenharmony_ci outb(origval, 0x2e); /* Oops, sorry to disturb */ 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci release_region(0x2e, 2); 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci#endif /* CONFIG_PARPORT_PC_SUPERIO */ 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_cistatic struct superio_struct *find_superio(struct parport *p) 13618c2ecf20Sopenharmony_ci{ 13628c2ecf20Sopenharmony_ci int i; 13638c2ecf20Sopenharmony_ci for (i = 0; i < NR_SUPERIOS; i++) 13648c2ecf20Sopenharmony_ci if (superios[i].io == p->base) 13658c2ecf20Sopenharmony_ci return &superios[i]; 13668c2ecf20Sopenharmony_ci return NULL; 13678c2ecf20Sopenharmony_ci} 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_cistatic int get_superio_dma(struct parport *p) 13708c2ecf20Sopenharmony_ci{ 13718c2ecf20Sopenharmony_ci struct superio_struct *s = find_superio(p); 13728c2ecf20Sopenharmony_ci if (s) 13738c2ecf20Sopenharmony_ci return s->dma; 13748c2ecf20Sopenharmony_ci return PARPORT_DMA_NONE; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int get_superio_irq(struct parport *p) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci struct superio_struct *s = find_superio(p); 13808c2ecf20Sopenharmony_ci if (s) 13818c2ecf20Sopenharmony_ci return s->irq; 13828c2ecf20Sopenharmony_ci return PARPORT_IRQ_NONE; 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci/* --- Mode detection ------------------------------------- */ 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci/* 13898c2ecf20Sopenharmony_ci * Checks for port existence, all ports support SPP MODE 13908c2ecf20Sopenharmony_ci * Returns: 13918c2ecf20Sopenharmony_ci * 0 : No parallel port at this address 13928c2ecf20Sopenharmony_ci * PARPORT_MODE_PCSPP : SPP port detected 13938c2ecf20Sopenharmony_ci * (if the user specified an ioport himself, 13948c2ecf20Sopenharmony_ci * this shall always be the case!) 13958c2ecf20Sopenharmony_ci * 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_cistatic int parport_SPP_supported(struct parport *pb) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci unsigned char r, w; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* 14028c2ecf20Sopenharmony_ci * first clear an eventually pending EPP timeout 14038c2ecf20Sopenharmony_ci * I (sailer@ife.ee.ethz.ch) have an SMSC chipset 14048c2ecf20Sopenharmony_ci * that does not even respond to SPP cycles if an EPP 14058c2ecf20Sopenharmony_ci * timeout is pending 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* Do a simple read-write test to make sure the port exists. */ 14108c2ecf20Sopenharmony_ci w = 0xc; 14118c2ecf20Sopenharmony_ci outb(w, CONTROL(pb)); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* Is there a control register that we can read from? Some 14148c2ecf20Sopenharmony_ci * ports don't allow reads, so read_control just returns a 14158c2ecf20Sopenharmony_ci * software copy. Some ports _do_ allow reads, so bypass the 14168c2ecf20Sopenharmony_ci * software copy here. In addition, some bits aren't 14178c2ecf20Sopenharmony_ci * writable. */ 14188c2ecf20Sopenharmony_ci r = inb(CONTROL(pb)); 14198c2ecf20Sopenharmony_ci if ((r & 0xf) == w) { 14208c2ecf20Sopenharmony_ci w = 0xe; 14218c2ecf20Sopenharmony_ci outb(w, CONTROL(pb)); 14228c2ecf20Sopenharmony_ci r = inb(CONTROL(pb)); 14238c2ecf20Sopenharmony_ci outb(0xc, CONTROL(pb)); 14248c2ecf20Sopenharmony_ci if ((r & 0xf) == w) 14258c2ecf20Sopenharmony_ci return PARPORT_MODE_PCSPP; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci if (user_specified) 14298c2ecf20Sopenharmony_ci /* That didn't work, but the user thinks there's a 14308c2ecf20Sopenharmony_ci * port here. */ 14318c2ecf20Sopenharmony_ci pr_info("parport 0x%lx (WARNING): CTR: wrote 0x%02x, read 0x%02x\n", 14328c2ecf20Sopenharmony_ci pb->base, w, r); 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci /* Try the data register. The data lines aren't tri-stated at 14358c2ecf20Sopenharmony_ci * this stage, so we expect back what we wrote. */ 14368c2ecf20Sopenharmony_ci w = 0xaa; 14378c2ecf20Sopenharmony_ci parport_pc_write_data(pb, w); 14388c2ecf20Sopenharmony_ci r = parport_pc_read_data(pb); 14398c2ecf20Sopenharmony_ci if (r == w) { 14408c2ecf20Sopenharmony_ci w = 0x55; 14418c2ecf20Sopenharmony_ci parport_pc_write_data(pb, w); 14428c2ecf20Sopenharmony_ci r = parport_pc_read_data(pb); 14438c2ecf20Sopenharmony_ci if (r == w) 14448c2ecf20Sopenharmony_ci return PARPORT_MODE_PCSPP; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci if (user_specified) { 14488c2ecf20Sopenharmony_ci /* Didn't work, but the user is convinced this is the 14498c2ecf20Sopenharmony_ci * place. */ 14508c2ecf20Sopenharmony_ci pr_info("parport 0x%lx (WARNING): DATA: wrote 0x%02x, read 0x%02x\n", 14518c2ecf20Sopenharmony_ci pb->base, w, r); 14528c2ecf20Sopenharmony_ci pr_info("parport 0x%lx: You gave this address, but there is probably no parallel port there!\n", 14538c2ecf20Sopenharmony_ci pb->base); 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci /* It's possible that we can't read the control register or 14578c2ecf20Sopenharmony_ci * the data register. In that case just believe the user. */ 14588c2ecf20Sopenharmony_ci if (user_specified) 14598c2ecf20Sopenharmony_ci return PARPORT_MODE_PCSPP; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return 0; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci/* Check for ECR 14658c2ecf20Sopenharmony_ci * 14668c2ecf20Sopenharmony_ci * Old style XT ports alias io ports every 0x400, hence accessing ECR 14678c2ecf20Sopenharmony_ci * on these cards actually accesses the CTR. 14688c2ecf20Sopenharmony_ci * 14698c2ecf20Sopenharmony_ci * Modern cards don't do this but reading from ECR will return 0xff 14708c2ecf20Sopenharmony_ci * regardless of what is written here if the card does NOT support 14718c2ecf20Sopenharmony_ci * ECP. 14728c2ecf20Sopenharmony_ci * 14738c2ecf20Sopenharmony_ci * We first check to see if ECR is the same as CTR. If not, the low 14748c2ecf20Sopenharmony_ci * two bits of ECR aren't writable, so we check by writing ECR and 14758c2ecf20Sopenharmony_ci * reading it back to see if it's what we expect. 14768c2ecf20Sopenharmony_ci */ 14778c2ecf20Sopenharmony_cistatic int parport_ECR_present(struct parport *pb) 14788c2ecf20Sopenharmony_ci{ 14798c2ecf20Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 14808c2ecf20Sopenharmony_ci unsigned char r = 0xc; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci outb(r, CONTROL(pb)); 14838c2ecf20Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x3) == (r & 0x3)) { 14848c2ecf20Sopenharmony_ci outb(r ^ 0x2, CONTROL(pb)); /* Toggle bit 1 */ 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci r = inb(CONTROL(pb)); 14878c2ecf20Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x2) == (r & 0x2)) 14888c2ecf20Sopenharmony_ci goto no_reg; /* Sure that no ECR register exists */ 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if ((inb(ECONTROL(pb)) & 0x3) != 0x1) 14928c2ecf20Sopenharmony_ci goto no_reg; 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci ECR_WRITE(pb, 0x34); 14958c2ecf20Sopenharmony_ci if (inb(ECONTROL(pb)) != 0x35) 14968c2ecf20Sopenharmony_ci goto no_reg; 14978c2ecf20Sopenharmony_ci 14988c2ecf20Sopenharmony_ci priv->ecr = 1; 14998c2ecf20Sopenharmony_ci outb(0xc, CONTROL(pb)); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* Go to mode 000 */ 15028c2ecf20Sopenharmony_ci frob_set_mode(pb, ECR_SPP); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci return 1; 15058c2ecf20Sopenharmony_ci 15068c2ecf20Sopenharmony_ci no_reg: 15078c2ecf20Sopenharmony_ci outb(0xc, CONTROL(pb)); 15088c2ecf20Sopenharmony_ci return 0; 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 15128c2ecf20Sopenharmony_ci/* Detect PS/2 support. 15138c2ecf20Sopenharmony_ci * 15148c2ecf20Sopenharmony_ci * Bit 5 (0x20) sets the PS/2 data direction; setting this high 15158c2ecf20Sopenharmony_ci * allows us to read data from the data lines. In theory we would get back 15168c2ecf20Sopenharmony_ci * 0xff but any peripheral attached to the port may drag some or all of the 15178c2ecf20Sopenharmony_ci * lines down to zero. So if we get back anything that isn't the contents 15188c2ecf20Sopenharmony_ci * of the data register we deem PS/2 support to be present. 15198c2ecf20Sopenharmony_ci * 15208c2ecf20Sopenharmony_ci * Some SPP ports have "half PS/2" ability - you can't turn off the line 15218c2ecf20Sopenharmony_ci * drivers, but an external peripheral with sufficiently beefy drivers of 15228c2ecf20Sopenharmony_ci * its own can overpower them and assert its own levels onto the bus, from 15238c2ecf20Sopenharmony_ci * where they can then be read back as normal. Ports with this property 15248c2ecf20Sopenharmony_ci * and the right type of device attached are likely to fail the SPP test, 15258c2ecf20Sopenharmony_ci * (as they will appear to have stuck bits) and so the fact that they might 15268c2ecf20Sopenharmony_ci * be misdetected here is rather academic. 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic int parport_PS2_supported(struct parport *pb) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci int ok = 0; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci /* try to tri-state the buffer */ 15368c2ecf20Sopenharmony_ci parport_pc_data_reverse(pb); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci parport_pc_write_data(pb, 0x55); 15398c2ecf20Sopenharmony_ci if (parport_pc_read_data(pb) != 0x55) 15408c2ecf20Sopenharmony_ci ok++; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci parport_pc_write_data(pb, 0xaa); 15438c2ecf20Sopenharmony_ci if (parport_pc_read_data(pb) != 0xaa) 15448c2ecf20Sopenharmony_ci ok++; 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci /* cancel input mode */ 15478c2ecf20Sopenharmony_ci parport_pc_data_forward(pb); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (ok) { 15508c2ecf20Sopenharmony_ci pb->modes |= PARPORT_MODE_TRISTATE; 15518c2ecf20Sopenharmony_ci } else { 15528c2ecf20Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 15538c2ecf20Sopenharmony_ci priv->ctr_writable &= ~0x20; 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci return ok; 15578c2ecf20Sopenharmony_ci} 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 15608c2ecf20Sopenharmony_cistatic int parport_ECP_supported(struct parport *pb) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci int i; 15638c2ecf20Sopenharmony_ci int config, configb; 15648c2ecf20Sopenharmony_ci int pword; 15658c2ecf20Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 15668c2ecf20Sopenharmony_ci /* Translate ECP intrLine to ISA irq value */ 15678c2ecf20Sopenharmony_ci static const int intrline[] = { 0, 7, 9, 10, 11, 14, 15, 5 }; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* If there is no ECR, we have no hope of supporting ECP. */ 15708c2ecf20Sopenharmony_ci if (!priv->ecr) 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci /* Find out FIFO depth */ 15748c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 15758c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_TST << 5); /* TEST FIFO */ 15768c2ecf20Sopenharmony_ci for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02); i++) 15778c2ecf20Sopenharmony_ci outb(0xaa, FIFO(pb)); 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci /* 15808c2ecf20Sopenharmony_ci * Using LGS chipset it uses ECR register, but 15818c2ecf20Sopenharmony_ci * it doesn't support ECP or FIFO MODE 15828c2ecf20Sopenharmony_ci */ 15838c2ecf20Sopenharmony_ci if (i == 1024) { 15848c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); 15858c2ecf20Sopenharmony_ci return 0; 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci priv->fifo_depth = i; 15898c2ecf20Sopenharmony_ci if (verbose_probing) 15908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: FIFO is %d bytes\n", pb->base, i); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci /* Find out writeIntrThreshold */ 15938c2ecf20Sopenharmony_ci frob_econtrol(pb, 1<<2, 1<<2); 15948c2ecf20Sopenharmony_ci frob_econtrol(pb, 1<<2, 0); 15958c2ecf20Sopenharmony_ci for (i = 1; i <= priv->fifo_depth; i++) { 15968c2ecf20Sopenharmony_ci inb(FIFO(pb)); 15978c2ecf20Sopenharmony_ci udelay(50); 15988c2ecf20Sopenharmony_ci if (inb(ECONTROL(pb)) & (1<<2)) 15998c2ecf20Sopenharmony_ci break; 16008c2ecf20Sopenharmony_ci } 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if (i <= priv->fifo_depth) { 16038c2ecf20Sopenharmony_ci if (verbose_probing) 16048c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: writeIntrThreshold is %d\n", 16058c2ecf20Sopenharmony_ci pb->base, i); 16068c2ecf20Sopenharmony_ci } else 16078c2ecf20Sopenharmony_ci /* Number of bytes we know we can write if we get an 16088c2ecf20Sopenharmony_ci interrupt. */ 16098c2ecf20Sopenharmony_ci i = 0; 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci priv->writeIntrThreshold = i; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci /* Find out readIntrThreshold */ 16148c2ecf20Sopenharmony_ci frob_set_mode(pb, ECR_PS2); /* Reset FIFO and enable PS2 */ 16158c2ecf20Sopenharmony_ci parport_pc_data_reverse(pb); /* Must be in PS2 mode */ 16168c2ecf20Sopenharmony_ci frob_set_mode(pb, ECR_TST); /* Test FIFO */ 16178c2ecf20Sopenharmony_ci frob_econtrol(pb, 1<<2, 1<<2); 16188c2ecf20Sopenharmony_ci frob_econtrol(pb, 1<<2, 0); 16198c2ecf20Sopenharmony_ci for (i = 1; i <= priv->fifo_depth; i++) { 16208c2ecf20Sopenharmony_ci outb(0xaa, FIFO(pb)); 16218c2ecf20Sopenharmony_ci if (inb(ECONTROL(pb)) & (1<<2)) 16228c2ecf20Sopenharmony_ci break; 16238c2ecf20Sopenharmony_ci } 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (i <= priv->fifo_depth) { 16268c2ecf20Sopenharmony_ci if (verbose_probing) 16278c2ecf20Sopenharmony_ci pr_info("0x%lx: readIntrThreshold is %d\n", 16288c2ecf20Sopenharmony_ci pb->base, i); 16298c2ecf20Sopenharmony_ci } else 16308c2ecf20Sopenharmony_ci /* Number of bytes we can read if we get an interrupt. */ 16318c2ecf20Sopenharmony_ci i = 0; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci priv->readIntrThreshold = i; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 16368c2ecf20Sopenharmony_ci ECR_WRITE(pb, 0xf4); /* Configuration mode */ 16378c2ecf20Sopenharmony_ci config = inb(CONFIGA(pb)); 16388c2ecf20Sopenharmony_ci pword = (config >> 4) & 0x7; 16398c2ecf20Sopenharmony_ci switch (pword) { 16408c2ecf20Sopenharmony_ci case 0: 16418c2ecf20Sopenharmony_ci pword = 2; 16428c2ecf20Sopenharmony_ci pr_warn("0x%lx: Unsupported pword size!\n", pb->base); 16438c2ecf20Sopenharmony_ci break; 16448c2ecf20Sopenharmony_ci case 2: 16458c2ecf20Sopenharmony_ci pword = 4; 16468c2ecf20Sopenharmony_ci pr_warn("0x%lx: Unsupported pword size!\n", pb->base); 16478c2ecf20Sopenharmony_ci break; 16488c2ecf20Sopenharmony_ci default: 16498c2ecf20Sopenharmony_ci pr_warn("0x%lx: Unknown implementation ID\n", pb->base); 16508c2ecf20Sopenharmony_ci fallthrough; /* Assume 1 */ 16518c2ecf20Sopenharmony_ci case 1: 16528c2ecf20Sopenharmony_ci pword = 1; 16538c2ecf20Sopenharmony_ci } 16548c2ecf20Sopenharmony_ci priv->pword = pword; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci if (verbose_probing) { 16578c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: PWord is %d bits\n", 16588c2ecf20Sopenharmony_ci pb->base, 8 * pword); 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: Interrupts are ISA-%s\n", 16618c2ecf20Sopenharmony_ci pb->base, config & 0x80 ? "Level" : "Pulses"); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci configb = inb(CONFIGB(pb)); 16648c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: ECP port cfgA=0x%02x cfgB=0x%02x\n", 16658c2ecf20Sopenharmony_ci pb->base, config, configb); 16668c2ecf20Sopenharmony_ci printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); 16678c2ecf20Sopenharmony_ci if ((configb >> 3) & 0x07) 16688c2ecf20Sopenharmony_ci pr_cont("%d", intrline[(configb >> 3) & 0x07]); 16698c2ecf20Sopenharmony_ci else 16708c2ecf20Sopenharmony_ci pr_cont("<none or set by other means>"); 16718c2ecf20Sopenharmony_ci pr_cont(" dma="); 16728c2ecf20Sopenharmony_ci if ((configb & 0x03) == 0x00) 16738c2ecf20Sopenharmony_ci pr_cont("<none or set by other means>\n"); 16748c2ecf20Sopenharmony_ci else 16758c2ecf20Sopenharmony_ci pr_cont("%d\n", configb & 0x07); 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci 16788c2ecf20Sopenharmony_ci /* Go back to mode 000 */ 16798c2ecf20Sopenharmony_ci frob_set_mode(pb, ECR_SPP); 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci return 1; 16828c2ecf20Sopenharmony_ci} 16838c2ecf20Sopenharmony_ci#endif 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32 16868c2ecf20Sopenharmony_cistatic int intel_bug_present_check_epp(struct parport *pb) 16878c2ecf20Sopenharmony_ci{ 16888c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = pb->private_data; 16898c2ecf20Sopenharmony_ci int bug_present = 0; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (priv->ecr) { 16928c2ecf20Sopenharmony_ci /* store value of ECR */ 16938c2ecf20Sopenharmony_ci unsigned char ecr = inb(ECONTROL(pb)); 16948c2ecf20Sopenharmony_ci unsigned char i; 16958c2ecf20Sopenharmony_ci for (i = 0x00; i < 0x80; i += 0x20) { 16968c2ecf20Sopenharmony_ci ECR_WRITE(pb, i); 16978c2ecf20Sopenharmony_ci if (clear_epp_timeout(pb)) { 16988c2ecf20Sopenharmony_ci /* Phony EPP in ECP. */ 16998c2ecf20Sopenharmony_ci bug_present = 1; 17008c2ecf20Sopenharmony_ci break; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci } 17038c2ecf20Sopenharmony_ci /* return ECR into the inital state */ 17048c2ecf20Sopenharmony_ci ECR_WRITE(pb, ecr); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci return bug_present; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_cistatic int intel_bug_present(struct parport *pb) 17108c2ecf20Sopenharmony_ci{ 17118c2ecf20Sopenharmony_ci/* Check whether the device is legacy, not PCI or PCMCIA. Only legacy is known to be affected. */ 17128c2ecf20Sopenharmony_ci if (pb->dev != NULL) { 17138c2ecf20Sopenharmony_ci return 0; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci return intel_bug_present_check_epp(pb); 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci#else 17198c2ecf20Sopenharmony_cistatic int intel_bug_present(struct parport *pb) 17208c2ecf20Sopenharmony_ci{ 17218c2ecf20Sopenharmony_ci return 0; 17228c2ecf20Sopenharmony_ci} 17238c2ecf20Sopenharmony_ci#endif /* CONFIG_X86_32 */ 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_cistatic int parport_ECPPS2_supported(struct parport *pb) 17268c2ecf20Sopenharmony_ci{ 17278c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = pb->private_data; 17288c2ecf20Sopenharmony_ci int result; 17298c2ecf20Sopenharmony_ci unsigned char oecr; 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci if (!priv->ecr) 17328c2ecf20Sopenharmony_ci return 0; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci oecr = inb(ECONTROL(pb)); 17358c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_PS2 << 5); 17368c2ecf20Sopenharmony_ci result = parport_PS2_supported(pb); 17378c2ecf20Sopenharmony_ci ECR_WRITE(pb, oecr); 17388c2ecf20Sopenharmony_ci return result; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci/* EPP mode detection */ 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic int parport_EPP_supported(struct parport *pb) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci /* 17468c2ecf20Sopenharmony_ci * Theory: 17478c2ecf20Sopenharmony_ci * Bit 0 of STR is the EPP timeout bit, this bit is 0 17488c2ecf20Sopenharmony_ci * when EPP is possible and is set high when an EPP timeout 17498c2ecf20Sopenharmony_ci * occurs (EPP uses the HALT line to stop the CPU while it does 17508c2ecf20Sopenharmony_ci * the byte transfer, an EPP timeout occurs if the attached 17518c2ecf20Sopenharmony_ci * device fails to respond after 10 micro seconds). 17528c2ecf20Sopenharmony_ci * 17538c2ecf20Sopenharmony_ci * This bit is cleared by either reading it (National Semi) 17548c2ecf20Sopenharmony_ci * or writing a 1 to the bit (SMC, UMC, WinBond), others ??? 17558c2ecf20Sopenharmony_ci * This bit is always high in non EPP modes. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* If EPP timeout bit clear then EPP available */ 17598c2ecf20Sopenharmony_ci if (!clear_epp_timeout(pb)) 17608c2ecf20Sopenharmony_ci return 0; /* No way to clear timeout */ 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci /* Check for Intel bug. */ 17638c2ecf20Sopenharmony_ci if (intel_bug_present(pb)) 17648c2ecf20Sopenharmony_ci return 0; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci pb->modes |= PARPORT_MODE_EPP; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci /* Set up access functions to use EPP hardware. */ 17698c2ecf20Sopenharmony_ci pb->ops->epp_read_data = parport_pc_epp_read_data; 17708c2ecf20Sopenharmony_ci pb->ops->epp_write_data = parport_pc_epp_write_data; 17718c2ecf20Sopenharmony_ci pb->ops->epp_read_addr = parport_pc_epp_read_addr; 17728c2ecf20Sopenharmony_ci pb->ops->epp_write_addr = parport_pc_epp_write_addr; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci return 1; 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_cistatic int parport_ECPEPP_supported(struct parport *pb) 17788c2ecf20Sopenharmony_ci{ 17798c2ecf20Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 17808c2ecf20Sopenharmony_ci int result; 17818c2ecf20Sopenharmony_ci unsigned char oecr; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (!priv->ecr) 17848c2ecf20Sopenharmony_ci return 0; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci oecr = inb(ECONTROL(pb)); 17878c2ecf20Sopenharmony_ci /* Search for SMC style EPP+ECP mode */ 17888c2ecf20Sopenharmony_ci ECR_WRITE(pb, 0x80); 17898c2ecf20Sopenharmony_ci outb(0x04, CONTROL(pb)); 17908c2ecf20Sopenharmony_ci result = parport_EPP_supported(pb); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci ECR_WRITE(pb, oecr); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (result) { 17958c2ecf20Sopenharmony_ci /* Set up access functions to use ECP+EPP hardware. */ 17968c2ecf20Sopenharmony_ci pb->ops->epp_read_data = parport_pc_ecpepp_read_data; 17978c2ecf20Sopenharmony_ci pb->ops->epp_write_data = parport_pc_ecpepp_write_data; 17988c2ecf20Sopenharmony_ci pb->ops->epp_read_addr = parport_pc_ecpepp_read_addr; 17998c2ecf20Sopenharmony_ci pb->ops->epp_write_addr = parport_pc_ecpepp_write_addr; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci return result; 18038c2ecf20Sopenharmony_ci} 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci#else /* No IEEE 1284 support */ 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci/* Don't bother probing for modes we know we won't use. */ 18088c2ecf20Sopenharmony_cistatic int parport_PS2_supported(struct parport *pb) { return 0; } 18098c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 18108c2ecf20Sopenharmony_cistatic int parport_ECP_supported(struct parport *pb) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci return 0; 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci#endif 18158c2ecf20Sopenharmony_cistatic int parport_EPP_supported(struct parport *pb) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci return 0; 18188c2ecf20Sopenharmony_ci} 18198c2ecf20Sopenharmony_ci 18208c2ecf20Sopenharmony_cistatic int parport_ECPEPP_supported(struct parport *pb) 18218c2ecf20Sopenharmony_ci{ 18228c2ecf20Sopenharmony_ci return 0; 18238c2ecf20Sopenharmony_ci} 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_cistatic int parport_ECPPS2_supported(struct parport *pb) 18268c2ecf20Sopenharmony_ci{ 18278c2ecf20Sopenharmony_ci return 0; 18288c2ecf20Sopenharmony_ci} 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci#endif /* No IEEE 1284 support */ 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci/* --- IRQ detection -------------------------------------- */ 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci/* Only if supports ECP mode */ 18358c2ecf20Sopenharmony_cistatic int programmable_irq_support(struct parport *pb) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci int irq, intrLine; 18388c2ecf20Sopenharmony_ci unsigned char oecr = inb(ECONTROL(pb)); 18398c2ecf20Sopenharmony_ci static const int lookup[8] = { 18408c2ecf20Sopenharmony_ci PARPORT_IRQ_NONE, 7, 9, 10, 11, 14, 15, 5 18418c2ecf20Sopenharmony_ci }; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_CNF << 5); /* Configuration MODE */ 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci intrLine = (inb(CONFIGB(pb)) >> 3) & 0x07; 18468c2ecf20Sopenharmony_ci irq = lookup[intrLine]; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci ECR_WRITE(pb, oecr); 18498c2ecf20Sopenharmony_ci return irq; 18508c2ecf20Sopenharmony_ci} 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_cistatic int irq_probe_ECP(struct parport *pb) 18538c2ecf20Sopenharmony_ci{ 18548c2ecf20Sopenharmony_ci int i; 18558c2ecf20Sopenharmony_ci unsigned long irqs; 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci irqs = probe_irq_on(); 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); /* Reset FIFO */ 18608c2ecf20Sopenharmony_ci ECR_WRITE(pb, (ECR_TST << 5) | 0x04); 18618c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_TST << 5); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* If Full FIFO sure that writeIntrThreshold is generated */ 18648c2ecf20Sopenharmony_ci for (i = 0; i < 1024 && !(inb(ECONTROL(pb)) & 0x02) ; i++) 18658c2ecf20Sopenharmony_ci outb(0xaa, FIFO(pb)); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci pb->irq = probe_irq_off(irqs); 18688c2ecf20Sopenharmony_ci ECR_WRITE(pb, ECR_SPP << 5); 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci if (pb->irq <= 0) 18718c2ecf20Sopenharmony_ci pb->irq = PARPORT_IRQ_NONE; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci return pb->irq; 18748c2ecf20Sopenharmony_ci} 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci/* 18778c2ecf20Sopenharmony_ci * This detection seems that only works in National Semiconductors 18788c2ecf20Sopenharmony_ci * This doesn't work in SMC, LGS, and Winbond 18798c2ecf20Sopenharmony_ci */ 18808c2ecf20Sopenharmony_cistatic int irq_probe_EPP(struct parport *pb) 18818c2ecf20Sopenharmony_ci{ 18828c2ecf20Sopenharmony_ci#ifndef ADVANCED_DETECT 18838c2ecf20Sopenharmony_ci return PARPORT_IRQ_NONE; 18848c2ecf20Sopenharmony_ci#else 18858c2ecf20Sopenharmony_ci int irqs; 18868c2ecf20Sopenharmony_ci unsigned char oecr; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 18898c2ecf20Sopenharmony_ci oecr = inb(ECONTROL(pb)); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci irqs = probe_irq_on(); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 18948c2ecf20Sopenharmony_ci frob_econtrol(pb, 0x10, 0x10); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 18978c2ecf20Sopenharmony_ci parport_pc_frob_control(pb, 0x20, 0x20); 18988c2ecf20Sopenharmony_ci parport_pc_frob_control(pb, 0x10, 0x10); 18998c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 19008c2ecf20Sopenharmony_ci 19018c2ecf20Sopenharmony_ci /* Device isn't expecting an EPP read 19028c2ecf20Sopenharmony_ci * and generates an IRQ. 19038c2ecf20Sopenharmony_ci */ 19048c2ecf20Sopenharmony_ci parport_pc_read_epp(pb); 19058c2ecf20Sopenharmony_ci udelay(20); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci pb->irq = probe_irq_off(irqs); 19088c2ecf20Sopenharmony_ci if (pb->modes & PARPORT_MODE_PCECR) 19098c2ecf20Sopenharmony_ci ECR_WRITE(pb, oecr); 19108c2ecf20Sopenharmony_ci parport_pc_write_control(pb, 0xc); 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (pb->irq <= 0) 19138c2ecf20Sopenharmony_ci pb->irq = PARPORT_IRQ_NONE; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci return pb->irq; 19168c2ecf20Sopenharmony_ci#endif /* Advanced detection */ 19178c2ecf20Sopenharmony_ci} 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_cistatic int irq_probe_SPP(struct parport *pb) 19208c2ecf20Sopenharmony_ci{ 19218c2ecf20Sopenharmony_ci /* Don't even try to do this. */ 19228c2ecf20Sopenharmony_ci return PARPORT_IRQ_NONE; 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci/* We will attempt to share interrupt requests since other devices 19268c2ecf20Sopenharmony_ci * such as sound cards and network cards seem to like using the 19278c2ecf20Sopenharmony_ci * printer IRQs. 19288c2ecf20Sopenharmony_ci * 19298c2ecf20Sopenharmony_ci * When ECP is available we can autoprobe for IRQs. 19308c2ecf20Sopenharmony_ci * NOTE: If we can autoprobe it, we can register the IRQ. 19318c2ecf20Sopenharmony_ci */ 19328c2ecf20Sopenharmony_cistatic int parport_irq_probe(struct parport *pb) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci struct parport_pc_private *priv = pb->private_data; 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci if (priv->ecr) { 19378c2ecf20Sopenharmony_ci pb->irq = programmable_irq_support(pb); 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 19408c2ecf20Sopenharmony_ci pb->irq = irq_probe_ECP(pb); 19418c2ecf20Sopenharmony_ci } 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci if ((pb->irq == PARPORT_IRQ_NONE) && priv->ecr && 19448c2ecf20Sopenharmony_ci (pb->modes & PARPORT_MODE_EPP)) 19458c2ecf20Sopenharmony_ci pb->irq = irq_probe_EPP(pb); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP)) 19508c2ecf20Sopenharmony_ci pb->irq = irq_probe_EPP(pb); 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci clear_epp_timeout(pb); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 19558c2ecf20Sopenharmony_ci pb->irq = irq_probe_SPP(pb); 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci if (pb->irq == PARPORT_IRQ_NONE) 19588c2ecf20Sopenharmony_ci pb->irq = get_superio_irq(pb); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci return pb->irq; 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci/* --- DMA detection -------------------------------------- */ 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci/* Only if chipset conforms to ECP ISA Interface Standard */ 19668c2ecf20Sopenharmony_cistatic int programmable_dma_support(struct parport *p) 19678c2ecf20Sopenharmony_ci{ 19688c2ecf20Sopenharmony_ci unsigned char oecr = inb(ECONTROL(p)); 19698c2ecf20Sopenharmony_ci int dma; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci frob_set_mode(p, ECR_CNF); 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci dma = inb(CONFIGB(p)) & 0x07; 19748c2ecf20Sopenharmony_ci /* 000: Indicates jumpered 8-bit DMA if read-only. 19758c2ecf20Sopenharmony_ci 100: Indicates jumpered 16-bit DMA if read-only. */ 19768c2ecf20Sopenharmony_ci if ((dma & 0x03) == 0) 19778c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci ECR_WRITE(p, oecr); 19808c2ecf20Sopenharmony_ci return dma; 19818c2ecf20Sopenharmony_ci} 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_cistatic int parport_dma_probe(struct parport *p) 19848c2ecf20Sopenharmony_ci{ 19858c2ecf20Sopenharmony_ci const struct parport_pc_private *priv = p->private_data; 19868c2ecf20Sopenharmony_ci if (priv->ecr) /* ask ECP chipset first */ 19878c2ecf20Sopenharmony_ci p->dma = programmable_dma_support(p); 19888c2ecf20Sopenharmony_ci if (p->dma == PARPORT_DMA_NONE) { 19898c2ecf20Sopenharmony_ci /* ask known Super-IO chips proper, although these 19908c2ecf20Sopenharmony_ci claim ECP compatible, some don't report their DMA 19918c2ecf20Sopenharmony_ci conforming to ECP standards */ 19928c2ecf20Sopenharmony_ci p->dma = get_superio_dma(p); 19938c2ecf20Sopenharmony_ci } 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci return p->dma; 19968c2ecf20Sopenharmony_ci} 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci/* --- Initialisation code -------------------------------- */ 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic LIST_HEAD(ports_list); 20018c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(ports_lock); 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_cistruct parport *parport_pc_probe_port(unsigned long int base, 20048c2ecf20Sopenharmony_ci unsigned long int base_hi, 20058c2ecf20Sopenharmony_ci int irq, int dma, 20068c2ecf20Sopenharmony_ci struct device *dev, 20078c2ecf20Sopenharmony_ci int irqflags) 20088c2ecf20Sopenharmony_ci{ 20098c2ecf20Sopenharmony_ci struct parport_pc_private *priv; 20108c2ecf20Sopenharmony_ci struct parport_operations *ops; 20118c2ecf20Sopenharmony_ci struct parport *p; 20128c2ecf20Sopenharmony_ci int probedirq = PARPORT_IRQ_NONE; 20138c2ecf20Sopenharmony_ci struct resource *base_res; 20148c2ecf20Sopenharmony_ci struct resource *ECR_res = NULL; 20158c2ecf20Sopenharmony_ci struct resource *EPP_res = NULL; 20168c2ecf20Sopenharmony_ci struct platform_device *pdev = NULL; 20178c2ecf20Sopenharmony_ci int ret; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci if (!dev) { 20208c2ecf20Sopenharmony_ci /* We need a physical device to attach to, but none was 20218c2ecf20Sopenharmony_ci * provided. Create our own. */ 20228c2ecf20Sopenharmony_ci pdev = platform_device_register_simple("parport_pc", 20238c2ecf20Sopenharmony_ci base, NULL, 0); 20248c2ecf20Sopenharmony_ci if (IS_ERR(pdev)) 20258c2ecf20Sopenharmony_ci return NULL; 20268c2ecf20Sopenharmony_ci dev = &pdev->dev; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(24)); 20298c2ecf20Sopenharmony_ci if (ret) { 20308c2ecf20Sopenharmony_ci dev_err(dev, "Unable to set coherent dma mask: disabling DMA\n"); 20318c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 20328c2ecf20Sopenharmony_ci } 20338c2ecf20Sopenharmony_ci } 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_ci ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL); 20368c2ecf20Sopenharmony_ci if (!ops) 20378c2ecf20Sopenharmony_ci goto out1; 20388c2ecf20Sopenharmony_ci 20398c2ecf20Sopenharmony_ci priv = kmalloc(sizeof(struct parport_pc_private), GFP_KERNEL); 20408c2ecf20Sopenharmony_ci if (!priv) 20418c2ecf20Sopenharmony_ci goto out2; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci /* a misnomer, actually - it's allocate and reserve parport number */ 20448c2ecf20Sopenharmony_ci p = parport_register_port(base, irq, dma, ops); 20458c2ecf20Sopenharmony_ci if (!p) 20468c2ecf20Sopenharmony_ci goto out3; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci base_res = request_region(base, 3, p->name); 20498c2ecf20Sopenharmony_ci if (!base_res) 20508c2ecf20Sopenharmony_ci goto out4; 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci memcpy(ops, &parport_pc_ops, sizeof(struct parport_operations)); 20538c2ecf20Sopenharmony_ci priv->ctr = 0xc; 20548c2ecf20Sopenharmony_ci priv->ctr_writable = ~0x10; 20558c2ecf20Sopenharmony_ci priv->ecr = 0; 20568c2ecf20Sopenharmony_ci priv->fifo_depth = 0; 20578c2ecf20Sopenharmony_ci priv->dma_buf = NULL; 20588c2ecf20Sopenharmony_ci priv->dma_handle = 0; 20598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&priv->list); 20608c2ecf20Sopenharmony_ci priv->port = p; 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci p->dev = dev; 20638c2ecf20Sopenharmony_ci p->base_hi = base_hi; 20648c2ecf20Sopenharmony_ci p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; 20658c2ecf20Sopenharmony_ci p->private_data = priv; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (base_hi) { 20688c2ecf20Sopenharmony_ci ECR_res = request_region(base_hi, 3, p->name); 20698c2ecf20Sopenharmony_ci if (ECR_res) 20708c2ecf20Sopenharmony_ci parport_ECR_present(p); 20718c2ecf20Sopenharmony_ci } 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci if (base != 0x3bc) { 20748c2ecf20Sopenharmony_ci EPP_res = request_region(base+0x3, 5, p->name); 20758c2ecf20Sopenharmony_ci if (EPP_res) 20768c2ecf20Sopenharmony_ci if (!parport_EPP_supported(p)) 20778c2ecf20Sopenharmony_ci parport_ECPEPP_supported(p); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci if (!parport_SPP_supported(p)) 20808c2ecf20Sopenharmony_ci /* No port. */ 20818c2ecf20Sopenharmony_ci goto out5; 20828c2ecf20Sopenharmony_ci if (priv->ecr) 20838c2ecf20Sopenharmony_ci parport_ECPPS2_supported(p); 20848c2ecf20Sopenharmony_ci else 20858c2ecf20Sopenharmony_ci parport_PS2_supported(p); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci p->size = (p->modes & PARPORT_MODE_EPP) ? 8 : 3; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci pr_info("%s: PC-style at 0x%lx", p->name, p->base); 20908c2ecf20Sopenharmony_ci if (p->base_hi && priv->ecr) 20918c2ecf20Sopenharmony_ci pr_cont(" (0x%lx)", p->base_hi); 20928c2ecf20Sopenharmony_ci if (p->irq == PARPORT_IRQ_AUTO) { 20938c2ecf20Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 20948c2ecf20Sopenharmony_ci parport_irq_probe(p); 20958c2ecf20Sopenharmony_ci } else if (p->irq == PARPORT_IRQ_PROBEONLY) { 20968c2ecf20Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 20978c2ecf20Sopenharmony_ci parport_irq_probe(p); 20988c2ecf20Sopenharmony_ci probedirq = p->irq; 20998c2ecf20Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 21008c2ecf20Sopenharmony_ci } 21018c2ecf20Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 21028c2ecf20Sopenharmony_ci pr_cont(", irq %d", p->irq); 21038c2ecf20Sopenharmony_ci priv->ctr_writable |= 0x10; 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (p->dma == PARPORT_DMA_AUTO) { 21068c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21078c2ecf20Sopenharmony_ci parport_dma_probe(p); 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci if (p->dma == PARPORT_DMA_AUTO) /* To use DMA, giving the irq 21118c2ecf20Sopenharmony_ci is mandatory (see above) */ 21128c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 21158c2ecf20Sopenharmony_ci if (parport_ECP_supported(p) && 21168c2ecf20Sopenharmony_ci p->dma != PARPORT_DMA_NOFIFO && 21178c2ecf20Sopenharmony_ci priv->fifo_depth > 0 && p->irq != PARPORT_IRQ_NONE) { 21188c2ecf20Sopenharmony_ci p->modes |= PARPORT_MODE_ECP | PARPORT_MODE_COMPAT; 21198c2ecf20Sopenharmony_ci p->ops->compat_write_data = parport_pc_compat_write_block_pio; 21208c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_1284 21218c2ecf20Sopenharmony_ci p->ops->ecp_write_data = parport_pc_ecp_write_block_pio; 21228c2ecf20Sopenharmony_ci /* currently broken, but working on it.. (FB) */ 21238c2ecf20Sopenharmony_ci /* p->ops->ecp_read_data = parport_pc_ecp_read_block_pio; */ 21248c2ecf20Sopenharmony_ci#endif /* IEEE 1284 support */ 21258c2ecf20Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) { 21268c2ecf20Sopenharmony_ci pr_cont(", dma %d", p->dma); 21278c2ecf20Sopenharmony_ci p->modes |= PARPORT_MODE_DMA; 21288c2ecf20Sopenharmony_ci } else 21298c2ecf20Sopenharmony_ci pr_cont(", using FIFO"); 21308c2ecf20Sopenharmony_ci } else 21318c2ecf20Sopenharmony_ci /* We can't use the DMA channel after all. */ 21328c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21338c2ecf20Sopenharmony_ci#endif /* Allowed to use FIFO/DMA */ 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci pr_cont(" ["); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci#define printmode(x) \ 21388c2ecf20Sopenharmony_cido { \ 21398c2ecf20Sopenharmony_ci if (p->modes & PARPORT_MODE_##x) \ 21408c2ecf20Sopenharmony_ci pr_cont("%s%s", f++ ? "," : "", #x); \ 21418c2ecf20Sopenharmony_ci} while (0) 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci { 21448c2ecf20Sopenharmony_ci int f = 0; 21458c2ecf20Sopenharmony_ci printmode(PCSPP); 21468c2ecf20Sopenharmony_ci printmode(TRISTATE); 21478c2ecf20Sopenharmony_ci printmode(COMPAT); 21488c2ecf20Sopenharmony_ci printmode(EPP); 21498c2ecf20Sopenharmony_ci printmode(ECP); 21508c2ecf20Sopenharmony_ci printmode(DMA); 21518c2ecf20Sopenharmony_ci } 21528c2ecf20Sopenharmony_ci#undef printmode 21538c2ecf20Sopenharmony_ci#ifndef CONFIG_PARPORT_1284 21548c2ecf20Sopenharmony_ci pr_cont("(,...)"); 21558c2ecf20Sopenharmony_ci#endif /* CONFIG_PARPORT_1284 */ 21568c2ecf20Sopenharmony_ci pr_cont("]\n"); 21578c2ecf20Sopenharmony_ci if (probedirq != PARPORT_IRQ_NONE) 21588c2ecf20Sopenharmony_ci pr_info("%s: irq %d detected\n", p->name, probedirq); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci /* If No ECP release the ports grabbed above. */ 21618c2ecf20Sopenharmony_ci if (ECR_res && (p->modes & PARPORT_MODE_ECP) == 0) { 21628c2ecf20Sopenharmony_ci release_region(base_hi, 3); 21638c2ecf20Sopenharmony_ci ECR_res = NULL; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci /* Likewise for EEP ports */ 21668c2ecf20Sopenharmony_ci if (EPP_res && (p->modes & PARPORT_MODE_EPP) == 0) { 21678c2ecf20Sopenharmony_ci release_region(base+3, 5); 21688c2ecf20Sopenharmony_ci EPP_res = NULL; 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 21718c2ecf20Sopenharmony_ci if (request_irq(p->irq, parport_irq_handler, 21728c2ecf20Sopenharmony_ci irqflags, p->name, p)) { 21738c2ecf20Sopenharmony_ci pr_warn("%s: irq %d in use, resorting to polled operation\n", 21748c2ecf20Sopenharmony_ci p->name, p->irq); 21758c2ecf20Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 21768c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_FIFO 21808c2ecf20Sopenharmony_ci#ifdef HAS_DMA 21818c2ecf20Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) { 21828c2ecf20Sopenharmony_ci if (request_dma(p->dma, p->name)) { 21838c2ecf20Sopenharmony_ci pr_warn("%s: dma %d in use, resorting to PIO operation\n", 21848c2ecf20Sopenharmony_ci p->name, p->dma); 21858c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21868c2ecf20Sopenharmony_ci } else { 21878c2ecf20Sopenharmony_ci priv->dma_buf = 21888c2ecf20Sopenharmony_ci dma_alloc_coherent(dev, 21898c2ecf20Sopenharmony_ci PAGE_SIZE, 21908c2ecf20Sopenharmony_ci &priv->dma_handle, 21918c2ecf20Sopenharmony_ci GFP_KERNEL); 21928c2ecf20Sopenharmony_ci if (!priv->dma_buf) { 21938c2ecf20Sopenharmony_ci pr_warn("%s: cannot get buffer for DMA, resorting to PIO operation\n", 21948c2ecf20Sopenharmony_ci p->name); 21958c2ecf20Sopenharmony_ci free_dma(p->dma); 21968c2ecf20Sopenharmony_ci p->dma = PARPORT_DMA_NONE; 21978c2ecf20Sopenharmony_ci } 21988c2ecf20Sopenharmony_ci } 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci#endif 22018c2ecf20Sopenharmony_ci#endif 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci /* Done probing. Now put the port into a sensible start-up state. */ 22058c2ecf20Sopenharmony_ci if (priv->ecr) 22068c2ecf20Sopenharmony_ci /* 22078c2ecf20Sopenharmony_ci * Put the ECP detected port in PS2 mode. 22088c2ecf20Sopenharmony_ci * Do this also for ports that have ECR but don't do ECP. 22098c2ecf20Sopenharmony_ci */ 22108c2ecf20Sopenharmony_ci ECR_WRITE(p, 0x34); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci parport_pc_write_data(p, 0); 22138c2ecf20Sopenharmony_ci parport_pc_data_forward(p); 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci /* Now that we've told the sharing engine about the port, and 22168c2ecf20Sopenharmony_ci found out its characteristics, let the high-level drivers 22178c2ecf20Sopenharmony_ci know about it. */ 22188c2ecf20Sopenharmony_ci spin_lock(&ports_lock); 22198c2ecf20Sopenharmony_ci list_add(&priv->list, &ports_list); 22208c2ecf20Sopenharmony_ci spin_unlock(&ports_lock); 22218c2ecf20Sopenharmony_ci parport_announce_port(p); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci return p; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ciout5: 22268c2ecf20Sopenharmony_ci if (ECR_res) 22278c2ecf20Sopenharmony_ci release_region(base_hi, 3); 22288c2ecf20Sopenharmony_ci if (EPP_res) 22298c2ecf20Sopenharmony_ci release_region(base+0x3, 5); 22308c2ecf20Sopenharmony_ci release_region(base, 3); 22318c2ecf20Sopenharmony_ciout4: 22328c2ecf20Sopenharmony_ci parport_del_port(p); 22338c2ecf20Sopenharmony_ciout3: 22348c2ecf20Sopenharmony_ci kfree(priv); 22358c2ecf20Sopenharmony_ciout2: 22368c2ecf20Sopenharmony_ci kfree(ops); 22378c2ecf20Sopenharmony_ciout1: 22388c2ecf20Sopenharmony_ci if (pdev) 22398c2ecf20Sopenharmony_ci platform_device_unregister(pdev); 22408c2ecf20Sopenharmony_ci return NULL; 22418c2ecf20Sopenharmony_ci} 22428c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_pc_probe_port); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_civoid parport_pc_unregister_port(struct parport *p) 22458c2ecf20Sopenharmony_ci{ 22468c2ecf20Sopenharmony_ci struct parport_pc_private *priv = p->private_data; 22478c2ecf20Sopenharmony_ci struct parport_operations *ops = p->ops; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci parport_remove_port(p); 22508c2ecf20Sopenharmony_ci spin_lock(&ports_lock); 22518c2ecf20Sopenharmony_ci list_del_init(&priv->list); 22528c2ecf20Sopenharmony_ci spin_unlock(&ports_lock); 22538c2ecf20Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) 22548c2ecf20Sopenharmony_ci if (p->dma != PARPORT_DMA_NONE) 22558c2ecf20Sopenharmony_ci free_dma(p->dma); 22568c2ecf20Sopenharmony_ci#endif 22578c2ecf20Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) 22588c2ecf20Sopenharmony_ci free_irq(p->irq, p); 22598c2ecf20Sopenharmony_ci release_region(p->base, 3); 22608c2ecf20Sopenharmony_ci if (p->size > 3) 22618c2ecf20Sopenharmony_ci release_region(p->base + 3, p->size - 3); 22628c2ecf20Sopenharmony_ci if (p->modes & PARPORT_MODE_ECP) 22638c2ecf20Sopenharmony_ci release_region(p->base_hi, 3); 22648c2ecf20Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_FIFO) && defined(HAS_DMA) 22658c2ecf20Sopenharmony_ci if (priv->dma_buf) 22668c2ecf20Sopenharmony_ci dma_free_coherent(p->physport->dev, PAGE_SIZE, 22678c2ecf20Sopenharmony_ci priv->dma_buf, 22688c2ecf20Sopenharmony_ci priv->dma_handle); 22698c2ecf20Sopenharmony_ci#endif 22708c2ecf20Sopenharmony_ci kfree(p->private_data); 22718c2ecf20Sopenharmony_ci parport_del_port(p); 22728c2ecf20Sopenharmony_ci kfree(ops); /* hope no-one cached it */ 22738c2ecf20Sopenharmony_ci} 22748c2ecf20Sopenharmony_ciEXPORT_SYMBOL(parport_pc_unregister_port); 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci/* ITE support maintained by Rich Liu <richliu@poorman.org> */ 22798c2ecf20Sopenharmony_cistatic int sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, int autodma, 22808c2ecf20Sopenharmony_ci const struct parport_pc_via_data *via) 22818c2ecf20Sopenharmony_ci{ 22828c2ecf20Sopenharmony_ci short inta_addr[6] = { 0x2A0, 0x2C0, 0x220, 0x240, 0x1E0 }; 22838c2ecf20Sopenharmony_ci u32 ite8872set; 22848c2ecf20Sopenharmony_ci u32 ite8872_lpt, ite8872_lpthi; 22858c2ecf20Sopenharmony_ci u8 ite8872_irq, type; 22868c2ecf20Sopenharmony_ci int irq; 22878c2ecf20Sopenharmony_ci int i; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci pr_debug("sio_ite_8872_probe()\n"); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci /* make sure which one chip */ 22928c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 22938c2ecf20Sopenharmony_ci if (request_region(inta_addr[i], 32, "it887x")) { 22948c2ecf20Sopenharmony_ci int test; 22958c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x60, 22968c2ecf20Sopenharmony_ci 0xe5000000 | inta_addr[i]); 22978c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x78, 22988c2ecf20Sopenharmony_ci 0x00000000 | inta_addr[i]); 22998c2ecf20Sopenharmony_ci test = inb(inta_addr[i]); 23008c2ecf20Sopenharmony_ci if (test != 0xff) 23018c2ecf20Sopenharmony_ci break; 23028c2ecf20Sopenharmony_ci release_region(inta_addr[i], 32); 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci if (i >= 5) { 23068c2ecf20Sopenharmony_ci pr_info("parport_pc: cannot find ITE8872 INTA\n"); 23078c2ecf20Sopenharmony_ci return 0; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci type = inb(inta_addr[i] + 0x18); 23118c2ecf20Sopenharmony_ci type &= 0x0f; 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci switch (type) { 23148c2ecf20Sopenharmony_ci case 0x2: 23158c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE8871 found (1P)\n"); 23168c2ecf20Sopenharmony_ci ite8872set = 0x64200000; 23178c2ecf20Sopenharmony_ci break; 23188c2ecf20Sopenharmony_ci case 0xa: 23198c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE8875 found (1P)\n"); 23208c2ecf20Sopenharmony_ci ite8872set = 0x64200000; 23218c2ecf20Sopenharmony_ci break; 23228c2ecf20Sopenharmony_ci case 0xe: 23238c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE8872 found (2S1P)\n"); 23248c2ecf20Sopenharmony_ci ite8872set = 0x64e00000; 23258c2ecf20Sopenharmony_ci break; 23268c2ecf20Sopenharmony_ci case 0x6: 23278c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE8873 found (1S)\n"); 23288c2ecf20Sopenharmony_ci release_region(inta_addr[i], 32); 23298c2ecf20Sopenharmony_ci return 0; 23308c2ecf20Sopenharmony_ci case 0x8: 23318c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE8874 found (2S)\n"); 23328c2ecf20Sopenharmony_ci release_region(inta_addr[i], 32); 23338c2ecf20Sopenharmony_ci return 0; 23348c2ecf20Sopenharmony_ci default: 23358c2ecf20Sopenharmony_ci pr_info("parport_pc: unknown ITE887x\n"); 23368c2ecf20Sopenharmony_ci pr_info("parport_pc: please mail 'lspci -nvv' output to Rich.Liu@ite.com.tw\n"); 23378c2ecf20Sopenharmony_ci release_region(inta_addr[i], 32); 23388c2ecf20Sopenharmony_ci return 0; 23398c2ecf20Sopenharmony_ci } 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, 0x3c, &ite8872_irq); 23428c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, 0x1c, &ite8872_lpt); 23438c2ecf20Sopenharmony_ci ite8872_lpt &= 0x0000ff00; 23448c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, 0x20, &ite8872_lpthi); 23458c2ecf20Sopenharmony_ci ite8872_lpthi &= 0x0000ff00; 23468c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x6c, 0xe3000000 | ite8872_lpt); 23478c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x70, 0xe3000000 | ite8872_lpthi); 23488c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x80, (ite8872_lpthi<<16) | ite8872_lpt); 23498c2ecf20Sopenharmony_ci /* SET SPP&EPP , Parallel Port NO DMA , Enable All Function */ 23508c2ecf20Sopenharmony_ci /* SET Parallel IRQ */ 23518c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x9c, 23528c2ecf20Sopenharmony_ci ite8872set | (ite8872_irq * 0x11111)); 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci pr_debug("ITE887x: The IRQ is %d\n", ite8872_irq); 23558c2ecf20Sopenharmony_ci pr_debug("ITE887x: The PARALLEL I/O port is 0x%x\n", ite8872_lpt); 23568c2ecf20Sopenharmony_ci pr_debug("ITE887x: The PARALLEL I/O porthi is 0x%x\n", ite8872_lpthi); 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* Let the user (or defaults) steer us away from interrupts */ 23598c2ecf20Sopenharmony_ci irq = ite8872_irq; 23608c2ecf20Sopenharmony_ci if (autoirq != PARPORT_IRQ_AUTO) 23618c2ecf20Sopenharmony_ci irq = PARPORT_IRQ_NONE; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci /* 23648c2ecf20Sopenharmony_ci * Release the resource so that parport_pc_probe_port can get it. 23658c2ecf20Sopenharmony_ci */ 23668c2ecf20Sopenharmony_ci release_region(inta_addr[i], 32); 23678c2ecf20Sopenharmony_ci if (parport_pc_probe_port(ite8872_lpt, ite8872_lpthi, 23688c2ecf20Sopenharmony_ci irq, PARPORT_DMA_NONE, &pdev->dev, 0)) { 23698c2ecf20Sopenharmony_ci pr_info("parport_pc: ITE 8872 parallel port: io=0x%X", 23708c2ecf20Sopenharmony_ci ite8872_lpt); 23718c2ecf20Sopenharmony_ci if (irq != PARPORT_IRQ_NONE) 23728c2ecf20Sopenharmony_ci pr_cont(", irq=%d", irq); 23738c2ecf20Sopenharmony_ci pr_cont("\n"); 23748c2ecf20Sopenharmony_ci return 1; 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci return 0; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci/* VIA 8231 support by Pavel Fedin <sonic_amiga@rambler.ru> 23818c2ecf20Sopenharmony_ci based on VIA 686a support code by Jeff Garzik <jgarzik@pobox.com> */ 23828c2ecf20Sopenharmony_cistatic int parport_init_mode; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci/* Data for two known VIA chips */ 23858c2ecf20Sopenharmony_cistatic struct parport_pc_via_data via_686a_data = { 23868c2ecf20Sopenharmony_ci 0x51, 23878c2ecf20Sopenharmony_ci 0x50, 23888c2ecf20Sopenharmony_ci 0x85, 23898c2ecf20Sopenharmony_ci 0x02, 23908c2ecf20Sopenharmony_ci 0xE2, 23918c2ecf20Sopenharmony_ci 0xF0, 23928c2ecf20Sopenharmony_ci 0xE6 23938c2ecf20Sopenharmony_ci}; 23948c2ecf20Sopenharmony_cistatic struct parport_pc_via_data via_8231_data = { 23958c2ecf20Sopenharmony_ci 0x45, 23968c2ecf20Sopenharmony_ci 0x44, 23978c2ecf20Sopenharmony_ci 0x50, 23988c2ecf20Sopenharmony_ci 0x04, 23998c2ecf20Sopenharmony_ci 0xF2, 24008c2ecf20Sopenharmony_ci 0xFA, 24018c2ecf20Sopenharmony_ci 0xF6 24028c2ecf20Sopenharmony_ci}; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_cistatic int sio_via_probe(struct pci_dev *pdev, int autoirq, int autodma, 24058c2ecf20Sopenharmony_ci const struct parport_pc_via_data *via) 24068c2ecf20Sopenharmony_ci{ 24078c2ecf20Sopenharmony_ci u8 tmp, tmp2, siofunc; 24088c2ecf20Sopenharmony_ci u8 ppcontrol = 0; 24098c2ecf20Sopenharmony_ci int dma, irq; 24108c2ecf20Sopenharmony_ci unsigned port1, port2; 24118c2ecf20Sopenharmony_ci unsigned have_epp = 0; 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: VIA 686A/8231 detected\n"); 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci switch (parport_init_mode) { 24168c2ecf20Sopenharmony_ci case 1: 24178c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting SPP mode\n"); 24188c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_SPP; 24198c2ecf20Sopenharmony_ci break; 24208c2ecf20Sopenharmony_ci case 2: 24218c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting PS/2 mode\n"); 24228c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_SPP; 24238c2ecf20Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 24248c2ecf20Sopenharmony_ci break; 24258c2ecf20Sopenharmony_ci case 3: 24268c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting EPP mode\n"); 24278c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_EPP; 24288c2ecf20Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 24298c2ecf20Sopenharmony_ci have_epp = 1; 24308c2ecf20Sopenharmony_ci break; 24318c2ecf20Sopenharmony_ci case 4: 24328c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting ECP mode\n"); 24338c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_ECP; 24348c2ecf20Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR; 24358c2ecf20Sopenharmony_ci break; 24368c2ecf20Sopenharmony_ci case 5: 24378c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: setting EPP+ECP mode\n"); 24388c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PARPORT_ECP; 24398c2ecf20Sopenharmony_ci ppcontrol = VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP; 24408c2ecf20Sopenharmony_ci have_epp = 1; 24418c2ecf20Sopenharmony_ci break; 24428c2ecf20Sopenharmony_ci default: 24438c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: probing current configuration\n"); 24448c2ecf20Sopenharmony_ci siofunc = VIA_FUNCTION_PROBE; 24458c2ecf20Sopenharmony_ci break; 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci /* 24488c2ecf20Sopenharmony_ci * unlock super i/o configuration 24498c2ecf20Sopenharmony_ci */ 24508c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_superio_config_reg, &tmp); 24518c2ecf20Sopenharmony_ci tmp |= via->via_pci_superio_config_data; 24528c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, via->via_pci_superio_config_reg, tmp); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci /* Bits 1-0: Parallel Port Mode / Enable */ 24558c2ecf20Sopenharmony_ci outb(via->viacfg_function, VIA_CONFIG_INDEX); 24568c2ecf20Sopenharmony_ci tmp = inb(VIA_CONFIG_DATA); 24578c2ecf20Sopenharmony_ci /* Bit 5: EPP+ECP enable; bit 7: PS/2 bidirectional port enable */ 24588c2ecf20Sopenharmony_ci outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); 24598c2ecf20Sopenharmony_ci tmp2 = inb(VIA_CONFIG_DATA); 24608c2ecf20Sopenharmony_ci if (siofunc == VIA_FUNCTION_PROBE) { 24618c2ecf20Sopenharmony_ci siofunc = tmp & VIA_FUNCTION_PARPORT_DISABLE; 24628c2ecf20Sopenharmony_ci ppcontrol = tmp2; 24638c2ecf20Sopenharmony_ci } else { 24648c2ecf20Sopenharmony_ci tmp &= ~VIA_FUNCTION_PARPORT_DISABLE; 24658c2ecf20Sopenharmony_ci tmp |= siofunc; 24668c2ecf20Sopenharmony_ci outb(via->viacfg_function, VIA_CONFIG_INDEX); 24678c2ecf20Sopenharmony_ci outb(tmp, VIA_CONFIG_DATA); 24688c2ecf20Sopenharmony_ci tmp2 &= ~(VIA_PARPORT_BIDIR|VIA_PARPORT_ECPEPP); 24698c2ecf20Sopenharmony_ci tmp2 |= ppcontrol; 24708c2ecf20Sopenharmony_ci outb(via->viacfg_parport_control, VIA_CONFIG_INDEX); 24718c2ecf20Sopenharmony_ci outb(tmp2, VIA_CONFIG_DATA); 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci /* Parallel Port I/O Base Address, bits 9-2 */ 24758c2ecf20Sopenharmony_ci outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); 24768c2ecf20Sopenharmony_ci port1 = inb(VIA_CONFIG_DATA) << 2; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: Current parallel port base: 0x%X\n", 24798c2ecf20Sopenharmony_ci port1); 24808c2ecf20Sopenharmony_ci if (port1 == 0x3BC && have_epp) { 24818c2ecf20Sopenharmony_ci outb(via->viacfg_parport_base, VIA_CONFIG_INDEX); 24828c2ecf20Sopenharmony_ci outb((0x378 >> 2), VIA_CONFIG_DATA); 24838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc: Parallel port base changed to 0x378\n"); 24848c2ecf20Sopenharmony_ci port1 = 0x378; 24858c2ecf20Sopenharmony_ci } 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci /* 24888c2ecf20Sopenharmony_ci * lock super i/o configuration 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_superio_config_reg, &tmp); 24918c2ecf20Sopenharmony_ci tmp &= ~via->via_pci_superio_config_data; 24928c2ecf20Sopenharmony_ci pci_write_config_byte(pdev, via->via_pci_superio_config_reg, tmp); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (siofunc == VIA_FUNCTION_PARPORT_DISABLE) { 24958c2ecf20Sopenharmony_ci pr_info("parport_pc: VIA parallel port disabled in BIOS\n"); 24968c2ecf20Sopenharmony_ci return 0; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci /* Bits 7-4: PnP Routing for Parallel Port IRQ */ 25008c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_parport_irq_reg, &tmp); 25018c2ecf20Sopenharmony_ci irq = ((tmp & VIA_IRQCONTROL_PARALLEL) >> 4); 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci if (siofunc == VIA_FUNCTION_PARPORT_ECP) { 25048c2ecf20Sopenharmony_ci /* Bits 3-2: PnP Routing for Parallel Port DMA */ 25058c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, via->via_pci_parport_dma_reg, &tmp); 25068c2ecf20Sopenharmony_ci dma = ((tmp & VIA_DMACONTROL_PARALLEL) >> 2); 25078c2ecf20Sopenharmony_ci } else 25088c2ecf20Sopenharmony_ci /* if ECP not enabled, DMA is not enabled, assumed 25098c2ecf20Sopenharmony_ci bogus 'dma' value */ 25108c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci /* Let the user (or defaults) steer us away from interrupts and DMA */ 25138c2ecf20Sopenharmony_ci if (autoirq == PARPORT_IRQ_NONE) { 25148c2ecf20Sopenharmony_ci irq = PARPORT_IRQ_NONE; 25158c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 25168c2ecf20Sopenharmony_ci } 25178c2ecf20Sopenharmony_ci if (autodma == PARPORT_DMA_NONE) 25188c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 25198c2ecf20Sopenharmony_ci 25208c2ecf20Sopenharmony_ci switch (port1) { 25218c2ecf20Sopenharmony_ci case 0x3bc: 25228c2ecf20Sopenharmony_ci port2 = 0x7bc; break; 25238c2ecf20Sopenharmony_ci case 0x378: 25248c2ecf20Sopenharmony_ci port2 = 0x778; break; 25258c2ecf20Sopenharmony_ci case 0x278: 25268c2ecf20Sopenharmony_ci port2 = 0x678; break; 25278c2ecf20Sopenharmony_ci default: 25288c2ecf20Sopenharmony_ci pr_info("parport_pc: Weird VIA parport base 0x%X, ignoring\n", 25298c2ecf20Sopenharmony_ci port1); 25308c2ecf20Sopenharmony_ci return 0; 25318c2ecf20Sopenharmony_ci } 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci /* filter bogus IRQs */ 25348c2ecf20Sopenharmony_ci switch (irq) { 25358c2ecf20Sopenharmony_ci case 0: 25368c2ecf20Sopenharmony_ci case 2: 25378c2ecf20Sopenharmony_ci case 8: 25388c2ecf20Sopenharmony_ci case 13: 25398c2ecf20Sopenharmony_ci irq = PARPORT_IRQ_NONE; 25408c2ecf20Sopenharmony_ci break; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci default: /* do nothing */ 25438c2ecf20Sopenharmony_ci break; 25448c2ecf20Sopenharmony_ci } 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci /* finally, do the probe with values obtained */ 25478c2ecf20Sopenharmony_ci if (parport_pc_probe_port(port1, port2, irq, dma, &pdev->dev, 0)) { 25488c2ecf20Sopenharmony_ci pr_info("parport_pc: VIA parallel port: io=0x%X", port1); 25498c2ecf20Sopenharmony_ci if (irq != PARPORT_IRQ_NONE) 25508c2ecf20Sopenharmony_ci pr_cont(", irq=%d", irq); 25518c2ecf20Sopenharmony_ci if (dma != PARPORT_DMA_NONE) 25528c2ecf20Sopenharmony_ci pr_cont(", dma=%d", dma); 25538c2ecf20Sopenharmony_ci pr_cont("\n"); 25548c2ecf20Sopenharmony_ci return 1; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci pr_warn("parport_pc: Strange, can't probe VIA parallel port: io=0x%X, irq=%d, dma=%d\n", 25588c2ecf20Sopenharmony_ci port1, irq, dma); 25598c2ecf20Sopenharmony_ci return 0; 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_cienum parport_pc_sio_types { 25648c2ecf20Sopenharmony_ci sio_via_686a = 0, /* Via VT82C686A motherboard Super I/O */ 25658c2ecf20Sopenharmony_ci sio_via_8231, /* Via VT8231 south bridge integrated Super IO */ 25668c2ecf20Sopenharmony_ci sio_ite_8872, 25678c2ecf20Sopenharmony_ci last_sio 25688c2ecf20Sopenharmony_ci}; 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci/* each element directly indexed from enum list, above */ 25718c2ecf20Sopenharmony_cistatic struct parport_pc_superio { 25728c2ecf20Sopenharmony_ci int (*probe) (struct pci_dev *pdev, int autoirq, int autodma, 25738c2ecf20Sopenharmony_ci const struct parport_pc_via_data *via); 25748c2ecf20Sopenharmony_ci const struct parport_pc_via_data *via; 25758c2ecf20Sopenharmony_ci} parport_pc_superio_info[] = { 25768c2ecf20Sopenharmony_ci { sio_via_probe, &via_686a_data, }, 25778c2ecf20Sopenharmony_ci { sio_via_probe, &via_8231_data, }, 25788c2ecf20Sopenharmony_ci { sio_ite_8872_probe, NULL, }, 25798c2ecf20Sopenharmony_ci}; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_cienum parport_pc_pci_cards { 25828c2ecf20Sopenharmony_ci siig_1p_10x = last_sio, 25838c2ecf20Sopenharmony_ci siig_2p_10x, 25848c2ecf20Sopenharmony_ci siig_1p_20x, 25858c2ecf20Sopenharmony_ci siig_2p_20x, 25868c2ecf20Sopenharmony_ci lava_parallel, 25878c2ecf20Sopenharmony_ci lava_parallel_dual_a, 25888c2ecf20Sopenharmony_ci lava_parallel_dual_b, 25898c2ecf20Sopenharmony_ci boca_ioppar, 25908c2ecf20Sopenharmony_ci plx_9050, 25918c2ecf20Sopenharmony_ci timedia_4006a, 25928c2ecf20Sopenharmony_ci timedia_4014, 25938c2ecf20Sopenharmony_ci timedia_4008a, 25948c2ecf20Sopenharmony_ci timedia_4018, 25958c2ecf20Sopenharmony_ci timedia_9018a, 25968c2ecf20Sopenharmony_ci syba_2p_epp, 25978c2ecf20Sopenharmony_ci syba_1p_ecp, 25988c2ecf20Sopenharmony_ci titan_010l, 25998c2ecf20Sopenharmony_ci avlab_1p, 26008c2ecf20Sopenharmony_ci avlab_2p, 26018c2ecf20Sopenharmony_ci oxsemi_952, 26028c2ecf20Sopenharmony_ci oxsemi_954, 26038c2ecf20Sopenharmony_ci oxsemi_840, 26048c2ecf20Sopenharmony_ci oxsemi_pcie_pport, 26058c2ecf20Sopenharmony_ci aks_0100, 26068c2ecf20Sopenharmony_ci mobility_pp, 26078c2ecf20Sopenharmony_ci netmos_9705, 26088c2ecf20Sopenharmony_ci netmos_9715, 26098c2ecf20Sopenharmony_ci netmos_9755, 26108c2ecf20Sopenharmony_ci netmos_9805, 26118c2ecf20Sopenharmony_ci netmos_9815, 26128c2ecf20Sopenharmony_ci netmos_9901, 26138c2ecf20Sopenharmony_ci netmos_9865, 26148c2ecf20Sopenharmony_ci quatech_sppxp100, 26158c2ecf20Sopenharmony_ci wch_ch382l, 26168c2ecf20Sopenharmony_ci brainboxes_uc146, 26178c2ecf20Sopenharmony_ci brainboxes_px203, 26188c2ecf20Sopenharmony_ci}; 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci/* each element directly indexed from enum list, above 26228c2ecf20Sopenharmony_ci * (but offset by last_sio) */ 26238c2ecf20Sopenharmony_cistatic struct parport_pc_pci { 26248c2ecf20Sopenharmony_ci int numports; 26258c2ecf20Sopenharmony_ci struct { /* BAR (base address registers) numbers in the config 26268c2ecf20Sopenharmony_ci space header */ 26278c2ecf20Sopenharmony_ci int lo; 26288c2ecf20Sopenharmony_ci int hi; 26298c2ecf20Sopenharmony_ci /* -1 if not there, >6 for offset-method (max BAR is 6) */ 26308c2ecf20Sopenharmony_ci } addr[4]; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* If set, this is called immediately after pci_enable_device. 26338c2ecf20Sopenharmony_ci * If it returns non-zero, no probing will take place and the 26348c2ecf20Sopenharmony_ci * ports will not be used. */ 26358c2ecf20Sopenharmony_ci int (*preinit_hook) (struct pci_dev *pdev, int autoirq, int autodma); 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci /* If set, this is called after probing for ports. If 'failed' 26388c2ecf20Sopenharmony_ci * is non-zero we couldn't use any of the ports. */ 26398c2ecf20Sopenharmony_ci void (*postinit_hook) (struct pci_dev *pdev, int failed); 26408c2ecf20Sopenharmony_ci} cards[] = { 26418c2ecf20Sopenharmony_ci /* siig_1p_10x */ { 1, { { 2, 3 }, } }, 26428c2ecf20Sopenharmony_ci /* siig_2p_10x */ { 2, { { 2, 3 }, { 4, 5 }, } }, 26438c2ecf20Sopenharmony_ci /* siig_1p_20x */ { 1, { { 0, 1 }, } }, 26448c2ecf20Sopenharmony_ci /* siig_2p_20x */ { 2, { { 0, 1 }, { 2, 3 }, } }, 26458c2ecf20Sopenharmony_ci /* lava_parallel */ { 1, { { 0, -1 }, } }, 26468c2ecf20Sopenharmony_ci /* lava_parallel_dual_a */ { 1, { { 0, -1 }, } }, 26478c2ecf20Sopenharmony_ci /* lava_parallel_dual_b */ { 1, { { 0, -1 }, } }, 26488c2ecf20Sopenharmony_ci /* boca_ioppar */ { 1, { { 0, -1 }, } }, 26498c2ecf20Sopenharmony_ci /* plx_9050 */ { 2, { { 4, -1 }, { 5, -1 }, } }, 26508c2ecf20Sopenharmony_ci /* timedia_4006a */ { 1, { { 0, -1 }, } }, 26518c2ecf20Sopenharmony_ci /* timedia_4014 */ { 2, { { 0, -1 }, { 2, -1 }, } }, 26528c2ecf20Sopenharmony_ci /* timedia_4008a */ { 1, { { 0, 1 }, } }, 26538c2ecf20Sopenharmony_ci /* timedia_4018 */ { 2, { { 0, 1 }, { 2, 3 }, } }, 26548c2ecf20Sopenharmony_ci /* timedia_9018a */ { 2, { { 0, 1 }, { 2, 3 }, } }, 26558c2ecf20Sopenharmony_ci /* SYBA uses fixed offsets in 26568c2ecf20Sopenharmony_ci a 1K io window */ 26578c2ecf20Sopenharmony_ci /* syba_2p_epp AP138B */ { 2, { { 0, 0x078 }, { 0, 0x178 }, } }, 26588c2ecf20Sopenharmony_ci /* syba_1p_ecp W83787 */ { 1, { { 0, 0x078 }, } }, 26598c2ecf20Sopenharmony_ci /* titan_010l */ { 1, { { 3, -1 }, } }, 26608c2ecf20Sopenharmony_ci /* avlab_1p */ { 1, { { 0, 1}, } }, 26618c2ecf20Sopenharmony_ci /* avlab_2p */ { 2, { { 0, 1}, { 2, 3 },} }, 26628c2ecf20Sopenharmony_ci /* The Oxford Semi cards are unusual: 954 doesn't support ECP, 26638c2ecf20Sopenharmony_ci * and 840 locks up if you write 1 to bit 2! */ 26648c2ecf20Sopenharmony_ci /* oxsemi_952 */ { 1, { { 0, 1 }, } }, 26658c2ecf20Sopenharmony_ci /* oxsemi_954 */ { 1, { { 0, -1 }, } }, 26668c2ecf20Sopenharmony_ci /* oxsemi_840 */ { 1, { { 0, 1 }, } }, 26678c2ecf20Sopenharmony_ci /* oxsemi_pcie_pport */ { 1, { { 0, 1 }, } }, 26688c2ecf20Sopenharmony_ci /* aks_0100 */ { 1, { { 0, -1 }, } }, 26698c2ecf20Sopenharmony_ci /* mobility_pp */ { 1, { { 0, 1 }, } }, 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci /* The netmos entries below are untested */ 26728c2ecf20Sopenharmony_ci /* netmos_9705 */ { 1, { { 0, -1 }, } }, 26738c2ecf20Sopenharmony_ci /* netmos_9715 */ { 2, { { 0, 1 }, { 2, 3 },} }, 26748c2ecf20Sopenharmony_ci /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, 26758c2ecf20Sopenharmony_ci /* netmos_9805 */ { 1, { { 0, 1 }, } }, 26768c2ecf20Sopenharmony_ci /* netmos_9815 */ { 2, { { 0, 1 }, { 2, 3 }, } }, 26778c2ecf20Sopenharmony_ci /* netmos_9901 */ { 1, { { 0, -1 }, } }, 26788c2ecf20Sopenharmony_ci /* netmos_9865 */ { 1, { { 0, -1 }, } }, 26798c2ecf20Sopenharmony_ci /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, 26808c2ecf20Sopenharmony_ci /* wch_ch382l */ { 1, { { 2, -1 }, } }, 26818c2ecf20Sopenharmony_ci /* brainboxes_uc146 */ { 1, { { 3, -1 }, } }, 26828c2ecf20Sopenharmony_ci /* brainboxes_px203 */ { 1, { { 0, -1 }, } }, 26838c2ecf20Sopenharmony_ci}; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_cistatic const struct pci_device_id parport_pc_pci_tbl[] = { 26868c2ecf20Sopenharmony_ci /* Super-IO onboard chips */ 26878c2ecf20Sopenharmony_ci { 0x1106, 0x0686, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_686a }, 26888c2ecf20Sopenharmony_ci { 0x1106, 0x8231, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_via_8231 }, 26898c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872, 26908c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, sio_ite_8872 }, 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci /* PCI cards */ 26938c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_10x, 26948c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_10x }, 26958c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_10x, 26968c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_10x }, 26978c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1P_20x, 26988c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_1p_20x }, 26998c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P_20x, 27008c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, siig_2p_20x }, 27018c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PARALLEL, 27028c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel }, 27038c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_A, 27048c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_a }, 27058c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 27068c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, lava_parallel_dual_b }, 27078c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, 27088c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, boca_ioppar }, 27098c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, 27108c2ecf20Sopenharmony_ci PCI_SUBVENDOR_ID_EXSYS, PCI_SUBDEVICE_ID_EXSYS_4014, 0, 0, plx_9050 }, 27118c2ecf20Sopenharmony_ci /* PCI_VENDOR_ID_TIMEDIA/SUNIX has many differing cards ...*/ 27128c2ecf20Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0101, 0, 0, timedia_4006a }, 27138c2ecf20Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0102, 0, 0, timedia_4014 }, 27148c2ecf20Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0103, 0, 0, timedia_4008a }, 27158c2ecf20Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x0104, 0, 0, timedia_4018 }, 27168c2ecf20Sopenharmony_ci { 0x1409, 0x7268, 0x1409, 0x9018, 0, 0, timedia_9018a }, 27178c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_2P_EPP, 27188c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_2p_epp }, 27198c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_SYBA, PCI_DEVICE_ID_SYBA_1P_ECP, 27208c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, syba_1p_ecp }, 27218c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_010L, 27228c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, titan_010l }, 27238c2ecf20Sopenharmony_ci /* PCI_VENDOR_ID_AVLAB/Intek21 has another bunch of cards ...*/ 27248c2ecf20Sopenharmony_ci /* AFAVLAB_TK9902 */ 27258c2ecf20Sopenharmony_ci { 0x14db, 0x2120, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_1p}, 27268c2ecf20Sopenharmony_ci { 0x14db, 0x2121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, avlab_2p}, 27278c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952PP, 27288c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_952 }, 27298c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, 27308c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_954 }, 27318c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, 27328c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_840 }, 27338c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840, 27348c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27358c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe840_G, 27368c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27378c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0, 27388c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27398c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_0_G, 27408c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27418c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1, 27428c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27438c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_G, 27448c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27458c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_U, 27468c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27478c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU, 27488c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27498c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_AKS, PCI_DEVICE_ID_AKS_ALADDINCARD, 27508c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, aks_0100 }, 27518c2ecf20Sopenharmony_ci { 0x14f2, 0x0121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, mobility_pp }, 27528c2ecf20Sopenharmony_ci /* NetMos communication controllers */ 27538c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9705, 27548c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9705 }, 27558c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9715, 27568c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9715 }, 27578c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9755, 27588c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9755 }, 27598c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9805, 27608c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 }, 27618c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815, 27628c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, 27638c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 27648c2ecf20Sopenharmony_ci 0xA000, 0x2000, 0, 0, netmos_9901 }, 27658c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, 27668c2ecf20Sopenharmony_ci 0xA000, 0x1000, 0, 0, netmos_9865 }, 27678c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865, 27688c2ecf20Sopenharmony_ci 0xA000, 0x2000, 0, 0, netmos_9865 }, 27698c2ecf20Sopenharmony_ci /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ 27708c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, 27718c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, 27728c2ecf20Sopenharmony_ci /* WCH CH382L PCI-E single parallel port card */ 27738c2ecf20Sopenharmony_ci { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l }, 27748c2ecf20Sopenharmony_ci /* Brainboxes IX-500/550 */ 27758c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x402a, 27768c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27778c2ecf20Sopenharmony_ci /* Brainboxes UC-146/UC-157 */ 27788c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x0be1, 27798c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc146 }, 27808c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x0be2, 27818c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_uc146 }, 27828c2ecf20Sopenharmony_ci /* Brainboxes PX-146/PX-257 */ 27838c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x401c, 27848c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27858c2ecf20Sopenharmony_ci /* Brainboxes PX-203 */ 27868c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x4007, 27878c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, brainboxes_px203 }, 27888c2ecf20Sopenharmony_ci /* Brainboxes PX-475 */ 27898c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_INTASHIELD, 0x401f, 27908c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, oxsemi_pcie_pport }, 27918c2ecf20Sopenharmony_ci { 0, } /* terminate list */ 27928c2ecf20Sopenharmony_ci}; 27938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_cistruct pci_parport_data { 27968c2ecf20Sopenharmony_ci int num; 27978c2ecf20Sopenharmony_ci struct parport *ports[2]; 27988c2ecf20Sopenharmony_ci}; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_cistatic int parport_pc_pci_probe(struct pci_dev *dev, 28018c2ecf20Sopenharmony_ci const struct pci_device_id *id) 28028c2ecf20Sopenharmony_ci{ 28038c2ecf20Sopenharmony_ci int err, count, n, i = id->driver_data; 28048c2ecf20Sopenharmony_ci struct pci_parport_data *data; 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci if (i < last_sio) 28078c2ecf20Sopenharmony_ci /* This is an onboard Super-IO and has already been probed */ 28088c2ecf20Sopenharmony_ci return 0; 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci /* This is a PCI card */ 28118c2ecf20Sopenharmony_ci i -= last_sio; 28128c2ecf20Sopenharmony_ci count = 0; 28138c2ecf20Sopenharmony_ci err = pci_enable_device(dev); 28148c2ecf20Sopenharmony_ci if (err) 28158c2ecf20Sopenharmony_ci return err; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci data = kmalloc(sizeof(struct pci_parport_data), GFP_KERNEL); 28188c2ecf20Sopenharmony_ci if (!data) 28198c2ecf20Sopenharmony_ci return -ENOMEM; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci if (cards[i].preinit_hook && 28228c2ecf20Sopenharmony_ci cards[i].preinit_hook(dev, PARPORT_IRQ_NONE, PARPORT_DMA_NONE)) { 28238c2ecf20Sopenharmony_ci kfree(data); 28248c2ecf20Sopenharmony_ci return -ENODEV; 28258c2ecf20Sopenharmony_ci } 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci for (n = 0; n < cards[i].numports; n++) { 28288c2ecf20Sopenharmony_ci int lo = cards[i].addr[n].lo; 28298c2ecf20Sopenharmony_ci int hi = cards[i].addr[n].hi; 28308c2ecf20Sopenharmony_ci int irq; 28318c2ecf20Sopenharmony_ci unsigned long io_lo, io_hi; 28328c2ecf20Sopenharmony_ci io_lo = pci_resource_start(dev, lo); 28338c2ecf20Sopenharmony_ci io_hi = 0; 28348c2ecf20Sopenharmony_ci if ((hi >= 0) && (hi <= 6)) 28358c2ecf20Sopenharmony_ci io_hi = pci_resource_start(dev, hi); 28368c2ecf20Sopenharmony_ci else if (hi > 6) 28378c2ecf20Sopenharmony_ci io_lo += hi; /* Reinterpret the meaning of 28388c2ecf20Sopenharmony_ci "hi" as an offset (see SYBA 28398c2ecf20Sopenharmony_ci def.) */ 28408c2ecf20Sopenharmony_ci /* TODO: test if sharing interrupts works */ 28418c2ecf20Sopenharmony_ci irq = dev->irq; 28428c2ecf20Sopenharmony_ci if (irq == IRQ_NONE) { 28438c2ecf20Sopenharmony_ci printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx)\n", 28448c2ecf20Sopenharmony_ci id->vendor, id->device, io_lo, io_hi); 28458c2ecf20Sopenharmony_ci irq = PARPORT_IRQ_NONE; 28468c2ecf20Sopenharmony_ci } else { 28478c2ecf20Sopenharmony_ci printk(KERN_DEBUG "PCI parallel port detected: %04x:%04x, I/O at %#lx(%#lx), IRQ %d\n", 28488c2ecf20Sopenharmony_ci id->vendor, id->device, io_lo, io_hi, irq); 28498c2ecf20Sopenharmony_ci } 28508c2ecf20Sopenharmony_ci data->ports[count] = 28518c2ecf20Sopenharmony_ci parport_pc_probe_port(io_lo, io_hi, irq, 28528c2ecf20Sopenharmony_ci PARPORT_DMA_NONE, &dev->dev, 28538c2ecf20Sopenharmony_ci IRQF_SHARED); 28548c2ecf20Sopenharmony_ci if (data->ports[count]) 28558c2ecf20Sopenharmony_ci count++; 28568c2ecf20Sopenharmony_ci } 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci data->num = count; 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci if (cards[i].postinit_hook) 28618c2ecf20Sopenharmony_ci cards[i].postinit_hook(dev, count == 0); 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci if (count) { 28648c2ecf20Sopenharmony_ci pci_set_drvdata(dev, data); 28658c2ecf20Sopenharmony_ci return 0; 28668c2ecf20Sopenharmony_ci } 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci kfree(data); 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci return -ENODEV; 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_cistatic void parport_pc_pci_remove(struct pci_dev *dev) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci struct pci_parport_data *data = pci_get_drvdata(dev); 28768c2ecf20Sopenharmony_ci int i; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci if (data) { 28798c2ecf20Sopenharmony_ci for (i = data->num - 1; i >= 0; i--) 28808c2ecf20Sopenharmony_ci parport_pc_unregister_port(data->ports[i]); 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci kfree(data); 28838c2ecf20Sopenharmony_ci } 28848c2ecf20Sopenharmony_ci} 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_cistatic struct pci_driver parport_pc_pci_driver = { 28878c2ecf20Sopenharmony_ci .name = "parport_pc", 28888c2ecf20Sopenharmony_ci .id_table = parport_pc_pci_tbl, 28898c2ecf20Sopenharmony_ci .probe = parport_pc_pci_probe, 28908c2ecf20Sopenharmony_ci .remove = parport_pc_pci_remove, 28918c2ecf20Sopenharmony_ci}; 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_cistatic int __init parport_pc_init_superio(int autoirq, int autodma) 28948c2ecf20Sopenharmony_ci{ 28958c2ecf20Sopenharmony_ci const struct pci_device_id *id; 28968c2ecf20Sopenharmony_ci struct pci_dev *pdev = NULL; 28978c2ecf20Sopenharmony_ci int ret = 0; 28988c2ecf20Sopenharmony_ci 28998c2ecf20Sopenharmony_ci for_each_pci_dev(pdev) { 29008c2ecf20Sopenharmony_ci id = pci_match_id(parport_pc_pci_tbl, pdev); 29018c2ecf20Sopenharmony_ci if (id == NULL || id->driver_data >= last_sio) 29028c2ecf20Sopenharmony_ci continue; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci if (parport_pc_superio_info[id->driver_data].probe( 29058c2ecf20Sopenharmony_ci pdev, autoirq, autodma, 29068c2ecf20Sopenharmony_ci parport_pc_superio_info[id->driver_data].via)) { 29078c2ecf20Sopenharmony_ci ret++; 29088c2ecf20Sopenharmony_ci } 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci return ret; /* number of devices found */ 29128c2ecf20Sopenharmony_ci} 29138c2ecf20Sopenharmony_ci#else 29148c2ecf20Sopenharmony_cistatic struct pci_driver parport_pc_pci_driver; 29158c2ecf20Sopenharmony_cistatic int __init parport_pc_init_superio(int autoirq, int autodma) 29168c2ecf20Sopenharmony_ci{ 29178c2ecf20Sopenharmony_ci return 0; 29188c2ecf20Sopenharmony_ci} 29198c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci#ifdef CONFIG_PNP 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_cistatic const struct pnp_device_id parport_pc_pnp_tbl[] = { 29248c2ecf20Sopenharmony_ci /* Standard LPT Printer Port */ 29258c2ecf20Sopenharmony_ci {.id = "PNP0400", .driver_data = 0}, 29268c2ecf20Sopenharmony_ci /* ECP Printer Port */ 29278c2ecf20Sopenharmony_ci {.id = "PNP0401", .driver_data = 0}, 29288c2ecf20Sopenharmony_ci { } 29298c2ecf20Sopenharmony_ci}; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pnp, parport_pc_pnp_tbl); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_cistatic int parport_pc_pnp_probe(struct pnp_dev *dev, 29348c2ecf20Sopenharmony_ci const struct pnp_device_id *id) 29358c2ecf20Sopenharmony_ci{ 29368c2ecf20Sopenharmony_ci struct parport *pdata; 29378c2ecf20Sopenharmony_ci unsigned long io_lo, io_hi; 29388c2ecf20Sopenharmony_ci int dma, irq; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci if (pnp_port_valid(dev, 0) && 29418c2ecf20Sopenharmony_ci !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) { 29428c2ecf20Sopenharmony_ci io_lo = pnp_port_start(dev, 0); 29438c2ecf20Sopenharmony_ci } else 29448c2ecf20Sopenharmony_ci return -EINVAL; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci if (pnp_port_valid(dev, 1) && 29478c2ecf20Sopenharmony_ci !(pnp_port_flags(dev, 1) & IORESOURCE_DISABLED)) { 29488c2ecf20Sopenharmony_ci io_hi = pnp_port_start(dev, 1); 29498c2ecf20Sopenharmony_ci } else 29508c2ecf20Sopenharmony_ci io_hi = 0; 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci if (pnp_irq_valid(dev, 0) && 29538c2ecf20Sopenharmony_ci !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) { 29548c2ecf20Sopenharmony_ci irq = pnp_irq(dev, 0); 29558c2ecf20Sopenharmony_ci } else 29568c2ecf20Sopenharmony_ci irq = PARPORT_IRQ_NONE; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci if (pnp_dma_valid(dev, 0) && 29598c2ecf20Sopenharmony_ci !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) { 29608c2ecf20Sopenharmony_ci dma = pnp_dma(dev, 0); 29618c2ecf20Sopenharmony_ci } else 29628c2ecf20Sopenharmony_ci dma = PARPORT_DMA_NONE; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci dev_info(&dev->dev, "reported by %s\n", dev->protocol->name); 29658c2ecf20Sopenharmony_ci pdata = parport_pc_probe_port(io_lo, io_hi, irq, dma, &dev->dev, 0); 29668c2ecf20Sopenharmony_ci if (pdata == NULL) 29678c2ecf20Sopenharmony_ci return -ENODEV; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci pnp_set_drvdata(dev, pdata); 29708c2ecf20Sopenharmony_ci return 0; 29718c2ecf20Sopenharmony_ci} 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_cistatic void parport_pc_pnp_remove(struct pnp_dev *dev) 29748c2ecf20Sopenharmony_ci{ 29758c2ecf20Sopenharmony_ci struct parport *pdata = (struct parport *)pnp_get_drvdata(dev); 29768c2ecf20Sopenharmony_ci if (!pdata) 29778c2ecf20Sopenharmony_ci return; 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci parport_pc_unregister_port(pdata); 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci/* we only need the pnp layer to activate the device, at least for now */ 29838c2ecf20Sopenharmony_cistatic struct pnp_driver parport_pc_pnp_driver = { 29848c2ecf20Sopenharmony_ci .name = "parport_pc", 29858c2ecf20Sopenharmony_ci .id_table = parport_pc_pnp_tbl, 29868c2ecf20Sopenharmony_ci .probe = parport_pc_pnp_probe, 29878c2ecf20Sopenharmony_ci .remove = parport_pc_pnp_remove, 29888c2ecf20Sopenharmony_ci}; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci#else 29918c2ecf20Sopenharmony_cistatic struct pnp_driver parport_pc_pnp_driver; 29928c2ecf20Sopenharmony_ci#endif /* CONFIG_PNP */ 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_cistatic int parport_pc_platform_probe(struct platform_device *pdev) 29958c2ecf20Sopenharmony_ci{ 29968c2ecf20Sopenharmony_ci /* Always succeed, the actual probing is done in 29978c2ecf20Sopenharmony_ci * parport_pc_probe_port(). */ 29988c2ecf20Sopenharmony_ci return 0; 29998c2ecf20Sopenharmony_ci} 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_cistatic struct platform_driver parport_pc_platform_driver = { 30028c2ecf20Sopenharmony_ci .driver = { 30038c2ecf20Sopenharmony_ci .name = "parport_pc", 30048c2ecf20Sopenharmony_ci }, 30058c2ecf20Sopenharmony_ci .probe = parport_pc_platform_probe, 30068c2ecf20Sopenharmony_ci}; 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci/* This is called by parport_pc_find_nonpci_ports (in asm/parport.h) */ 30098c2ecf20Sopenharmony_cistatic int __attribute__((unused)) 30108c2ecf20Sopenharmony_ciparport_pc_find_isa_ports(int autoirq, int autodma) 30118c2ecf20Sopenharmony_ci{ 30128c2ecf20Sopenharmony_ci int count = 0; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci if (parport_pc_probe_port(0x3bc, 0x7bc, autoirq, autodma, NULL, 0)) 30158c2ecf20Sopenharmony_ci count++; 30168c2ecf20Sopenharmony_ci if (parport_pc_probe_port(0x378, 0x778, autoirq, autodma, NULL, 0)) 30178c2ecf20Sopenharmony_ci count++; 30188c2ecf20Sopenharmony_ci if (parport_pc_probe_port(0x278, 0x678, autoirq, autodma, NULL, 0)) 30198c2ecf20Sopenharmony_ci count++; 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci return count; 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci/* This function is called by parport_pc_init if the user didn't 30258c2ecf20Sopenharmony_ci * specify any ports to probe. Its job is to find some ports. Order 30268c2ecf20Sopenharmony_ci * is important here -- we want ISA ports to be registered first, 30278c2ecf20Sopenharmony_ci * followed by PCI cards (for least surprise), but before that we want 30288c2ecf20Sopenharmony_ci * to do chipset-specific tests for some onboard ports that we know 30298c2ecf20Sopenharmony_ci * about. 30308c2ecf20Sopenharmony_ci * 30318c2ecf20Sopenharmony_ci * autoirq is PARPORT_IRQ_NONE, PARPORT_IRQ_AUTO, or PARPORT_IRQ_PROBEONLY 30328c2ecf20Sopenharmony_ci * autodma is PARPORT_DMA_NONE or PARPORT_DMA_AUTO 30338c2ecf20Sopenharmony_ci */ 30348c2ecf20Sopenharmony_cistatic void __init parport_pc_find_ports(int autoirq, int autodma) 30358c2ecf20Sopenharmony_ci{ 30368c2ecf20Sopenharmony_ci int count = 0, err; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci#ifdef CONFIG_PARPORT_PC_SUPERIO 30398c2ecf20Sopenharmony_ci detect_and_report_it87(); 30408c2ecf20Sopenharmony_ci detect_and_report_winbond(); 30418c2ecf20Sopenharmony_ci detect_and_report_smsc(); 30428c2ecf20Sopenharmony_ci#endif 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci /* Onboard SuperIO chipsets that show themselves on the PCI bus. */ 30458c2ecf20Sopenharmony_ci count += parport_pc_init_superio(autoirq, autodma); 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci /* PnP ports, skip detection if SuperIO already found them */ 30488c2ecf20Sopenharmony_ci if (!count) { 30498c2ecf20Sopenharmony_ci err = pnp_register_driver(&parport_pc_pnp_driver); 30508c2ecf20Sopenharmony_ci if (!err) 30518c2ecf20Sopenharmony_ci pnp_registered_parport = 1; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* ISA ports and whatever (see asm/parport.h). */ 30558c2ecf20Sopenharmony_ci parport_pc_find_nonpci_ports(autoirq, autodma); 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci err = pci_register_driver(&parport_pc_pci_driver); 30588c2ecf20Sopenharmony_ci if (!err) 30598c2ecf20Sopenharmony_ci pci_registered_parport = 1; 30608c2ecf20Sopenharmony_ci} 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ci/* 30638c2ecf20Sopenharmony_ci * Piles of crap below pretend to be a parser for module and kernel 30648c2ecf20Sopenharmony_ci * parameters. Say "thank you" to whoever had come up with that 30658c2ecf20Sopenharmony_ci * syntax and keep in mind that code below is a cleaned up version. 30668c2ecf20Sopenharmony_ci */ 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_cistatic int __initdata io[PARPORT_PC_MAX_PORTS+1] = { 30698c2ecf20Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS] = 0 30708c2ecf20Sopenharmony_ci}; 30718c2ecf20Sopenharmony_cistatic int __initdata io_hi[PARPORT_PC_MAX_PORTS+1] = { 30728c2ecf20Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS] = PARPORT_IOHI_AUTO 30738c2ecf20Sopenharmony_ci}; 30748c2ecf20Sopenharmony_cistatic int __initdata dmaval[PARPORT_PC_MAX_PORTS] = { 30758c2ecf20Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_DMA_NONE 30768c2ecf20Sopenharmony_ci}; 30778c2ecf20Sopenharmony_cistatic int __initdata irqval[PARPORT_PC_MAX_PORTS] = { 30788c2ecf20Sopenharmony_ci [0 ... PARPORT_PC_MAX_PORTS-1] = PARPORT_IRQ_PROBEONLY 30798c2ecf20Sopenharmony_ci}; 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_cistatic int __init parport_parse_param(const char *s, int *val, 30828c2ecf20Sopenharmony_ci int automatic, int none, int nofifo) 30838c2ecf20Sopenharmony_ci{ 30848c2ecf20Sopenharmony_ci if (!s) 30858c2ecf20Sopenharmony_ci return 0; 30868c2ecf20Sopenharmony_ci if (!strncmp(s, "auto", 4)) 30878c2ecf20Sopenharmony_ci *val = automatic; 30888c2ecf20Sopenharmony_ci else if (!strncmp(s, "none", 4)) 30898c2ecf20Sopenharmony_ci *val = none; 30908c2ecf20Sopenharmony_ci else if (nofifo && !strncmp(s, "nofifo", 6)) 30918c2ecf20Sopenharmony_ci *val = nofifo; 30928c2ecf20Sopenharmony_ci else { 30938c2ecf20Sopenharmony_ci char *ep; 30948c2ecf20Sopenharmony_ci unsigned long r = simple_strtoul(s, &ep, 0); 30958c2ecf20Sopenharmony_ci if (ep != s) 30968c2ecf20Sopenharmony_ci *val = r; 30978c2ecf20Sopenharmony_ci else { 30988c2ecf20Sopenharmony_ci pr_err("parport: bad specifier `%s'\n", s); 30998c2ecf20Sopenharmony_ci return -1; 31008c2ecf20Sopenharmony_ci } 31018c2ecf20Sopenharmony_ci } 31028c2ecf20Sopenharmony_ci return 0; 31038c2ecf20Sopenharmony_ci} 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_cistatic int __init parport_parse_irq(const char *irqstr, int *val) 31068c2ecf20Sopenharmony_ci{ 31078c2ecf20Sopenharmony_ci return parport_parse_param(irqstr, val, PARPORT_IRQ_AUTO, 31088c2ecf20Sopenharmony_ci PARPORT_IRQ_NONE, 0); 31098c2ecf20Sopenharmony_ci} 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_cistatic int __init parport_parse_dma(const char *dmastr, int *val) 31128c2ecf20Sopenharmony_ci{ 31138c2ecf20Sopenharmony_ci return parport_parse_param(dmastr, val, PARPORT_DMA_AUTO, 31148c2ecf20Sopenharmony_ci PARPORT_DMA_NONE, PARPORT_DMA_NOFIFO); 31158c2ecf20Sopenharmony_ci} 31168c2ecf20Sopenharmony_ci 31178c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 31188c2ecf20Sopenharmony_cistatic int __init parport_init_mode_setup(char *str) 31198c2ecf20Sopenharmony_ci{ 31208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "parport_pc.c: Specified parameter parport_init_mode=%s\n", 31218c2ecf20Sopenharmony_ci str); 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci if (!strcmp(str, "spp")) 31248c2ecf20Sopenharmony_ci parport_init_mode = 1; 31258c2ecf20Sopenharmony_ci if (!strcmp(str, "ps2")) 31268c2ecf20Sopenharmony_ci parport_init_mode = 2; 31278c2ecf20Sopenharmony_ci if (!strcmp(str, "epp")) 31288c2ecf20Sopenharmony_ci parport_init_mode = 3; 31298c2ecf20Sopenharmony_ci if (!strcmp(str, "ecp")) 31308c2ecf20Sopenharmony_ci parport_init_mode = 4; 31318c2ecf20Sopenharmony_ci if (!strcmp(str, "ecpepp")) 31328c2ecf20Sopenharmony_ci parport_init_mode = 5; 31338c2ecf20Sopenharmony_ci return 1; 31348c2ecf20Sopenharmony_ci} 31358c2ecf20Sopenharmony_ci#endif 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci#ifdef MODULE 31388c2ecf20Sopenharmony_cistatic char *irq[PARPORT_PC_MAX_PORTS]; 31398c2ecf20Sopenharmony_cistatic char *dma[PARPORT_PC_MAX_PORTS]; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(io, "Base I/O address (SPP regs)"); 31428c2ecf20Sopenharmony_cimodule_param_hw_array(io, int, ioport, NULL, 0); 31438c2ecf20Sopenharmony_ciMODULE_PARM_DESC(io_hi, "Base I/O address (ECR)"); 31448c2ecf20Sopenharmony_cimodule_param_hw_array(io_hi, int, ioport, NULL, 0); 31458c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ line"); 31468c2ecf20Sopenharmony_cimodule_param_hw_array(irq, charp, irq, NULL, 0); 31478c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dma, "DMA channel"); 31488c2ecf20Sopenharmony_cimodule_param_hw_array(dma, charp, dma, NULL, 0); 31498c2ecf20Sopenharmony_ci#if defined(CONFIG_PARPORT_PC_SUPERIO) || \ 31508c2ecf20Sopenharmony_ci (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO)) 31518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation"); 31528c2ecf20Sopenharmony_cimodule_param(verbose_probing, int, 0644); 31538c2ecf20Sopenharmony_ci#endif 31548c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 31558c2ecf20Sopenharmony_cistatic char *init_mode; 31568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(init_mode, 31578c2ecf20Sopenharmony_ci "Initialise mode for VIA VT8231 port (spp, ps2, epp, ecp or ecpepp)"); 31588c2ecf20Sopenharmony_cimodule_param(init_mode, charp, 0); 31598c2ecf20Sopenharmony_ci#endif 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_cistatic int __init parse_parport_params(void) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci unsigned int i; 31648c2ecf20Sopenharmony_ci int val; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 31678c2ecf20Sopenharmony_ci if (init_mode) 31688c2ecf20Sopenharmony_ci parport_init_mode_setup(init_mode); 31698c2ecf20Sopenharmony_ci#endif 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci for (i = 0; i < PARPORT_PC_MAX_PORTS && io[i]; i++) { 31728c2ecf20Sopenharmony_ci if (parport_parse_irq(irq[i], &val)) 31738c2ecf20Sopenharmony_ci return 1; 31748c2ecf20Sopenharmony_ci irqval[i] = val; 31758c2ecf20Sopenharmony_ci if (parport_parse_dma(dma[i], &val)) 31768c2ecf20Sopenharmony_ci return 1; 31778c2ecf20Sopenharmony_ci dmaval[i] = val; 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci if (!io[0]) { 31808c2ecf20Sopenharmony_ci /* The user can make us use any IRQs or DMAs we find. */ 31818c2ecf20Sopenharmony_ci if (irq[0] && !parport_parse_irq(irq[0], &val)) 31828c2ecf20Sopenharmony_ci switch (val) { 31838c2ecf20Sopenharmony_ci case PARPORT_IRQ_NONE: 31848c2ecf20Sopenharmony_ci case PARPORT_IRQ_AUTO: 31858c2ecf20Sopenharmony_ci irqval[0] = val; 31868c2ecf20Sopenharmony_ci break; 31878c2ecf20Sopenharmony_ci default: 31888c2ecf20Sopenharmony_ci pr_warn("parport_pc: irq specified without base address. Use 'io=' to specify one\n"); 31898c2ecf20Sopenharmony_ci } 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci if (dma[0] && !parport_parse_dma(dma[0], &val)) 31928c2ecf20Sopenharmony_ci switch (val) { 31938c2ecf20Sopenharmony_ci case PARPORT_DMA_NONE: 31948c2ecf20Sopenharmony_ci case PARPORT_DMA_AUTO: 31958c2ecf20Sopenharmony_ci dmaval[0] = val; 31968c2ecf20Sopenharmony_ci break; 31978c2ecf20Sopenharmony_ci default: 31988c2ecf20Sopenharmony_ci pr_warn("parport_pc: dma specified without base address. Use 'io=' to specify one\n"); 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci } 32018c2ecf20Sopenharmony_ci return 0; 32028c2ecf20Sopenharmony_ci} 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci#else 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_cistatic int parport_setup_ptr __initdata; 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci/* 32098c2ecf20Sopenharmony_ci * Acceptable parameters: 32108c2ecf20Sopenharmony_ci * 32118c2ecf20Sopenharmony_ci * parport=0 32128c2ecf20Sopenharmony_ci * parport=auto 32138c2ecf20Sopenharmony_ci * parport=0xBASE[,IRQ[,DMA]] 32148c2ecf20Sopenharmony_ci * 32158c2ecf20Sopenharmony_ci * IRQ/DMA may be numeric or 'auto' or 'none' 32168c2ecf20Sopenharmony_ci */ 32178c2ecf20Sopenharmony_cistatic int __init parport_setup(char *str) 32188c2ecf20Sopenharmony_ci{ 32198c2ecf20Sopenharmony_ci char *endptr; 32208c2ecf20Sopenharmony_ci char *sep; 32218c2ecf20Sopenharmony_ci int val; 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci if (!str || !*str || (*str == '0' && !*(str+1))) { 32248c2ecf20Sopenharmony_ci /* Disable parport if "parport=0" in cmdline */ 32258c2ecf20Sopenharmony_ci io[0] = PARPORT_DISABLE; 32268c2ecf20Sopenharmony_ci return 1; 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci if (!strncmp(str, "auto", 4)) { 32308c2ecf20Sopenharmony_ci irqval[0] = PARPORT_IRQ_AUTO; 32318c2ecf20Sopenharmony_ci dmaval[0] = PARPORT_DMA_AUTO; 32328c2ecf20Sopenharmony_ci return 1; 32338c2ecf20Sopenharmony_ci } 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci val = simple_strtoul(str, &endptr, 0); 32368c2ecf20Sopenharmony_ci if (endptr == str) { 32378c2ecf20Sopenharmony_ci pr_warn("parport=%s not understood\n", str); 32388c2ecf20Sopenharmony_ci return 1; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci if (parport_setup_ptr == PARPORT_PC_MAX_PORTS) { 32428c2ecf20Sopenharmony_ci pr_err("parport=%s ignored, too many ports\n", str); 32438c2ecf20Sopenharmony_ci return 1; 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci 32468c2ecf20Sopenharmony_ci io[parport_setup_ptr] = val; 32478c2ecf20Sopenharmony_ci irqval[parport_setup_ptr] = PARPORT_IRQ_NONE; 32488c2ecf20Sopenharmony_ci dmaval[parport_setup_ptr] = PARPORT_DMA_NONE; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci sep = strchr(str, ','); 32518c2ecf20Sopenharmony_ci if (sep++) { 32528c2ecf20Sopenharmony_ci if (parport_parse_irq(sep, &val)) 32538c2ecf20Sopenharmony_ci return 1; 32548c2ecf20Sopenharmony_ci irqval[parport_setup_ptr] = val; 32558c2ecf20Sopenharmony_ci sep = strchr(sep, ','); 32568c2ecf20Sopenharmony_ci if (sep++) { 32578c2ecf20Sopenharmony_ci if (parport_parse_dma(sep, &val)) 32588c2ecf20Sopenharmony_ci return 1; 32598c2ecf20Sopenharmony_ci dmaval[parport_setup_ptr] = val; 32608c2ecf20Sopenharmony_ci } 32618c2ecf20Sopenharmony_ci } 32628c2ecf20Sopenharmony_ci parport_setup_ptr++; 32638c2ecf20Sopenharmony_ci return 1; 32648c2ecf20Sopenharmony_ci} 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_cistatic int __init parse_parport_params(void) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci return io[0] == PARPORT_DISABLE; 32698c2ecf20Sopenharmony_ci} 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci__setup("parport=", parport_setup); 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci/* 32748c2ecf20Sopenharmony_ci * Acceptable parameters: 32758c2ecf20Sopenharmony_ci * 32768c2ecf20Sopenharmony_ci * parport_init_mode=[spp|ps2|epp|ecp|ecpepp] 32778c2ecf20Sopenharmony_ci */ 32788c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 32798c2ecf20Sopenharmony_ci__setup("parport_init_mode=", parport_init_mode_setup); 32808c2ecf20Sopenharmony_ci#endif 32818c2ecf20Sopenharmony_ci#endif 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci/* "Parser" ends here */ 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_cistatic int __init parport_pc_init(void) 32868c2ecf20Sopenharmony_ci{ 32878c2ecf20Sopenharmony_ci int err; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci if (parse_parport_params()) 32908c2ecf20Sopenharmony_ci return -EINVAL; 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci err = platform_driver_register(&parport_pc_platform_driver); 32938c2ecf20Sopenharmony_ci if (err) 32948c2ecf20Sopenharmony_ci return err; 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci if (io[0]) { 32978c2ecf20Sopenharmony_ci int i; 32988c2ecf20Sopenharmony_ci /* Only probe the ports we were given. */ 32998c2ecf20Sopenharmony_ci user_specified = 1; 33008c2ecf20Sopenharmony_ci for (i = 0; i < PARPORT_PC_MAX_PORTS; i++) { 33018c2ecf20Sopenharmony_ci if (!io[i]) 33028c2ecf20Sopenharmony_ci break; 33038c2ecf20Sopenharmony_ci if (io_hi[i] == PARPORT_IOHI_AUTO) 33048c2ecf20Sopenharmony_ci io_hi[i] = 0x400 + io[i]; 33058c2ecf20Sopenharmony_ci parport_pc_probe_port(io[i], io_hi[i], 33068c2ecf20Sopenharmony_ci irqval[i], dmaval[i], NULL, 0); 33078c2ecf20Sopenharmony_ci } 33088c2ecf20Sopenharmony_ci } else 33098c2ecf20Sopenharmony_ci parport_pc_find_ports(irqval[0], dmaval[0]); 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci return 0; 33128c2ecf20Sopenharmony_ci} 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_cistatic void __exit parport_pc_exit(void) 33158c2ecf20Sopenharmony_ci{ 33168c2ecf20Sopenharmony_ci if (pci_registered_parport) 33178c2ecf20Sopenharmony_ci pci_unregister_driver(&parport_pc_pci_driver); 33188c2ecf20Sopenharmony_ci if (pnp_registered_parport) 33198c2ecf20Sopenharmony_ci pnp_unregister_driver(&parport_pc_pnp_driver); 33208c2ecf20Sopenharmony_ci platform_driver_unregister(&parport_pc_platform_driver); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci while (!list_empty(&ports_list)) { 33238c2ecf20Sopenharmony_ci struct parport_pc_private *priv; 33248c2ecf20Sopenharmony_ci struct parport *port; 33258c2ecf20Sopenharmony_ci struct device *dev; 33268c2ecf20Sopenharmony_ci priv = list_entry(ports_list.next, 33278c2ecf20Sopenharmony_ci struct parport_pc_private, list); 33288c2ecf20Sopenharmony_ci port = priv->port; 33298c2ecf20Sopenharmony_ci dev = port->dev; 33308c2ecf20Sopenharmony_ci parport_pc_unregister_port(port); 33318c2ecf20Sopenharmony_ci if (dev && dev->bus == &platform_bus_type) 33328c2ecf20Sopenharmony_ci platform_device_unregister(to_platform_device(dev)); 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci} 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ciMODULE_AUTHOR("Phil Blundell, Tim Waugh, others"); 33378c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PC-style parallel port driver"); 33388c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 33398c2ecf20Sopenharmony_cimodule_init(parport_pc_init) 33408c2ecf20Sopenharmony_cimodule_exit(parport_pc_exit) 3341