patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / char / ppdev.c
index 525905c..5eda075 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/ioctl.h>
 #include <linux/parport.h>
@@ -102,7 +103,7 @@ static inline void pp_enable_irq (struct pp_struct *pp)
        port->ops->enable_irq (port);
 }
 
-static ssize_t pp_read (struct file * file, char * buf, size_t count,
+static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
                        loff_t * ppos)
 {
        unsigned int minor = iminor(file->f_dentry->d_inode);
@@ -185,8 +186,8 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
        return bytes_read;
 }
 
-static ssize_t pp_write (struct file * file, const char * buf, size_t count,
-                        loff_t * ppos)
+static ssize_t pp_write (struct file * file, const char __user * buf,
+                        size_t count, loff_t * ppos)
 {
        unsigned int minor = iminor(file->f_dentry->d_inode);
        struct pp_struct *pp = file->private_data;
@@ -334,6 +335,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
        unsigned int minor = iminor(inode);
        struct pp_struct *pp = file->private_data;
        struct parport * port;
+       void __user *argp = (void __user *)arg;
 
        /* First handle the cases that don't take arguments. */
        switch (cmd) {
@@ -395,7 +397,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
        case PPSETMODE:
            {
                int mode;
-               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+               if (copy_from_user (&mode, argp, sizeof (mode)))
                        return -EFAULT;
                /* FIXME: validate mode */
                pp->state.mode = mode;
@@ -417,7 +419,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                } else {
                        mode = pp->state.mode;
                }
-               if (copy_to_user ((int *)arg, &mode, sizeof (mode))) {
+               if (copy_to_user (argp, &mode, sizeof (mode))) {
                        return -EFAULT;
                }
                return 0;
@@ -425,7 +427,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
        case PPSETPHASE:
            {
                int phase;
-               if (copy_from_user (&phase, (int *) arg, sizeof (phase))) {
+               if (copy_from_user (&phase, argp, sizeof (phase))) {
                        return -EFAULT;
                }
                /* FIXME: validate phase */
@@ -446,7 +448,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                } else {
                        phase = pp->state.phase;
                }
-               if (copy_to_user ((int *)arg, &phase, sizeof (phase))) {
+               if (copy_to_user (argp, &phase, sizeof (phase))) {
                        return -EFAULT;
                }
                return 0;
@@ -460,7 +462,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                        return -ENODEV;
 
                modes = port->modes;
-               if (copy_to_user ((unsigned int *)arg, &modes, sizeof (modes))) {
+               if (copy_to_user (argp, &modes, sizeof (modes))) {
                        return -EFAULT;
                }
                return 0;
@@ -469,7 +471,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
            {
                int uflags;
 
-               if (copy_from_user (&uflags, (int *)arg, sizeof (uflags))) {
+               if (copy_from_user (&uflags, argp, sizeof (uflags))) {
                        return -EFAULT;
                }
                pp->flags &= ~PP_FLAGMASK;
@@ -481,7 +483,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                int uflags;
 
                uflags = pp->flags & PP_FLAGMASK;
-               if (copy_to_user ((int *)arg, &uflags, sizeof (uflags))) {
+               if (copy_to_user (argp, &uflags, sizeof (uflags))) {
                        return -EFAULT;
                }
                return 0;
@@ -508,17 +510,17 @@ static int pp_ioctl(struct inode *inode, struct file *file,
 
        case PPRSTATUS:
                reg = parport_read_status (port);
-               if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+               if (copy_to_user (argp, &reg, sizeof (reg)))
                        return -EFAULT;
                return 0;
        case PPRDATA:
                reg = parport_read_data (port);
-               if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+               if (copy_to_user (argp, &reg, sizeof (reg)))
                        return -EFAULT;
                return 0;
        case PPRCONTROL:
                reg = parport_read_control (port);
-               if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+               if (copy_to_user (argp, &reg, sizeof (reg)))
                        return -EFAULT;
                return 0;
        case PPYIELD:
@@ -537,29 +539,29 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case PPWCONTROL:
-               if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+               if (copy_from_user (&reg, argp, sizeof (reg)))
                        return -EFAULT;
                parport_write_control (port, reg);
                return 0;
 
        case PPWDATA:
-               if (copy_from_user (&reg, (unsigned char *) arg, sizeof (reg)))
+               if (copy_from_user (&reg, argp, sizeof (reg)))
                        return -EFAULT;
                parport_write_data (port, reg);
                return 0;
 
        case PPFCONTROL:
-               if (copy_from_user (&mask, (unsigned char *) arg,
+               if (copy_from_user (&mask, argp,
                                    sizeof (mask)))
                        return -EFAULT;
-               if (copy_from_user (&reg, 1 + (unsigned char *) arg,
+               if (copy_from_user (&reg, 1 + (unsigned char __user *) arg,
                                    sizeof (reg)))
                        return -EFAULT;
                parport_frob_control (port, mask, reg);
                return 0;
 
        case PPDATADIR:
-               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+               if (copy_from_user (&mode, argp, sizeof (mode)))
                        return -EFAULT;
                if (mode)
                        port->ops->data_reverse (port);
@@ -568,7 +570,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                return 0;
 
        case PPNEGOT:
-               if (copy_from_user (&mode, (int *) arg, sizeof (mode)))
+               if (copy_from_user (&mode, argp, sizeof (mode)))
                        return -EFAULT;
                switch ((ret = parport_negotiate (port, mode))) {
                case 0: break;
@@ -583,8 +585,7 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                return ret;
 
        case PPWCTLONIRQ:
-               if (copy_from_user (&reg, (unsigned char *) arg,
-                                   sizeof (reg)))
+               if (copy_from_user (&reg, argp, sizeof (reg)))
                        return -EFAULT;
 
                /* Remember what to set the control lines to, for next
@@ -595,14 +596,13 @@ static int pp_ioctl(struct inode *inode, struct file *file,
 
        case PPCLRIRQ:
                ret = atomic_read (&pp->irqc);
-               if (copy_to_user ((int *) arg, &ret, sizeof (ret)))
+               if (copy_to_user (argp, &ret, sizeof (ret)))
                        return -EFAULT;
                atomic_sub (ret, &pp->irqc);
                return 0;
 
        case PPSETTIME:
-               if (copy_from_user (&par_timeout, (struct timeval *)arg,
-                                   sizeof(struct timeval))) {
+               if (copy_from_user (&par_timeout, argp, sizeof(struct timeval))) {
                        return -EFAULT;
                }
                /* Convert to jiffies, place in pp->pdev->timeout */
@@ -621,10 +621,8 @@ static int pp_ioctl(struct inode *inode, struct file *file,
                to_jiffies = pp->pdev->timeout;
                par_timeout.tv_sec = to_jiffies / HZ;
                par_timeout.tv_usec = (to_jiffies % (long)HZ) * (1000000/HZ);
-               if (copy_to_user ((struct timeval *)arg, &par_timeout,
-                                 sizeof(struct timeval))) {
+               if (copy_to_user (argp, &par_timeout, sizeof(struct timeval)))
                        return -EFAULT;
-               }
                return 0;
 
        default:
@@ -739,6 +737,8 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
        return mask;
 }
 
+static struct class_simple *ppdev_class;
+
 static struct file_operations pp_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
@@ -750,23 +750,59 @@ static struct file_operations pp_fops = {
        .release        = pp_release,
 };
 
+static void pp_attach(struct parport *port)
+{
+       class_simple_device_add(ppdev_class, MKDEV(PP_MAJOR, port->number),
+                       NULL, "parport%d", port->number);
+}
+
+static void pp_detach(struct parport *port)
+{
+       class_simple_device_remove(MKDEV(PP_MAJOR, port->number));
+}
+
+static struct parport_driver pp_driver = {
+       .name           = CHRDEV,
+       .attach         = pp_attach,
+       .detach         = pp_detach,
+};
+
 static int __init ppdev_init (void)
 {
-       int i;
+       int i, err = 0;
 
        if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
                printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
                        PP_MAJOR);
                return -EIO;
        }
+       ppdev_class = class_simple_create(THIS_MODULE, CHRDEV);
+       if (IS_ERR(ppdev_class)) {
+               err = PTR_ERR(ppdev_class);
+               goto out_chrdev;
+       }
        devfs_mk_dir("parports");
        for (i = 0; i < PARPORT_MAX; i++) {
                devfs_mk_cdev(MKDEV(PP_MAJOR, i),
                                S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i);
        }
+       if (parport_register_driver(&pp_driver)) {
+               printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
+               goto out_class;
+       }
 
        printk (KERN_INFO PP_VERSION "\n");
-       return 0;
+       goto out;
+
+out_class:
+       for (i = 0; i < PARPORT_MAX; i++)
+               devfs_remove("parports/%d", i);
+       devfs_remove("parports");
+       class_simple_destroy(ppdev_class);
+out_chrdev:
+       unregister_chrdev(PP_MAJOR, CHRDEV);
+out:
+       return err;
 }
 
 static void __exit ppdev_cleanup (void)
@@ -775,7 +811,9 @@ static void __exit ppdev_cleanup (void)
        /* Clean up all parport stuff */
        for (i = 0; i < PARPORT_MAX; i++)
                devfs_remove("parports/%d", i);
+       parport_unregister_driver(&pp_driver);
        devfs_remove("parports");
+       class_simple_destroy(ppdev_class);
        unregister_chrdev (PP_MAJOR, CHRDEV);
 }