vmod/vmodttl: fixed bug related to luns not ordered and/or not starting from zero.
[ht-drivers.git] / vmod / driver / vmoddordrvr.c
blobf47a3b899b2ec48eab505dd6cedb59da0abba3b1
1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/fs.h>
4 #include <linux/cdev.h>
5 #include <linux/kernel.h>
6 #include <linux/errno.h>
7 #include <asm/uaccess.h>
8 #include <linux/pci.h>
9 #include "vmoddor.h"
10 #include "modulbus_register.h"
11 #include "lunargs.h"
13 #define DRIVER_NAME "vmoddor"
14 #define PFX DRIVER_NAME ": "
16 static struct vmod_devices dt, *dev_table = &dt;
18 static struct vmoddor_dev vmoddor[VMODDOR_MAX_DEVICES];
20 static struct cdev *cdev;
21 static dev_t dev;
23 static inline void vmoddor_write_word(struct vmoddor_dev *pd, int offset, uint16_t value)
25 unsigned long ioaddr = pd->handle + offset;
27 if (pd->is_big_endian)
28 iowrite16be(value, (u16 *)ioaddr);
29 else
30 iowrite16(value, (u16 *)ioaddr);
33 static void vmoddor_write_byte(struct vmoddor_dev *pd, int offset, uint8_t value)
35 unsigned long ioaddr = pd->handle + offset;
37 iowrite8(value, (u8 *)ioaddr);
40 static void vmoddor_write_4bits(struct vmoddor_dev *pd, int offset, uint8_t value)
42 vmoddor_write_byte(pd, offset, value & 0xf);
45 int vmoddor_open(struct inode *ino, struct file *filp)
47 return 0;
50 int vmoddor_release(struct inode *ino, struct file *filp)
52 return 0;
55 static int vmoddor_ioctl(struct inode *inode, struct file *fp, unsigned op,
56 unsigned long arg)
58 unsigned int minor = iminor(inode);
59 struct vmoddor_dev *pd = &vmoddor[minor];
61 if (pd == NULL)
62 return -EINVAL;
64 switch(op){
65 case VMODDOR_WRITE:
67 struct vmoddor_arg val;
69 if(copy_from_user((char *)&val, (char *)arg, sizeof(struct vmoddor_arg)))
70 return -EIO;
72 switch(val.size){
73 case 16:
74 if(val.offset != 0)
75 return -EINVAL;
77 vmoddor_write_word(pd, 0, val.data);
78 break;
80 case 8:
81 if(val.offset > 1)
82 return -EINVAL;
84 vmoddor_write_byte(pd, val.offset, val.data & 0xff);
85 break;
87 case 4:
88 if((val.offset < 2) || (val.offset > 5))
89 return -EINVAL;
91 vmoddor_write_4bits(pd, val.offset, val.data & 0xff);
92 break;
93 default:
94 return -EINVAL;
97 break;
99 default:
100 printk(KERN_INFO PFX "Ioctl operation not implemented\n");
101 return -EINVAL;
105 return 0;
108 struct file_operations vmoddor_fops = {
109 .owner = THIS_MODULE,
110 .ioctl = vmoddor_ioctl,
111 .open = vmoddor_open,
112 .release = vmoddor_release
116 static int __init vmoddor_init(void)
118 int err;
119 int major = 0;
120 int minor = 0;
121 int i;
123 printk (KERN_INFO PFX "Init Module\n");
125 err = read_params(DRIVER_NAME, dev_table);
126 if (err != 0)
127 return -1;
129 printk(KERN_INFO PFX "initialized driver for %d (max %d) cards\n",
130 dev_table->num_modules, VMODDOR_MAX_DEVICES);
132 err = alloc_chrdev_region(&dev, 0, VMODDOR_MAX_DEVICES, "vmoddor");
133 if (err){
134 printk(KERN_ALERT PFX "Cannot allocate character device\n");
135 goto error;
138 major = MAJOR(dev);
139 minor = MINOR(dev);
140 cdev = cdev_alloc();
141 if (cdev == NULL)
142 goto error;
144 cdev_init(cdev, &vmoddor_fops);
145 cdev->owner = THIS_MODULE;
146 cdev->ops = &vmoddor_fops;
148 err = cdev_add(cdev, dev, VMODDOR_MAX_DEVICES);
149 if (err){
150 printk(KERN_ALERT PFX "Error %d adding device\n", err);
151 goto error_cdev_add;
154 for(i = 0; i < dev_table->num_modules; i++){
155 struct vmod_dev *mod = &dev_table->module[i];
157 vmoddor[i].lun = mod->lun;
158 vmoddor[i].cname = mod->carrier_name;
159 vmoddor[i].carrier = mod->carrier_lun;
160 vmoddor[i].slot = mod->slot;
161 vmoddor[i].handle = mod->address;
163 vmoddor[i].is_big_endian = mod->is_big_endian;
166 return 0;
168 error_cdev_add:
169 cdev_del(cdev);
170 unregister_chrdev_region(dev, VMODDOR_MAX_DEVICES);
171 error:
172 return -1;
175 static void __exit vmoddor_exit(void)
177 cdev_del(cdev);
178 unregister_chrdev_region(dev, VMODDOR_MAX_DEVICES);
179 printk(KERN_INFO PFX "Exit module.\n");
182 module_init(vmoddor_init);
183 module_exit(vmoddor_exit);
185 MODULE_AUTHOR("Samuel I. Gonsalvez");
186 MODULE_LICENSE("GPL");
187 MODULE_DESCRIPTION("VMODDOR device driver");
188 MODULE_VERSION("1.0");