vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / vmod / driver / vmod16a2drvr.c
blobbefd24786557614ae6e5557e7af37b9f48c9f71c
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/pci.h>
4 #include <linux/init.h>
5 #include <linux/cdev.h>
6 #include <linux/fs.h>
7 #include <asm/uaccess.h> /* copy_*_user */
9 #include "vmod16a2.h"
10 #include "lunargs.h"
11 #include "modulbus_register.h"
13 #define DRIVER_NAME "vmod16a2"
14 #define PFX DRIVER_NAME ": "
16 /* The One And Only Device (OAOD) */
17 static dev_t devno;
18 static struct cdev cdev;
20 /* module config tables */
21 static struct vmod_devices config;
23 static int open(struct inode *ino, struct file *filp)
25 unsigned int lun = iminor(ino);
26 unsigned int idx = lun_to_index(&config, lun);
28 if (idx < 0) {
29 printk(KERN_ERR PFX
30 "cannot open, invalid lun %d\n", lun);
31 return -EINVAL;
33 filp->private_data = &config.module[idx];
34 return 0;
37 static int release(struct inode *ino, struct file *filp)
39 return 0;
42 static int do_output(struct vmod_dev *dev,
43 struct vmod16a2_convert *cvrt)
45 int value = cvrt->value;
46 int channel = cvrt->channel;
47 struct vmod16a2_registers __iomem *regp =
48 (struct vmod16a2_registers __iomem *)dev->address;
50 if (channel == 0) {
51 iowrite16be(value, &(regp->dac0in));
52 iowrite16be(value, &(regp->ldac0));
53 } else if (channel == 1) {
54 iowrite16be(value, &(regp->dac1in));
55 iowrite16be(value, &(regp->ldac1));
56 } else {
57 printk(KERN_ERR PFX "invalid channel %d\n", channel);
58 return -EINVAL;
60 return 0;
63 static int ioctl(struct inode *inode,
64 struct file *fp,
65 unsigned op,
66 unsigned long arg)
68 struct vmod_dev *devp = fp->private_data;
69 struct vmod16a2_convert cvrt, *cvrtp = &cvrt;
71 switch (op) {
73 case VMOD16A2_IOCPUT:
74 if (copy_from_user(cvrtp, (const void __user*)arg, sizeof(cvrt)) != 0)
75 return -EINVAL;
76 return do_output(devp, cvrtp);
77 break;
79 default:
80 return -ENOTTY;
82 return -ENOTTY;
85 /* @brief file operations for this driver */
86 static struct file_operations vmod16a2_fops = {
87 .owner = THIS_MODULE,
88 .ioctl = ioctl,
89 .open = open,
90 .release = release,
93 /* module initialization and cleanup */
94 static int __init init(void)
96 int err;
98 printk(KERN_INFO PFX "initializing driver");
99 err = read_params(DRIVER_NAME, &config);
100 if (err != 0)
101 return -1;
103 err = alloc_chrdev_region(&devno, 0, VMOD16A2_MAX_MODULES, DRIVER_NAME);
104 if (err != 0)
105 goto fail_chrdev;
106 printk(KERN_INFO PFX "allocated device %0d\n", MAJOR(devno));
108 cdev_init(&cdev, &vmod16a2_fops);
109 cdev.owner = THIS_MODULE;
110 err = cdev_add(&cdev, devno, VMOD16A2_MAX_MODULES);
111 if (err) {
112 printk(KERN_ERR PFX
113 "failed to create chardev %d with err %d\n",
114 MAJOR(devno), err);
115 goto fail_cdev;
117 return 0;
119 fail_cdev: unregister_chrdev_region(devno, VMOD16A2_MAX_MODULES);
120 fail_chrdev: return -1;
123 static void __exit exit(void)
125 cdev_del(&cdev);
126 unregister_chrdev_region(devno, VMOD16A2_MAX_MODULES);
129 module_init(init);
130 module_exit(exit);
132 MODULE_LICENSE("GPL");
133 MODULE_AUTHOR("Juan David Gonzalez Cobas <dcobas@cern.ch>");