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