root/drivers/misc/phantom.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. phantom_status
  2. phantom_ioctl
  3. phantom_compat_ioctl
  4. phantom_open
  5. phantom_release
  6. phantom_poll
  7. phantom_isr
  8. phantom_get_free
  9. phantom_probe
  10. phantom_remove
  11. phantom_suspend
  12. phantom_resume
  13. phantom_init
  14. phantom_exit

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

/* [<][>][^][v][top][bottom][index][help] */