Close all vdi's before exit, by Daniel.
[vdi_driver.git] / src / driver / vdi.c
blobc2779941ae8ab9c1eb75742172efb3656db55809
1 /*
2 * vdi.h - The driver for virtual disks of VirtualBox
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 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #ifndef __KERNEL__
19 # define __KERNEL__
20 #endif
21 #ifndef MODULE
22 # define MODULE
23 #endif
25 //TODO: Remove? #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
30 #include <linux/blkdev.h>
31 #include <linux/cdev.h>
32 #include <linux/errno.h>
33 #include <linux/fs.h>
34 #include <linux/genhd.h>
35 #include <linux/hdreg.h>
36 #include <linux/kernel.h>
37 #include <linux/types.h>
39 #include "vdi.h"
42 * Macros
44 #define VDIS_BUF_SIZE 80
47 * Variables
49 static int vdi_major = VDI_MAJOR;
50 static int vdis_major = VDIS_MAJOR;
54 * Some disk parameters
56 static int major = VDI_MAJOR;
59 static vdi_dev vdi;
60 static struct request_queue *Queue;
62 // Used to prevent multiple access do vdis
63 static int is_vdis_open = 0;
64 static char vdis_buf[VDIS_BUF_SIZE];
65 static struct cdev vdis_cdev;
66 dev_t vdis_dev_t = MKDEV(VDIS_MAJOR, VDIS_MINOR);
68 //TODO: static char *vdis_buf
72 * Prototypes
75 // Open the char device to communicate with daemon
76 static int vdis_open(struct inode *, struct file *);
77 static int vdis_release(struct inode *, struct file *);
78 static ssize_t vdis_read(struct file *, char *, size_t, loff_t *);
79 static ssize_t vdis_write(struct file *, const char *, size_t, loff_t *);
83 * Implementation
86 static int vdis_open(struct inode *inode, struct file *file)
88 if (is_vdis_open) {
89 return -EBUSY;
91 is_vdis_open++;
92 try_module_get(THIS_MODULE);
94 return 0;
98 static int vdis_release(struct inode * inode, struct file * file)
100 is_vdis_open--;
101 return 0;
105 static ssize_t vdis_read(struct file * file, char * response, size_t length, loff_t * offset)
107 int i;
109 i = 0;
110 while ( (vdis_buf[i] != '\0') && length ) {
111 put_user(vdis_buf[i], response++);
112 i++;
113 length--;
115 vdis_buf[0] = '\0';
116 return (i + 1);
120 static ssize_t vdis_write(struct file *file, const char *message, size_t length, loff_t *offset)
122 return -EINVAL;
126 void vdi_request(request_queue_t *q)
128 struct request *req;
130 while ( (req = elv_next_request(q)) != NULL ) {
131 if (!blk_fs_request(req)) {
132 end_request(req, 0);
133 continue;
136 printk("vdi request: sec %lu (nr, %u)\n", req->nr_sectors,
137 req->current_nr_sectors);
138 // TODO: send data to the daemon
140 // Verify data direction
141 if (rq_data_dir(req)) {
142 // Write
143 //sprintf(vdis_buf, "write %lu %lu\n", req->sector, req->nr_sectors);
144 } else {
145 // Read
146 //sprintf(vdis_buf, "read %lu %lu\n", req->sector, req->nr_sectors);
149 end_request(req, 1);
154 int vdi_ioctl (struct inode *inode, struct file *filp, unsigned int cmd,
155 unsigned long arg)
157 // Unknown command
158 return -ENOTTY;
162 * Operations with the block driver
164 static struct block_device_operations vdi_oper = {
165 .owner = THIS_MODULE,
166 .ioctl = vdi_ioctl
171 * Operations with the char driver
173 struct file_operations vdis_oper = {
174 .read = vdis_read,
175 .write = vdis_write,
176 .open = vdis_open,
177 .release = vdis_release
181 static int __init vdi_init(void)
183 int err;
185 * Char device setup
187 vdis_major = alloc_chrdev_region(&vdis_dev_t, 0, 1, "vdis");
188 if (vdis_major < 0) {
189 printk(KERN_WARNING "vdi: Unable to create the char device\n");
190 return vdis_major;
192 vdis_major = MAJOR(vdis_dev_t);
194 printk(KERN_WARNING "vdi: vdis major = %d\n", vdis_major);
196 cdev_init(&vdis_cdev, &vdis_oper);
197 vdis_cdev.owner = THIS_MODULE;
198 vdis_cdev.ops = &vdis_oper;
199 err = cdev_add(&vdis_cdev, vdis_dev_t, 1);
200 if (err) {
201 printk(KERN_NOTICE "vdi: Error while adding char device\n");
206 * Block device setup
208 vdi.size = VDI_SECTORS * VDI_HARDSECT_SIZE;
210 spin_lock_init(&vdi.lock);
212 Queue = blk_init_queue(vdi_request, &vdi.lock);
213 if (Queue == NULL) {
214 printk(KERN_WARNING "vdi: Unable to create request queue.\n");
215 return -ENOMEM;
217 blk_queue_hardsect_size(Queue, VDI_HARDSECT_SIZE);
221 * Register your major, and accept a dynamic number
223 vdi_major = register_blkdev(vdi_major, "vdi");
224 if (vdi_major < 0) {
225 printk(KERN_WARNING "vdi: Unable to create block device major %d\n", vdi_major);
226 return vdi_major;
229 // Create the gendisk structure
230 vdi.gd = alloc_disk(16);
231 if (!vdi.gd) {
232 // TODO: Unregister it
233 unregister_blkdev(major, "vdi");
236 // Set gendisk fields
237 vdi.gd->major = vdi_major;
238 vdi.gd->first_minor = 0;
239 vdi.gd->fops = &vdi_oper;
240 vdi.gd->private_data = &vdi;
241 strcpy(vdi.gd->disk_name, "vdi0");
242 set_capacity(vdi.gd, VDI_SECTORS*(VDI_HARDSECT_SIZE/KERNEL_SECTOR_SIZE));
243 vdi.gd->queue = Queue;
245 add_disk(vdi.gd);
246 printk("vdi: init complete\n");
247 return 0; /* succeed */
250 static void __exit vdi_exit(void)
252 cdev_del(&vdis_cdev);
253 unregister_chrdev_region(vdis_dev_t, 1);
254 del_gendisk(vdi.gd);
255 put_disk(vdi.gd);
256 unregister_blkdev(vdi_major, "vdi");
257 blk_cleanup_queue(Queue);
258 printk("vdi: exit complete\n");
261 MODULE_LICENSE("GPL");
263 module_init(vdi_init);
264 module_exit(vdi_exit);