* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
- * You need an userspace library to cooperate with this driver. It (and other
+ * You need a userspace library to cooperate with this driver. It (and other
* info) may be obtained here:
* http://www.fi.muni.cz/~xslaby/phantom.html
* or alternatively, you might use OpenHaptics provided by Sensable.
*/
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/phantom.h>
+#include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <asm/io.h>
unsigned long flags;
unsigned int i;
- if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
- _IOC_NR(cmd) > PH_IOC_MAXNR)
- return -ENOTTY;
-
switch (cmd) {
+ case PHN_SETREG:
case PHN_SET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
phantom_status(dev, dev->status & ~PHB_RUNNING);
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_SETREGS:
case PHN_SET_REGS:
if (copy_from_user(&rs, argp, sizeof(rs)))
return -EFAULT;
}
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_GETREG:
case PHN_GET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
break;
+ case PHN_GETREGS:
case PHN_GET_REGS: {
u32 m;
for (i = 0; i < m; i++)
if (rs.mask & BIT(i))
rs.values[i] = ioread32(dev->iaddr + i);
+ atomic_set(&dev->counter, 0);
spin_unlock_irqrestore(&dev->regs_lock, flags);
if (copy_to_user(argp, &rs, sizeof(rs)))
return 0;
}
+#ifdef CONFIG_COMPAT
+static long phantom_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+ cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT);
+ cmd |= sizeof(void *) << _IOC_SIZESHIFT;
+ }
+ return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define phantom_compat_ioctl NULL
+#endif
+
static int phantom_open(struct inode *inode, struct file *file)
{
struct phantom_device *dev = container_of(inode->i_cdev,
struct phantom_device, cdev);
+ lock_kernel();
nonseekable_open(inode, file);
- if (mutex_lock_interruptible(&dev->open_lock))
+ if (mutex_lock_interruptible(&dev->open_lock)) {
+ unlock_kernel();
return -ERESTARTSYS;
+ }
if (dev->opened) {
mutex_unlock(&dev->open_lock);
+ unlock_kernel();
return -EINVAL;
}
atomic_set(&dev->counter, 0);
dev->opened++;
mutex_unlock(&dev->open_lock);
-
+ unlock_kernel();
return 0;
}
pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
poll_wait(file, &dev->wait, wait);
- if (atomic_read(&dev->counter)) {
+
+ if (!(dev->status & PHB_RUNNING))
+ mask = POLLERR;
+ else if (atomic_read(&dev->counter))
mask = POLLIN | POLLRDNORM;
- atomic_dec(&dev->counter);
- } else if ((dev->status & PHB_RUNNING) == 0)
- mask = POLLIN | POLLRDNORM | POLLERR;
+
pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
return mask;
.open = phantom_open,
.release = phantom_release,
.unlocked_ioctl = phantom_ioctl,
+ .compat_ioctl = phantom_compat_ioctl,
.poll = phantom_poll,
};
goto err_irq;
}
- if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major,
- minor), "phantom%u", minor)))
+ if (IS_ERR(device_create(phantom_class, &pdev->dev,
+ MKDEV(phantom_major, minor), NULL,
+ "phantom%u", minor)))
dev_err(&pdev->dev, "can't create device\n");
pci_set_drvdata(pdev, pht);
module_exit(phantom_exit);
MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
-MODULE_DESCRIPTION("Sensable Phantom driver");
+MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");
MODULE_LICENSE("GPL");
MODULE_VERSION(PHANTOM_VERSION);