mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 00:51:35 +00:00
Misc: phantom, improved data passing
This new version guarantees amb_bit switch in small enough intervals, so that the device won't stop working in the middle of a movement anymore. However it preserves old (openhaptics) functionality. Signed-off-by: Jiri Slaby <jirislaby@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
b2afe33170
commit
bc552f7715
2 changed files with 81 additions and 19 deletions
|
@ -25,13 +25,14 @@
|
||||||
#include <asm/atomic.h>
|
#include <asm/atomic.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
|
||||||
#define PHANTOM_VERSION "n0.9.5"
|
#define PHANTOM_VERSION "n0.9.7"
|
||||||
|
|
||||||
#define PHANTOM_MAX_MINORS 8
|
#define PHANTOM_MAX_MINORS 8
|
||||||
|
|
||||||
#define PHN_IRQCTL 0x4c /* irq control in caddr space */
|
#define PHN_IRQCTL 0x4c /* irq control in caddr space */
|
||||||
|
|
||||||
#define PHB_RUNNING 1
|
#define PHB_RUNNING 1
|
||||||
|
#define PHB_NOT_OH 2
|
||||||
|
|
||||||
static struct class *phantom_class;
|
static struct class *phantom_class;
|
||||||
static int phantom_major;
|
static int phantom_major;
|
||||||
|
@ -48,7 +49,11 @@ struct phantom_device {
|
||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
|
|
||||||
struct mutex open_lock;
|
struct mutex open_lock;
|
||||||
spinlock_t ioctl_lock;
|
spinlock_t regs_lock;
|
||||||
|
|
||||||
|
/* used in NOT_OH mode */
|
||||||
|
struct phm_regs oregs;
|
||||||
|
u32 ctl_reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
|
static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
|
||||||
|
@ -83,6 +88,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
|
||||||
struct phm_regs rs;
|
struct phm_regs rs;
|
||||||
struct phm_reg r;
|
struct phm_reg r;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
|
unsigned long flags;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
|
if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
|
||||||
|
@ -97,32 +103,45 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
|
||||||
if (r.reg > 7)
|
if (r.reg > 7)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
spin_lock(&dev->ioctl_lock);
|
spin_lock_irqsave(&dev->regs_lock, flags);
|
||||||
if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
|
if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
|
||||||
phantom_status(dev, dev->status | PHB_RUNNING)){
|
phantom_status(dev, dev->status | PHB_RUNNING)){
|
||||||
spin_unlock(&dev->ioctl_lock);
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
|
pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
|
||||||
|
|
||||||
|
/* preserve amp bit (don't allow to change it when in NOT_OH) */
|
||||||
|
if (r.reg == PHN_CONTROL && (dev->status & PHB_NOT_OH)) {
|
||||||
|
r.value &= ~PHN_CTL_AMP;
|
||||||
|
r.value |= dev->ctl_reg & PHN_CTL_AMP;
|
||||||
|
dev->ctl_reg = r.value;
|
||||||
|
}
|
||||||
|
|
||||||
iowrite32(r.value, dev->iaddr + r.reg);
|
iowrite32(r.value, dev->iaddr + r.reg);
|
||||||
ioread32(dev->iaddr); /* PCI posting */
|
ioread32(dev->iaddr); /* PCI posting */
|
||||||
|
|
||||||
if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
|
if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
|
||||||
phantom_status(dev, dev->status & ~PHB_RUNNING);
|
phantom_status(dev, dev->status & ~PHB_RUNNING);
|
||||||
spin_unlock(&dev->ioctl_lock);
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
break;
|
break;
|
||||||
case PHN_SET_REGS:
|
case PHN_SET_REGS:
|
||||||
if (copy_from_user(&rs, argp, sizeof(rs)))
|
if (copy_from_user(&rs, argp, sizeof(rs)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
|
pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
|
||||||
spin_lock(&dev->ioctl_lock);
|
spin_lock_irqsave(&dev->regs_lock, flags);
|
||||||
for (i = 0; i < min(rs.count, 8U); i++)
|
if (dev->status & PHB_NOT_OH)
|
||||||
if ((1 << i) & rs.mask)
|
memcpy(&dev->oregs, &rs, sizeof(rs));
|
||||||
|
else {
|
||||||
|
u32 m = min(rs.count, 8U);
|
||||||
|
for (i = 0; i < m; i++)
|
||||||
|
if (rs.mask & BIT(i))
|
||||||
iowrite32(rs.values[i], dev->oaddr + i);
|
iowrite32(rs.values[i], dev->oaddr + i);
|
||||||
ioread32(dev->iaddr); /* PCI posting */
|
ioread32(dev->iaddr); /* PCI posting */
|
||||||
spin_unlock(&dev->ioctl_lock);
|
}
|
||||||
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
break;
|
break;
|
||||||
case PHN_GET_REG:
|
case PHN_GET_REG:
|
||||||
if (copy_from_user(&r, argp, sizeof(r)))
|
if (copy_from_user(&r, argp, sizeof(r)))
|
||||||
|
@ -136,20 +155,35 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
|
||||||
if (copy_to_user(argp, &r, sizeof(r)))
|
if (copy_to_user(argp, &r, sizeof(r)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
case PHN_GET_REGS:
|
case PHN_GET_REGS: {
|
||||||
|
u32 m;
|
||||||
|
|
||||||
if (copy_from_user(&rs, argp, sizeof(rs)))
|
if (copy_from_user(&rs, argp, sizeof(rs)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
m = min(rs.count, 8U);
|
||||||
|
|
||||||
pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
|
pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
|
||||||
spin_lock(&dev->ioctl_lock);
|
spin_lock_irqsave(&dev->regs_lock, flags);
|
||||||
for (i = 0; i < min(rs.count, 8U); i++)
|
for (i = 0; i < m; i++)
|
||||||
if ((1 << i) & rs.mask)
|
if (rs.mask & BIT(i))
|
||||||
rs.values[i] = ioread32(dev->iaddr + i);
|
rs.values[i] = ioread32(dev->iaddr + i);
|
||||||
spin_unlock(&dev->ioctl_lock);
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
|
|
||||||
if (copy_to_user(argp, &rs, sizeof(rs)))
|
if (copy_to_user(argp, &rs, sizeof(rs)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
break;
|
break;
|
||||||
|
} case PHN_NOT_OH:
|
||||||
|
spin_lock_irqsave(&dev->regs_lock, flags);
|
||||||
|
if (dev->status & PHB_RUNNING) {
|
||||||
|
printk(KERN_ERR "phantom: you need to set NOT_OH "
|
||||||
|
"before you start the device!\n");
|
||||||
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
dev->status |= PHB_NOT_OH;
|
||||||
|
spin_unlock_irqrestore(&dev->regs_lock, flags);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -172,8 +206,11 @@ static int phantom_open(struct inode *inode, struct file *file)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WARN_ON(dev->status & PHB_NOT_OH);
|
||||||
|
|
||||||
file->private_data = dev;
|
file->private_data = dev;
|
||||||
|
|
||||||
|
atomic_set(&dev->counter, 0);
|
||||||
dev->opened++;
|
dev->opened++;
|
||||||
mutex_unlock(&dev->open_lock);
|
mutex_unlock(&dev->open_lock);
|
||||||
|
|
||||||
|
@ -188,6 +225,7 @@ static int phantom_release(struct inode *inode, struct file *file)
|
||||||
|
|
||||||
dev->opened = 0;
|
dev->opened = 0;
|
||||||
phantom_status(dev, dev->status & ~PHB_RUNNING);
|
phantom_status(dev, dev->status & ~PHB_RUNNING);
|
||||||
|
dev->status &= ~PHB_NOT_OH;
|
||||||
|
|
||||||
mutex_unlock(&dev->open_lock);
|
mutex_unlock(&dev->open_lock);
|
||||||
|
|
||||||
|
@ -221,12 +259,32 @@ static struct file_operations phantom_file_ops = {
|
||||||
static irqreturn_t phantom_isr(int irq, void *data)
|
static irqreturn_t phantom_isr(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct phantom_device *dev = data;
|
struct phantom_device *dev = data;
|
||||||
|
unsigned int i;
|
||||||
|
u32 ctl;
|
||||||
|
|
||||||
if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ))
|
spin_lock(&dev->regs_lock);
|
||||||
|
ctl = ioread32(dev->iaddr + PHN_CONTROL);
|
||||||
|
if (!(ctl & PHN_CTL_IRQ)) {
|
||||||
|
spin_unlock(&dev->regs_lock);
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
iowrite32(0, dev->iaddr);
|
iowrite32(0, dev->iaddr);
|
||||||
iowrite32(0xc0, dev->iaddr);
|
iowrite32(0xc0, dev->iaddr);
|
||||||
|
|
||||||
|
if (dev->status & PHB_NOT_OH) {
|
||||||
|
struct phm_regs *r = &dev->oregs;
|
||||||
|
u32 m = min(r->count, 8U);
|
||||||
|
|
||||||
|
for (i = 0; i < m; i++)
|
||||||
|
if (r->mask & BIT(i))
|
||||||
|
iowrite32(r->values[i], dev->oaddr + i);
|
||||||
|
|
||||||
|
dev->ctl_reg ^= PHN_CTL_AMP;
|
||||||
|
iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL);
|
||||||
|
}
|
||||||
|
spin_unlock(&dev->regs_lock);
|
||||||
|
|
||||||
ioread32(dev->iaddr); /* PCI posting */
|
ioread32(dev->iaddr); /* PCI posting */
|
||||||
|
|
||||||
atomic_inc(&dev->counter);
|
atomic_inc(&dev->counter);
|
||||||
|
@ -298,7 +356,7 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_init(&pht->open_lock);
|
mutex_init(&pht->open_lock);
|
||||||
spin_lock_init(&pht->ioctl_lock);
|
spin_lock_init(&pht->regs_lock);
|
||||||
init_waitqueue_head(&pht->wait);
|
init_waitqueue_head(&pht->wait);
|
||||||
cdev_init(&pht->cdev, &phantom_file_ops);
|
cdev_init(&pht->cdev, &phantom_file_ops);
|
||||||
pht->cdev.owner = THIS_MODULE;
|
pht->cdev.owner = THIS_MODULE;
|
||||||
|
|
|
@ -30,7 +30,11 @@ struct phm_regs {
|
||||||
#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
|
#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
|
||||||
#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
|
#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
|
||||||
#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
|
#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
|
||||||
#define PH_IOC_MAXNR 3
|
/* this ioctl tells the driver, that the caller is not OpenHaptics and might
|
||||||
|
* use improved registers update (no more phantom switchoffs when using
|
||||||
|
* libphantom) */
|
||||||
|
#define PHN_NOT_OH _IO (PH_IOC_MAGIC, 4)
|
||||||
|
#define PH_IOC_MAXNR 4
|
||||||
|
|
||||||
#define PHN_CONTROL 0x6 /* control byte in iaddr space */
|
#define PHN_CONTROL 0x6 /* control byte in iaddr space */
|
||||||
#define PHN_CTL_AMP 0x1 /* switch after torques change */
|
#define PHN_CTL_AMP 0x1 /* switch after torques change */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue