565 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (C) 2005-2007 Jiri Slaby <jirislaby@gmail.com>4 *5 * You need a userspace library to cooperate with this driver. It (and other6 * info) may be obtained here:7 * http://www.fi.muni.cz/~xslaby/phantom.html8 * or alternatively, you might use OpenHaptics provided by Sensable.9 */10 11#include <linux/compat.h>12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/device.h>15#include <linux/pci.h>16#include <linux/fs.h>17#include <linux/poll.h>18#include <linux/interrupt.h>19#include <linux/cdev.h>20#include <linux/slab.h>21#include <linux/phantom.h>22#include <linux/sched.h>23#include <linux/mutex.h>24 25#include <linux/atomic.h>26#include <asm/io.h>27 28#define PHANTOM_VERSION "n0.9.8"29 30#define PHANTOM_MAX_MINORS 831 32#define PHN_IRQCTL 0x4c /* irq control in caddr space */33 34#define PHB_RUNNING 135#define PHB_NOT_OH 236 37static DEFINE_MUTEX(phantom_mutex);38static int phantom_major;39 40static const struct class phantom_class = {41 .name = "phantom",42};43 44struct phantom_device {45 unsigned int opened;46 void __iomem *caddr;47 u32 __iomem *iaddr;48 u32 __iomem *oaddr;49 unsigned long status;50 atomic_t counter;51 52 wait_queue_head_t wait;53 struct cdev cdev;54 55 struct mutex open_lock;56 spinlock_t regs_lock;57 58 /* used in NOT_OH mode */59 struct phm_regs oregs;60 u32 ctl_reg;61};62 63static unsigned char phantom_devices[PHANTOM_MAX_MINORS];64 65static int phantom_status(struct phantom_device *dev, unsigned long newstat)66{67 pr_debug("phantom_status %lx %lx\n", dev->status, newstat);68 69 if (!(dev->status & PHB_RUNNING) && (newstat & PHB_RUNNING)) {70 atomic_set(&dev->counter, 0);71 iowrite32(PHN_CTL_IRQ, dev->iaddr + PHN_CONTROL);72 iowrite32(0x43, dev->caddr + PHN_IRQCTL);73 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */74 } else if ((dev->status & PHB_RUNNING) && !(newstat & PHB_RUNNING)) {75 iowrite32(0, dev->caddr + PHN_IRQCTL);76 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */77 }78 79 dev->status = newstat;80 81 return 0;82}83 84/*85 * File ops86 */87 88static long phantom_ioctl(struct file *file, unsigned int cmd,89 unsigned long arg)90{91 struct phantom_device *dev = file->private_data;92 struct phm_regs rs;93 struct phm_reg r;94 void __user *argp = (void __user *)arg;95 unsigned long flags;96 unsigned int i;97 98 switch (cmd) {99 case PHN_SETREG:100 case PHN_SET_REG:101 if (copy_from_user(&r, argp, sizeof(r)))102 return -EFAULT;103 104 if (r.reg > 7)105 return -EINVAL;106 107 spin_lock_irqsave(&dev->regs_lock, flags);108 if (r.reg == PHN_CONTROL && (r.value & PHN_CTL_IRQ) &&109 phantom_status(dev, dev->status | PHB_RUNNING)){110 spin_unlock_irqrestore(&dev->regs_lock, flags);111 return -ENODEV;112 }113 114 pr_debug("phantom: writing %x to %u\n", r.value, r.reg);115 116 /* preserve amp bit (don't allow to change it when in NOT_OH) */117 if (r.reg == PHN_CONTROL && (dev->status & PHB_NOT_OH)) {118 r.value &= ~PHN_CTL_AMP;119 r.value |= dev->ctl_reg & PHN_CTL_AMP;120 dev->ctl_reg = r.value;121 }122 123 iowrite32(r.value, dev->iaddr + r.reg);124 ioread32(dev->iaddr); /* PCI posting */125 126 if (r.reg == PHN_CONTROL && !(r.value & PHN_CTL_IRQ))127 phantom_status(dev, dev->status & ~PHB_RUNNING);128 spin_unlock_irqrestore(&dev->regs_lock, flags);129 break;130 case PHN_SETREGS:131 case PHN_SET_REGS:132 if (copy_from_user(&rs, argp, sizeof(rs)))133 return -EFAULT;134 135 pr_debug("phantom: SRS %u regs %x\n", rs.count, rs.mask);136 spin_lock_irqsave(&dev->regs_lock, flags);137 if (dev->status & PHB_NOT_OH)138 memcpy(&dev->oregs, &rs, sizeof(rs));139 else {140 u32 m = min(rs.count, 8U);141 for (i = 0; i < m; i++)142 if (rs.mask & BIT(i))143 iowrite32(rs.values[i], dev->oaddr + i);144 ioread32(dev->iaddr); /* PCI posting */145 }146 spin_unlock_irqrestore(&dev->regs_lock, flags);147 break;148 case PHN_GETREG:149 case PHN_GET_REG:150 if (copy_from_user(&r, argp, sizeof(r)))151 return -EFAULT;152 153 if (r.reg > 7)154 return -EINVAL;155 156 r.value = ioread32(dev->iaddr + r.reg);157 158 if (copy_to_user(argp, &r, sizeof(r)))159 return -EFAULT;160 break;161 case PHN_GETREGS:162 case PHN_GET_REGS: {163 u32 m;164 165 if (copy_from_user(&rs, argp, sizeof(rs)))166 return -EFAULT;167 168 m = min(rs.count, 8U);169 170 pr_debug("phantom: GRS %u regs %x\n", rs.count, rs.mask);171 spin_lock_irqsave(&dev->regs_lock, flags);172 for (i = 0; i < m; i++)173 if (rs.mask & BIT(i))174 rs.values[i] = ioread32(dev->iaddr + i);175 atomic_set(&dev->counter, 0);176 spin_unlock_irqrestore(&dev->regs_lock, flags);177 178 if (copy_to_user(argp, &rs, sizeof(rs)))179 return -EFAULT;180 break;181 } case PHN_NOT_OH:182 spin_lock_irqsave(&dev->regs_lock, flags);183 if (dev->status & PHB_RUNNING) {184 printk(KERN_ERR "phantom: you need to set NOT_OH "185 "before you start the device!\n");186 spin_unlock_irqrestore(&dev->regs_lock, flags);187 return -EINVAL;188 }189 dev->status |= PHB_NOT_OH;190 spin_unlock_irqrestore(&dev->regs_lock, flags);191 break;192 default:193 return -ENOTTY;194 }195 196 return 0;197}198 199#ifdef CONFIG_COMPAT200static long phantom_compat_ioctl(struct file *filp, unsigned int cmd,201 unsigned long arg)202{203 if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {204 cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT);205 cmd |= sizeof(void *) << _IOC_SIZESHIFT;206 }207 return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));208}209#else210#define phantom_compat_ioctl NULL211#endif212 213static int phantom_open(struct inode *inode, struct file *file)214{215 struct phantom_device *dev = container_of(inode->i_cdev,216 struct phantom_device, cdev);217 218 mutex_lock(&phantom_mutex);219 nonseekable_open(inode, file);220 221 if (mutex_lock_interruptible(&dev->open_lock)) {222 mutex_unlock(&phantom_mutex);223 return -ERESTARTSYS;224 }225 226 if (dev->opened) {227 mutex_unlock(&dev->open_lock);228 mutex_unlock(&phantom_mutex);229 return -EINVAL;230 }231 232 WARN_ON(dev->status & PHB_NOT_OH);233 234 file->private_data = dev;235 236 atomic_set(&dev->counter, 0);237 dev->opened++;238 mutex_unlock(&dev->open_lock);239 mutex_unlock(&phantom_mutex);240 return 0;241}242 243static int phantom_release(struct inode *inode, struct file *file)244{245 struct phantom_device *dev = file->private_data;246 247 mutex_lock(&dev->open_lock);248 249 dev->opened = 0;250 phantom_status(dev, dev->status & ~PHB_RUNNING);251 dev->status &= ~PHB_NOT_OH;252 253 mutex_unlock(&dev->open_lock);254 255 return 0;256}257 258static __poll_t phantom_poll(struct file *file, poll_table *wait)259{260 struct phantom_device *dev = file->private_data;261 __poll_t mask = 0;262 263 pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));264 poll_wait(file, &dev->wait, wait);265 266 if (!(dev->status & PHB_RUNNING))267 mask = EPOLLERR;268 else if (atomic_read(&dev->counter))269 mask = EPOLLIN | EPOLLRDNORM;270 271 pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));272 273 return mask;274}275 276static const struct file_operations phantom_file_ops = {277 .open = phantom_open,278 .release = phantom_release,279 .unlocked_ioctl = phantom_ioctl,280 .compat_ioctl = phantom_compat_ioctl,281 .poll = phantom_poll,282};283 284static irqreturn_t phantom_isr(int irq, void *data)285{286 struct phantom_device *dev = data;287 unsigned int i;288 u32 ctl;289 290 spin_lock(&dev->regs_lock);291 ctl = ioread32(dev->iaddr + PHN_CONTROL);292 if (!(ctl & PHN_CTL_IRQ)) {293 spin_unlock(&dev->regs_lock);294 return IRQ_NONE;295 }296 297 iowrite32(0, dev->iaddr);298 iowrite32(0xc0, dev->iaddr);299 300 if (dev->status & PHB_NOT_OH) {301 struct phm_regs *r = &dev->oregs;302 u32 m = min(r->count, 8U);303 304 for (i = 0; i < m; i++)305 if (r->mask & BIT(i))306 iowrite32(r->values[i], dev->oaddr + i);307 308 dev->ctl_reg ^= PHN_CTL_AMP;309 iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL);310 }311 spin_unlock(&dev->regs_lock);312 313 ioread32(dev->iaddr); /* PCI posting */314 315 atomic_inc(&dev->counter);316 wake_up_interruptible(&dev->wait);317 318 return IRQ_HANDLED;319}320 321/*322 * Init and deinit driver323 */324 325static unsigned int phantom_get_free(void)326{327 unsigned int i;328 329 for (i = 0; i < PHANTOM_MAX_MINORS; i++)330 if (phantom_devices[i] == 0)331 break;332 333 return i;334}335 336static int phantom_probe(struct pci_dev *pdev,337 const struct pci_device_id *pci_id)338{339 struct phantom_device *pht;340 unsigned int minor;341 int retval;342 343 retval = pci_enable_device(pdev);344 if (retval) {345 dev_err(&pdev->dev, "pci_enable_device failed!\n");346 goto err;347 }348 349 minor = phantom_get_free();350 if (minor == PHANTOM_MAX_MINORS) {351 dev_err(&pdev->dev, "too many devices found!\n");352 retval = -EIO;353 goto err_dis;354 }355 356 phantom_devices[minor] = 1;357 358 retval = pci_request_regions(pdev, "phantom");359 if (retval) {360 dev_err(&pdev->dev, "pci_request_regions failed!\n");361 goto err_null;362 }363 364 retval = -ENOMEM;365 pht = kzalloc(sizeof(*pht), GFP_KERNEL);366 if (pht == NULL) {367 dev_err(&pdev->dev, "unable to allocate device\n");368 goto err_reg;369 }370 371 pht->caddr = pci_iomap(pdev, 0, 0);372 if (pht->caddr == NULL) {373 dev_err(&pdev->dev, "can't remap conf space\n");374 goto err_fr;375 }376 pht->iaddr = pci_iomap(pdev, 2, 0);377 if (pht->iaddr == NULL) {378 dev_err(&pdev->dev, "can't remap input space\n");379 goto err_unmc;380 }381 pht->oaddr = pci_iomap(pdev, 3, 0);382 if (pht->oaddr == NULL) {383 dev_err(&pdev->dev, "can't remap output space\n");384 goto err_unmi;385 }386 387 mutex_init(&pht->open_lock);388 spin_lock_init(&pht->regs_lock);389 init_waitqueue_head(&pht->wait);390 cdev_init(&pht->cdev, &phantom_file_ops);391 pht->cdev.owner = THIS_MODULE;392 393 iowrite32(0, pht->caddr + PHN_IRQCTL);394 ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */395 retval = request_irq(pdev->irq, phantom_isr,396 IRQF_SHARED, "phantom", pht);397 if (retval) {398 dev_err(&pdev->dev, "can't establish ISR\n");399 goto err_unmo;400 }401 402 retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1);403 if (retval) {404 dev_err(&pdev->dev, "chardev registration failed\n");405 goto err_irq;406 }407 408 if (IS_ERR(device_create(&phantom_class, &pdev->dev,409 MKDEV(phantom_major, minor), NULL,410 "phantom%u", minor)))411 dev_err(&pdev->dev, "can't create device\n");412 413 pci_set_drvdata(pdev, pht);414 415 return 0;416err_irq:417 free_irq(pdev->irq, pht);418err_unmo:419 pci_iounmap(pdev, pht->oaddr);420err_unmi:421 pci_iounmap(pdev, pht->iaddr);422err_unmc:423 pci_iounmap(pdev, pht->caddr);424err_fr:425 kfree(pht);426err_reg:427 pci_release_regions(pdev);428err_null:429 phantom_devices[minor] = 0;430err_dis:431 pci_disable_device(pdev);432err:433 return retval;434}435 436static void phantom_remove(struct pci_dev *pdev)437{438 struct phantom_device *pht = pci_get_drvdata(pdev);439 unsigned int minor = MINOR(pht->cdev.dev);440 441 device_destroy(&phantom_class, MKDEV(phantom_major, minor));442 443 cdev_del(&pht->cdev);444 445 iowrite32(0, pht->caddr + PHN_IRQCTL);446 ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */447 free_irq(pdev->irq, pht);448 449 pci_iounmap(pdev, pht->oaddr);450 pci_iounmap(pdev, pht->iaddr);451 pci_iounmap(pdev, pht->caddr);452 453 kfree(pht);454 455 pci_release_regions(pdev);456 457 phantom_devices[minor] = 0;458 459 pci_disable_device(pdev);460}461 462static int __maybe_unused phantom_suspend(struct device *dev_d)463{464 struct phantom_device *dev = dev_get_drvdata(dev_d);465 466 iowrite32(0, dev->caddr + PHN_IRQCTL);467 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */468 469 synchronize_irq(to_pci_dev(dev_d)->irq);470 471 return 0;472}473 474static int __maybe_unused phantom_resume(struct device *dev_d)475{476 struct phantom_device *dev = dev_get_drvdata(dev_d);477 478 iowrite32(0, dev->caddr + PHN_IRQCTL);479 480 return 0;481}482 483static struct pci_device_id phantom_pci_tbl[] = {484 { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050,485 .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050,486 .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 },487 { 0, }488};489MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);490 491static SIMPLE_DEV_PM_OPS(phantom_pm_ops, phantom_suspend, phantom_resume);492 493static struct pci_driver phantom_pci_driver = {494 .name = "phantom",495 .id_table = phantom_pci_tbl,496 .probe = phantom_probe,497 .remove = phantom_remove,498 .driver.pm = &phantom_pm_ops,499};500 501static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION);502 503static int __init phantom_init(void)504{505 int retval;506 dev_t dev;507 508 retval = class_register(&phantom_class);509 if (retval) {510 printk(KERN_ERR "phantom: can't register phantom class\n");511 goto err;512 }513 retval = class_create_file(&phantom_class, &class_attr_version.attr);514 if (retval) {515 printk(KERN_ERR "phantom: can't create sysfs version file\n");516 goto err_class;517 }518 519 retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom");520 if (retval) {521 printk(KERN_ERR "phantom: can't register character device\n");522 goto err_attr;523 }524 phantom_major = MAJOR(dev);525 526 retval = pci_register_driver(&phantom_pci_driver);527 if (retval) {528 printk(KERN_ERR "phantom: can't register pci driver\n");529 goto err_unchr;530 }531 532 printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", "533 "init OK\n");534 535 return 0;536err_unchr:537 unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);538err_attr:539 class_remove_file(&phantom_class, &class_attr_version.attr);540err_class:541 class_unregister(&phantom_class);542err:543 return retval;544}545 546static void __exit phantom_exit(void)547{548 pci_unregister_driver(&phantom_pci_driver);549 550 unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS);551 552 class_remove_file(&phantom_class, &class_attr_version.attr);553 class_unregister(&phantom_class);554 555 pr_debug("phantom: module successfully removed\n");556}557 558module_init(phantom_init);559module_exit(phantom_exit);560 561MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");562MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");563MODULE_LICENSE("GPL");564MODULE_VERSION(PHANTOM_VERSION);565