I didn't want to do this, but it looks like it's necessary.
I'd like to add two functions to the parport API, for reference
counting the ports.
* Don't use parport_enumerate
* Do use parport_register_driver
* In your attach(port) function, port is valid. To make it valid
outside the attach() function, use parport_get_port, and remember to
use parport_put_port when you're done with it (at module unload or
whenever).
Comments?
Tim.
*/
Index: drivers/parport/share.c
===================================================================
RCS file: /usr/local/src/cvsroot/linux/drivers/parport/share.c,v
retrieving revision 1.15
diff -d -u -r1.15 share.c
--- drivers/parport/share.c 2000/06/06 13:15:55 1.15
+++ drivers/parport/share.c 2000/06/15 17:33:14
@@ -87,6 +87,7 @@
{
struct parport_driver *drv;
+ parport_get_port (port);
spin_lock (&driverlist_lock);
for (drv = driver_chain; drv; drv = drv->next) {
if (attach)
@@ -95,6 +96,7 @@
drv->detach (port);
}
spin_unlock (&driverlist_lock);
+ parport_put_port (port);
}
/* Ask kmod for some lowlevel drivers. */
@@ -196,6 +198,53 @@
}
}
+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);
+}
+
+/**
+ * parport_get_port - increment the port's reference count
+ *
+ * This ensure's that a struct parport pointer remains valid
+ * until the matching parport_put_port() call.
+ **/
+struct parport *parport_get_port (struct parport *port)
+{
+ atomic_inc (&port->ref_count);
+ return port;
+}
+
+/**
+ * parport_put_port - decrement the port's reference count
+ *
+ * This should be called once for each call to parport_get_port(),
+ * once the port is no longer needed.
+ **/
+void parport_put_port (struct parport *port)
+{
+ if (!atomic_dec_and_test (&port->ref_count))
+ /* Can destroy it now. */
+ free_port (port);
+
+ return;
+}
+
/**
* parport_enumerate - return a list of the system's parallel ports
*
@@ -298,6 +347,7 @@
tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
tmp->spintime = parport_default_spintime;
+ atomic_set (&tmp->ref_count, 0);
name = kmalloc(15, GFP_KERNEL);
if (!name) {
@@ -377,26 +427,6 @@
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);
-}
-
/**
* parport_unregister_port - deregister a parallel port
* @port: parallel port to deregister
@@ -451,7 +481,7 @@
spin_unlock(&parportlist_lock);
/* Yes, parport_enumerate _is_ unsafe. Don't use it. */
- if (!port->devices)
+ if (!atomic_read (&port->ref_count))
free_port (port);
}
Index: include/linux/parport.h
===================================================================
RCS file: /usr/local/src/cvsroot/linux/include/linux/parport.h,v
retrieving revision 1.7
diff -d -u -r1.7 parport.h
--- include/linux/parport.h 2000/04/06 10:22:15 1.7
+++ include/linux/parport.h 2000/06/15 17:33:14
@@ -302,6 +302,7 @@
rwlock_t cad_lock;
int spintime;
+ atomic_t ref_count;
};
#define DEFAULT_SPIN_TIME 500 /* us */
@@ -330,12 +331,9 @@
/* Unregister a port. */
extern void parport_unregister_port(struct parport *port);
-/* parport_in_use returns nonzero if there are devices attached to a
- port. */
-#define parport_in_use(x) ((x)->devices != NULL)
-
/* parport_enumerate returns a pointer to the linked list of all the
- ports in this machine. */
+ ports in this machine. DON'T USE THIS. Use
+ parport_register_driver instead. */
struct parport *parport_enumerate(void);
/* Register a new high-level driver. */
@@ -343,6 +341,10 @@
/* Unregister a high-level driver. */
extern void parport_unregister_driver (struct parport_driver *);
+
+/* Reference counting for ports. */
+extern struct parport *parport_get_port (struct parport *);
+extern void parport_put_port (struct parport *);
/* parport_register_device declares that a device is connected to a
port, and tells the kernel all it needs to know.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/
This archive was generated by hypermail 2b29 : Thu Jun 15 2000 - 21:00:35 EST