patch-2.2.8 linux/drivers/misc/parport_pc.c
Next file: linux/drivers/net/3c507.c
Previous file: linux/drivers/misc/parport_mfc3.c
Back to the patch index
Back to the overall index
- Lines: 149
- Date:
Mon May 10 10:26:31 1999
- Orig file:
v2.2.7/linux/drivers/misc/parport_pc.c
- Orig date:
Tue Mar 23 14:35:47 1999
diff -u --recursive --new-file v2.2.7/linux/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
@@ -53,6 +53,8 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
+static int user_specified = 0;
+
static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
parport_generic_irq(irq, (struct parport *) dev_id, regs);
@@ -103,19 +105,24 @@
void parport_pc_write_control(struct parport *p, unsigned char d)
{
+ struct parport_pc_private *priv = p->private_data;
+ priv->ctr = d;/* update soft copy */
outb(d, p->base+CONTROL);
}
unsigned char parport_pc_read_control(struct parport *p)
{
- return inb(p->base+CONTROL);
+ struct parport_pc_private *priv = p->private_data;
+ return priv->ctr;
}
unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned char old = inb(p->base+CONTROL);
- outb(((old & ~mask) ^ val), p->base+CONTROL);
- return old;
+ struct parport_pc_private *priv = p->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ outb (ctr, p->base+CONTROL);
+ return priv->ctr = ctr; /* update soft copy */
}
void parport_pc_write_status(struct parport *p, unsigned char d)
@@ -345,6 +352,8 @@
*/
static int parport_SPP_supported(struct parport *pb)
{
+ unsigned char r, w;
+
/*
* first clear an eventually pending EPP timeout
* I (sailer@ife.ee.ethz.ch) have an SMSC chipset
@@ -354,14 +363,54 @@
parport_pc_epp_clear_timeout(pb);
/* Do a simple read-write test to make sure the port exists. */
- parport_pc_write_control(pb, 0xc);
- parport_pc_write_data(pb, 0xaa);
- if (parport_pc_read_data(pb) != 0xaa) return 0;
-
- parport_pc_write_data(pb, 0x55);
- if (parport_pc_read_data(pb) != 0x55) return 0;
+ w = 0xc;
+ parport_pc_write_control(pb, w);
+
+ /* Can we read from the control register? Some ports don't
+ * allow reads, so read_control just returns a software
+ * copy. Some ports _do_ allow reads, so bypass the software
+ * copy here. In addition, some bits aren't writable. */
+ r = inb (pb->base+CONTROL);
+ if ((r & 0x3f) == w) {
+ w = 0xe;
+ parport_pc_write_control (pb, w);
+ r = inb (pb->base+CONTROL);
+ parport_pc_write_control (pb, 0xc);
+ if ((r & 0x3f) == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* That didn't work, but the user thinks there's a
+ * port here. */
+ printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* Try the data register. The data lines aren't tri-stated at
+ * this stage, so we expect back what we wrote. */
+ w = 0xaa;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w) {
+ w = 0x55;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* Didn't work with 0xaa, but the user is convinced
+ * this is the place. */
+ printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* It's possible that we can't read the control register or
+ the data register. In that case just believe the user. */
+ if (user_specified)
+ return PARPORT_MODE_PCSPP;
- return PARPORT_MODE_PCSPP;
+ return 0;
}
/* Check for ECP
@@ -712,6 +761,15 @@
if (check_region(base, 3)) return 0;
if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
return 0;
+ p->private_data = kmalloc (sizeof (struct parport_pc_private),
+ GFP_KERNEL);
+ if (!p->private_data) {
+ /* Not enough memory. */
+ printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+ parport_unregister_port (p);
+ return 0;
+ }
+ ((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
if (p->base != 0x3bc) {
if (!check_region(base+0x400,3)) {
p->modes |= parport_ECR_present(p);
@@ -725,6 +783,7 @@
}
if (!parport_SPP_supported(p)) {
/* No port. */
+ kfree (p->private_data);
parport_unregister_port (p);
return 0;
}
@@ -787,6 +846,7 @@
int count = 0, i = 0;
if (io && *io) {
/* Only probe the ports we were given. */
+ user_specified = 1;
do {
count += probe_one_port(*(io++), *(irq++), *(dma++));
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
@@ -829,6 +889,7 @@
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
parport_proc_unregister(p);
+ kfree (p->private_data);
parport_unregister_port(p);
}
p = tmp;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)