at v2.6.22-rc2 463 lines 11 kB view raw
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 35static struct class *phantom_class; 36static int phantom_major; 37 38struct 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 52static unsigned char phantom_devices[PHANTOM_MAX_MINORS]; 53 54static 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 74static 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 145static 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 168static 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 182static 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 199static struct file_operations phantom_file_ops = { 200 .open = phantom_open, 201 .release = phantom_release, 202 .ioctl = phantom_ioctl, 203 .poll = phantom_poll, 204}; 205 206static 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 226static 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 237static 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; 310err_irq: 311 free_irq(pdev->irq, pht); 312err_unmo: 313 pci_iounmap(pdev, pht->oaddr); 314err_unmi: 315 pci_iounmap(pdev, pht->iaddr); 316err_unmc: 317 pci_iounmap(pdev, pht->caddr); 318err_fr: 319 kfree(pht); 320err_reg: 321 pci_release_regions(pdev); 322err_null: 323 phantom_devices[minor] = 0; 324err_dis: 325 pci_disable_device(pdev); 326err: 327 return retval; 328} 329 330static 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 356static 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 365static 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 378static 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}; 383MODULE_DEVICE_TABLE(pci, phantom_pci_tbl); 384 385static 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 394static ssize_t phantom_show_version(struct class *cls, char *buf) 395{ 396 return sprintf(buf, PHANTOM_VERSION "\n"); 397} 398 399static CLASS_ATTR(version, 0444, phantom_show_version, NULL); 400 401static 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; 435err_unchr: 436 unregister_chrdev_region(dev, PHANTOM_MAX_MINORS); 437err_attr: 438 class_remove_file(phantom_class, &class_attr_version); 439err_class: 440 class_destroy(phantom_class); 441err: 442 return retval; 443} 444 445static 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 457module_init(phantom_init); 458module_exit(phantom_exit); 459 460MODULE_AUTHOR("Jiri Slaby <jirislaby@gmail.com>"); 461MODULE_DESCRIPTION("Sensable Phantom driver"); 462MODULE_LICENSE("GPL"); 463MODULE_VERSION(PHANTOM_VERSION);