18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* Low-level parallel port routines for the Multiface 3 card 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Joerg Dorchain <joerg@dorchain.net> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * (C) The elitist m68k Users(TM) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * based on the existing parport_amiga and lp_mfc 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * From the MFC3 documentation: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Miscellaneous PIA Details 148c2ecf20Sopenharmony_ci * ------------------------- 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * The two open-drain interrupt outputs /IRQA and /IRQB are routed to 178c2ecf20Sopenharmony_ci * /INT2 of the Z2 bus. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * The CPU data bus of the PIA (D0-D7) is connected to D8-D15 on the Z2 208c2ecf20Sopenharmony_ci * bus. This means that any PIA registers are accessed at even addresses. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Centronics Pin Connections for the PIA 238c2ecf20Sopenharmony_ci * -------------------------------------- 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * The following table shows the connections between the PIA and the 268c2ecf20Sopenharmony_ci * Centronics interface connector. These connections implement a single, but 278c2ecf20Sopenharmony_ci * very complete, Centronics type interface. The Pin column gives the pin 288c2ecf20Sopenharmony_ci * numbers of the PIA. The Centronics pin numbers can be found in the section 298c2ecf20Sopenharmony_ci * "Parallel Connectors". 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Pin | PIA | Dir | Centronics Names 338c2ecf20Sopenharmony_ci * -------+-----+-----+--------------------------------------------------------- 348c2ecf20Sopenharmony_ci * 19 | CB2 | --> | /STROBE (aka /DRDY) 358c2ecf20Sopenharmony_ci * 10-17 | PBx | <-> | DATA0 - DATA7 368c2ecf20Sopenharmony_ci * 18 | CB1 | <-- | /ACK 378c2ecf20Sopenharmony_ci * 40 | CA1 | <-- | BUSY 388c2ecf20Sopenharmony_ci * 3 | PA1 | <-- | PAPER-OUT (aka POUT) 398c2ecf20Sopenharmony_ci * 4 | PA2 | <-- | SELECTED (aka SEL) 408c2ecf20Sopenharmony_ci * 9 | PA7 | --> | /INIT (aka /RESET or /INPUT-PRIME) 418c2ecf20Sopenharmony_ci * 6 | PA4 | <-- | /ERROR (aka /FAULT) 428c2ecf20Sopenharmony_ci * 7 | PA5 | --> | DIR (aka /SELECT-IN) 438c2ecf20Sopenharmony_ci * 8 | PA6 | --> | /AUTO-FEED-XT 448c2ecf20Sopenharmony_ci * 39 | CA2 | --> | open 458c2ecf20Sopenharmony_ci * 5 | PA3 | <-- | /ACK (same as CB1!) 468c2ecf20Sopenharmony_ci * 2 | PA0 | <-- | BUSY (same as CA1!) 478c2ecf20Sopenharmony_ci * -------+-----+-----+--------------------------------------------------------- 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Should be enough to understand some of the driver. 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * Per convention for normal use the port registers are visible. 528c2ecf20Sopenharmony_ci * If you need the data direction registers, restore the value in the 538c2ecf20Sopenharmony_ci * control register. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include "multiface.h" 578c2ecf20Sopenharmony_ci#include <linux/module.h> 588c2ecf20Sopenharmony_ci#include <linux/init.h> 598c2ecf20Sopenharmony_ci#include <linux/parport.h> 608c2ecf20Sopenharmony_ci#include <linux/delay.h> 618c2ecf20Sopenharmony_ci#include <linux/mc6821.h> 628c2ecf20Sopenharmony_ci#include <linux/zorro.h> 638c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 648c2ecf20Sopenharmony_ci#include <asm/setup.h> 658c2ecf20Sopenharmony_ci#include <asm/amigahw.h> 668c2ecf20Sopenharmony_ci#include <asm/irq.h> 678c2ecf20Sopenharmony_ci#include <asm/amigaints.h> 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Maximum Number of Cards supported */ 708c2ecf20Sopenharmony_ci#define MAX_MFC 5 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#undef DEBUG 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct parport *this_port[MAX_MFC] = {NULL, }; 758c2ecf20Sopenharmony_cistatic volatile int dummy; /* for trigger readds */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define pia(dev) ((struct pia *)(dev->base)) 788c2ecf20Sopenharmony_cistatic struct parport_operations pp_mfc3_ops; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic void mfc3_write_data(struct parport *p, unsigned char data) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci pr_debug("write_data %c\n", data); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci dummy = pia(p)->pprb; /* clears irq bit */ 858c2ecf20Sopenharmony_ci /* Triggers also /STROBE.*/ 868c2ecf20Sopenharmony_ci pia(p)->pprb = data; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic unsigned char mfc3_read_data(struct parport *p) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci /* clears interrupt bit. Triggers also /STROBE. */ 928c2ecf20Sopenharmony_ci return pia(p)->pprb; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic unsigned char control_pc_to_mfc3(unsigned char control) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci unsigned char ret = 32|64; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (control & PARPORT_CONTROL_SELECT) /* XXX: What is SELECP? */ 1008c2ecf20Sopenharmony_ci ret &= ~32; /* /SELECT_IN */ 1018c2ecf20Sopenharmony_ci if (control & PARPORT_CONTROL_INIT) /* INITP */ 1028c2ecf20Sopenharmony_ci ret |= 128; 1038c2ecf20Sopenharmony_ci if (control & PARPORT_CONTROL_AUTOFD) /* AUTOLF */ 1048c2ecf20Sopenharmony_ci ret &= ~64; 1058c2ecf20Sopenharmony_ci if (control & PARPORT_CONTROL_STROBE) /* Strobe */ 1068c2ecf20Sopenharmony_ci /* Handled directly by hardware */; 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic unsigned char control_mfc3_to_pc(unsigned char control) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci unsigned char ret = PARPORT_CONTROL_STROBE 1138c2ecf20Sopenharmony_ci | PARPORT_CONTROL_AUTOFD | PARPORT_CONTROL_SELECT; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci if (control & 128) /* /INITP */ 1168c2ecf20Sopenharmony_ci ret |= PARPORT_CONTROL_INIT; 1178c2ecf20Sopenharmony_ci if (control & 64) /* /AUTOLF */ 1188c2ecf20Sopenharmony_ci ret &= ~PARPORT_CONTROL_AUTOFD; 1198c2ecf20Sopenharmony_ci if (control & 32) /* /SELECT_IN */ 1208c2ecf20Sopenharmony_ci ret &= ~PARPORT_CONTROL_SELECT; 1218c2ecf20Sopenharmony_ci return ret; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void mfc3_write_control(struct parport *p, unsigned char control) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci pr_debug("write_control %02x\n", control); 1278c2ecf20Sopenharmony_ci pia(p)->ppra = (pia(p)->ppra & 0x1f) | control_pc_to_mfc3(control); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic unsigned char mfc3_read_control( struct parport *p) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci pr_debug("read_control\n"); 1338c2ecf20Sopenharmony_ci return control_mfc3_to_pc(pia(p)->ppra & 0xe0); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic unsigned char mfc3_frob_control( struct parport *p, unsigned char mask, unsigned char val) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci unsigned char old; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci pr_debug("frob_control mask %02x, value %02x\n", mask, val); 1418c2ecf20Sopenharmony_ci old = mfc3_read_control(p); 1428c2ecf20Sopenharmony_ci mfc3_write_control(p, (old & ~mask) ^ val); 1438c2ecf20Sopenharmony_ci return old; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic unsigned char status_mfc3_to_pc(unsigned char status) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci unsigned char ret = PARPORT_STATUS_BUSY; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (status & 1) /* Busy */ 1518c2ecf20Sopenharmony_ci ret &= ~PARPORT_STATUS_BUSY; 1528c2ecf20Sopenharmony_ci if (status & 2) /* PaperOut */ 1538c2ecf20Sopenharmony_ci ret |= PARPORT_STATUS_PAPEROUT; 1548c2ecf20Sopenharmony_ci if (status & 4) /* Selected */ 1558c2ecf20Sopenharmony_ci ret |= PARPORT_STATUS_SELECT; 1568c2ecf20Sopenharmony_ci if (status & 8) /* Ack */ 1578c2ecf20Sopenharmony_ci ret |= PARPORT_STATUS_ACK; 1588c2ecf20Sopenharmony_ci if (status & 16) /* /ERROR */ 1598c2ecf20Sopenharmony_ci ret |= PARPORT_STATUS_ERROR; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic unsigned char mfc3_read_status(struct parport *p) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci unsigned char status; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci status = status_mfc3_to_pc(pia(p)->ppra & 0x1f); 1698c2ecf20Sopenharmony_ci pr_debug("read_status %02x\n", status); 1708c2ecf20Sopenharmony_ci return status; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int use_cnt; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic irqreturn_t mfc3_interrupt(int irq, void *dev_id) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci int i; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for( i = 0; i < MAX_MFC; i++) 1808c2ecf20Sopenharmony_ci if (this_port[i] != NULL) 1818c2ecf20Sopenharmony_ci if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */ 1828c2ecf20Sopenharmony_ci dummy = pia(this_port[i])->pprb; /* clear irq bit */ 1838c2ecf20Sopenharmony_ci parport_generic_irq(this_port[i]); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void mfc3_enable_irq(struct parport *p) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci pia(p)->crb |= PIA_C1_ENABLE_IRQ; 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void mfc3_disable_irq(struct parport *p) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci pia(p)->crb &= ~PIA_C1_ENABLE_IRQ; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic void mfc3_data_forward(struct parport *p) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci pr_debug("forward\n"); 2018c2ecf20Sopenharmony_ci pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */ 2028c2ecf20Sopenharmony_ci pia(p)->pddrb = 255; /* all pins output */ 2038c2ecf20Sopenharmony_ci pia(p)->crb |= PIA_DDR; /* make data register visible - default */ 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void mfc3_data_reverse(struct parport *p) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci pr_debug("reverse\n"); 2098c2ecf20Sopenharmony_ci pia(p)->crb &= ~PIA_DDR; /* make data direction register visible */ 2108c2ecf20Sopenharmony_ci pia(p)->pddrb = 0; /* all pins input */ 2118c2ecf20Sopenharmony_ci pia(p)->crb |= PIA_DDR; /* make data register visible - default */ 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void mfc3_init_state(struct pardevice *dev, struct parport_state *s) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci s->u.amiga.data = 0; 2178c2ecf20Sopenharmony_ci s->u.amiga.datadir = 255; 2188c2ecf20Sopenharmony_ci s->u.amiga.status = 0; 2198c2ecf20Sopenharmony_ci s->u.amiga.statusdir = 0xe0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void mfc3_save_state(struct parport *p, struct parport_state *s) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci s->u.amiga.data = pia(p)->pprb; 2258c2ecf20Sopenharmony_ci pia(p)->crb &= ~PIA_DDR; 2268c2ecf20Sopenharmony_ci s->u.amiga.datadir = pia(p)->pddrb; 2278c2ecf20Sopenharmony_ci pia(p)->crb |= PIA_DDR; 2288c2ecf20Sopenharmony_ci s->u.amiga.status = pia(p)->ppra; 2298c2ecf20Sopenharmony_ci pia(p)->cra &= ~PIA_DDR; 2308c2ecf20Sopenharmony_ci s->u.amiga.statusdir = pia(p)->pddrb; 2318c2ecf20Sopenharmony_ci pia(p)->cra |= PIA_DDR; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic void mfc3_restore_state(struct parport *p, struct parport_state *s) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci pia(p)->pprb = s->u.amiga.data; 2378c2ecf20Sopenharmony_ci pia(p)->crb &= ~PIA_DDR; 2388c2ecf20Sopenharmony_ci pia(p)->pddrb = s->u.amiga.datadir; 2398c2ecf20Sopenharmony_ci pia(p)->crb |= PIA_DDR; 2408c2ecf20Sopenharmony_ci pia(p)->ppra = s->u.amiga.status; 2418c2ecf20Sopenharmony_ci pia(p)->cra &= ~PIA_DDR; 2428c2ecf20Sopenharmony_ci pia(p)->pddrb = s->u.amiga.statusdir; 2438c2ecf20Sopenharmony_ci pia(p)->cra |= PIA_DDR; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic struct parport_operations pp_mfc3_ops = { 2478c2ecf20Sopenharmony_ci .write_data = mfc3_write_data, 2488c2ecf20Sopenharmony_ci .read_data = mfc3_read_data, 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci .write_control = mfc3_write_control, 2518c2ecf20Sopenharmony_ci .read_control = mfc3_read_control, 2528c2ecf20Sopenharmony_ci .frob_control = mfc3_frob_control, 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci .read_status = mfc3_read_status, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci .enable_irq = mfc3_enable_irq, 2578c2ecf20Sopenharmony_ci .disable_irq = mfc3_disable_irq, 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci .data_forward = mfc3_data_forward, 2608c2ecf20Sopenharmony_ci .data_reverse = mfc3_data_reverse, 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci .init_state = mfc3_init_state, 2638c2ecf20Sopenharmony_ci .save_state = mfc3_save_state, 2648c2ecf20Sopenharmony_ci .restore_state = mfc3_restore_state, 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci .epp_write_data = parport_ieee1284_epp_write_data, 2678c2ecf20Sopenharmony_ci .epp_read_data = parport_ieee1284_epp_read_data, 2688c2ecf20Sopenharmony_ci .epp_write_addr = parport_ieee1284_epp_write_addr, 2698c2ecf20Sopenharmony_ci .epp_read_addr = parport_ieee1284_epp_read_addr, 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci .ecp_write_data = parport_ieee1284_ecp_write_data, 2728c2ecf20Sopenharmony_ci .ecp_read_data = parport_ieee1284_ecp_read_data, 2738c2ecf20Sopenharmony_ci .ecp_write_addr = parport_ieee1284_ecp_write_addr, 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci .compat_write_data = parport_ieee1284_write_compat, 2768c2ecf20Sopenharmony_ci .nibble_read_data = parport_ieee1284_read_nibble, 2778c2ecf20Sopenharmony_ci .byte_read_data = parport_ieee1284_read_byte, 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 2808c2ecf20Sopenharmony_ci}; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* ----------- Initialisation code --------------------------------- */ 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int __init parport_mfc3_init(void) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct parport *p; 2878c2ecf20Sopenharmony_ci int pias = 0; 2888c2ecf20Sopenharmony_ci struct pia *pp; 2898c2ecf20Sopenharmony_ci struct zorro_dev *z = NULL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!MACH_IS_AMIGA) 2928c2ecf20Sopenharmony_ci return -ENODEV; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci while ((z = zorro_find_device(ZORRO_PROD_BSC_MULTIFACE_III, z))) { 2958c2ecf20Sopenharmony_ci unsigned long piabase = z->resource.start+PIABASE; 2968c2ecf20Sopenharmony_ci if (!request_mem_region(piabase, sizeof(struct pia), "PIA")) 2978c2ecf20Sopenharmony_ci continue; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci pp = ZTWO_VADDR(piabase); 3008c2ecf20Sopenharmony_ci pp->crb = 0; 3018c2ecf20Sopenharmony_ci pp->pddrb = 255; /* all data pins output */ 3028c2ecf20Sopenharmony_ci pp->crb = PIA_DDR|32|8; 3038c2ecf20Sopenharmony_ci dummy = pp->pddrb; /* reading clears interrupt */ 3048c2ecf20Sopenharmony_ci pp->cra = 0; 3058c2ecf20Sopenharmony_ci pp->pddra = 0xe0; /* /RESET, /DIR ,/AUTO-FEED output */ 3068c2ecf20Sopenharmony_ci pp->cra = PIA_DDR; 3078c2ecf20Sopenharmony_ci pp->ppra = 0; /* reset printer */ 3088c2ecf20Sopenharmony_ci udelay(10); 3098c2ecf20Sopenharmony_ci pp->ppra = 128; 3108c2ecf20Sopenharmony_ci p = parport_register_port((unsigned long)pp, IRQ_AMIGA_PORTS, 3118c2ecf20Sopenharmony_ci PARPORT_DMA_NONE, &pp_mfc3_ops); 3128c2ecf20Sopenharmony_ci if (!p) 3138c2ecf20Sopenharmony_ci goto out_port; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (p->irq != PARPORT_IRQ_NONE) { 3168c2ecf20Sopenharmony_ci if (use_cnt++ == 0) 3178c2ecf20Sopenharmony_ci if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops)) 3188c2ecf20Sopenharmony_ci goto out_irq; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci p->dev = &z->dev; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci this_port[pias++] = p; 3238c2ecf20Sopenharmony_ci pr_info("%s: Multiface III port using irq\n", p->name); 3248c2ecf20Sopenharmony_ci /* XXX: set operating mode */ 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci p->private_data = (void *)piabase; 3278c2ecf20Sopenharmony_ci parport_announce_port (p); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (pias >= MAX_MFC) 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci continue; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci out_irq: 3348c2ecf20Sopenharmony_ci parport_put_port(p); 3358c2ecf20Sopenharmony_ci out_port: 3368c2ecf20Sopenharmony_ci release_mem_region(piabase, sizeof(struct pia)); 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return pias ? 0 : -ENODEV; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void __exit parport_mfc3_exit(void) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci int i; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci for (i = 0; i < MAX_MFC; i++) { 3478c2ecf20Sopenharmony_ci if (!this_port[i]) 3488c2ecf20Sopenharmony_ci continue; 3498c2ecf20Sopenharmony_ci parport_remove_port(this_port[i]); 3508c2ecf20Sopenharmony_ci if (this_port[i]->irq != PARPORT_IRQ_NONE) { 3518c2ecf20Sopenharmony_ci if (--use_cnt == 0) 3528c2ecf20Sopenharmony_ci free_irq(IRQ_AMIGA_PORTS, &pp_mfc3_ops); 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci release_mem_region(ZTWO_PADDR(this_port[i]->private_data), sizeof(struct pia)); 3558c2ecf20Sopenharmony_ci parport_put_port(this_port[i]); 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>"); 3618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Parport Driver for Multiface 3 expansion cards Parallel Port"); 3628c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("Multiface 3 Parallel Port"); 3638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cimodule_init(parport_mfc3_init) 3668c2ecf20Sopenharmony_cimodule_exit(parport_mfc3_exit) 367