patch-2.4.0-test2 linux/drivers/char/ppdev.c
Next file: linux/drivers/char/qpmouse.c
Previous file: linux/drivers/char/pcwd.c
Back to the patch index
Back to the overall index
- Lines: 164
- Date:
Wed Jun 21 22:31:01 2000
- Orig file:
v2.4.0-test1/linux/drivers/char/ppdev.c
- Orig date:
Wed Apr 26 16:34:07 2000
diff -u --recursive --new-file v2.4.0-test1/linux/drivers/char/ppdev.c linux/drivers/char/ppdev.c
@@ -83,6 +83,63 @@
/* ROUND_UP macro from fs/select.c */
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+struct pp_port_list_struct {
+ struct parport *port;
+ struct pp_port_list_struct *next;
+};
+static struct pp_port_list_struct *pp_port_list;
+static DECLARE_MUTEX(pp_port_list_lock);
+
+/* pp_attach and pp_detach are for keeping a list of currently
+ * available ports, held under a mutex. We do this rather than
+ * using parport_enumerate because it stops a load of races.
+ */
+
+static void pp_attach (struct parport *port)
+{
+ struct pp_port_list_struct *add;
+
+ add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL);
+ if (!add) {
+ printk (KERN_WARNING CHRDEV ": memory squeeze\n");
+ return;
+ }
+
+ add->next = pp_port_list;
+ down (&pp_port_list_lock);
+ pp_port_list = add;
+ up (&pp_port_list_lock);
+}
+
+static void pp_detach (struct parport *port)
+{
+ struct pp_port_list_struct *del;
+
+ down (&pp_port_list_lock);
+ del = pp_port_list;
+ if (del->port == port)
+ pp_port_list = del->next;
+ else {
+ struct pp_port_list_struct *prev;
+ do {
+ prev = del;
+ del = del->next;
+ } while (del && del->port != port);
+ if (del)
+ prev->next = del->next;
+ }
+ up (&pp_port_list_lock);
+
+ if (del)
+ kfree (del);
+}
+
+static struct parport_driver ppdev_driver = {
+ name: CHRDEV,
+ attach: pp_attach,
+ detach: pp_detach
+};
+
static inline void pp_enable_irq (struct pp_struct *pp)
{
struct parport *port = pp->pdev->port;
@@ -216,7 +273,7 @@
static int register_device (int minor, struct pp_struct *pp)
{
- struct parport * port;
+ struct pp_port_list_struct *ports;
struct pardevice * pdev = NULL;
char *name;
int fl;
@@ -226,20 +283,24 @@
return -ENOMEM;
sprintf (name, CHRDEV "%x", minor);
- port = parport_enumerate (); /* FIXME: use attach/detach */
- while (port && port->number != minor)
- port = port->next;
+ down (&pp_port_list_lock);
+ ports = pp_port_list;
+ while (ports && ports->port->number != minor)
+ ports = ports->next;
+ if (ports->port) {
+ fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+ pdev = parport_register_device (ports->port, name, NULL,
+ NULL, pp_irq, fl, pp);
+ }
+ up (&pp_port_list_lock);
- if (!port) {
+ if (!ports->port) {
printk (KERN_WARNING "%s: no associated port!\n", name);
kfree (name);
return -ENXIO;
}
- fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
- pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
- pp);
if (!pdev) {
printk (KERN_WARNING "%s: failed to register device!\n", name);
@@ -507,13 +568,9 @@
if (minor >= PARPORT_MAX)
return -ENXIO;
- MOD_INC_USE_COUNT;
-
pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL);
- if (!pp) {
- MOD_DEC_USE_COUNT;
+ if (!pp)
return -ENOMEM;
- }
pp->state.mode = IEEE1284_MODE_COMPAT;
pp->state.phase = init_phase (pp->state.mode);
@@ -565,7 +622,6 @@
kfree (pp);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -583,6 +639,7 @@
}
static struct file_operations pp_fops = {
+ owner: THIS_MODULE,
llseek: pp_lseek,
read: pp_read,
write: pp_write,
@@ -596,6 +653,10 @@
static int __init ppdev_init (void)
{
+ if (parport_register_driver (&ppdev_driver)) {
+ printk (KERN_WARNING CHRDEV ": unable to register driver\n");
+ return -EIO;
+ }
if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
@@ -604,7 +665,7 @@
devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL);
devfs_register_series (devfs_handle, "%u", PARPORT_MAX,
DEVFS_FL_DEFAULT, PP_MAJOR, 0,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&pp_fops, NULL);
printk (KERN_INFO PP_VERSION "\n");
@@ -616,6 +677,7 @@
/* Clean up all parport stuff */
devfs_unregister (devfs_handle);
devfs_unregister_chrdev (PP_MAJOR, CHRDEV);
+ parport_unregister_driver (&ppdev_driver);
}
module_init(ppdev_init);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)