summaryrefslogtreecommitdiffstats
path: root/drivers/char/ppdev.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-06-19 22:45:37 +0000
commit6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch)
tree0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /drivers/char/ppdev.c
parentecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff)
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine status unknown.
Diffstat (limited to 'drivers/char/ppdev.c')
-rw-r--r--drivers/char/ppdev.c90
1 files changed, 76 insertions, 14 deletions
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index f4c84ac95..819ed0b1a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -83,6 +83,63 @@ struct pp_struct {
/* 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 void pp_irq (int irq, void * private, struct pt_regs * unused)
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 @@ static int register_device (int minor, struct pp_struct *pp)
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 @@ static int pp_open (struct inode * inode, struct file * file)
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 @@ static int pp_release (struct inode * inode, struct file * file)
kfree (pp);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -583,6 +639,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
}
static struct file_operations pp_fops = {
+ owner: THIS_MODULE,
llseek: pp_lseek,
read: pp_read,
write: pp_write,
@@ -596,6 +653,10 @@ static devfs_handle_t devfs_handle = NULL;
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);
@@ -616,6 +677,7 @@ static void __exit ppdev_cleanup (void)
/* Clean up all parport stuff */
devfs_unregister (devfs_handle);
devfs_unregister_chrdev (PP_MAJOR, CHRDEV);
+ parport_unregister_driver (&ppdev_driver);
}
module_init(ppdev_init);