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