ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / char / ftape / zftape / zftape-init.c
1 /*
2  *      Copyright (C) 1996, 1997 Claus-Justus Heine.
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, or (at your option)
7  any later version.
8
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.
13
14  You should have received a copy of the GNU General Public License
15  along with this program; see the file COPYING.  If not, write to
16  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17
18  *
19  *      This file contains the code that registers the zftape frontend 
20  *      to the ftape floppy tape driver for Linux
21  */
22
23 #include <linux/config.h>
24 #include <linux/module.h>
25 #include <linux/errno.h>
26 #include <linux/version.h>
27 #include <linux/fs.h>
28 #include <linux/kernel.h>
29 #include <linux/signal.h>
30 #include <linux/major.h>
31 #include <linux/slab.h>
32 #ifdef CONFIG_KMOD
33 #include <linux/kmod.h>
34 #endif
35 #include <linux/fcntl.h>
36 #include <linux/smp_lock.h>
37 #include <linux/devfs_fs_kernel.h>
38
39 #include <linux/zftape.h>
40 #include <linux/init.h>
41 #include <linux/device.h>
42
43 #include "../zftape/zftape-init.h"
44 #include "../zftape/zftape-read.h"
45 #include "../zftape/zftape-write.h"
46 #include "../zftape/zftape-ctl.h"
47 #include "../zftape/zftape-buffers.h"
48
49 char zft_src[] __initdata = "$Source: /homes/cvs/ftape-stacked/ftape/zftape/zftape-init.c,v $";
50 char zft_rev[] __initdata = "$Revision: 1.8 $";
51 char zft_dat[] __initdata = "$Date: 1997/11/06 00:48:56 $";
52
53 MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine "
54               "(claus@momo.math.rwth-aachen.de)");
55 MODULE_DESCRIPTION(ZFTAPE_VERSION " - "
56                    "VFS interface for the Linux floppy tape driver. "
57                    "Support for QIC-113 compatible volume table "
58                    "and builtin compression (lzrw3 algorithm)");
59 MODULE_SUPPORTED_DEVICE("char-major-27");
60 MODULE_LICENSE("GPL");
61
62 /*      Global vars.
63  */
64 struct zft_cmpr_ops *zft_cmpr_ops = NULL;
65 const ftape_info *zft_status;
66
67 /*      Local vars.
68  */
69 static unsigned long busy_flag;
70
71 static sigset_t orig_sigmask;
72
73 /*  the interface to the kernel vfs layer
74  */
75
76 /* Note about llseek():
77  *
78  * st.c and tpqic.c update fp->f_pos but don't implment llseek() and
79  * initialize the llseek component of the file_ops struct with NULL.
80  * This means that the user will get the default seek, but the tape
81  * device will not respect the new position, but happily read from the
82  * old position. Think a zftape specific llseek() function would be
83  * better, returning -ESPIPE. TODO.
84  */
85
86 static int  zft_open (struct inode *ino, struct file *filep);
87 static int zft_close(struct inode *ino, struct file *filep);
88 static int  zft_ioctl(struct inode *ino, struct file *filep,
89                       unsigned int command, unsigned long arg);
90 static int  zft_mmap(struct file *filep, struct vm_area_struct *vma);
91 static ssize_t zft_read (struct file *fp, char *buff,
92                          size_t req_len, loff_t *ppos);
93 static ssize_t zft_write(struct file *fp, const char *buff,
94                          size_t req_len, loff_t *ppos);
95
96 static struct file_operations zft_cdev =
97 {
98         .owner          = THIS_MODULE,
99         .read           = zft_read,
100         .write          = zft_write,
101         .ioctl          = zft_ioctl,
102         .mmap           = zft_mmap,
103         .open           = zft_open,
104         .release        = zft_close,
105 };
106
107 static struct class_simple *zft_class;
108
109 /*      Open floppy tape device
110  */
111 static int zft_open(struct inode *ino, struct file *filep)
112 {
113         int result;
114         TRACE_FUN(ft_t_flow);
115
116         TRACE(ft_t_flow, "called for minor %d", iminor(ino));
117         if ( test_and_set_bit(0,&busy_flag) ) {
118                 TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy");
119         }
120         if ((iminor(ino) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND))
121              > 
122             FTAPE_SEL_D) {
123                 clear_bit(0,&busy_flag);
124                 TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr");
125         }
126         orig_sigmask = current->blocked;
127         sigfillset(&current->blocked);
128         result = _zft_open(iminor(ino), filep->f_flags & O_ACCMODE);
129         if (result < 0) {
130                 current->blocked = orig_sigmask; /* restore mask */
131                 clear_bit(0,&busy_flag);
132                 TRACE_ABORT(result, ft_t_err, "_ftape_open failed");
133         } else {
134                 /* Mask signals that will disturb proper operation of the
135                  * program that is calling.
136                  */
137                 current->blocked = orig_sigmask;
138                 sigaddsetmask (&current->blocked, _DO_BLOCK);
139                 TRACE_EXIT 0;
140         }
141 }
142
143 /*      Close floppy tape device
144  */
145 static int zft_close(struct inode *ino, struct file *filep)
146 {
147         int result;
148         TRACE_FUN(ft_t_flow);
149
150         if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit) {
151                 TRACE(ft_t_err, "failed: not busy or wrong unit");
152                 TRACE_EXIT 0;
153         }
154         sigfillset(&current->blocked);
155         result = _zft_close();
156         if (result < 0) {
157                 TRACE(ft_t_err, "_zft_close failed");
158         }
159         current->blocked = orig_sigmask; /* restore before open state */
160         clear_bit(0,&busy_flag);
161         TRACE_EXIT 0;
162 }
163
164 /*      Ioctl for floppy tape device
165  */
166 static int zft_ioctl(struct inode *ino, struct file *filep,
167                      unsigned int command, unsigned long arg)
168 {
169         int result = -EIO;
170         sigset_t old_sigmask;
171         TRACE_FUN(ft_t_flow);
172
173         if ( !test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) {
174                 TRACE_ABORT(-EIO, ft_t_err,
175                             "failed: not busy, failure or wrong unit");
176         }
177         old_sigmask = current->blocked; /* save mask */
178         sigfillset(&current->blocked);
179         /* This will work as long as sizeof(void *) == sizeof(long) */
180         result = _zft_ioctl(command, (void *) arg);
181         current->blocked = old_sigmask; /* restore mask */
182         TRACE_EXIT result;
183 }
184
185 /*      Ioctl for floppy tape device
186  */
187 static int  zft_mmap(struct file *filep, struct vm_area_struct *vma)
188 {
189         int result = -EIO;
190         sigset_t old_sigmask;
191         TRACE_FUN(ft_t_flow);
192
193         if ( !test_bit(0,&busy_flag) || 
194             iminor(filep->f_dentry->d_inode) != zft_unit || 
195             ft_failure)
196         {
197                 TRACE_ABORT(-EIO, ft_t_err,
198                             "failed: not busy, failure or wrong unit");
199         }
200         old_sigmask = current->blocked; /* save mask */
201         sigfillset(&current->blocked);
202         if ((result = ftape_mmap(vma)) >= 0) {
203 #ifndef MSYNC_BUG_WAS_FIXED
204                 static struct vm_operations_struct dummy = { NULL, };
205                 vma->vm_ops = &dummy;
206 #endif
207         }
208         current->blocked = old_sigmask; /* restore mask */
209         TRACE_EXIT result;
210 }
211
212 /*      Read from floppy tape device
213  */
214 static ssize_t zft_read(struct file *fp, char *buff,
215                         size_t req_len, loff_t *ppos)
216 {
217         int result = -EIO;
218         sigset_t old_sigmask;
219         struct inode *ino = fp->f_dentry->d_inode;
220         TRACE_FUN(ft_t_flow);
221
222         TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len);
223         if (!test_bit(0,&busy_flag)  || iminor(ino) != zft_unit || ft_failure) {
224                 TRACE_ABORT(-EIO, ft_t_err,
225                             "failed: not busy, failure or wrong unit");
226         }
227         old_sigmask = current->blocked; /* save mask */
228         sigfillset(&current->blocked);
229         result = _zft_read(buff, req_len);
230         current->blocked = old_sigmask; /* restore mask */
231         TRACE(ft_t_data_flow, "return with count: %d", result);
232         TRACE_EXIT result;
233 }
234
235 /*      Write to tape device
236  */
237 static ssize_t zft_write(struct file *fp, const char *buff,
238                          size_t req_len, loff_t *ppos)
239 {
240         int result = -EIO;
241         sigset_t old_sigmask;
242         struct inode *ino = fp->f_dentry->d_inode;
243         TRACE_FUN(ft_t_flow);
244
245         TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len);
246         if (!test_bit(0,&busy_flag) || iminor(ino) != zft_unit || ft_failure) {
247                 TRACE_ABORT(-EIO, ft_t_err,
248                             "failed: not busy, failure or wrong unit");
249         }
250         old_sigmask = current->blocked; /* save mask */
251         sigfillset(&current->blocked);
252         result = _zft_write(buff, req_len);
253         current->blocked = old_sigmask; /* restore mask */
254         TRACE(ft_t_data_flow, "return with count: %d", result);
255         TRACE_EXIT result;
256 }
257
258 /*                    END OF VFS INTERFACE 
259  *          
260  *****************************************************************************/
261
262 /*  driver/module initialization
263  */
264
265 /*  the compression module has to call this function to hook into the zftape 
266  *  code
267  */
268 int zft_cmpr_register(struct zft_cmpr_ops *new_ops)
269 {
270         TRACE_FUN(ft_t_flow);
271         
272         if (zft_cmpr_ops != NULL) {
273                 TRACE_EXIT -EBUSY;
274         } else {
275                 zft_cmpr_ops = new_ops;
276                 TRACE_EXIT 0;
277         }
278 }
279
280 struct zft_cmpr_ops *zft_cmpr_unregister(void)
281 {
282         struct zft_cmpr_ops *old_ops = zft_cmpr_ops;
283         TRACE_FUN(ft_t_flow);
284
285         zft_cmpr_ops = NULL;
286         TRACE_EXIT old_ops;
287 }
288
289 /*  lock the zft-compressor() module.
290  */
291 int zft_cmpr_lock(int try_to_load)
292 {
293         if (zft_cmpr_ops == NULL) {
294 #ifdef CONFIG_KMOD
295                 if (try_to_load) {
296                         request_module("zft-compressor");
297                         if (zft_cmpr_ops == NULL) {
298                                 return -ENOSYS;
299                         }
300                 } else {
301                         return -ENOSYS;
302                 }
303 #else
304                 return -ENOSYS;
305 #endif
306         }
307         (*zft_cmpr_ops->lock)();
308         return 0;
309 }
310
311 #ifdef CONFIG_ZFT_COMPRESSOR
312 extern int zft_compressor_init(void);
313 #endif
314
315 /*  Called by modules package when installing the driver or by kernel
316  *  during the initialization phase
317  */
318 int __init zft_init(void)
319 {
320         int i;
321         TRACE_FUN(ft_t_flow);
322
323 #ifdef MODULE
324         printk(KERN_INFO ZFTAPE_VERSION "\n");
325         if (TRACE_LEVEL >= ft_t_info) {
326                 printk(
327 KERN_INFO
328 "(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
329 KERN_INFO
330 "vfs interface for ftape floppy tape driver.\n"
331 KERN_INFO
332 "Support for QIC-113 compatible volume table, dynamic memory allocation\n"
333 KERN_INFO
334 "and builtin compression (lzrw3 algorithm).\n"
335 KERN_INFO
336 "Compiled for Linux version %s\n", UTS_RELEASE);
337         }
338 #else /* !MODULE */
339         /* print a short no-nonsense boot message */
340         printk(KERN_INFO ZFTAPE_VERSION " for Linux " UTS_RELEASE "\n");
341 #endif /* MODULE */
342         TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
343         TRACE(ft_t_info,
344               "installing zftape VFS interface for ftape driver ...");
345         TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
346
347         zft_class = class_simple_create(THIS_MODULE, "zft");
348         for (i = 0; i < 4; i++) {
349                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
350                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i),
351                                 S_IFCHR | S_IRUSR | S_IWUSR,
352                                 "qft%i", i);
353                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
354                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4),
355                                 S_IFCHR | S_IRUSR | S_IWUSR,
356                                 "nqft%i", i);
357                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
358                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16),
359                                 S_IFCHR | S_IRUSR | S_IWUSR,
360                                 "zqft%i", i);
361                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
362                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20),
363                                 S_IFCHR | S_IRUSR | S_IWUSR,
364                                 "nzqft%i", i);
365                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
366                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32),
367                                 S_IFCHR | S_IRUSR | S_IWUSR,
368                                 "rawqft%i", i);
369                 class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
370                 devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36),
371                                 S_IFCHR | S_IRUSR | S_IWUSR,
372                                 "nrawqft%i", i);
373         }
374
375 #ifdef CONFIG_ZFT_COMPRESSOR
376         (void)zft_compressor_init();
377 #endif
378         zft_status = ftape_get_status(); /*  fetch global data of ftape 
379                                           *  hardware driver 
380                                           */
381         TRACE_EXIT 0;
382 }
383
384
385 /* Called by modules package when removing the driver 
386  */
387 static void zft_exit(void)
388 {
389         int i;
390         TRACE_FUN(ft_t_flow);
391
392         if (unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
393                 TRACE(ft_t_warn, "failed");
394         } else {
395                 TRACE(ft_t_info, "successful");
396         }
397         for (i = 0; i < 4; i++) {
398                 devfs_remove("qft%i", i);
399                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i));
400                 devfs_remove("nqft%i", i);
401                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 4));
402                 devfs_remove("zqft%i", i);
403                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 16));
404                 devfs_remove("nzqft%i", i);
405                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 20));
406                 devfs_remove("rawqft%i", i);
407                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 32));
408                 devfs_remove("nrawqft%i", i);
409                 class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 36));
410         }
411         class_simple_destroy(zft_class);
412         zft_uninit_mem(); /* release remaining memory, if any */
413         printk(KERN_INFO "zftape successfully unloaded.\n");
414         TRACE_EXIT;
415 }
416
417 module_init(zft_init);
418 module_exit(zft_exit);