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