linux/drivers/misc/phantom.c
<<
>>
Prefs
   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
  37static DEFINE_MUTEX(phantom_mutex);
  38static struct class *phantom_class;
  39static int phantom_major;
  40
  41struct 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
  60static unsigned char phantom_devices[PHANTOM_MAX_MINORS];
  61
  62static 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
  85static 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
 197static 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
 210static 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
 240static 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
 255static __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
 273static 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
 282static 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
 323static 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
 334static 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;
 414err_irq:
 415        free_irq(pdev->irq, pht);
 416err_unmo:
 417        pci_iounmap(pdev, pht->oaddr);
 418err_unmi:
 419        pci_iounmap(pdev, pht->iaddr);
 420err_unmc:
 421        pci_iounmap(pdev, pht->caddr);
 422err_fr:
 423        kfree(pht);
 424err_reg:
 425        pci_release_regions(pdev);
 426err_null:
 427        phantom_devices[minor] = 0;
 428err_dis:
 429        pci_disable_device(pdev);
 430err:
 431        return retval;
 432}
 433
 434static 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
 461static 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
 473static 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
 486static 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};
 492MODULE_DEVICE_TABLE(pci, phantom_pci_tbl);
 493
 494static 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
 503static CLASS_ATTR_STRING(version, 0444, PHANTOM_VERSION);
 504
 505static 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;
 539err_unchr:
 540        unregister_chrdev_region(dev, PHANTOM_MAX_MINORS);
 541err_attr:
 542        class_remove_file(phantom_class, &class_attr_version.attr);
 543err_class:
 544        class_destroy(phantom_class);
 545err:
 546        return retval;
 547}
 548
 549static 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
 561module_init(phantom_init);
 562module_exit(phantom_exit);
 563
 564MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>");
 565MODULE_DESCRIPTION("Sensable Phantom driver (PCI devices)");
 566MODULE_LICENSE("GPL");
 567MODULE_VERSION(PHANTOM_VERSION);
 568