Re: [PARPORT] ppdev ECP addr ops


Tim Waugh (tim@cyberelk.demon.co.uk)
Mon, 26 Jul 1999 20:52:43 +0100 (GMT)


On Mon, 26 Jul 1999, Thomas Sailer wrote:

> Another issue: the parport probing routines play games with
> parport_pc_ops, replacing method pointers there, and then a reference
> to parport_pc_ops is stored in parport->ops. Doesn't that mean that
> all PC parports share the same method table? That does only work if
> all ports have the same hw capabilities...

I've fixed that now, and while I was about it I've made unregistered ports
that still have registered device drivers persist until the device drivers
take notice of the detach() call on them.

Tim.
*/

diff -durN linux-current/drivers/parport/parport_pc.c linux/drivers/parport/parport_pc.c
--- linux-current/drivers/parport/parport_pc.c Mon Jul 26 16:55:03 1999
+++ linux/drivers/parport/parport_pc.c Mon Jul 26 20:42:58 1999
@@ -1521,6 +1521,7 @@
                                  int irq, int dma)
 {
         struct parport_pc_private *priv;
+ struct parport_operations *ops;
         struct parport tmp;
         struct parport *p = &tmp;
         int probedirq = PARPORT_IRQ_NONE;
@@ -1530,6 +1531,14 @@
                 printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
                 return 0;
         }
+ ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+ if (!ops) {
+ printk (KERN_DEBUG "parport (0x%lx): no memory for ops!\n",
+ base);
+ kfree (priv);
+ return 0;
+ }
+ memcpy (ops, &parport_pc_ops, sizeof (struct parport_operations));
         priv->ctr = 0xc;
         priv->ctr_writable = 0xff;
         priv->ecr = 0;
@@ -1540,7 +1549,7 @@
         p->irq = irq;
         p->dma = dma;
         p->modes = PARPORT_MODE_PCSPP;
- p->ops = &parport_pc_ops;
+ p->ops = ops;
         p->private_data = priv;
         p->physport = p;
         if (base_hi && !check_region(base_hi,3)) {
@@ -1564,8 +1573,9 @@
         parport_PS2_supported (p);
 
         if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
- PARPORT_DMA_NONE, &parport_pc_ops))) {
+ PARPORT_DMA_NONE, ops))) {
                 kfree (priv);
+ kfree (ops);
                 return 0;
         }
 
@@ -1896,6 +1906,7 @@
                         if (priv->dma_buf)
                                 free_page((unsigned long) priv->dma_buf);
                         kfree (p->private_data);
+ kfree (p->ops); /* hope no-one cached it */
                         parport_unregister_port(p);
                 }
                 p = tmp;
diff -durN linux-current/drivers/parport/share.c linux/drivers/parport/share.c
--- linux-current/drivers/parport/share.c Mon Jul 26 16:55:03 1999
+++ linux/drivers/parport/share.c Mon Jul 26 20:27:30 1999
@@ -41,6 +41,51 @@
 static struct parport_driver *driver_chain = NULL;
 spinlock_t driverlist_lock = SPIN_LOCK_UNLOCKED;
 
+/* What you can do to a port that's gone away.. */
+static void dead_write_lines (struct parport *p, unsigned char b){}
+static unsigned char dead_read_lines (struct parport *p) { return 0; }
+static unsigned char dead_frob_lines (struct parport *p, unsigned char b,
+ unsigned char c) { return 0; }
+static void dead_onearg (struct parport *p){}
+static void dead_irq (int i, void *p, struct pt_regs *r) { }
+static void dead_initstate (struct pardevice *d, struct parport_state *s) { }
+static void dead_state (struct parport *p, struct parport_state *s) { }
+static void dead_noargs (void) { }
+static void dead_fill (struct inode *i, int f) { }
+static size_t dead_write (struct parport *p, const void *b, size_t l, int f)
+{ return 0; }
+static size_t dead_read (struct parport *p, void *b, size_t l, int f)
+{ return 0; }
+static struct parport_operations dead_ops = {
+ dead_write_lines, /* data */
+ dead_read_lines,
+ dead_write_lines, /* control */
+ dead_read_lines,
+ dead_frob_lines,
+ dead_read_lines, /* status */
+ dead_onearg, /* enable_irq */
+ dead_onearg, /* disable_irq */
+ dead_onearg, /* data_forward */
+ dead_onearg, /* data_reverse */
+ dead_irq,
+ dead_initstate, /* init_state */
+ dead_state,
+ dead_state,
+ dead_noargs, /* xxx_use_count */
+ dead_noargs,
+ dead_fill, /* fill_inode */
+ dead_write, /* epp */
+ dead_read,
+ dead_write,
+ dead_read,
+ dead_write, /* ecp */
+ dead_read,
+ dead_write,
+ dead_write, /* compat */
+ dead_read, /* nibble */
+ dead_read /* byte */
+};
+
 static void call_driver_chain(int attach, struct parport *port)
 {
         struct parport_driver *drv;
@@ -188,10 +233,31 @@
         call_driver_chain (1, port);
 }
 
+static void free_port (struct parport *port)
+{
+ int d;
+ for (d = 0; d < 5; d++) {
+ if (port->probe_info[d].class_name)
+ kfree (port->probe_info[d].class_name);
+ if (port->probe_info[d].mfr)
+ kfree (port->probe_info[d].mfr);
+ if (port->probe_info[d].model)
+ kfree (port->probe_info[d].model);
+ if (port->probe_info[d].cmdset)
+ kfree (port->probe_info[d].cmdset);
+ if (port->probe_info[d].description)
+ kfree (port->probe_info[d].description);
+ }
+
+ kfree(port->name);
+ kfree(port);
+}
+
 void parport_unregister_port(struct parport *port)
 {
         struct parport *p;
- int d;
+
+ port->ops = &dead_ops;
 
         /* Spread the word. */
         call_driver_chain (0, port);
@@ -217,21 +283,8 @@
         }
         spin_unlock(&parportlist_lock);
 
- for (d = 0; d < 5; d++) {
- if (port->probe_info[d].class_name)
- kfree (port->probe_info[d].class_name);
- if (port->probe_info[d].mfr)
- kfree (port->probe_info[d].mfr);
- if (port->probe_info[d].model)
- kfree (port->probe_info[d].model);
- if (port->probe_info[d].cmdset)
- kfree (port->probe_info[d].cmdset);
- if (port->probe_info[d].description)
- kfree (port->probe_info[d].description);
- }
-
- kfree(port->name);
- kfree(port);
+ if (!port->devices)
+ free_port (port);
 }
 
 struct pardevice *parport_register_device(struct parport *port, const char *name,
@@ -361,6 +414,11 @@
 
         dec_parport_count();
         port->ops->dec_use_count();
+
+ /* If this was the last device on a port that's already gone away,
+ * free up the resources. */
+ if (port->ops == &dead_ops && !port->devices)
+ free_port (port);
 }
 
 int parport_claim(struct pardevice *dev)

-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --



This archive was generated by hypermail 2.0b3 on Mon 26 Jul 1999 - 15:56:35 EDT