109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /* Low-level parallel port routines for the Multiface 3 card
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Author: Joerg Dorchain <joerg@dorchain.net>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * (C) The elitist m68k Users(TM)
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * based on the existing parport_amiga and lp_mfc
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * From the MFC3 documentation:
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  * Miscellaneous PIA Details
141da177e4SLinus Torvalds  * -------------------------
151da177e4SLinus Torvalds  *
161da177e4SLinus Torvalds  * 	The two open-drain interrupt outputs /IRQA and /IRQB are routed to
171da177e4SLinus Torvalds  * /INT2 of the Z2 bus.
181da177e4SLinus Torvalds  *
191da177e4SLinus Torvalds  * 	The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2
201da177e4SLinus Torvalds  * bus. This means that any PIA registers are accessed at even addresses.
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  * Centronics Pin Connections for the PIA
231da177e4SLinus Torvalds  * --------------------------------------
241da177e4SLinus Torvalds  *
251da177e4SLinus Torvalds  * 	The following table shows the connections between the PIA and the
261da177e4SLinus Torvalds  * Centronics interface connector. These connections implement a single, but
271da177e4SLinus Torvalds  * very complete, Centronics type interface. The Pin column gives the pin
281da177e4SLinus Torvalds  * numbers of the PIA. The Centronics pin numbers can be found in the section
291da177e4SLinus Torvalds  * "Parallel Connectors".
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  *
321da177e4SLinus Torvalds  *    Pin | PIA | Dir | Centronics Names
331da177e4SLinus Torvalds  * -------+-----+-----+---------------------------------------------------------
341da177e4SLinus Torvalds  *     19 | CB2 | --> | /STROBE (aka /DRDY)
351da177e4SLinus Torvalds  *  10-17 | PBx | <-> | DATA0 - DATA7
361da177e4SLinus Torvalds  *     18 | CB1 | <-- | /ACK
371da177e4SLinus Torvalds  *     40 | CA1 | <-- | BUSY
381da177e4SLinus Torvalds  *      3 | PA1 | <-- | PAPER-OUT (aka POUT)
391da177e4SLinus Torvalds  *      4 | PA2 | <-- | SELECTED (aka SEL)
401da177e4SLinus Torvalds  *      9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME)
411da177e4SLinus Torvalds  *      6 | PA4 | <-- | /ERROR (aka /FAULT)
421da177e4SLinus Torvalds  *      7 | PA5 | --> | DIR (aka /SELECT-IN)
431da177e4SLinus Torvalds  *      8 | PA6 | --> | /AUTO-FEED-XT
441da177e4SLinus Torvalds  *     39 | CA2 | --> | open
451da177e4SLinus Torvalds  *      5 | PA3 | <-- | /ACK (same as CB1!)
461da177e4SLinus Torvalds  *      2 | PA0 | <-- | BUSY (same as CA1!)
471da177e4SLinus Torvalds  * -------+-----+-----+---------------------------------------------------------
481da177e4SLinus Torvalds  *
491da177e4SLinus Torvalds  * Should be enough to understand some of the driver.
501da177e4SLinus Torvalds  *
511da177e4SLinus Torvalds  * Per convention for normal use the port registers are visible.
521da177e4SLinus Torvalds  * If you need the data direction registers, restore the value in the
531da177e4SLinus Torvalds  * control register.
541da177e4SLinus Torvalds  */
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds #include "multiface.h"
571da177e4SLinus Torvalds #include <linux/module.h>
581da177e4SLinus Torvalds #include <linux/init.h>
591da177e4SLinus Torvalds #include <linux/parport.h>
601da177e4SLinus Torvalds #include <linux/delay.h>
611da177e4SLinus Torvalds #include <linux/mc6821.h>
621da177e4SLinus Torvalds #include <linux/zorro.h>
631da177e4SLinus Torvalds #include <linux/interrupt.h>
641da177e4SLinus Torvalds #include <asm/setup.h>
651da177e4SLinus Torvalds #include <asm/amigahw.h>
661da177e4SLinus Torvalds #include <asm/irq.h>
671da177e4SLinus Torvalds #include <asm/amigaints.h>
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds /* Maximum Number of Cards supported */
701da177e4SLinus Torvalds #define MAX_MFC 5
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds #undef DEBUG
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds static struct parport *this_port[MAX_MFC] = {NULL, };
751da177e4SLinus Torvalds static volatile int dummy; /* for trigger readds */
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds #define pia(dev) ((struct pia *)(dev->base))
781da177e4SLinus Torvalds static struct parport_operations pp_mfc3_ops;
791da177e4SLinus Torvalds 
mfc3_write_data(struct parport * p,unsigned char data)801da177e4SLinus Torvalds static void mfc3_write_data(struct parport *p, unsigned char data)
811da177e4SLinus Torvalds {
8246aea0d4SJoe Perches 	pr_debug("write_data %c\n", data);
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 	dummy = pia(p)->pprb; /* clears irq bit */
851da177e4SLinus Torvalds 	/* Triggers also /STROBE.*/
861da177e4SLinus Torvalds 	pia(p)->pprb = data;
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
mfc3_read_data(struct parport * p)891da177e4SLinus Torvalds static unsigned char mfc3_read_data(struct parport *p)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds 	/* clears interrupt bit. Triggers also /STROBE. */
921da177e4SLinus Torvalds 	return pia(p)->pprb;
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds 
control_pc_to_mfc3(unsigned char control)951da177e4SLinus Torvalds static unsigned char control_pc_to_mfc3(unsigned char control)
961da177e4SLinus Torvalds {
971da177e4SLinus Torvalds 	unsigned char ret = 32|64;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 	if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */
1001da177e4SLinus Torvalds 		ret &= ~32; /* /SELECT_IN */
1011da177e4SLinus Torvalds 	if (control & PARPORT_CONTROL_INIT) /* INITP */
1021da177e4SLinus Torvalds 		ret |= 128;
1031da177e4SLinus Torvalds 	if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */
1041da177e4SLinus Torvalds 		ret &= ~64;
1051da177e4SLinus Torvalds 	if (control & PARPORT_CONTROL_STROBE) /* Strobe */
1061da177e4SLinus Torvalds 		/* Handled directly by hardware */;
1071da177e4SLinus Torvalds 	return ret;
1081da177e4SLinus Torvalds }
1091da177e4SLinus Torvalds 
control_mfc3_to_pc(unsigned char control)1101da177e4SLinus Torvalds static unsigned char control_mfc3_to_pc(unsigned char control)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	unsigned char ret = PARPORT_CONTROL_STROBE
1131da177e4SLinus Torvalds 			  | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT;
1141da177e4SLinus Torvalds 
1151da177e4SLinus Torvalds 	if (control & 128) /* /INITP */
1161da177e4SLinus Torvalds 		ret |= PARPORT_CONTROL_INIT;
1171da177e4SLinus Torvalds 	if (control & 64) /* /AUTOLF */
1181da177e4SLinus Torvalds 		ret &= ~PARPORT_CONTROL_AUTOFD;
1191da177e4SLinus Torvalds 	if (control & 32) /* /SELECT_IN */
1201da177e4SLinus Torvalds 		ret &= ~PARPORT_CONTROL_SELECT;
1211da177e4SLinus Torvalds 	return ret;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
mfc3_write_control(struct parport * p,unsigned char control)1241da177e4SLinus Torvalds static void mfc3_write_control(struct parport *p, unsigned char control)
1251da177e4SLinus Torvalds {
12646aea0d4SJoe Perches 	pr_debug("write_control %02x\n", control);
1271da177e4SLinus Torvalds 	pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control);
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
mfc3_read_control(struct parport * p)1301da177e4SLinus Torvalds static unsigned char mfc3_read_control( struct parport *p)
1311da177e4SLinus Torvalds {
13246aea0d4SJoe Perches 	pr_debug("read_control\n");
1331da177e4SLinus Torvalds 	return control_mfc3_to_pc(pia(p)->ppra & 0xe0);
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds 
mfc3_frob_control(struct parport * p,unsigned char mask,unsigned char val)1361da177e4SLinus Torvalds static unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds 	unsigned char old;
1391da177e4SLinus Torvalds 
14046aea0d4SJoe Perches 	pr_debug("frob_control mask %02x, value %02x\n", mask, val);
1411da177e4SLinus Torvalds 	old = mfc3_read_control(p);
1421da177e4SLinus Torvalds 	mfc3_write_control(p, (old & ~mask) ^ val);
1431da177e4SLinus Torvalds 	return old;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds 
status_mfc3_to_pc(unsigned char status)1461da177e4SLinus Torvalds static unsigned char status_mfc3_to_pc(unsigned char status)
1471da177e4SLinus Torvalds {
1481da177e4SLinus Torvalds 	unsigned char ret = PARPORT_STATUS_BUSY;
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	if (status & 1) /* Busy */
1511da177e4SLinus Torvalds 		ret &= ~PARPORT_STATUS_BUSY;
1521da177e4SLinus Torvalds 	if (status & 2) /* PaperOut */
1531da177e4SLinus Torvalds 		ret |= PARPORT_STATUS_PAPEROUT;
1541da177e4SLinus Torvalds 	if (status & 4) /* Selected */
1551da177e4SLinus Torvalds 		ret |= PARPORT_STATUS_SELECT;
1561da177e4SLinus Torvalds 	if (status & 8) /* Ack */
1571da177e4SLinus Torvalds 		ret |= PARPORT_STATUS_ACK;
1581da177e4SLinus Torvalds 	if (status & 16) /* /ERROR */
1591da177e4SLinus Torvalds 		ret |= PARPORT_STATUS_ERROR;
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	return ret;
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds 
mfc3_read_status(struct parport * p)1641da177e4SLinus Torvalds static unsigned char mfc3_read_status(struct parport *p)
1651da177e4SLinus Torvalds {
1661da177e4SLinus Torvalds 	unsigned char status;
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	status = status_mfc3_to_pc(pia(p)->ppra & 0x1f);
16946aea0d4SJoe Perches 	pr_debug("read_status %02x\n", status);
1701da177e4SLinus Torvalds 	return status;
1711da177e4SLinus Torvalds }
1721da177e4SLinus Torvalds 
173df4c756eSCarlos Palminha static int use_cnt;
1741da177e4SLinus Torvalds 
mfc3_interrupt(int irq,void * dev_id)1757d12e780SDavid Howells static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds 	int i;
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds 	for( i = 0; i < MAX_MFC; i++)
1801da177e4SLinus Torvalds 		if (this_port[i] != NULL)
1811da177e4SLinus Torvalds 			if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
1821da177e4SLinus Torvalds 				dummy = pia(this_port[i])->pprb; /* clear irq bit */
183f230d101SJeff Garzik 				parport_generic_irq(this_port[i]);
1841da177e4SLinus Torvalds 			}
1851da177e4SLinus Torvalds 	return IRQ_HANDLED;
1861da177e4SLinus Torvalds }
1871da177e4SLinus Torvalds 
mfc3_enable_irq(struct parport * p)1881da177e4SLinus Torvalds static void mfc3_enable_irq(struct parport *p)
1891da177e4SLinus Torvalds {
1901da177e4SLinus Torvalds 	pia(p)->crb |= PIA_C1_ENABLE_IRQ;
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds 
mfc3_disable_irq(struct parport * p)1931da177e4SLinus Torvalds static void mfc3_disable_irq(struct parport *p)
1941da177e4SLinus Torvalds {
1951da177e4SLinus Torvalds 	pia(p)->crb &= ~PIA_C1_ENABLE_IRQ;
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
mfc3_data_forward(struct parport * p)1981da177e4SLinus Torvalds static void mfc3_data_forward(struct parport *p)
1991da177e4SLinus Torvalds {
20046aea0d4SJoe Perches 	pr_debug("forward\n");
2011da177e4SLinus Torvalds 	pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */
2021da177e4SLinus Torvalds 	pia(p)->pddrb = 255; /* all pins output */
2031da177e4SLinus Torvalds 	pia(p)->crb |= PIA_DDR; /* make data register visible - default */
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
mfc3_data_reverse(struct parport * p)2061da177e4SLinus Torvalds static void mfc3_data_reverse(struct parport *p)
2071da177e4SLinus Torvalds {
20846aea0d4SJoe Perches 	pr_debug("reverse\n");
2091da177e4SLinus Torvalds 	pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */
2101da177e4SLinus Torvalds 	pia(p)->pddrb = 0; /* all pins input */
2111da177e4SLinus Torvalds 	pia(p)->crb |= PIA_DDR; /* make data register visible - default */
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
mfc3_init_state(struct pardevice * dev,struct parport_state * s)2141da177e4SLinus Torvalds static void mfc3_init_state(struct pardevice *dev, struct parport_state *s)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	s->u.amiga.data = 0;
2171da177e4SLinus Torvalds 	s->u.amiga.datadir = 255;
2181da177e4SLinus Torvalds 	s->u.amiga.status = 0;
2191da177e4SLinus Torvalds 	s->u.amiga.statusdir = 0xe0;
2201da177e4SLinus Torvalds }
2211da177e4SLinus Torvalds 
mfc3_save_state(struct parport * p,struct parport_state * s)2221da177e4SLinus Torvalds static void mfc3_save_state(struct parport *p, struct parport_state *s)
2231da177e4SLinus Torvalds {
2241da177e4SLinus Torvalds 	s->u.amiga.data = pia(p)->pprb;
2251da177e4SLinus Torvalds 	pia(p)->crb &= ~PIA_DDR;
2261da177e4SLinus Torvalds 	s->u.amiga.datadir = pia(p)->pddrb;
2271da177e4SLinus Torvalds 	pia(p)->crb |= PIA_DDR;
2281da177e4SLinus Torvalds 	s->u.amiga.status = pia(p)->ppra;
2291da177e4SLinus Torvalds 	pia(p)->cra &= ~PIA_DDR;
2301da177e4SLinus Torvalds 	s->u.amiga.statusdir = pia(p)->pddrb;
2311da177e4SLinus Torvalds 	pia(p)->cra |= PIA_DDR;
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
mfc3_restore_state(struct parport * p,struct parport_state * s)2341da177e4SLinus Torvalds static void mfc3_restore_state(struct parport *p, struct parport_state *s)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds 	pia(p)->pprb = s->u.amiga.data;
2371da177e4SLinus Torvalds 	pia(p)->crb &= ~PIA_DDR;
2381da177e4SLinus Torvalds 	pia(p)->pddrb = s->u.amiga.datadir;
2391da177e4SLinus Torvalds 	pia(p)->crb |= PIA_DDR;
2401da177e4SLinus Torvalds 	pia(p)->ppra = s->u.amiga.status;
2411da177e4SLinus Torvalds 	pia(p)->cra &= ~PIA_DDR;
2421da177e4SLinus Torvalds 	pia(p)->pddrb = s->u.amiga.statusdir;
2431da177e4SLinus Torvalds 	pia(p)->cra |= PIA_DDR;
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static struct parport_operations pp_mfc3_ops = {
2471da177e4SLinus Torvalds 	.write_data	= mfc3_write_data,
2481da177e4SLinus Torvalds 	.read_data	= mfc3_read_data,
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	.write_control	= mfc3_write_control,
2511da177e4SLinus Torvalds 	.read_control	= mfc3_read_control,
2521da177e4SLinus Torvalds 	.frob_control	= mfc3_frob_control,
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	.read_status	= mfc3_read_status,
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	.enable_irq	= mfc3_enable_irq,
2571da177e4SLinus Torvalds 	.disable_irq	= mfc3_disable_irq,
2581da177e4SLinus Torvalds 
2591da177e4SLinus Torvalds 	.data_forward	= mfc3_data_forward,
2601da177e4SLinus Torvalds 	.data_reverse	= mfc3_data_reverse,
2611da177e4SLinus Torvalds 
2621da177e4SLinus Torvalds 	.init_state	= mfc3_init_state,
2631da177e4SLinus Torvalds 	.save_state	= mfc3_save_state,
2641da177e4SLinus Torvalds 	.restore_state	= mfc3_restore_state,
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	.epp_write_data	= parport_ieee1284_epp_write_data,
2671da177e4SLinus Torvalds 	.epp_read_data	= parport_ieee1284_epp_read_data,
2681da177e4SLinus Torvalds 	.epp_write_addr	= parport_ieee1284_epp_write_addr,
2691da177e4SLinus Torvalds 	.epp_read_addr	= parport_ieee1284_epp_read_addr,
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	.ecp_write_data	= parport_ieee1284_ecp_write_data,
2721da177e4SLinus Torvalds 	.ecp_read_data	= parport_ieee1284_ecp_read_data,
2731da177e4SLinus Torvalds 	.ecp_write_addr	= parport_ieee1284_ecp_write_addr,
2741da177e4SLinus Torvalds 
2751da177e4SLinus Torvalds 	.compat_write_data	= parport_ieee1284_write_compat,
2761da177e4SLinus Torvalds 	.nibble_read_data	= parport_ieee1284_read_nibble,
2771da177e4SLinus Torvalds 	.byte_read_data		= parport_ieee1284_read_byte,
2781da177e4SLinus Torvalds 
2791da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
2801da177e4SLinus Torvalds };
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds /* ----------- Initialisation code --------------------------------- */
2831da177e4SLinus Torvalds 
parport_mfc3_init(void)2841da177e4SLinus Torvalds static int __init parport_mfc3_init(void)
2851da177e4SLinus Torvalds {
2861da177e4SLinus Torvalds 	struct parport *p;
2871da177e4SLinus Torvalds 	int pias = 0;
2881da177e4SLinus Torvalds 	struct pia *pp;
2891da177e4SLinus Torvalds 	struct zorro_dev *z = NULL;
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	if (!MACH_IS_AMIGA)
2921da177e4SLinus Torvalds 		return -ENODEV;
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds 	while ((z = zorro_find_device(ZORRO_PROD_BSC_MULTIFACE_III, z))) {
2951da177e4SLinus Torvalds 		unsigned long piabase = z->resource.start+PIABASE;
2961da177e4SLinus Torvalds 		if (!request_mem_region(piabase, sizeof(struct pia), "PIA"))
2971da177e4SLinus Torvalds 			continue;
2981da177e4SLinus Torvalds 
2996112ea08SGeert Uytterhoeven 		pp = ZTWO_VADDR(piabase);
3001da177e4SLinus Torvalds 		pp->crb = 0;
3011da177e4SLinus Torvalds 		pp->pddrb = 255; /* all data pins output */
3021da177e4SLinus Torvalds 		pp->crb = PIA_DDR|32|8;
3031da177e4SLinus Torvalds 		dummy = pp->pddrb; /* reading clears interrupt */
3041da177e4SLinus Torvalds 		pp->cra = 0;
3051da177e4SLinus Torvalds 		pp->pddra = 0xe0; /* /RESET,  /DIR ,/AUTO-FEED output */
3061da177e4SLinus Torvalds 		pp->cra = PIA_DDR;
3071da177e4SLinus Torvalds 		pp->ppra = 0; /* reset printer */
3081da177e4SLinus Torvalds 		udelay(10);
3091da177e4SLinus Torvalds 		pp->ppra = 128;
3101da177e4SLinus Torvalds 		p = parport_register_port((unsigned long)pp, IRQ_AMIGA_PORTS,
3111da177e4SLinus Torvalds 					  PARPORT_DMA_NONE, &pp_mfc3_ops);
3121da177e4SLinus Torvalds 		if (!p)
3131da177e4SLinus Torvalds 			goto out_port;
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds 		if (p->irq != PARPORT_IRQ_NONE) {
3161da177e4SLinus Torvalds 			if (use_cnt++ == 0)
317dace1453SThomas Gleixner 				if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops))
3181da177e4SLinus Torvalds 					goto out_irq;
3191da177e4SLinus Torvalds 		}
320c15a3837SDavid Brownell 		p->dev = &z->dev;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 		this_port[pias++] = p;
323decf26f6SJoe Perches 		pr_info("%s: Multiface III port using irq\n", p->name);
3241da177e4SLinus Torvalds 		/* XXX: set operating mode */
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 		p->private_data = (void *)piabase;
3271da177e4SLinus Torvalds 		parport_announce_port (p);
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 		if (pias >= MAX_MFC)
3301da177e4SLinus Torvalds 			break;
3311da177e4SLinus Torvalds 		continue;
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	out_irq:
3341da177e4SLinus Torvalds 		parport_put_port(p);
3351da177e4SLinus Torvalds 	out_port:
3361da177e4SLinus Torvalds 		release_mem_region(piabase, sizeof(struct pia));
3371da177e4SLinus Torvalds 	}
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	return pias ? 0 : -ENODEV;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
parport_mfc3_exit(void)3421da177e4SLinus Torvalds static void __exit parport_mfc3_exit(void)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	int i;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds 	for (i = 0; i < MAX_MFC; i++) {
3471da177e4SLinus Torvalds 		if (!this_port[i])
3481da177e4SLinus Torvalds 			continue;
3491da177e4SLinus Torvalds 		parport_remove_port(this_port[i]);
35049966baeSRoel Kluin 		if (this_port[i]->irq != PARPORT_IRQ_NONE) {
3511da177e4SLinus Torvalds 			if (--use_cnt == 0)
3521da177e4SLinus Torvalds 				free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops);
3531da177e4SLinus Torvalds 		}
3541da177e4SLinus Torvalds 		release_mem_region(ZTWO_PADDR(this_port[i]->private_data), sizeof(struct pia));
3551da177e4SLinus Torvalds 		parport_put_port(this_port[i]);
3561da177e4SLinus Torvalds 	}
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
36142b2aa86SJustin P. Mattock MODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Parallel Port");
3621da177e4SLinus Torvalds MODULE_LICENSE("GPL");
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds module_init(parport_mfc3_init)
3651da177e4SLinus Torvalds module_exit(parport_mfc3_exit)
366