162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Low-level parallel-support for PC-style hardware integrated in the 462306a36Sopenharmony_ci * LASI-Controller (on GSC-Bus) for HP-PARISC Workstations 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * (C) 1999-2001 by Helge Deller <deller@gmx.de> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * based on parport_pc.c by 962306a36Sopenharmony_ci * Grant Guenther <grant@torque.net> 1062306a36Sopenharmony_ci * Phil Blundell <philb@gnu.org> 1162306a36Sopenharmony_ci * Tim Waugh <tim@cyberelk.demon.co.uk> 1262306a36Sopenharmony_ci * Jose Renau <renau@acm.org> 1362306a36Sopenharmony_ci * David Campbell 1462306a36Sopenharmony_ci * Andrea Arcangeli 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#undef DEBUG /* undef for production */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/init.h> 2162306a36Sopenharmony_ci#include <linux/delay.h> 2262306a36Sopenharmony_ci#include <linux/errno.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/ioport.h> 2562306a36Sopenharmony_ci#include <linux/kernel.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/pci.h> 2862306a36Sopenharmony_ci#include <linux/sysctl.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <asm/io.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci#include <asm/superio.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include <linux/parport.h> 3562306a36Sopenharmony_ci#include <asm/pdc.h> 3662306a36Sopenharmony_ci#include <asm/parisc-device.h> 3762306a36Sopenharmony_ci#include <asm/hardware.h> 3862306a36Sopenharmony_ci#include "parport_gsc.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ciMODULE_AUTHOR("Helge Deller <deller@gmx.de>"); 4262306a36Sopenharmony_ciMODULE_DESCRIPTION("HP-PARISC PC-style parallel port driver"); 4362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * Clear TIMEOUT BIT in EPP MODE 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * This is also used in SPP detection. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_cistatic int clear_epp_timeout(struct parport *pb) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci unsigned char r; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (!(parport_gsc_read_status(pb) & 0x01)) 5662306a36Sopenharmony_ci return 1; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* To clear timeout some chips require double read */ 5962306a36Sopenharmony_ci parport_gsc_read_status(pb); 6062306a36Sopenharmony_ci r = parport_gsc_read_status(pb); 6162306a36Sopenharmony_ci parport_writeb (r | 0x01, STATUS (pb)); /* Some reset by writing 1 */ 6262306a36Sopenharmony_ci parport_writeb (r & 0xfe, STATUS (pb)); /* Others by writing 0 */ 6362306a36Sopenharmony_ci r = parport_gsc_read_status(pb); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return !(r & 0x01); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * Access functions. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Most of these aren't static because they may be used by the 7262306a36Sopenharmony_ci * parport_xxx_yyy macros. extern __inline__ versions of several 7362306a36Sopenharmony_ci * of these are in parport_gsc.h. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_civoid parport_gsc_init_state(struct pardevice *dev, struct parport_state *s) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci s->u.pc.ctr = 0xc | (dev->irq_func ? 0x10 : 0x0); 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_civoid parport_gsc_save_state(struct parport *p, struct parport_state *s) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci s->u.pc.ctr = parport_readb (CONTROL (p)); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_civoid parport_gsc_restore_state(struct parport *p, struct parport_state *s) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci parport_writeb (s->u.pc.ctr, CONTROL (p)); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct parport_operations parport_gsc_ops = 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci .write_data = parport_gsc_write_data, 9462306a36Sopenharmony_ci .read_data = parport_gsc_read_data, 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci .write_control = parport_gsc_write_control, 9762306a36Sopenharmony_ci .read_control = parport_gsc_read_control, 9862306a36Sopenharmony_ci .frob_control = parport_gsc_frob_control, 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci .read_status = parport_gsc_read_status, 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci .enable_irq = parport_gsc_enable_irq, 10362306a36Sopenharmony_ci .disable_irq = parport_gsc_disable_irq, 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci .data_forward = parport_gsc_data_forward, 10662306a36Sopenharmony_ci .data_reverse = parport_gsc_data_reverse, 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci .init_state = parport_gsc_init_state, 10962306a36Sopenharmony_ci .save_state = parport_gsc_save_state, 11062306a36Sopenharmony_ci .restore_state = parport_gsc_restore_state, 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci .epp_write_data = parport_ieee1284_epp_write_data, 11362306a36Sopenharmony_ci .epp_read_data = parport_ieee1284_epp_read_data, 11462306a36Sopenharmony_ci .epp_write_addr = parport_ieee1284_epp_write_addr, 11562306a36Sopenharmony_ci .epp_read_addr = parport_ieee1284_epp_read_addr, 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci .ecp_write_data = parport_ieee1284_ecp_write_data, 11862306a36Sopenharmony_ci .ecp_read_data = parport_ieee1284_ecp_read_data, 11962306a36Sopenharmony_ci .ecp_write_addr = parport_ieee1284_ecp_write_addr, 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci .compat_write_data = parport_ieee1284_write_compat, 12262306a36Sopenharmony_ci .nibble_read_data = parport_ieee1284_read_nibble, 12362306a36Sopenharmony_ci .byte_read_data = parport_ieee1284_read_byte, 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci .owner = THIS_MODULE, 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* --- Mode detection ------------------------------------- */ 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/* 13162306a36Sopenharmony_ci * Checks for port existence, all ports support SPP MODE 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic int parport_SPP_supported(struct parport *pb) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci unsigned char r, w; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * first clear an eventually pending EPP timeout 13962306a36Sopenharmony_ci * I (sailer@ife.ee.ethz.ch) have an SMSC chipset 14062306a36Sopenharmony_ci * that does not even respond to SPP cycles if an EPP 14162306a36Sopenharmony_ci * timeout is pending 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci clear_epp_timeout(pb); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* Do a simple read-write test to make sure the port exists. */ 14662306a36Sopenharmony_ci w = 0xc; 14762306a36Sopenharmony_ci parport_writeb (w, CONTROL (pb)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* Is there a control register that we can read from? Some 15062306a36Sopenharmony_ci * ports don't allow reads, so read_control just returns a 15162306a36Sopenharmony_ci * software copy. Some ports _do_ allow reads, so bypass the 15262306a36Sopenharmony_ci * software copy here. In addition, some bits aren't 15362306a36Sopenharmony_ci * writable. */ 15462306a36Sopenharmony_ci r = parport_readb (CONTROL (pb)); 15562306a36Sopenharmony_ci if ((r & 0xf) == w) { 15662306a36Sopenharmony_ci w = 0xe; 15762306a36Sopenharmony_ci parport_writeb (w, CONTROL (pb)); 15862306a36Sopenharmony_ci r = parport_readb (CONTROL (pb)); 15962306a36Sopenharmony_ci parport_writeb (0xc, CONTROL (pb)); 16062306a36Sopenharmony_ci if ((r & 0xf) == w) 16162306a36Sopenharmony_ci return PARPORT_MODE_PCSPP; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Try the data register. The data lines aren't tri-stated at 16562306a36Sopenharmony_ci * this stage, so we expect back what we wrote. */ 16662306a36Sopenharmony_ci w = 0xaa; 16762306a36Sopenharmony_ci parport_gsc_write_data (pb, w); 16862306a36Sopenharmony_ci r = parport_gsc_read_data (pb); 16962306a36Sopenharmony_ci if (r == w) { 17062306a36Sopenharmony_ci w = 0x55; 17162306a36Sopenharmony_ci parport_gsc_write_data (pb, w); 17262306a36Sopenharmony_ci r = parport_gsc_read_data (pb); 17362306a36Sopenharmony_ci if (r == w) 17462306a36Sopenharmony_ci return PARPORT_MODE_PCSPP; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* Detect PS/2 support. 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Bit 5 (0x20) sets the PS/2 data direction; setting this high 18362306a36Sopenharmony_ci * allows us to read data from the data lines. In theory we would get back 18462306a36Sopenharmony_ci * 0xff but any peripheral attached to the port may drag some or all of the 18562306a36Sopenharmony_ci * lines down to zero. So if we get back anything that isn't the contents 18662306a36Sopenharmony_ci * of the data register we deem PS/2 support to be present. 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * Some SPP ports have "half PS/2" ability - you can't turn off the line 18962306a36Sopenharmony_ci * drivers, but an external peripheral with sufficiently beefy drivers of 19062306a36Sopenharmony_ci * its own can overpower them and assert its own levels onto the bus, from 19162306a36Sopenharmony_ci * where they can then be read back as normal. Ports with this property 19262306a36Sopenharmony_ci * and the right type of device attached are likely to fail the SPP test, 19362306a36Sopenharmony_ci * (as they will appear to have stuck bits) and so the fact that they might 19462306a36Sopenharmony_ci * be misdetected here is rather academic. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int parport_PS2_supported(struct parport *pb) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci int ok = 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci clear_epp_timeout(pb); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* try to tri-state the buffer */ 20462306a36Sopenharmony_ci parport_gsc_data_reverse (pb); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci parport_gsc_write_data(pb, 0x55); 20762306a36Sopenharmony_ci if (parport_gsc_read_data(pb) != 0x55) ok++; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci parport_gsc_write_data(pb, 0xaa); 21062306a36Sopenharmony_ci if (parport_gsc_read_data(pb) != 0xaa) ok++; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* cancel input mode */ 21362306a36Sopenharmony_ci parport_gsc_data_forward (pb); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if (ok) { 21662306a36Sopenharmony_ci pb->modes |= PARPORT_MODE_TRISTATE; 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci struct parport_gsc_private *priv = pb->private_data; 21962306a36Sopenharmony_ci priv->ctr_writable &= ~0x20; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci return ok; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/* --- Initialisation code -------------------------------- */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic struct parport *parport_gsc_probe_port(unsigned long base, 22962306a36Sopenharmony_ci unsigned long base_hi, int irq, 23062306a36Sopenharmony_ci struct parisc_device *padev) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct parport_gsc_private *priv; 23362306a36Sopenharmony_ci struct parport_operations *ops; 23462306a36Sopenharmony_ci struct parport tmp; 23562306a36Sopenharmony_ci struct parport *p = &tmp; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci priv = kzalloc (sizeof (struct parport_gsc_private), GFP_KERNEL); 23862306a36Sopenharmony_ci if (!priv) { 23962306a36Sopenharmony_ci printk(KERN_DEBUG "parport (0x%lx): no memory!\n", base); 24062306a36Sopenharmony_ci return NULL; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci ops = kmemdup(&parport_gsc_ops, sizeof(struct parport_operations), 24362306a36Sopenharmony_ci GFP_KERNEL); 24462306a36Sopenharmony_ci if (!ops) { 24562306a36Sopenharmony_ci printk(KERN_DEBUG "parport (0x%lx): no memory for ops!\n", 24662306a36Sopenharmony_ci base); 24762306a36Sopenharmony_ci kfree (priv); 24862306a36Sopenharmony_ci return NULL; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci priv->ctr = 0xc; 25162306a36Sopenharmony_ci priv->ctr_writable = 0xff; 25262306a36Sopenharmony_ci p->base = base; 25362306a36Sopenharmony_ci p->base_hi = base_hi; 25462306a36Sopenharmony_ci p->irq = irq; 25562306a36Sopenharmony_ci p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT; 25662306a36Sopenharmony_ci p->ops = ops; 25762306a36Sopenharmony_ci p->private_data = priv; 25862306a36Sopenharmony_ci p->physport = p; 25962306a36Sopenharmony_ci if (!parport_SPP_supported (p)) { 26062306a36Sopenharmony_ci /* No port. */ 26162306a36Sopenharmony_ci kfree (priv); 26262306a36Sopenharmony_ci kfree(ops); 26362306a36Sopenharmony_ci return NULL; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci parport_PS2_supported (p); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (!(p = parport_register_port(base, PARPORT_IRQ_NONE, 26862306a36Sopenharmony_ci PARPORT_DMA_NONE, ops))) { 26962306a36Sopenharmony_ci kfree (priv); 27062306a36Sopenharmony_ci kfree (ops); 27162306a36Sopenharmony_ci return NULL; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci p->dev = &padev->dev; 27562306a36Sopenharmony_ci p->base_hi = base_hi; 27662306a36Sopenharmony_ci p->modes = tmp.modes; 27762306a36Sopenharmony_ci p->size = (p->modes & PARPORT_MODE_EPP)?8:3; 27862306a36Sopenharmony_ci p->private_data = priv; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci pr_info("%s: PC-style at 0x%lx", p->name, p->base); 28162306a36Sopenharmony_ci p->irq = irq; 28262306a36Sopenharmony_ci if (p->irq == PARPORT_IRQ_AUTO) { 28362306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) 28662306a36Sopenharmony_ci pr_cont(", irq %d", p->irq); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci pr_cont(" ["); 28962306a36Sopenharmony_ci#define printmode(x) \ 29062306a36Sopenharmony_cido { \ 29162306a36Sopenharmony_ci if (p->modes & PARPORT_MODE_##x) \ 29262306a36Sopenharmony_ci pr_cont("%s%s", f++ ? "," : "", #x); \ 29362306a36Sopenharmony_ci} while (0) 29462306a36Sopenharmony_ci { 29562306a36Sopenharmony_ci int f = 0; 29662306a36Sopenharmony_ci printmode(PCSPP); 29762306a36Sopenharmony_ci printmode(TRISTATE); 29862306a36Sopenharmony_ci printmode(COMPAT); 29962306a36Sopenharmony_ci printmode(EPP); 30062306a36Sopenharmony_ci// printmode(ECP); 30162306a36Sopenharmony_ci// printmode(DMA); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci#undef printmode 30462306a36Sopenharmony_ci pr_cont("]\n"); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 30762306a36Sopenharmony_ci if (request_irq (p->irq, parport_irq_handler, 30862306a36Sopenharmony_ci 0, p->name, p)) { 30962306a36Sopenharmony_ci pr_warn("%s: irq %d in use, resorting to polled operation\n", 31062306a36Sopenharmony_ci p->name, p->irq); 31162306a36Sopenharmony_ci p->irq = PARPORT_IRQ_NONE; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Done probing. Now put the port into a sensible start-up state. */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci parport_gsc_write_data(p, 0); 31862306a36Sopenharmony_ci parport_gsc_data_forward (p); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Now that we've told the sharing engine about the port, and 32162306a36Sopenharmony_ci found out its characteristics, let the high-level drivers 32262306a36Sopenharmony_ci know about it. */ 32362306a36Sopenharmony_ci parport_announce_port (p); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return p; 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#define PARPORT_GSC_OFFSET 0x800 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int parport_count; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int __init parport_init_chip(struct parisc_device *dev) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct parport *p; 33662306a36Sopenharmony_ci unsigned long port; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!dev->irq) { 33962306a36Sopenharmony_ci pr_warn("IRQ not found for parallel device at 0x%llx\n", 34062306a36Sopenharmony_ci (unsigned long long)dev->hpa.start); 34162306a36Sopenharmony_ci return -ENODEV; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci port = dev->hpa.start + PARPORT_GSC_OFFSET; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* some older machines with ASP-chip don't support 34762306a36Sopenharmony_ci * the enhanced parport modes. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) { 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ 35262306a36Sopenharmony_ci pr_info("%s: initialize bidirectional-mode\n", __func__); 35362306a36Sopenharmony_ci parport_writeb ( (0x10 + 0x20), port + 4); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci } else { 35662306a36Sopenharmony_ci pr_info("%s: enhanced parport-modes not supported\n", __func__); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci p = parport_gsc_probe_port(port, 0, dev->irq, dev); 36062306a36Sopenharmony_ci if (p) 36162306a36Sopenharmony_ci parport_count++; 36262306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, p); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return 0; 36562306a36Sopenharmony_ci} 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic void __exit parport_remove_chip(struct parisc_device *dev) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct parport *p = dev_get_drvdata(&dev->dev); 37062306a36Sopenharmony_ci if (p) { 37162306a36Sopenharmony_ci struct parport_operations *ops = p->ops; 37262306a36Sopenharmony_ci parport_remove_port(p); 37362306a36Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) 37462306a36Sopenharmony_ci free_irq(p->irq, p); 37562306a36Sopenharmony_ci kfree (p->private_data); 37662306a36Sopenharmony_ci parport_put_port(p); 37762306a36Sopenharmony_ci kfree (ops); /* hope no-one cached it */ 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic const struct parisc_device_id parport_tbl[] __initconst = { 38262306a36Sopenharmony_ci { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x74 }, 38362306a36Sopenharmony_ci { 0, } 38462306a36Sopenharmony_ci}; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(parisc, parport_tbl); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic struct parisc_driver parport_driver __refdata = { 38962306a36Sopenharmony_ci .name = "Parallel", 39062306a36Sopenharmony_ci .id_table = parport_tbl, 39162306a36Sopenharmony_ci .probe = parport_init_chip, 39262306a36Sopenharmony_ci .remove = __exit_p(parport_remove_chip), 39362306a36Sopenharmony_ci}; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ciint parport_gsc_init(void) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci return register_parisc_driver(&parport_driver); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic void parport_gsc_exit(void) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci unregister_parisc_driver(&parport_driver); 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cimodule_init(parport_gsc_init); 40662306a36Sopenharmony_cimodule_exit(parport_gsc_exit); 407