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