OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [misc/] [phantom.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.