4b5959b2c93435e5009538108747d524fd80f8af
[sfrench/cifs-2.6.git] / drivers / misc / phantom.c
1 /*
2  *  Copyright (C) 2005-2007 Jiri Slaby <jirislaby@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  You need an userspace library to cooperate with this driver. It (and other
10  *  info) may be obtained here:
11  *  http://www.fi.muni.cz/~xslaby/phantom.html
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/pci.h>
18 #include <linux/fs.h>
19 #include <linux/poll.h>
20 #include <linux/interrupt.h>
21 #include <linux/cdev.h>
22 #include <linux/phantom.h>
23
24 #include <asm/atomic.h>
25 #include <asm/io.h>
26
27 #define PHANTOM_VERSION         "n0.9.5"
28
29 #define PHANTOM_MAX_MINORS      8
30
31 #define PHN_IRQCTL              0x4c    /* irq control in caddr space */
32
33 #define PHB_RUNNING             1
34
35 static struct class *phantom_class;
36 static int phantom_major;
37
38 struct phantom_device {
39         unsigned int opened;
40         void __iomem *caddr;
41         u32 __iomem *iaddr;
42         u32 __iomem *oaddr;
43         unsigned long status;
44         atomic_t counter;
45
46         wait_queue_head_t wait;
47         struct cdev cdev;
48
49         struct mutex open_lock;
50         spinlock_t ioctl_lock;
51 };
52
53 static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
54
55 static int phantom_status(struct phantom_device *dev, unsigned long newstat)
56 {
57         pr_debug("phantom_status %lx %lx\n", dev->status, newstat);
58
59         if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) {
60                 atomic_set(&dev->counter, 0);
61                 iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL);
62                 iowrite32(0x43, dev->caddr + PHN_IRQCTL);
63         } else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING))
64                 iowrite32(0, dev->caddr + PHN_IRQCTL);
65
66         dev->status = newstat;
67
68         return 0;
69 }
70
71 /*
72  * File ops
73  */
74
75 static long phantom_ioctl(struct file *file, unsigned int cmd,
76                 unsigned long arg)
77 {
78         struct phantom_device *dev = file->private_data;
79         struct phm_regs rs;
80         struct phm_reg r;
81         void __user *argp = (void __user *)arg;
82         unsigned int i;
83
84         if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
85                         _IOC_NR(cmd) > PH_IOC_MAXNR)
86                 return -ENOTTY;
87
88         switch (cmd) {
89         case PHN_SET_REG:
90                 if (copy_from_user(&r, argp, sizeof(r)))
91                         return -EFAULT;
92
93                 if (r.reg > 7)
94                         return -EINVAL;
95
96                 spin_lock(&dev->ioctl_lock);
97                 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&
98                                 phantom_status(dev, dev->status | PHB_RUNNING)){
99                         spin_unlock(&dev->ioctl_lock);
100                         return -ENODEV;
101                 }
102
103                 pr_debug("phantom: writing %x to %u\n", r.value, r.reg);
104                 iowrite32(r.value, dev->iaddr + r.reg);
105
106                 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))
107                         phantom_status(dev, dev->status & ~PHB_RUNNING);
108                 spin_unlock(&dev->ioctl_lock);
109                 break;
110         case PHN_SET_REGS:
111                 if (copy_from_user(&rs, argp, sizeof(rs)))
112                         return -EFAULT;
113
114                 pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);
115                 spin_lock(&dev->ioctl_lock);
116                 for (i = 0; i < min(rs.count, 8U); i++)
117                         if ((1 << i) & rs.mask)
118                                 iowrite32(rs.values[i], dev->oaddr + i);
119                 spin_unlock(&dev->ioctl_lock);
120                 break;
121         case PHN_GET_REG:
122                 if (copy_from_user(&r, argp, sizeof(r)))
123                         return -EFAULT;
124
125                 if (r.reg > 7)
126                         return -EINVAL;
127
128                 r.value = ioread32(dev->iaddr + r.reg);
129
130                 if (copy_to_user(argp, &r, sizeof(r)))
131                         return -EFAULT;
132                 break;
133         case PHN_GET_REGS:
134                 if (copy_from_user(&rs, argp, sizeof(rs)))
135                         return -EFAULT;
136
137                 pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);
138                 spin_lock(&dev->ioctl_lock);
139                 for (i = 0; i < min(rs.count, 8U); i++)
140                         if ((1 << i) & rs.mask)
141                                 rs.values[i] = ioread32(dev->iaddr + i);
142                 spin_unlock(&dev->ioctl_lock);
143
144                 if (copy_to_user(argp, &rs, sizeof(rs)))
145                         return -EFAULT;
146                 break;
147         default:
148                 return -ENOTTY;
149         }
150
151         return 0;
152 }
153
154 static int phantom_open(struct inode *inode, struct file *file)
155 {
156         struct phantom_device *dev = container_of(inode->i_cdev,
157                         struct phantom_device, cdev);
158
159         nonseekable_open(inode, file);
160
161         if (mutex_lock_interruptible(&dev->open_lock))
162                 return -ERESTARTSYS;
163
164         if (dev->opened) {
165                 mutex_unlock(&dev->open_lock);
166                 return -EINVAL;
167         }
168
169         file->private_data = dev;
170
171         dev->opened++;
172         mutex_unlock(&dev->open_lock);
173
174         return 0;
175 }
176
177 static int phantom_release(struct inode *inode, struct file *file)
178 {
179         struct phantom_device *dev = file->private_data;
180
181         mutex_lock(&dev->open_lock);
182
183         dev->opened = 0;
184         phantom_status(dev, dev->status & ~PHB_RUNNING);
185
186         mutex_unlock(&dev->open_lock);
187
188         return 0;
189 }
190
191 static unsigned int phantom_poll(struct file *file, poll_table *wait)
192 {
193         struct phantom_device *dev = file->private_data;
194         unsigned int mask = 0;
195
196         pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
197         poll_wait(file, &dev->wait, wait);
198         if (atomic_read(&dev->counter)) {
199                 mask = POLLIN | POLLRDNORM;
200                 atomic_dec(&dev->counter);
201         } else if ((dev->status & PHB_RUNNING) == 0)
202                 mask = POLLIN | POLLRDNORM | POLLERR;
203         pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
204
205         return mask;
206 }
207
208 static struct file_operations phantom_file_ops = {
209         .open = phantom_open,
210         .release = phantom_release,
211         .unlocked_ioctl = phantom_ioctl,
212         .poll = phantom_poll,
213 };
214
215 static irqreturn_t phantom_isr(int irq, void *data)
216 {
217         struct phantom_device *dev = data;
218
219         if (!(ioread32(dev->iaddr + PHN_CONTROL) & PHN_CTL_IRQ))
220                 return IRQ_NONE;
221
222         iowrite32(0, dev->iaddr);
223         iowrite32(0xc0, dev->iaddr);
224
225         atomic_inc(&dev->counter);
226         wake_up_interruptible(&dev->wait);
227
228         return IRQ_HANDLED;
229 }
230
231 /*
232  * Init and deinit driver
233  */
234
235 static unsigned int __devinit phantom_get_free(void)
236 {
237         unsigned int i;
238
239         for (i = 0; i < PHANTOM_MAX_MINORS; i++)
240                 if (phantom_devices[i] == 0)
241                         break;
242
243         return i;
244 }
245
246 static int __devinit phantom_probe(struct pci_dev *pdev,
247         const struct pci_device_id *pci_id)
248 {
249         struct phantom_device *pht;
250         unsigned int minor;
251         int retval;
252
253         retval = pci_enable_device(pdev);
254         if (retval)
255                 goto err;
256
257         minor = phantom_get_free();
258         if (minor == PHANTOM_MAX_MINORS) {
259                 dev_err(&pdev->dev, "too many devices found!\n");
260                 retval = -EIO;
261                 goto err_dis;
262         }
263
264         phantom_devices[minor] = 1;
265
266         retval = pci_request_regions(pdev, "phantom");
267         if (retval)
268                 goto err_null;
269
270         retval = -ENOMEM;
271         pht = kzalloc(sizeof(*pht), GFP_KERNEL);
272         if (pht == NULL) {
273                 dev_err(&pdev->dev, "unable to allocate device\n");
274                 goto err_reg;
275         }
276
277         pht->caddr = pci_iomap(pdev, 0, 0);
278         if (pht->caddr == NULL) {
279                 dev_err(&pdev->dev, "can't remap conf space\n");
280                 goto err_fr;
281         }
282         pht->iaddr = pci_iomap(pdev, 2, 0);
283         if (pht->iaddr == NULL) {
284                 dev_err(&pdev->dev, "can't remap input space\n");
285                 goto err_unmc;
286         }
287         pht->oaddr = pci_iomap(pdev, 3, 0);
288         if (pht->oaddr == NULL) {
289                 dev_err(&pdev->dev, "can't remap output space\n");
290                 goto err_unmi;
291         }
292
293         mutex_init(&pht->open_lock);
294         spin_lock_init(&pht->ioctl_lock);
295         init_waitqueue_head(&pht->wait);
296         cdev_init(&pht->cdev, &phantom_file_ops);
297         pht->cdev.owner = THIS_MODULE;
298
299         iowrite32(0, pht->caddr + PHN_IRQCTL);
300         retval = request_irq(pdev->irq, phantom_isr,
301                         IRQF_SHARED | IRQF_DISABLED, "phantom", pht);
302         if (retval) {
303                 dev_err(&pdev->dev, "can't establish ISR\n");
304                 goto err_unmo;
305         }
306
307         retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1);
308         if (retval) {
309                 dev_err(&pdev->dev, "chardev registration failed\n");
310                 goto err_irq;
311         }
312
313         if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major,
314                         minor), "phantom%u", minor)))
315                 dev_err(&pdev->dev, "can't create device\n");
316
317         pci_set_drvdata(pdev, pht);
318
319         return 0;
320 err_irq:
321         free_irq(pdev->irq, pht);
322 err_unmo:
323         pci_iounmap(pdev, pht->oaddr);
324 err_unmi:
325         pci_iounmap(pdev, pht->iaddr);
326 err_unmc:
327         pci_iounmap(pdev, pht->caddr);
328 err_fr:
329         kfree(pht);
330 err_reg:
331         pci_release_regions(pdev);
332 err_null:
333         phantom_devices[minor] = 0;
334 err_dis:
335         pci_disable_device(pdev);
336 err:
337         return retval;
338 }
339
340 static void __devexit phantom_remove(struct pci_dev *pdev)
341 {
342         struct phantom_device *pht = pci_get_drvdata(pdev);
343         unsigned int minor = MINOR(pht->cdev.dev);
344
345         device_destroy(phantom_class, MKDEV(phantom_major, minor));
346
347         cdev_del(&pht->cdev);
348
349         iowrite32(0, pht->caddr + PHN_IRQCTL);
350         free_irq(pdev->irq, pht);
351
352         pci_iounmap(pdev, pht->oaddr);
353         pci_iounmap(pdev, pht->iaddr);
354         pci_iounmap(pdev, pht->caddr);
355
356         kfree(pht);
357
358         pci_release_regions(pdev);
359
360         phantom_devices[minor] = 0;
361
362         pci_disable_device(pdev);
363 }
364
365 #ifdef CONFIG_PM
366 static int phantom_suspend(struct pci_dev *pdev, pm_message_t state)
367 {
368         struct phantom_device *dev = pci_get_drvdata(pdev);
369
370         iowrite32(0, dev->caddr + PHN_IRQCTL);
371
372         return 0;
373 }
374
375 static int phantom_resume(struct pci_dev *pdev)
376 {
377         struct phantom_device *dev = pci_get_drvdata(pdev);
378
379         iowrite32(0, dev->caddr + PHN_IRQCTL);
380
381         return 0;
382 }
383 #else
384 #define phantom_suspend NULL
385 #define phantom_resume  NULL
386 #endif
387
388 static struct pci_device_id phantom_pci_tbl[] __devinitdata = {
389         { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
390                 .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },
391         { 0, }
392 };
393 MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
394
395 static struct pci_driver phantom_pci_driver = {
396         .name = "phantom",
397         .id_table = phantom_pci_tbl,
398         .probe = phantom_probe,
399         .remove = __devexit_p(phantom_remove),
400         .suspend = phantom_suspend,
401         .resume = phantom_resume
402 };
403
404 static ssize_t phantom_show_version(struct class *cls, char *buf)
405 {
406         return sprintf(buf, PHANTOM_VERSION "\n");
407 }
408
409 static CLASS_ATTR(version, 0444, phantom_show_version, NULL);
410
411 static int __init phantom_init(void)
412 {
413         int retval;
414         dev_t dev;
415
416         phantom_class = class_create(THIS_MODULE, "phantom");
417         if (IS_ERR(phantom_class)) {
418                 retval = PTR_ERR(phantom_class);
419                 printk(KERN_ERR "phantom: can't register phantom class\n");
420                 goto err;
421         }
422         retval = class_create_file(phantom_class, &class_attr_version);
423         if (retval) {
424                 printk(KERN_ERR "phantom: can't create sysfs version file\n");
425                 goto err_class;
426         }
427
428         retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom");
429         if (retval) {
430                 printk(KERN_ERR "phantom: can't register character device\n");
431                 goto err_attr;
432         }
433         phantom_major = MAJOR(dev);
434
435         retval = pci_register_driver(&phantom_pci_driver);
436         if (retval) {
437                 printk(KERN_ERR "phantom: can't register pci driver\n");
438                 goto err_unchr;
439         }
440
441         printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", "
442                         "init OK\n");
443
444         return 0;
445 err_unchr:
446         unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
447 err_attr:
448         class_remove_file(phantom_class, &class_attr_version);
449 err_class:
450         class_destroy(phantom_class);
451 err:
452         return retval;
453 }
454
455 static void __exit phantom_exit(void)
456 {
457         pci_unregister_driver(&phantom_pci_driver);
458
459         unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);
460
461         class_remove_file(phantom_class, &class_attr_version);
462         class_destroy(phantom_class);
463
464         pr_debug("phantom: module successfully removed\n");
465 }
466
467 module_init(phantom_init);
468 module_exit(phantom_exit);
469
470 MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
471 MODULE_DESCRIPTION("Sensable Phantom driver");
472 MODULE_LICENSE("GPL");
473 MODULE_VERSION(PHANTOM_VERSION);