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 * or alternatively, you might use OpenHaptics provided by Sensable. 13 */ 14 15 #include <linux/compat.h> 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/device.h> 19 #include <linux/pci.h> 20 #include <linux/fs.h> 21 #include <linux/poll.h> 22 #include <linux/interrupt.h> 23 #include <linux/cdev.h> 24 #include <linux/phantom.h> 25 26 #include <asm/atomic.h> 27 #include <asm/io.h> 28 29 #define PHANTOM_VERSION "n0.9.8" 30 31 #define PHANTOM_MAX_MINORS 8 32 33 #define PHN_IRQCTL 0x4c /* irq control in caddr space */ 34 35 #define PHB_RUNNING 1 36 #define PHB_NOT_OH 2 37 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 nonseekable_open(inode, file); 216 217 if (mutex_lock_interruptible(&dev->open_lock)) 218 return -ERESTARTSYS; 219 220 if (dev->opened) { 221 mutex_unlock(&dev->open_lock); 222 return -EINVAL; 223 } 224 225 WARN_ON(dev->status & PHB_NOT_OH); 226 227 file->private_data = dev; 228 229 atomic_set(&dev->counter, 0); 230 dev->opened++; 231 mutex_unlock(&dev->open_lock); 232 233 return 0; 234 } 235 236 static int phantom_release(struct inode *inode, struct file *file) 237 { 238 struct phantom_device *dev = file->private_data; 239 240 mutex_lock(&dev->open_lock); 241 242 dev->opened = 0; 243 phantom_status(dev, dev->status & ~PHB_RUNNING); 244 dev->status &= ~PHB_NOT_OH; 245 246 mutex_unlock(&dev->open_lock); 247 248 return 0; 249 } 250 251 static unsigned int phantom_poll(struct file *file, poll_table *wait) 252 { 253 struct phantom_device *dev = file->private_data; 254 unsigned int mask = 0; 255 256 pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter)); 257 poll_wait(file, &dev->wait, wait); 258 259 if (!(dev->status & PHB_RUNNING)) 260 mask = POLLERR; 261 else if (atomic_read(&dev->counter)) 262 mask = POLLIN | POLLRDNORM; 263 264 pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter)); 265 266 return mask; 267 } 268 269 static struct file_operations phantom_file_ops = { 270 .open = phantom_open, 271 .release = phantom_release, 272 .unlocked_ioctl = phantom_ioctl, 273 .compat_ioctl = phantom_compat_ioctl, 274 .poll = phantom_poll, 275 }; 276 277 static irqreturn_t phantom_isr(int irq, void *data) 278 { 279 struct phantom_device *dev = data; 280 unsigned int i; 281 u32 ctl; 282 283 spin_lock(&dev->regs_lock); 284 ctl = ioread32(dev->iaddr + PHN_CONTROL); 285 if (!(ctl & PHN_CTL_IRQ)) { 286 spin_unlock(&dev->regs_lock); 287 return IRQ_NONE; 288 } 289 290 iowrite32(0, dev->iaddr); 291 iowrite32(0xc0, dev->iaddr); 292 293 if (dev->status & PHB_NOT_OH) { 294 struct phm_regs *r = &dev->oregs; 295 u32 m = min(r->count, 8U); 296 297 for (i = 0; i < m; i++) 298 if (r->mask & BIT(i)) 299 iowrite32(r->values[i], dev->oaddr + i); 300 301 dev->ctl_reg ^= PHN_CTL_AMP; 302 iowrite32(dev->ctl_reg, dev->iaddr + PHN_CONTROL); 303 } 304 spin_unlock(&dev->regs_lock); 305 306 ioread32(dev->iaddr); /* PCI posting */ 307 308 atomic_inc(&dev->counter); 309 wake_up_interruptible(&dev->wait); 310 311 return IRQ_HANDLED; 312 } 313 314 /* 315 * Init and deinit driver 316 */ 317 318 static unsigned int __devinit phantom_get_free(void) 319 { 320 unsigned int i; 321 322 for (i = 0; i < PHANTOM_MAX_MINORS; i++) 323 if (phantom_devices[i] == 0) 324 break; 325 326 return i; 327 } 328 329 static int __devinit phantom_probe(struct pci_dev *pdev, 330 const struct pci_device_id *pci_id) 331 { 332 struct phantom_device *pht; 333 unsigned int minor; 334 int retval; 335 336 retval = pci_enable_device(pdev); 337 if (retval) 338 goto err; 339 340 minor = phantom_get_free(); 341 if (minor == PHANTOM_MAX_MINORS) { 342 dev_err(&pdev->dev, "too many devices found!\n"); 343 retval = -EIO; 344 goto err_dis; 345 } 346 347 phantom_devices[minor] = 1; 348 349 retval = pci_request_regions(pdev, "phantom"); 350 if (retval) 351 goto err_null; 352 353 retval = -ENOMEM; 354 pht = kzalloc(sizeof(*pht), GFP_KERNEL); 355 if (pht == NULL) { 356 dev_err(&pdev->dev, "unable to allocate device\n"); 357 goto err_reg; 358 } 359 360 pht->caddr = pci_iomap(pdev, 0, 0); 361 if (pht->caddr == NULL) { 362 dev_err(&pdev->dev, "can't remap conf space\n"); 363 goto err_fr; 364 } 365 pht->iaddr = pci_iomap(pdev, 2, 0); 366 if (pht->iaddr == NULL) { 367 dev_err(&pdev->dev, "can't remap input space\n"); 368 goto err_unmc; 369 } 370 pht->oaddr = pci_iomap(pdev, 3, 0); 371 if (pht->oaddr == NULL) { 372 dev_err(&pdev->dev, "can't remap output space\n"); 373 goto err_unmi; 374 } 375 376 mutex_init(&pht->open_lock); 377 spin_lock_init(&pht->regs_lock); 378 init_waitqueue_head(&pht->wait); 379 cdev_init(&pht->cdev, &phantom_file_ops); 380 pht->cdev.owner = THIS_MODULE; 381 382 iowrite32(0, pht->caddr + PHN_IRQCTL); 383 ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */ 384 retval = request_irq(pdev->irq, phantom_isr, 385 IRQF_SHARED | IRQF_DISABLED, "phantom", pht); 386 if (retval) { 387 dev_err(&pdev->dev, "can't establish ISR\n"); 388 goto err_unmo; 389 } 390 391 retval = cdev_add(&pht->cdev, MKDEV(phantom_major, minor), 1); 392 if (retval) { 393 dev_err(&pdev->dev, "chardev registration failed\n"); 394 goto err_irq; 395 } 396 397 if (IS_ERR(device_create(phantom_class, &pdev->dev, MKDEV(phantom_major, 398 minor), "phantom%u", minor))) 399 dev_err(&pdev->dev, "can't create device\n"); 400 401 pci_set_drvdata(pdev, pht); 402 403 return 0; 404 err_irq: 405 free_irq(pdev->irq, pht); 406 err_unmo: 407 pci_iounmap(pdev, pht->oaddr); 408 err_unmi: 409 pci_iounmap(pdev, pht->iaddr); 410 err_unmc: 411 pci_iounmap(pdev, pht->caddr); 412 err_fr: 413 kfree(pht); 414 err_reg: 415 pci_release_regions(pdev); 416 err_null: 417 phantom_devices[minor] = 0; 418 err_dis: 419 pci_disable_device(pdev); 420 err: 421 return retval; 422 } 423 424 static void __devexit phantom_remove(struct pci_dev *pdev) 425 { 426 struct phantom_device *pht = pci_get_drvdata(pdev); 427 unsigned int minor = MINOR(pht->cdev.dev); 428 429 device_destroy(phantom_class, MKDEV(phantom_major, minor)); 430 431 cdev_del(&pht->cdev); 432 433 iowrite32(0, pht->caddr + PHN_IRQCTL); 434 ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */ 435 free_irq(pdev->irq, pht); 436 437 pci_iounmap(pdev, pht->oaddr); 438 pci_iounmap(pdev, pht->iaddr); 439 pci_iounmap(pdev, pht->caddr); 440 441 kfree(pht); 442 443 pci_release_regions(pdev); 444 445 phantom_devices[minor] = 0; 446 447 pci_disable_device(pdev); 448 } 449 450 #ifdef CONFIG_PM 451 static int phantom_suspend(struct pci_dev *pdev, pm_message_t state) 452 { 453 struct phantom_device *dev = pci_get_drvdata(pdev); 454 455 iowrite32(0, dev->caddr + PHN_IRQCTL); 456 ioread32(dev->caddr + PHN_IRQCTL); /* PCI posting */ 457 458 synchronize_irq(pdev->irq); 459 460 return 0; 461 } 462 463 static int phantom_resume(struct pci_dev *pdev) 464 { 465 struct phantom_device *dev = pci_get_drvdata(pdev); 466 467 iowrite32(0, dev->caddr + PHN_IRQCTL); 468 469 return 0; 470 } 471 #else 472 #define phantom_suspend NULL 473 #define phantom_resume NULL 474 #endif 475 476 static struct pci_device_id phantom_pci_tbl[] __devinitdata = { 477 { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, 478 .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, 479 .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, 480 { 0, } 481 }; 482 MODULE_DEVICE_TABLE(pci, phantom_pci_tbl); 483 484 static struct pci_driver phantom_pci_driver = { 485 .name = "phantom", 486 .id_table = phantom_pci_tbl, 487 .probe = phantom_probe, 488 .remove = __devexit_p(phantom_remove), 489 .suspend = phantom_suspend, 490 .resume = phantom_resume 491 }; 492 493 static ssize_t phantom_show_version(struct class *cls, char *buf) 494 { 495 return sprintf(buf, PHANTOM_VERSION "\n"); 496 } 497 498 static CLASS_ATTR(version, 0444, phantom_show_version, NULL); 499 500 static int __init phantom_init(void) 501 { 502 int retval; 503 dev_t dev; 504 505 phantom_class = class_create(THIS_MODULE, "phantom"); 506 if (IS_ERR(phantom_class)) { 507 retval = PTR_ERR(phantom_class); 508 printk(KERN_ERR "phantom: can't register phantom class\n"); 509 goto err; 510 } 511 retval = class_create_file(phantom_class, &class_attr_version); 512 if (retval) { 513 printk(KERN_ERR "phantom: can't create sysfs version file\n"); 514 goto err_class; 515 } 516 517 retval = alloc_chrdev_region(&dev, 0, PHANTOM_MAX_MINORS, "phantom"); 518 if (retval) { 519 printk(KERN_ERR "phantom: can't register character device\n"); 520 goto err_attr; 521 } 522 phantom_major = MAJOR(dev); 523 524 retval = pci_register_driver(&phantom_pci_driver); 525 if (retval) { 526 printk(KERN_ERR "phantom: can't register pci driver\n"); 527 goto err_unchr; 528 } 529 530 printk(KERN_INFO "Phantom Linux Driver, version " PHANTOM_VERSION ", " 531 "init OK\n"); 532 533 return 0; 534 err_unchr: 535 unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); 536 err_attr: 537 class_remove_file(phantom_class, &class_attr_version); 538 err_class: 539 class_destroy(phantom_class); 540 err: 541 return retval; 542 } 543 544 static void __exit phantom_exit(void) 545 { 546 pci_unregister_driver(&phantom_pci_driver); 547 548 unregister_chrdev_region(MKDEV(phantom_major, 0), PHANTOM_MAX_MINORS); 549 550 class_remove_file(phantom_class, &class_attr_version); 551 class_destroy(phantom_class); 552 553 pr_debug("phantom: module successfully removed\n"); 554 } 555 556 module_init(phantom_init); 557 module_exit(phantom_exit); 558 559 MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>"); 560 MODULE_DESCRIPTION("Sensable Phantom driver"); 561 MODULE_LICENSE("GPL"); 562 MODULE_VERSION(PHANTOM_VERSION); 563