vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / vmod / driver / vmod12e16drvr.c
blobe45bdb115c9a711a7712496873e73f242fe35fe8
1 /**
2 * @file vmod12e16.c
4 * @brief Driver for VMOD12E16 ADC mezzanine on VMOD/MOD-PCI MODULBUS
5 * carrier
7 * Copyright (c) 2009 CERN
8 * @author Juan David Gonzalez Cobas <dcobas@cern.ch>
10 * @section license_sec License
11 * Released under the GPL v2. (and only v2, not any later version)
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/pci.h>
17 #include <linux/init.h>
18 #include <linux/cdev.h>
19 #include <linux/delay.h>
20 #include <linux/fs.h>
21 #include <linux/uaccess.h>
22 #include <linux/semaphore.h>
23 #include "modulbus_register.h"
24 #include "lunargs.h"
25 #include "vmod12e16.h"
27 #define DRIVER_NAME "vmod12e16"
28 #define PFX DRIVER_NAME ": "
29 #define VMOD12E16_MAX_MODULES VMOD_MAX_BOARDS
31 /* The One And Only Device (OAOD) */
32 static dev_t devno;
33 static struct cdev cdev;
35 /** configuration parameters from module params */
36 static struct vmod_devices config;
37 static struct vmod12e16_dev device_list[VMOD12E16_MAX_MODULES];
39 static int vmod12e16_open(struct inode *ino, struct file *filp)
41 unsigned int lun = iminor(ino);
42 unsigned int idx = lun_to_index(&config, lun);
44 if (idx < 0) {
45 printk(KERN_ERR PFX "could not open, bad lun %d\n", lun);
46 return -ENODEV;
48 filp->private_data = &device_list[idx];
49 return 0;
52 static int vmod12e16_release(struct inode *ino, struct file *filp)
54 return 0;
57 static int do_conversion(struct file *filp,
58 struct vmod12e16_conversion *conversion)
60 struct vmod12e16_dev *dev = filp->private_data;
61 struct vmod12e16_registers __iomem *regs =
62 (struct vmod12e16_registers __iomem *)dev->config->address;
64 int channel = conversion->channel;
65 int ampli = conversion->amplification;
66 int us_elapsed;
68 if (down_interruptible(&dev->sem))
69 return -ERESTARTSYS;
71 /* explicitly disable interrupt mode for safely polling */
72 iowrite16be(VMOD_12E16_ADC_INTERRUPT_MASK, &regs->interrupt);
74 /* specify channel and amplification */
75 if ((ampli & ~((1<<2)-1)) || channel & ~((1<<4)-1)) {
76 up(&dev->sem);
77 return -EINVAL;
79 iowrite16be((ampli<<4) | channel, &regs->control);
81 /* wait at most the manufacturer-supplied max time */
82 us_elapsed = 0;
83 while (us_elapsed < VMOD_12E16_MAX_CONVERSION_TIME) {
84 udelay(VMOD_12E16_CONVERSION_TIME);
85 if ((ioread16be(&regs->ready) & VMOD_12E16_RDY_BIT) == 0) {
86 conversion->data = ioread16be(&regs->data) & VMOD_12E16_ADC_DATA_MASK;
87 udelay(VMOD_12E16_CONVERSION_TIME);
88 up(&dev->sem);
89 return 0;
91 us_elapsed += VMOD_12E16_CONVERSION_TIME;
94 /* timeout */
95 up(&dev->sem);
96 return -ETIME;
99 static int vmod12e16_ioctl(struct inode *ino,
100 struct file *filp,
101 unsigned int cmd,
102 unsigned long arg)
104 struct vmod12e16_conversion cnv, *cnvp = &cnv;
105 int err;
107 switch (cmd) {
109 case VMOD12E16_IOCCONVERT:
110 if (copy_from_user(cnvp, (const void __user*)arg, sizeof(cnv)))
111 return -EINVAL;
112 if ((err = do_conversion(filp, cnvp)) != 0)
113 return err;
114 if (copy_to_user((void __user *)arg, cnvp, sizeof(cnv)))
115 return -EINVAL;
117 return 0;
118 break;
120 default:
121 return -ENOTTY;
122 break;
124 return 0;
127 static struct file_operations fops = {
128 .owner = THIS_MODULE,
129 .ioctl = vmod12e16_ioctl,
130 .open = vmod12e16_open,
131 .release = vmod12e16_release,
134 /* module initialization and cleanup */
135 static int __init init(void)
137 int i, err;
139 printk(KERN_INFO PFX "reading parameters\n");
140 err = read_params(DRIVER_NAME, &config);
141 if (err != 0)
142 return -1;
143 printk(KERN_INFO PFX
144 "initializing driver for %d (max %d) cards\n",
145 config.num_modules, VMOD_MAX_BOARDS);
147 /* fill in config data and semaphore */
148 for (i = 0; i < config.num_modules; i++) {
149 device_list[i].config = &config.module[i];
150 init_MUTEX(&device_list[i].sem);
153 err = alloc_chrdev_region(&devno, 0, VMOD12E16_MAX_MODULES, DRIVER_NAME);
154 if (err != 0)
155 goto fail_chrdev;
156 printk(KERN_INFO PFX "allocated device %d\n", MAJOR(devno));
158 cdev_init(&cdev, &fops);
159 cdev.owner = THIS_MODULE;
160 if (cdev_add(&cdev, devno, VMOD12E16_MAX_MODULES) != 0) {
161 printk(KERN_ERR PFX
162 "failed to create chardev %d with err %d\n",
163 MAJOR(devno), err);
164 goto fail_cdev;
166 return 0;
168 fail_cdev:
169 unregister_chrdev_region(devno, VMOD12E16_MAX_MODULES);
170 fail_chrdev:
171 return -1;
174 static void __exit exit(void)
176 cdev_del(&cdev);
177 unregister_chrdev_region(devno, VMOD12E16_MAX_MODULES);
181 module_init(init);
182 module_exit(exit);
184 MODULE_LICENSE("GPL");
185 MODULE_AUTHOR("Juan David Gonzalez Cobas <dcobas@cern.ch>");