patch-2.1.36 linux/drivers/pnp/parport_init.c
Next file: linux/drivers/pnp/parport_procfs.c
Previous file: linux/drivers/pnp/TODO-parport
Back to the patch index
Back to the overall index
- Lines: 569
- Date:
Tue Apr 22 09:32:11 1997
- Orig file:
v2.1.35/linux/drivers/pnp/parport_init.c
- Orig date:
Mon Apr 14 16:28:12 1997
diff -u --recursive --new-file v2.1.35/linux/drivers/pnp/parport_init.c linux/drivers/pnp/parport_init.c
@@ -1,4 +1,4 @@
-/* $Id: parport_init.c,v 1.1.2.4 1997/04/01 18:19:10 phil Exp $
+/* $Id: parport_init.c,v 1.3.2.4 1997/04/16 21:20:44 phil Exp $
* Parallel-port initialisation code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -26,8 +26,8 @@
#include "parport_ll_io.h"
static int io[PARPORT_MAX] = { 0, };
-static int irq[PARPORT_MAX] = { -1, };
-static int dma[PARPORT_MAX] = { -1, };
+static int irq[PARPORT_MAX] = { PARPORT_IRQ_NONE, };
+static int dma[PARPORT_MAX] = { PARPORT_DMA_NONE, };
/******************************************************
* DMA detection section:
@@ -76,7 +76,7 @@
return dma;
}
-static int parport_detect_dma_transfer(int dma,int size)
+static int parport_detect_dma_transfer(int dma,int size,int *resid)
{
int i,n,retv;
int count=0;
@@ -88,10 +88,11 @@
clear_dma_ff(i);
n = get_dma_residue(i);
if (n != size) {
+ *resid = n;
retv = i;
if (count > 0) {
retv = -1; /* Multiple DMA's */
- printk("Multiple DMA detected.\n");
+ printk(KERN_ERR "parport: multiple DMA detected. Huh?\n");
}
count++;
}
@@ -118,7 +119,7 @@
return dma;
}
-/* Only called if port support ECP mode.
+/* Only called if port supports 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
@@ -146,12 +147,11 @@
char *buff;
retv = programmable_dma_support(pb);
- if( retv != -1 )
+ if (retv != -1)
return retv;
- buff = kmalloc(16, GFP_KERNEL | GFP_DMA);
- if( !buff ){
- printk("parport: memory squezze\n");
+ if (!(buff = kmalloc(2048, GFP_KERNEL | GFP_DMA))) {
+ printk(KERN_ERR "parport: memory squeeze\n");
return -1;
}
@@ -160,24 +160,26 @@
w_ecr(pb, 0xc0); /* ECP MODE */
w_ctr(pb, dsr_read );
- dma=parport_prepare_dma(buff,8);
+ dma=parport_prepare_dma(buff,1000);
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);
+ udelay(500); /* Give some for DMA tranfer */
+ retv = parport_detect_dma_transfer(dma,1000,&pb->speed);
+ pb->speed = pb->speed * 2000; /* 500uSec * 2000 = 1sec */
/*
* National Semiconductors only supports DMA tranfers
* in ECP MODE
*/
- if( retv == -1 ){
+ if (retv == -1) {
w_ecr(pb, 0x60); /* ECP MODE */
w_ctr(pb, dsr_read );
- dma=parport_prepare_dma(buff,8);
+ dma=parport_prepare_dma(buff,1000);
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);
+ udelay(500); /* Give some for DMA tranfer */
+ retv = parport_detect_dma_transfer(dma,1000,&pb->speed);
+ pb->speed = pb->speed * 2000; /* 500uSec * 2000 = 1sec */
}
kfree(buff);
@@ -198,10 +200,10 @@
{
int r;
- if( !(r_str(pb) & 0x01) )
+ if (!(r_str(pb) & 0x01))
return 1;
- /* To clear timeout some chip requiere double read */
+ /* To clear timeout some chips require double read */
r_str(pb);
r = r_str(pb);
w_str(pb, r | 0x01); /* Some reset by writing 1 */
@@ -213,23 +215,18 @@
/*
- * Checks for por existence, all ports support SPP MODE
+ * Checks for port 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);
+ if (r_dtr(pb) != 0xaa) return 0;
w_dtr(pb, 0x55);
- rr = r_dtr(pb);
-
- if (r != 0xaa || rr != 0x55) {
- return 0;
- }
-
+ if (r_dtr(pb) != 0x55) return 0;
+
return PARPORT_MODE_SPP;
}
@@ -249,23 +246,20 @@
{
int r;
- if( pb->base == 0x3BC )
- return 0;
-
r= r_ctr(pb);
- if( (r_ecr(pb) & 0x03) == (r & 0x03) ){
+ 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) )
+ if ((r_ecr(pb) & 0x03) == (r & 0x03))
return 0; /* Sure that no ECR register exists */
}
- if( (r_ecr(pb) & 0x03 ) != 0x01 )
+ if ((r_ecr(pb) & 0x03 ) != 0x01)
return 0;
w_ecr(pb,0x34);
- if( r_ecr(pb) != 0x35 )
+ if (r_ecr(pb) != 0x35)
return 0;
w_ecr(pb,pb->ecr);
@@ -278,20 +272,22 @@
{
int i;
- if( !(pb->modes & PARPORT_MODE_ECR) )
+ /* If there is no ECR, we have no hope of supporting ECP. */
+ if (!(pb->modes & PARPORT_MODE_ECR))
return 0;
+
/*
- * Usign LGS chipset it uses ECR register, but
+ * Using 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_ecr(pb, 0xc0); /* TEST FIFO */
+ for (i=0; i < 1024 && (r_ecr(pb) & 0x01); i++)
w_fifo(pb, 0xaa);
- w_ecr(pb,pb->ecr);
+ w_ecr(pb, pb->ecr);
- if( i >= 1024 )
+ if (i == 1024)
return 0;
return PARPORT_MODE_ECP;
@@ -311,11 +307,8 @@
*/
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) )
+ if (!epp_clear_timeout(pb))
return 0; /* No way to clear timeout */
w_ctr(pb, r_ctr(pb) | 0x20);
@@ -325,7 +318,7 @@
r_epp(pb);
udelay(30); /* Wait for possible EPP timeout */
- if( r_str(pb) & 0x01 ){
+ if (r_str(pb) & 0x01) {
epp_clear_timeout(pb);
return PARPORT_MODE_EPP;
}
@@ -337,7 +330,7 @@
{
int mode;
- if( !(pb->modes & PARPORT_MODE_ECR) )
+ if (!(pb->modes & PARPORT_MODE_ECR))
return 0;
/* Search for SMC style EPP+ECP mode */
@@ -345,47 +338,55 @@
mode = parport_EPP_supported(pb);
- w_ecr(pb,pb->ecr);
+ w_ecr(pb, pb->ecr);
- if( mode )
+ 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.
+/* Detect PS/2 support.
+ *
+ * Bit 5 (0x20) sets the PS/2 data direction; setting this high
+ * allows us to read data from the data lines. In theory we would get back
+ * 0xff but any peripheral attached to the port may drag some or all of the
+ * lines down to zero. So if we get back anything that isn't the contents
+ * of the data register we deem PS/2 support to be present.
+ *
+ * Some SPP ports have "half PS/2" ability - you can't turn off the line
+ * drivers, but an external peripheral with sufficiently beefy drivers of
+ * its own can overpower them and assert its own levels onto the bus, from
+ * where they can then be read back as normal. Ports with this property
+ * and the right type of device attached are likely to fail the SPP test,
+ * (as they will appear to have stuck bits) and so the fact that they might
+ * be misdetected here is rather academic.
*/
+
static int parport_PS2_supported(struct parport *pb)
{
- int r,rr;
-
+ int ok = 0;
+
epp_clear_timeout(pb);
- w_ctr(pb, pb->ctr | 0x20); /* Tri-state the buffer */
+ w_ctr(pb, pb->ctr | 0x20); /* try to 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_dtr(pb) != 0x55) ok++;
- if (r != 0xAA || rr != 0x55 )
- return PARPORT_MODE_PS2;
+ w_dtr(pb, 0xaa);
+ if (r_dtr(pb) != 0xaa) ok++;
- return 0;
+ w_ctr(pb, pb->ctr); /* cancel input mode */
+
+ return ok?PARPORT_MODE_PS2:0;
}
static int parport_ECPPS2_supported(struct parport *pb)
{
int mode;
- if( !(pb->modes & PARPORT_MODE_ECR) )
+ if (!(pb->modes & PARPORT_MODE_ECR))
return 0;
w_ecr(pb, 0x20);
@@ -402,15 +403,19 @@
/******************************************************
* 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...)
+ *
+ * This is horribly x86-specific at the moment. I'm not convinced it
+ * belongs at all.
*/
+
static int intr_vote[16];
+
static void parport_vote_intr_func(int irq, void *dev_id, struct pt_regs *regs)
{
intr_vote[irq]++;
@@ -434,17 +439,16 @@
static int close_intr_election(long tmp)
{
- long max_vote = 0;
- int irq = -1;
+ int irq = PARPORT_IRQ_NONE;
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];
+ if (intr_vote[i]) {
+ if (irq != PARPORT_IRQ_NONE)
+ /* More than one interrupt */
+ return PARPORT_IRQ_NONE;
irq = i;
}
free_irq(i, intr_vote);
@@ -488,7 +492,7 @@
irqs = open_intr_election();
w_ecr(pb, 0x00); /* Reset FIFO */
- w_ctr(pb, pb->ctr ); /* Force direction = 0 */
+ w_ctr(pb, pb->ctr ); /* Force direction = 0 */
w_ecr(pb, 0xd0); /* TEST FIFO + nErrIntrEn */
/* If Full FIFO sure that WriteIntrThresold is generated */
@@ -497,8 +501,6 @@
}
pb->irq = close_intr_election(irqs);
- if (pb->irq == 0)
- pb->irq = -1; /* No interrupt detected */
w_ecr(pb, pb->ecr);
@@ -506,7 +508,7 @@
}
/*
- * It's called only if supports EPP on National Semiconductors
+ * This detection seems that only works in National Semiconductors
* This doesn't work in SMC, LGS, and Winbond
*/
static int irq_probe_EPP(struct parport *pb)
@@ -535,8 +537,6 @@
udelay(20);
pb->irq = close_intr_election(irqs);
- if (pb->irq == 0)
- pb->irq = -1; /* No interrupt detected */
w_ctr(pb,pb->ctr);
@@ -572,7 +572,7 @@
pb->irq = probe_irq_off(irqs);
if (pb->irq <= 0)
- pb->irq = -1; /* No interrupt detected */
+ pb->irq = PARPORT_IRQ_NONE; /* No interrupt detected */
w_ctr(pb,pb->ctr);
@@ -583,18 +583,18 @@
* such as sound cards and network cards seem to like using the
* printer IRQs.
*
- * When LP_ECP is available we can autoprobe for IRQs.
+ * When 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 )
+ if (pb->modes & PARPORT_MODE_ECR)
pb->irq = programmable_irq_support(pb);
- if( pb->modes & PARPORT_MODE_ECP )
+ if (pb->modes & PARPORT_MODE_ECP)
pb->irq = irq_probe_ECP(pb);
- if( pb->irq == -1 && (pb->modes & PARPORT_MODE_ECPEPP)){
+ if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_ECPEPP)) {
w_ecr(pb,0x80);
pb->irq = irq_probe_EPP(pb);
w_ecr(pb,pb->ecr);
@@ -602,12 +602,12 @@
epp_clear_timeout(pb);
- if( pb->irq == -1 && (pb->modes & PARPORT_MODE_EPP))
+ if (pb->irq == PARPORT_IRQ_NONE && (pb->modes & PARPORT_MODE_EPP))
pb->irq = irq_probe_EPP(pb);
epp_clear_timeout(pb);
- if( pb->irq == -1 )
+ if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = irq_probe_SPP(pb);
return pb->irq;
@@ -618,12 +618,12 @@
{
/* Check some parameters */
if (dma < -2) {
- printk("parport: Invalid DMA[%d] at base 0x%lx\n",dma,base);
+ printk(KERN_ERR "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);
+ printk(KERN_ERR "parport: Invalid IRQ[%d] at base 0x%lx\n",irq,base);
return 0;
}
@@ -643,7 +643,7 @@
pb->name = kmalloc(15, GFP_KERNEL);
if (!pb->name) {
- printk("parport: memory squeeze\n");
+ printk(KERN_ERR "parport: memory squeeze\n");
return 0;
}
sprintf(pb->name, "parport%d", count);
@@ -657,12 +657,15 @@
}
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);
+
+ if (pb->base != 0x3bc) {
+ pb->modes |= parport_ECR_present(pb);
+ pb->modes |= parport_ECP_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)) &&
@@ -678,17 +681,17 @@
/* DMA check */
if (pb->modes & PARPORT_MODE_ECP) {
- if (pb->dma == -1)
+ if (pb->dma == PARPORT_DMA_NONE)
pb->dma = parport_dma_probe(pb);
else if (pb->dma == -2)
- pb->dma = -1;
+ pb->dma = PARPORT_DMA_NONE;
}
/* IRQ check */
- if (pb->irq == -1)
+ if (pb->irq == PARPORT_IRQ_NONE)
pb->irq = parport_irq_probe(pb);
else if (pb->irq == -2)
- pb->irq = -1;
+ pb->irq = PARPORT_IRQ_NONE;
return 1;
}
@@ -700,7 +703,7 @@
{
if (ints[0] == 0 || ints[1] == 0) {
/* Disable parport if "parport=" or "parport=0" in cmdline */
- io[0] = -2;
+ io[0] = PARPORT_DISABLE;
return;
}
if (parport_setup_ptr < PARPORT_MAX) {
@@ -738,17 +741,20 @@
struct parport *pb;
printk(KERN_INFO "Parallel port sharing: %s\n",
- "$Revision: 1.1.2.4 $");
+ "$Revision: 1.3.2.4 $");
- if (io[0] == -2) return 1;
+ if (io[0] == PARPORT_DISABLE) return 1;
- /* Register /proc/parport */
- parport_proc_register(NULL);
+#ifdef CONFIG_PROC_FS
+ parport_proc_init();
+#endif
/* 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;
@@ -757,16 +763,22 @@
}
} else {
/* Go for the standard ports. */
- PORT(0x378, -1, -1);
- PORT(0x278, -1, -1);
- PORT(0x3bc, -1, -1);
+ PORT(0x378, PARPORT_IRQ_NONE, PARPORT_DMA_NONE);
+ PORT(0x278, PARPORT_IRQ_NONE, PARPORT_DMA_NONE);
+ PORT(0x3bc, PARPORT_IRQ_NONE, PARPORT_DMA_NONE);
#undef PORT
}
+#if defined(CONFIG_PNP_PARPORT_AUTOPROBE) || defined(CONFIG_PROC_FS)
+ for (pb = parport_enumerate(); pb; pb = pb->next) {
#ifdef CONFIG_PNP_PARPORT_AUTOPROBE
- for (pb = parport_enumerate(); pb; pb = pb->next)
parport_probe_one(pb);
#endif
+#ifdef CONFIG_PROC_FS
+ parport_proc_register(pb);
+#endif
+ }
+#endif
return 0;
}
@@ -784,7 +796,7 @@
kfree(port);
}
- parport_proc_unregister(NULL);
+ parport_proc_cleanup();
}
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov