drivers: Push down BKL into various drivers
[safe/jmp/linux-2.6] / drivers / char / dtlk.c
index d4005e9..e3859d4 100644 (file)
 #include <linux/errno.h>       /* for -EBUSY */
 #include <linux/ioport.h>      /* for request_region */
 #include <linux/delay.h>       /* for loops_per_jiffy */
+#include <linux/sched.h>
+#include <linux/smp_lock.h>    /* cycle_kernel_lock() */
 #include <asm/io.h>            /* for inb_p, outb_p, inb, outb, etc. */
 #include <asm/uaccess.h>       /* for get_user, etc. */
 #include <linux/wait.h>                /* for wait_queue */
 #include <linux/init.h>                /* for __init, module_{init,exit} */
 #include <linux/poll.h>                /* for POLLIN, etc. */
 #include <linux/dtlk.h>                /* local header file for DoubleTalk values */
-#include <linux/smp_lock.h>
 
 #ifdef TRACING
 #define TRACE_TEXT(str) printk(str);
@@ -72,6 +73,7 @@
 #define TRACE_RET ((void) 0)
 #endif                         /* TRACING */
 
+static void dtlk_timer_tick(unsigned long data);
 
 static int dtlk_major;
 static int dtlk_port_lpc;
@@ -81,7 +83,7 @@ static int dtlk_has_indexing;
 static unsigned int dtlk_portlist[] =
 {0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0};
 static wait_queue_head_t dtlk_process_list;
-static struct timer_list dtlk_timer;
+static DEFINE_TIMER(dtlk_timer, dtlk_timer_tick, 0, 0);
 
 /* prototypes for file_operations struct */
 static ssize_t dtlk_read(struct file *, char __user *,
@@ -91,8 +93,8 @@ static ssize_t dtlk_write(struct file *, const char __user *,
 static unsigned int dtlk_poll(struct file *, poll_table *);
 static int dtlk_open(struct inode *, struct file *);
 static int dtlk_release(struct inode *, struct file *);
-static int dtlk_ioctl(struct inode *inode, struct file *file,
-                     unsigned int cmd, unsigned long arg);
+static long dtlk_ioctl(struct file *file,
+                      unsigned int cmd, unsigned long arg);
 
 static const struct file_operations dtlk_fops =
 {
@@ -100,7 +102,7 @@ static const struct file_operations dtlk_fops =
        .read           = dtlk_read,
        .write          = dtlk_write,
        .poll           = dtlk_poll,
-       .ioctl          = dtlk_ioctl,
+       .unlocked_ioctl = dtlk_ioctl,
        .open           = dtlk_open,
        .release        = dtlk_release,
 };
@@ -117,7 +119,6 @@ static char dtlk_write_tts(char);
 /*
    static void dtlk_handle_error(char, char, unsigned int);
  */
-static void dtlk_timer_tick(unsigned long data);
 
 static ssize_t dtlk_read(struct file *file, char __user *buf,
                         size_t count, loff_t * ppos)
@@ -262,10 +263,9 @@ static void dtlk_timer_tick(unsigned long data)
        wake_up_interruptible(&dtlk_process_list);
 }
 
-static int dtlk_ioctl(struct inode *inode,
-                     struct file *file,
-                     unsigned int cmd,
-                     unsigned long arg)
+static long dtlk_ioctl(struct file *file,
+                      unsigned int cmd,
+                      unsigned long arg)
 {
        char __user *argp = (char __user *)arg;
        struct dtlk_settings *sp;
@@ -275,7 +275,9 @@ static int dtlk_ioctl(struct inode *inode,
        switch (cmd) {
 
        case DTLK_INTERROGATE:
+               lock_kernel();
                sp = dtlk_interrogate();
+               unlock_kernel();
                if (copy_to_user(argp, sp, sizeof(struct dtlk_settings)))
                        return -EINVAL;
                return 0;
@@ -289,10 +291,12 @@ static int dtlk_ioctl(struct inode *inode,
        }
 }
 
+/* Note that nobody ever sets dtlk_busy... */
 static int dtlk_open(struct inode *inode, struct file *file)
 {
        TRACE_TEXT("(dtlk_open");
 
+       cycle_kernel_lock();
        nonseekable_open(inode, file);
        switch (iminor(inode)) {
        case DTLK_MINOR:
@@ -318,26 +322,30 @@ static int dtlk_release(struct inode *inode, struct file *file)
        }
        TRACE_RET;
        
-       del_timer(&dtlk_timer);
+       del_timer_sync(&dtlk_timer);
 
        return 0;
 }
 
 static int __init dtlk_init(void)
 {
+       int err;
+
        dtlk_port_lpc = 0;
        dtlk_port_tts = 0;
        dtlk_busy = 0;
        dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
-       if (dtlk_major == 0) {
+       if (dtlk_major < 0) {
                printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
-               return 0;
+               return dtlk_major;
+       }
+       err = dtlk_dev_probe();
+       if (err) {
+               unregister_chrdev(dtlk_major, "dtlk");
+               return err;
        }
-       if (dtlk_dev_probe() == 0)
-               printk(", MAJOR %d\n", dtlk_major);
+       printk(", MAJOR %d\n", dtlk_major);
 
-       init_timer(&dtlk_timer);
-       dtlk_timer.function = dtlk_timer_tick;
        init_waitqueue_head(&dtlk_process_list);
 
        return 0;
@@ -565,7 +573,7 @@ static char dtlk_read_tts(void)
                portval = inb_p(dtlk_port_tts);
        } while ((portval & TTS_READABLE) == 0 &&
                 retries++ < DTLK_MAX_RETRIES);
-       if (retries == DTLK_MAX_RETRIES)
+       if (retries > DTLK_MAX_RETRIES)
                printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
        ch = inb_p(dtlk_port_tts);      /* input from TTS port */
@@ -577,7 +585,7 @@ static char dtlk_read_tts(void)
                portval = inb_p(dtlk_port_tts);
        } while ((portval & TTS_READABLE) != 0 &&
                 retries++ < DTLK_MAX_RETRIES);
-       if (retries == DTLK_MAX_RETRIES)
+       if (retries > DTLK_MAX_RETRIES)
                printk(KERN_ERR "dtlk_read_tts() timeout\n");
 
        TRACE_RET;
@@ -634,7 +642,7 @@ static char dtlk_write_tts(char ch)
                while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
                       retries++ < DTLK_MAX_RETRIES)    /* DT ready? */
                        ;
-       if (retries == DTLK_MAX_RETRIES)
+       if (retries > DTLK_MAX_RETRIES)
                printk(KERN_ERR "dtlk_write_tts() timeout\n");
 
        outb_p(ch, dtlk_port_tts);      /* output to TTS port */