aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/misc/phantom.c94
-rw-r--r--include/linux/phantom.h6
2 files changed, 81 insertions, 19 deletions
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index bc532ac8b7d8..cd221fd0fb94 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -25,13 +25,14 @@
25#include <asm/atomic.h> 25#include <asm/atomic.h>
26#include <asm/io.h> 26#include <asm/io.h>
27 27
28#define PHANTOM_VERSION "n0.9.5" 28#define PHANTOM_VERSION "n0.9.7"
29 29
30#define PHANTOM_MAX_MINORS 8 30#define PHANTOM_MAX_MINORS 8
31 31
32#define PHN_IRQCTL 0x4c /* irq control in caddr space */ 32#define PHN_IRQCTL 0x4c /* irq control in caddr space */
33 33
34#define PHB_RUNNING 1 34#define PHB_RUNNING 1
35#define PHB_NOT_OH 2
35 36
36static struct class *phantom_class; 37static struct class *phantom_class;
37static int phantom_major; 38static int phantom_major;
@@ -48,7 +49,11 @@ struct phantom_device {
48 struct cdev cdev; 49 struct cdev cdev;
49 50
50 struct mutex open_lock; 51 struct mutex open_lock;
51 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;
52}; 57};
53 58
54static unsigned char phantom_devices[PHANTOM_MAX_MINORS]; 59static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
@@ -83,6 +88,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
83 struct phm_regs rs; 88 struct phm_regs rs;
84 struct phm_reg r; 89 struct phm_reg r;
85 void __user *argp = (void __user *)arg; 90 void __user *argp = (void __user *)arg;
91 unsigned long flags;
86 unsigned int i; 92 unsigned int i;
87 93
88 if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || 94 if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
@@ -97,32 +103,45 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
97 if (r.reg > 7) 103 if (r.reg > 7)
98 return -EINVAL; 104 return -EINVAL;
99 105
100 spin_lock(&dev->ioctl_lock); 106 spin_lock_irqsave(&dev->regs_lock, flags);
101 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) && 107 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
102 phantom_status(dev, dev->status | PHB_RUNNING)){ 108 phantom_status(dev, dev->status | PHB_RUNNING)){
103 spin_unlock(&dev->ioctl_lock); 109 spin_unlock_irqrestore(&dev->regs_lock, flags);
104 return -ENODEV; 110 return -ENODEV;
105 } 111 }
106 112
107 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
108 iowrite32(r.value, dev->iaddr + r.reg); 122 iowrite32(r.value, dev->iaddr + r.reg);
109 ioread32(dev->iaddr); /* PCI posting */ 123 ioread32(dev->iaddr); /* PCI posting */
110 124
111 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ)) 125 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
112 phantom_status(dev, dev->status & ~PHB_RUNNING); 126 phantom_status(dev, dev->status & ~PHB_RUNNING);
113 spin_unlock(&dev->ioctl_lock); 127 spin_unlock_irqrestore(&dev->regs_lock, flags);
114 break; 128 break;
115 case PHN_SET_REGS: 129 case PHN_SET_REGS:
116 if (copy_from_user(&rs, argp, sizeof(rs))) 130 if (copy_from_user(&rs, argp, sizeof(rs)))
117 return -EFAULT; 131 return -EFAULT;
118 132
119 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);
120 spin_lock(&dev->ioctl_lock); 134 spin_lock_irqsave(&dev->regs_lock, flags);
121 for (i = 0; i < min(rs.count, 8U); i++) 135 if (dev->status & PHB_NOT_OH)
122 if ((1 << i) & rs.mask) 136 memcpy(&dev->oregs, &rs, sizeof(rs));
123 iowrite32(rs.values[i], dev->oaddr + i); 137 else {
124 ioread32(dev->iaddr); /* PCI posting */ 138 u32 m = min(rs.count, 8U);
125 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);
126 break; 145 break;
127 case PHN_GET_REG: 146 case PHN_GET_REG:
128 if (copy_from_user(&r, argp, sizeof(r))) 147 if (copy_from_user(&r, argp, sizeof(r)))
@@ -136,20 +155,35 @@ static long phantom_ioctl(struct file *file, unsigned int cmd,
136 if (copy_to_user(argp, &r, sizeof(r))) 155 if (copy_to_user(argp, &r, sizeof(r)))
137 return -EFAULT; 156 return -EFAULT;
138 break; 157 break;
139 case PHN_GET_REGS: 158 case PHN_GET_REGS: {
159 u32 m;
160
140 if (copy_from_user(&rs, argp, sizeof(rs))) 161 if (copy_from_user(&rs, argp, sizeof(rs)))
141 return -EFAULT; 162 return -EFAULT;
142 163
164 m = min(rs.count, 8U);
165
143 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);
144 spin_lock(&dev->ioctl_lock); 167 spin_lock_irqsave(&dev->regs_lock, flags);
145 for (i = 0; i < min(rs.count, 8U); i++) 168 for (i = 0; i < m; i++)
146 if ((1 << i) & rs.mask) 169 if (rs.mask & BIT(i))
147 rs.values[i] = ioread32(dev->iaddr + i); 170 rs.values[i] = ioread32(dev->iaddr + i);
148 spin_unlock(&dev->ioctl_lock); 171 spin_unlock_irqrestore(&dev->regs_lock, flags);
149 172
150 if (copy_to_user(argp, &rs, sizeof(rs))) 173 if (copy_to_user(argp, &rs, sizeof(rs)))
151 return -EFAULT; 174 return -EFAULT;
152 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;
153 default: 187 default:
154 return -ENOTTY; 188 return -ENOTTY;
155 } 189 }
@@ -172,8 +206,11 @@ static int phantom_open(struct inode *inode, struct file *file)
172 return -EINVAL; 206 return -EINVAL;
173 } 207 }
174 208
209 WARN_ON(dev->status & PHB_NOT_OH);
210
175 file->private_data = dev; 211 file->private_data = dev;
176 212
213 atomic_set(&dev->counter, 0);
177 dev->opened++; 214 dev->opened++;
178 mutex_unlock(&dev->open_lock); 215 mutex_unlock(&dev->open_lock);
179 216
@@ -188,6 +225,7 @@ static int phantom_release(struct inode *inode, struct file *file)
188 225
189 dev->opened = 0; 226 dev->opened = 0;
190 phantom_status(dev, dev->status & ~PHB_RUNNING); 227 phantom_status(dev, dev->status & ~PHB_RUNNING);
228 dev->status &= ~PHB_NOT_OH;
191 229
192 mutex_unlock(&dev->open_lock); 230 mutex_unlock(&dev->open_lock);
193 231
@@ -221,12 +259,32 @@ static struct file_operations phantom_file_ops = {
221static irqreturn_t phantom_isr(int irq, void *data) 259static irqreturn_t phantom_isr(int irq, void *data)
222{ 260{
223 struct phantom_device *dev = data; 261 struct phantom_device *dev = data;
262 unsigned int i;
263 u32 ctl;
224 264
225 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);
226 return IRQ_NONE; 269 return IRQ_NONE;
270 }
227 271
228 iowrite32(0, dev->iaddr); 272 iowrite32(0, dev->iaddr);
229 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
230 ioread32(dev->iaddr); /* PCI posting */ 288 ioread32(dev->iaddr); /* PCI posting */
231 289
232 atomic_inc(&dev->counter); 290 atomic_inc(&dev->counter);
@@ -298,7 +356,7 @@ static int __devinit phantom_probe(struct pci_dev *pdev,
298 } 356 }
299 357
300 mutex_init(&pht->open_lock); 358 mutex_init(&pht->open_lock);
301 spin_lock_init(&pht->ioctl_lock); 359 spin_lock_init(&pht->regs_lock);
302 init_waitqueue_head(&pht->wait); 360 init_waitqueue_head(&pht->wait);
303 cdev_init(&pht->cdev, &phantom_file_ops); 361 cdev_init(&pht->cdev, &phantom_file_ops);
304 pht->cdev.owner = THIS_MODULE; 362 pht->cdev.owner = THIS_MODULE;
diff --git a/include/linux/phantom.h b/include/linux/phantom.h
index d3ebbfae6903..96f4048a6cc3 100644
--- a/include/linux/phantom.h
+++ b/include/linux/phantom.h
@@ -30,7 +30,11 @@ struct phm_regs {
30#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *) 30#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
31#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *) 31#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
32#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *) 32#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
33#define PH_IOC_MAXNR 3 33/* this ioctl tells the driver, that the caller is not OpenHaptics and might
34 * use improved registers update (no more phantom switchoffs when using
35 * libphantom) */
36#define PHN_NOT_OH _IO (PH_IOC_MAGIC, 4)
37#define PH_IOC_MAXNR 4
34 38
35#define PHN_CONTROL 0x6 /* control byte in iaddr space */ 39#define PHN_CONTROL 0x6 /* control byte in iaddr space */
36#define PHN_CTL_AMP 0x1 /* switch after torques change */ 40#define PHN_CTL_AMP 0x1 /* switch after torques change */