aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc/phantom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc/phantom.c')
-rw-r--r--drivers/misc/phantom.c97
1 files changed, 79 insertions, 18 deletions
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 5108b7c576df..cd221fd0fb94 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -9,6 +9,7 @@
9 * You need an userspace library to cooperate with this driver. It (and other 9 * You need an userspace library to cooperate with this driver. It (and other
10 * info) may be obtained here: 10 * info) may be obtained here:
11 * http://www.fi.muni.cz/~xslaby/phantom.html 11 * http://www.fi.muni.cz/~xslaby/phantom.html
12 * or alternatively, you might use OpenHaptics provided by Sensable.
12 */ 13 */
13 14
14#include <linux/kernel.h> 15#include <linux/kernel.h>
@@ -24,13 +25,14 @@
24#include <asm/atomic.h> 25#include <asm/atomic.h>
25#include <asm/io.h> 26#include <asm/io.h>
26 27
27#define PHANTOM_VERSION "n0.9.5" 28#define PHANTOM_VERSION "n0.9.7"
28 29
29#define PHANTOM_MAX_MINORS 8 30#define PHANTOM_MAX_MINORS 8
30 31
31#define PHN_IRQCTL 0x4c /* irq control in caddr space */ 32#define PHN_IRQCTL 0x4c /* irq control in caddr space */
32 33
33#define PHB_RUNNING 1 34#define PHB_RUNNING 1
35#define PHB_NOT_OH 2
34 36
35static struct class *phantom_class; 37static struct class *phantom_class;
36static int phantom_major; 38static int phantom_major;
@@ -47,7 +49,11 @@ struct phantom_device {
47 struct cdev cdev; 49 struct cdev cdev;
48 50
49 struct mutex open_lock; 51 struct mutex open_lock;
50 spinlock_t ioctl_lock; 52 spinlock_t regs_lock;
53
54 /* used in NOT_OH mode */
55 struct phm_regs oregs;
56 u32 ctl_reg;
51}; 57};
52 58
53static unsigned char phantom_devices[PHANTOM_MAX_MINORS]; 59static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
@@ -82,6 +88,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
82 struct phm_regs rs; 88 struct phm_regs rs;
83 struct phm_reg r; 89 struct phm_reg r;
84 void __user *argp = (void __user *)arg; 90 void __user *argp = (void __user *)arg;
91 unsigned long flags;
85 unsigned int i; 92 unsigned int i;
86 93
87 if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || 94 if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
@@ -96,32 +103,45 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
96 if (r.reg > 7) 103 if (r.reg > 7)
97 return -EINVAL; 104 return -EINVAL;
98 105
99 spin_lock(&dev->ioctl_lock); 106 spin_lock_irqsave(&dev->regs_lock, flags);
100 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) && 107 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
101 phantom_status(dev, dev->status | PHB_RUNNING)){ 108 phantom_status(dev, dev->status | PHB_RUNNING)){
102 spin_unlock(&dev->ioctl_lock); 109 spin_unlock_irqrestore(&dev->regs_lock, flags);
103 return -ENODEV; 110 return -ENODEV;
104 } 111 }
105 112
106 pr_debug("phantom: writing %x to %u\n", r.value, r.reg); 113 pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
114
115 /* preserve amp bit (don't allow to change it when in NOT_OH) */
116 if (r.reg == PHN_CONTROL && (dev->status & PHB_NOT_OH)) {
117 r.value &= ~PHN_CTL_AMP;
118 r.value |= dev->ctl_reg & PHN_CTL_AMP;
119 dev->ctl_reg = r.value;
120 }
121
107 iowrite32(r.value, dev->iaddr + r.reg); 122 iowrite32(r.value, dev->iaddr + r.reg);
108 ioread32(dev->iaddr); /* PCI posting */ 123 ioread32(dev->iaddr); /* PCI posting */
109 124
110 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ)) 125 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
111 phantom_status(dev, dev->status & ~PHB_RUNNING); 126 phantom_status(dev, dev->status & ~PHB_RUNNING);
112 spin_unlock(&dev->ioctl_lock); 127 spin_unlock_irqrestore(&dev->regs_lock, flags);
113 break; 128 break;
114 case PHN_SET_REGS: 129 case PHN_SET_REGS:
115 if (copy_from_user(&rs, argp, sizeof(rs))) 130 if (copy_from_user(&rs, argp, sizeof(rs)))
116 return -EFAULT; 131 return -EFAULT;
117 132
118 pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask); 133 pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
119 spin_lock(&dev->ioctl_lock); 134 spin_lock_irqsave(&dev->regs_lock, flags);
120 for (i = 0; i < min(rs.count, 8U); i++) 135 if (dev->status & PHB_NOT_OH)
121 if ((1 << i) & rs.mask) 136 memcpy(&dev->oregs, &rs, sizeof(rs));
122 iowrite32(rs.values[i], dev->oaddr + i); 137 else {
123 ioread32(dev->iaddr); /* PCI posting */ 138 u32 m = min(rs.count, 8U);
124 spin_unlock(&dev->ioctl_lock); 139 for (i = 0; i < m; i++)
140 if (rs.mask & BIT(i))
141 iowrite32(rs.values[i], dev->oaddr + i);
142 ioread32(dev->iaddr); /* PCI posting */
143 }
144 spin_unlock_irqrestore(&dev->regs_lock, flags);
125 break; 145 break;
126 case PHN_GET_REG: 146 case PHN_GET_REG:
127 if (copy_from_user(&r, argp, sizeof(r))) 147 if (copy_from_user(&r, argp, sizeof(r)))
@@ -135,20 +155,35 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
135 if (copy_to_user(argp, &r, sizeof(r))) 155 if (copy_to_user(argp, &r, sizeof(r)))
136 return -EFAULT; 156 return -EFAULT;
137 break; 157 break;
138 case PHN_GET_REGS: 158 case PHN_GET_REGS: {
159 u32 m;
160
139 if (copy_from_user(&rs, argp, sizeof(rs))) 161 if (copy_from_user(&rs, argp, sizeof(rs)))
140 return -EFAULT; 162 return -EFAULT;
141 163
164 m = min(rs.count, 8U);
165
142 pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask); 166 pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
143 spin_lock(&dev->ioctl_lock); 167 spin_lock_irqsave(&dev->regs_lock, flags);
144 for (i = 0; i < min(rs.count, 8U); i++) 168 for (i = 0; i < m; i++)
145 if ((1 << i) & rs.mask) 169 if (rs.mask & BIT(i))
146 rs.values[i] = ioread32(dev->iaddr + i); 170 rs.values[i] = ioread32(dev->iaddr + i);
147 spin_unlock(&dev->ioctl_lock); 171 spin_unlock_irqrestore(&dev->regs_lock, flags);
148 172
149 if (copy_to_user(argp, &rs, sizeof(rs))) 173 if (copy_to_user(argp, &rs, sizeof(rs)))
150 return -EFAULT; 174 return -EFAULT;
151 break; 175 break;
176 } case PHN_NOT_OH:
177 spin_lock_irqsave(&dev->regs_lock, flags);
178 if (dev->status & PHB_RUNNING) {
179 printk(KERN_ERR "phantom: you need to set NOT_OH "
180 "before you start the device!\n");
181 spin_unlock_irqrestore(&dev->regs_lock, flags);
182 return -EINVAL;
183 }
184 dev->status |= PHB_NOT_OH;
185 spin_unlock_irqrestore(&dev->regs_lock, flags);
186 break;
152 default: 187 default:
153 return -ENOTTY; 188 return -ENOTTY;
154 } 189 }
@@ -171,8 +206,11 @@ static int phantom_open(struct inode *inode, struct file *file)
171 return -EINVAL; 206 return -EINVAL;
172 } 207 }
173 208
209 WARN_ON(dev->status & PHB_NOT_OH);
210
174 file->private_data = dev; 211 file->private_data = dev;
175 212
213 atomic_set(&dev->counter, 0);
176 dev->opened++; 214 dev->opened++;
177 mutex_unlock(&dev->open_lock); 215 mutex_unlock(&dev->open_lock);
178 216
@@ -187,6 +225,7 @@ static int phantom_release(struct inode *inode, struct file *file)
187 225
188 dev->opened = 0; 226 dev->opened = 0;
189 phantom_status(dev, dev->status & ~PHB_RUNNING); 227 phantom_status(dev, dev->status & ~PHB_RUNNING);
228 dev->status &= ~PHB_NOT_OH;
190 229
191 mutex_unlock(&dev->open_lock); 230 mutex_unlock(&dev->open_lock);
192 231
@@ -220,12 +259,32 @@ static struct file_operations phantom_file_ops = {
220static irqreturn_t phantom_isr(int irq, void *data) 259static irqreturn_t phantom_isr(int irq, void *data)
221{ 260{
222 struct phantom_device *dev = data; 261 struct phantom_device *dev = data;
262 unsigned int i;
263 u32 ctl;
223 264
224 if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ)) 265 spin_lock(&dev->regs_lock);
266 ctl = ioread32(dev->iaddr + PHN_CONTROL);
267 if (!(ctl & PHN_CTL_IRQ)) {
268 spin_unlock(&dev->regs_lock);
225 return IRQ_NONE; 269 return IRQ_NONE;
270 }
226 271
227 iowrite32(0, dev->iaddr); 272 iowrite32(0, dev->iaddr);
228 iowrite32(0xc0, dev->iaddr); 273 iowrite32(0xc0, dev->iaddr);
274
275 if (dev->status & PHB_NOT_OH) {
276 struct phm_regs *r = &dev->oregs;
277 u32 m = min(r->count, 8U);
278
279 for (i = 0; i < m; i++)
280 if (r->mask & BIT(i))
281 iowrite32(r->values[i], dev->oaddr + i);
282
283 dev->ctl_reg ^= PHN_CTL_AMP;
284 iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL);
285 }
286 spin_unlock(&dev->regs_lock);
287
229 ioread32(dev->iaddr); /* PCI posting */ 288 ioread32(dev->iaddr); /* PCI posting */
230 289
231 atomic_inc(&dev->counter); 290 atomic_inc(&dev->counter);
@@ -297,7 +356,7 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
297 } 356 }
298 357
299 mutex_init(&pht->open_lock); 358 mutex_init(&pht->open_lock);
300 spin_lock_init(&pht->ioctl_lock); 359 spin_lock_init(&pht->regs_lock);
301 init_waitqueue_head(&pht->wait); 360 init_waitqueue_head(&pht->wait);
302 cdev_init(&pht->cdev, &phantom_file_ops); 361 cdev_init(&pht->cdev, &phantom_file_ops);
303 pht->cdev.owner = THIS_MODULE; 362 pht->cdev.owner = THIS_MODULE;
@@ -378,6 +437,8 @@ static int phantom_suspend(struct pci_dev *pdev, pm_message_t state)
378 iowrite32(0, dev->caddr + PHN_IRQCTL); 437 iowrite32(0, dev->caddr + PHN_IRQCTL);
379 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */ 438 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */
380 439
440 synchronize_irq(pdev->irq);
441
381 return 0; 442 return 0;
382} 443}
383 444