patch-2.1.33 linux/drivers/pnp/parport_init.c

Next file: linux/drivers/pnp/parport_ll_io.h
Previous file: linux/drivers/pnp/TODO-parport
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.32/linux/drivers/pnp/parport_init.c linux/drivers/pnp/parport_init.c
@@ -0,0 +1,815 @@
+/* $Id: parport_init.c,v 1.1.2.4 1997/04/01 18:19:10 phil Exp $
+ * Parallel-port initialisation code.
+ * 
+ * Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
+ *          Tim Waugh <tmw20@cam.ac.uk>
+ *	    Jose Renau <renau@acm.org>
+ *
+ * based on work by Grant Guenther <grant@torque.net>
+ *              and Philip Blundell <Philip.Blundell@pobox.com>
+ */
+
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+
+#include "parport_ll_io.h"
+
+static int io[PARPORT_MAX] = { 0, };
+static int irq[PARPORT_MAX] = { -1, };
+static int dma[PARPORT_MAX] = { -1, };
+
+/******************************************************
+ *  DMA detection section:
+ */
+
+/*
+ * Prepare DMA channels from 0-8 to transmit towards buffer
+ */
+static int parport_prepare_dma(char *buff, int size)
+{
+	int tmp = 0;
+	int i,retv;
+	
+	for (i = 0; i < 8; i++) {
+		retv = request_dma(i, "probe");
+		if (retv)
+			continue;
+		tmp |= 1 << i;
+
+		cli();
+		disable_dma(i);
+		clear_dma_ff(i);
+		set_dma_addr(i, virt_to_bus(buff));
+		set_dma_count(i, size);
+		set_dma_mode(i, DMA_MODE_READ);
+		sti();
+	}
+
+	return tmp;
+}
+
+/*
+ * Activate all DMA channels passed in dma
+ */
+static int parport_enable_dma(int dma)
+{
+	int i;
+	
+	for (i = 0; i < 8; i++)
+		if (dma & (1 << i)) {
+		cli();
+		enable_dma(i);
+		sti();
+	    }
+
+	return dma;
+}
+
+static int parport_detect_dma_transfer(int dma,int size)
+{
+	int i,n,retv;
+	int count=0;
+
+	retv = -1;
+	for (i = 0; i < 8; i++)
+		if (dma & (1 << i)) {
+			disable_dma(i);
+			clear_dma_ff(i);
+			n = get_dma_residue(i);
+			if (n != size) {
+				retv = i;
+				if (count > 0) {
+					retv = -1;	/* Multiple DMA's */
+					printk("Multiple DMA detected.\n");
+				}
+				count++;
+			}
+			free_dma(i);
+		}
+
+	return retv;	
+}
+
+/* Only if supports ECP mode */
+static int programmable_dma_support(struct parport *pb)
+{
+	int dma;
+
+	w_ecr(pb,0xE0); /* Configuration MODE */
+	
+	dma = r_cnfgB(pb) & 0x07;
+
+	w_ecr(pb,pb->ecr);
+	
+	if( dma == 0 || dma == 4 ) /* Jumper selection */
+		return -1;
+	else
+		return dma;
+}
+
+/* Only called if port support ECP mode.
+ *
+ * The only restriction on DMA channels is that it has to be
+ * between 0 to 7 (inclusive). Used only in an ECP mode, DMAs are
+ * considered a shared resource and hence they should be registered
+ * when needed and then immediately unregistered.
+ *
+ * DMA autoprobes for ECP mode are known not to work for some
+ * main board BIOS configs. I had to remove everything from the
+ * port, set the mode to SPP, reboot to DOS, set the mode to ECP,
+ * and reboot again, then I got IRQ probes and DMA probes to work.
+ * [Is the BIOS doing a device detection?]
+ *
+ * A value of -1 is allowed indicating no DMA support.
+ *
+ * if( 0 < DMA < 4 )
+ *    1Byte DMA transfer
+ * else // 4 < DMA < 8
+ *    2Byte DMA transfer
+ *
+ */
+static int parport_dma_probe(struct parport *pb)
+{
+	int dma,retv;
+	int dsr,dsr_read;
+	char *buff;
+
+	retv = programmable_dma_support(pb);
+	if( retv != -1 )
+		return retv;
+	
+	buff = kmalloc(16, GFP_KERNEL | GFP_DMA);
+	if( !buff ){
+	    printk("parport: memory squezze\n");
+	    return -1;
+	}
+	
+ 	dsr = r_ctr(pb);
+	dsr_read = (dsr & ~(0x20)) | 0x04;    /* Direction == read */
+
+	w_ecr(pb, 0xc0);	   /* ECP MODE */
+ 	w_ctr(pb, dsr_read );
+	dma=parport_prepare_dma(buff,8);
+	w_ecr(pb, 0xd8);	   /* ECP FIFO + enable DMA */
+	parport_enable_dma(dma);
+	udelay(30);           /* Give some for DMA tranfer */
+	retv = parport_detect_dma_transfer(dma,8);
+	
+	/*
+	 * National Semiconductors only supports DMA tranfers
+	 * in ECP MODE
+	 */
+	if( retv == -1 ){
+		w_ecr(pb, 0x60);	   /* ECP MODE */
+		w_ctr(pb, dsr_read );
+		dma=parport_prepare_dma(buff,8);
+		w_ecr(pb, 0x68);	   /* ECP FIFO + enable DMA */
+		parport_enable_dma(dma);
+		udelay(30);           /* Give some for DMA tranfer */
+		retv = parport_detect_dma_transfer(dma,8);
+	}
+	
+	kfree(buff);
+	
+	w_ctr(pb, pb->ctr);
+	w_ecr(pb, pb->ecr);
+
+	return retv;
+}
+/******************************************************
+ *  MODE detection section:
+ */
+
+/*
+ * Clear TIMEOUT BIT in EPP MODE
+ */
+static int epp_clear_timeout(struct parport *pb)
+{
+	int r;
+
+    if( !(r_str(pb) & 0x01) )
+		return 1;
+
+	/* To clear timeout some chip requiere double read */
+	r_str(pb);
+	r = r_str(pb);
+	w_str(pb, r | 0x01); /* Some reset by writing 1 */
+	w_str(pb, r & 0xfe); /* Others by writing 0 */
+	r = r_str(pb);
+
+	return !(r & 0x01);
+}
+
+
+/*
+ * Checks for por existence, all ports support SPP MODE
+ */
+static int parport_SPP_supported(struct parport *pb)
+{
+	int r,rr;
+	
+	/* Do a simple read-write test to make sure the port exists. */
+	w_dtr(pb, 0xaa);
+	r = r_dtr(pb);
+	
+	w_dtr(pb, 0x55);
+	rr = r_dtr(pb);
+	
+	if (r != 0xaa || rr != 0x55) {
+		return 0;
+	}
+	
+	return PARPORT_MODE_SPP;
+}
+
+/* Check for ECP
+ *
+ * Old style XT ports alias io ports every 0x400, hence accessing ECR
+ * on these cards actually accesses the CTR.
+ *
+ * Modern cards don't do this but reading from ECR will return 0xff
+ * regardless of what is written here if the card does NOT support
+ * ECP.
+ *
+ * We will write 0x2c to ECR and 0xcc to CTR since both of these
+ * values are "safe" on the CTR since bits 6-7 of CTR are unused.
+ */
+static int parport_ECR_present(struct parport *pb)
+{
+	int r;
+
+	if( pb->base == 0x3BC )
+		return 0;
+	
+	r= r_ctr(pb);	
+	if( (r_ecr(pb) & 0x03) == (r & 0x03) ){
+		w_ctr(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
+
+		r= r_ctr(pb);	
+		if( (r_ecr(pb) & 0x03) == (r & 0x03) )
+			return 0; /* Sure that no ECR register exists */
+	}
+	
+	if( (r_ecr(pb) & 0x03 ) != 0x01 )
+		return 0;
+
+	w_ecr(pb,0x34);
+	if( r_ecr(pb) != 0x35 )
+		return 0;
+
+	w_ecr(pb,pb->ecr);
+	w_ctr(pb,pb->ctr);
+	
+	return PARPORT_MODE_ECR;
+}
+
+static int parport_ECP_supported(struct parport *pb)
+{
+	int i;
+	
+	if( !(pb->modes & PARPORT_MODE_ECR) )
+		return 0;
+	/*
+	 * Usign LGS chipset it uses ECR register, but
+	 * it doesn't support ECP or FIFO MODE
+	 */
+	
+	w_ecr(pb,0xc0); /* TEST FIFO */
+	for( i=0 ; i < 1024 && (r_ecr(pb) & 0x01) ; i++ )
+		w_fifo(pb, 0xaa);
+
+	w_ecr(pb,pb->ecr);
+
+	if( i >= 1024 )
+		return 0;
+	
+	return PARPORT_MODE_ECP;
+}
+
+/* EPP mode detection
+ * Theory:
+ *	Bit 0 of STR is the EPP timeout bit, this bit is 0
+ *	when EPP is possible and is set high when an EPP timeout
+ *	occurs (EPP uses the HALT line to stop the CPU while it does
+ *	the byte transfer, an EPP timeout occurs if the attached
+ *	device fails to respond after 10 micro seconds).
+ *
+ *	This bit is cleared by either reading it (National Semi)
+ *	or writing a 1 to the bit (SMC, UMC, WinBond), others ???
+ *	This bit is always high in non EPP modes.
+ */
+static int parport_EPP_supported(struct parport *pb)
+{
+	if( pb->base == 0x3BC )
+		return 0;
+
+	/* If EPP timeout bit clear then EPP available */
+	if( !epp_clear_timeout(pb) )
+		return 0;  /* No way to clear timeout */
+
+	w_ctr(pb, r_ctr(pb) | 0x20);
+	w_ctr(pb, r_ctr(pb) | 0x10);
+	epp_clear_timeout(pb);
+	
+	r_epp(pb);
+	udelay(30);  /* Wait for possible EPP timeout */
+	
+	if( r_str(pb) & 0x01 ){
+		epp_clear_timeout(pb);
+		return PARPORT_MODE_EPP;
+	}
+
+	return 0;
+}
+
+static int parport_ECPEPP_supported(struct parport *pb)
+{
+	int mode;
+
+	if( !(pb->modes & PARPORT_MODE_ECR) )
+		return 0;
+	
+	/* Search for SMC style EPP+ECP mode */
+	w_ecr(pb, 0x80);
+	
+	mode = parport_EPP_supported(pb);
+
+	w_ecr(pb,pb->ecr);
+	
+	if( mode )
+		return PARPORT_MODE_ECPEPP;
+	
+	return 0;
+}
+
+/* Detect LP_PS2 support
+ * Bit 5 (0x20) sets the PS/2 data direction, setting this high
+ * allows us to read data from the data lines, old style SPP ports
+ * will return 0xff.  This may not be reliable if there is a
+ * peripheral attached to the port. 
+ */
+static int parport_PS2_supported(struct parport *pb)
+{
+	int r,rr;
+
+	epp_clear_timeout(pb);
+
+	w_ctr(pb, pb->ctr | 0x20);	/* Tri-state the buffer */
+	
+	w_dtr(pb, 0xAA);
+	r = r_dtr(pb);
+
+	w_dtr(pb, 0x55);
+	rr = r_dtr(pb);
+	
+	w_ctr(pb, pb->ctr);	/* Reset CTR register */
+
+	if (r != 0xAA || rr != 0x55 )
+		return PARPORT_MODE_PS2;
+	
+	return 0;
+}
+
+static int parport_ECPPS2_supported(struct parport *pb)
+{
+	int mode;
+
+	if( !(pb->modes & PARPORT_MODE_ECR) )
+		return 0;
+	
+	w_ecr(pb, 0x20);
+	
+	mode = parport_PS2_supported(pb);
+
+	w_ecr(pb,pb->ecr);
+	
+	if (mode)
+		return PARPORT_MODE_ECPPS2;
+	
+	return 0;
+}
+
+/******************************************************
+ *  IRQ detection section:
+ */
+/*
+ * This code is for detecting ECP interrupts (due to problems with the
+ * monolithic interrupt probing routines).
+ *
+ * In short this is a voting system where the interrupt with the most
+ * "votes" is the elected interrupt (it SHOULD work...)
+ */
+static int intr_vote[16];
+static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
+{
+	intr_vote[irq]++;
+	return;
+}
+
+static long open_intr_election(void)
+{
+	long tmp = 0;
+	int i;
+
+	/* We ignore the timer - irq 0 */
+	for (i = 1; i < 16; i++) {
+		intr_vote[i] = 0;
+		if (request_irq(i, parport_vote_intr_func,
+		       SA_INTERRUPT, "probe", intr_vote) == 0)
+			tmp |= 1 << i;
+	}
+	return tmp;
+}
+
+static int close_intr_election(long tmp)
+{
+	long max_vote = 0;
+	int irq = -1;
+	int i;
+
+	/* We ignore the timer - irq 0 */
+	for (i = 1; i < 16; i++)
+		if (tmp & (1 << i)) {
+			if (intr_vote[i] > max_vote) {
+				if (max_vote)
+					return -1;
+				max_vote = intr_vote[i];
+				irq = i;
+			}
+			free_irq(i, intr_vote);
+		}
+	return irq;
+}
+
+/* Only if supports ECP mode */
+static int programmable_irq_support(struct parport *pb)
+{
+	int irq;
+
+	w_ecr(pb,0xE0); /* Configuration MODE */
+	
+	irq = (r_cnfgB(pb) >> 3) & 0x07;
+
+	switch(irq){
+	  case 2:
+		  irq = 9;
+		  break;
+	  case 7:
+		  irq = 5;
+		  break;
+	  case 0:
+		  irq = -1;
+		  break;
+	  default:
+		  irq += 7;
+	}
+		  
+	w_ecr(pb,pb->ecr);
+	
+	return irq;
+}
+
+static int irq_probe_ECP(struct parport *pb)
+{
+	int irqs,i;
+		
+	probe_irq_off(probe_irq_on());	/* Clear any interrupts */
+	irqs = open_intr_election();
+		
+	w_ecr(pb, 0x00);	    /* Reset FIFO */
+	w_ctr(pb, pb->ctr );    /* Force direction = 0 */
+	w_ecr(pb, 0xd0);	    /* TEST FIFO + nErrIntrEn */
+
+	/* If Full FIFO sure that WriteIntrThresold is generated */
+	for( i=0 ; i < 1024 && !(r_ecr(pb) & 0x02) ; i++ ){
+		w_fifo(pb, 0xaa);
+	}
+		
+	pb->irq = close_intr_election(irqs);
+	if (pb->irq == 0)
+		pb->irq = -1;	/* No interrupt detected */
+	
+	w_ecr(pb, pb->ecr);
+
+	return pb->irq;
+}
+
+/*
+ * It's called only if supports EPP on National Semiconductors
+ * This doesn't work in SMC, LGS, and Winbond 
+ */
+static int irq_probe_EPP(struct parport *pb)
+{
+	int irqs;
+
+#ifndef ADVANCED_DETECT
+	return -1;
+#endif
+	
+	probe_irq_off(probe_irq_on());	/* Clear any interrupts */
+	irqs = open_intr_election();
+
+	if( pb->modes & PARPORT_MODE_ECR )
+		w_ecr(pb, r_ecr(pb) | 0x10 );
+	
+	epp_clear_timeout(pb);
+	w_ctr(pb, r_ctr(pb) | 0x20);
+	w_ctr(pb, r_ctr(pb) | 0x10);
+	epp_clear_timeout(pb);
+
+	/*  Device isn't expecting an EPP read
+	 * and generates an IRQ.
+	 */
+	r_epp(pb);
+	udelay(20);
+
+	pb->irq = close_intr_election(irqs);
+	if (pb->irq == 0)
+		pb->irq = -1;	/* No interrupt detected */
+	
+	w_ctr(pb,pb->ctr);
+	
+	return pb->irq;
+}
+
+static int irq_probe_SPP(struct parport *pb)
+{
+	int irqs;
+
+#ifndef ADVANCED_DETECT
+	return -1;
+#endif
+
+	probe_irq_off(probe_irq_on());	/* Clear any interrupts */
+	irqs = probe_irq_on();
+
+	if( pb->modes & PARPORT_MODE_ECR )
+		w_ecr(pb, 0x10 );
+
+	w_dtr(pb,0x00);
+	w_ctr(pb,0x00);
+	w_ctr(pb,0x0c);
+	udelay(5);
+	w_ctr(pb,0x0d);
+	udelay(5);
+	w_ctr(pb,0x0c);
+	udelay(25);
+	w_ctr(pb,0x08);
+	udelay(25);
+	w_ctr(pb,0x0c);
+	udelay(50);
+
+	pb->irq = probe_irq_off(irqs);
+	if (pb->irq <= 0)
+		pb->irq = -1;	/* No interrupt detected */
+	
+	w_ctr(pb,pb->ctr);
+	
+	return pb->irq;
+}
+
+/* We will attempt to share interrupt requests since other devices
+ * such as sound cards and network cards seem to like using the
+ * printer IRQs.
+ *
+ * When LP_ECP is available we can autoprobe for IRQs.
+ * NOTE: If we can autoprobe it, we can register the IRQ.
+ */
+static int parport_irq_probe(struct parport *pb)
+{
+	if( pb->modes & PARPORT_MODE_ECR )
+		pb->irq = programmable_irq_support(pb);
+
+	if( pb->modes & PARPORT_MODE_ECP )
+		pb->irq = irq_probe_ECP(pb);
+			
+	if( pb->irq == -1 && (pb->modes & PARPORT_MODE_ECPEPP)){
+		w_ecr(pb,0x80);
+		pb->irq = irq_probe_EPP(pb);
+		w_ecr(pb,pb->ecr);
+	}
+
+	epp_clear_timeout(pb);
+
+	if( pb->irq == -1 && (pb->modes & PARPORT_MODE_EPP))
+		pb->irq = irq_probe_EPP(pb);
+
+	epp_clear_timeout(pb);
+
+	if( pb->irq == -1 )
+		pb->irq = irq_probe_SPP(pb);
+
+	return pb->irq;
+}
+
+
+int initialize_parport(struct parport *pb, unsigned long base, int irq, int dma, int count)
+{
+	/* Check some parameters */
+	if (dma < -2) {
+		printk("parport: Invalid DMA[%d] at base 0x%lx\n",dma,base);
+		return 0;
+	}
+
+	if (irq < -2) {
+		printk("parport: Invalid IRQ[%d] at base 0x%lx\n",irq,base);
+		return 0;
+	}
+	
+	/* Init our structure */
+ 	memset(pb, 0, sizeof(struct parport));
+	pb->base = base;
+	pb->irq = irq;
+	pb->dma = dma;
+	pb->modes = 0;
+ 	pb->next = NULL;
+	pb->devices = pb->cad = pb->lurker = NULL;
+	pb->flags = 0;
+
+	/* Before we start, set the control registers to something sensible. */
+	pb->ecr = 0xc;
+	pb->ctr = 0xc;
+
+	pb->name = kmalloc(15, GFP_KERNEL);
+	if (!pb->name) {
+		printk("parport: memory squeeze\n");
+		return 0;
+	}
+	sprintf(pb->name, "parport%d", count);
+
+	if (!parport_SPP_supported(pb)) {
+		epp_clear_timeout(pb);
+		if (!parport_SPP_supported(pb)) {
+			kfree(pb->name);
+			return 0;
+		}
+	}
+
+	pb->modes |= PARPORT_MODE_SPP; 	/* All ports support SPP mode. */
+	pb->modes |= parport_ECR_present(pb);	
+	pb->modes |= parport_ECP_supported(pb);
+	pb->modes |= parport_PS2_supported(pb);
+	pb->modes |= parport_ECPPS2_supported(pb);
+	pb->modes |= parport_EPP_supported(pb);
+	pb->modes |= parport_ECPEPP_supported(pb);
+
+	/* Now register regions */
+	if ((pb->modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) && 
+	    (check_region(pb->base, 8))) {
+		printk(KERN_INFO "%s: EPP disabled due to port conflict at %x.\n", pb->name, pb->base + 3);
+		pb->modes &= ~(PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP);
+	}
+	pb->size = (pb->modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) ? 8 : 3;
+
+	request_region(pb->base, pb->size, pb->name);
+	if (pb->modes & PARPORT_MODE_ECR)
+		request_region(pb->base+0x400, 3, pb->name);
+
+	/* DMA check */
+	if (pb->modes & PARPORT_MODE_ECP) {
+		if (pb->dma == -1)
+			pb->dma = parport_dma_probe(pb);
+		else if (pb->dma == -2)
+			pb->dma = -1;
+	}
+
+	/* IRQ check */
+	if (pb->irq == -1)
+		pb->irq = parport_irq_probe(pb);
+	else if (pb->irq == -2)
+		pb->irq = -1;
+
+	return 1;
+}
+
+#ifndef MODULE
+static int parport_setup_ptr = 0;
+
+void parport_setup(char *str, int *ints)
+{
+	if (ints[0] == 0 || ints[1] == 0) {
+		/* Disable parport if "parport=" or "parport=0" in cmdline */
+		io[0] = -2; 
+		return;
+	}
+	if (parport_setup_ptr < PARPORT_MAX) {
+		io[parport_setup_ptr] = ints[1];
+		if (ints[0]>1) {
+			irq[parport_setup_ptr] = ints[2];
+			if (ints[0]>2) dma[parport_setup_ptr] = ints[3];
+		}
+		parport_setup_ptr++;
+	} else {
+		printk(KERN_ERR "parport=0x%x", ints[1]);
+		if (ints[0]>1) {
+			printk(",%d", ints[2]);
+			if (ints[0]>2) printk(",%d", ints[3]);
+		}
+		printk(" ignored, too many ports.\n");
+	}
+}
+#endif
+
+#ifdef CONFIG_PNP_PARPORT_AUTOPROBE
+extern void parport_probe_one(struct parport *port);
+#endif
+
+#ifdef MODULE
+MODULE_PARM(io, "1-" __MODULE_STRING(PARPORT_MAX) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_MAX) "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_MAX) "i");
+
+int init_module(void)
+#else
+int pnp_parport_init(void)
+#endif				/* MODULE */
+{
+	struct parport *pb;
+
+	printk(KERN_INFO "Parallel port sharing: %s\n",
+	       "$Revision: 1.1.2.4 $");
+
+	if (io[0] == -2) return 1; 
+
+	/* Register /proc/parport */
+	parport_proc_register(NULL);
+
+	/* Run probes to ensure parport does exist */
+#define PORT(a,b,c) \
+		if ((pb = parport_register_port((a), (b), (c))))  \
+		        parport_destroy(pb); 
+	if (io[0]) {
+		/* If the user specified any ports, use them */
+		int i;
+		for (i = 0; io[i] && i < PARPORT_MAX; i++) {
+			PORT(io[i], irq[i], dma[i]);
+		}
+	} else {
+		/* Go for the standard ports. */
+		PORT(0x378, -1, -1);
+		PORT(0x278, -1, -1);
+		PORT(0x3bc, -1, -1);
+#undef PORT
+	}
+
+	for (pb = parport_enumerate(); pb; pb = pb->next)
+		parport_probe_one(pb);
+
+	return 0;
+}
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	struct parport *port, *next;
+   
+	for (port = parport_enumerate(); port; port = next) {
+		next = port->next;
+		parport_destroy(port);
+		parport_proc_unregister(port);
+		kfree(port->name);
+		kfree(port);
+	}
+	
+	parport_proc_unregister(NULL);
+}
+#endif
+
+/* Exported symbols for modules. */
+
+EXPORT_SYMBOL(parport_claim);
+EXPORT_SYMBOL(parport_release);
+EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_destroy);
+EXPORT_SYMBOL(parport_register_device);
+EXPORT_SYMBOL(parport_unregister_device);
+EXPORT_SYMBOL(parport_enumerate);
+EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
+
+#ifdef CONFIG_PNP_PARPORT_AUTOPROBE
+EXPORT_SYMBOL(parport_probe);
+EXPORT_SYMBOL(parport_probe_one);
+#endif
+
+void inc_parport_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void dec_parport_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov