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 <asm/segment.h>
29#include <linux/kernel.h>
30#include <linux/signal.h>
31#include <linux/major.h>
32#include <linux/slab.h>
33#ifdef CONFIG_KMOD
34#include <linux/kmod.h>
35#endif
36#include <linux/fcntl.h>
37#include <linux/wrapper.h>
38#include <linux/smp_lock.h>
39#include <linux/devfs_fs_kernel.h>
40
41#include <linux/zftape.h>
42#include <linux/init.h>
43
44#include "../zftape/zftape-init.h"
45#include "../zftape/zftape-read.h"
46#include "../zftape/zftape-write.h"
47#include "../zftape/zftape-ctl.h"
48#include "../zftape/zftape-buffers.h"
49#include "../zftape/zftape_syms.h"
50
51char zft_src[] __initdata = "$Source: /home/user/PROJECT/WL-520gu-NewUI/src/linux/linux/drivers/char/ftape/zftape/zftape-init.c,v $";
52char zft_rev[] __initdata = "$Revision: 1.1.1.1 $";
53char zft_dat[] __initdata = "$Date: 2008/10/15 03:26:29 $";
54
55MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine "
56	      "(claus@momo.math.rwth-aachen.de)");
57MODULE_DESCRIPTION(ZFTAPE_VERSION " - "
58		   "VFS interface for the Linux floppy tape driver. "
59		   "Support for QIC-113 compatible volume table "
60		   "and builtin compression (lzrw3 algorithm)");
61MODULE_SUPPORTED_DEVICE("char-major-27");
62MODULE_LICENSE("GPL");
63
64/*      Global vars.
65 */
66struct zft_cmpr_ops *zft_cmpr_ops = NULL;
67const ftape_info *zft_status;
68
69/*      Local vars.
70 */
71static int busy_flag = 0;
72static sigset_t orig_sigmask;
73
74/*  the interface to the kernel vfs layer
75 */
76
77/* Note about llseek():
78 *
79 * st.c and tpqic.c update fp->f_pos but don't implment llseek() and
80 * initialize the llseek component of the file_ops struct with NULL.
81 * This means that the user will get the default seek, but the tape
82 * device will not respect the new position, but happily read from the
83 * old position. Think a zftape specific llseek() function would be
84 * better, returning -ESPIPE. TODO.
85 */
86
87static int  zft_open (struct inode *ino, struct file *filep);
88static int zft_close(struct inode *ino, struct file *filep);
89static int  zft_ioctl(struct inode *ino, struct file *filep,
90		      unsigned int command, unsigned long arg);
91static int  zft_mmap(struct file *filep, struct vm_area_struct *vma);
92static ssize_t zft_read (struct file *fp, char *buff,
93			 size_t req_len, loff_t *ppos);
94static ssize_t zft_write(struct file *fp, const char *buff,
95			 size_t req_len, loff_t *ppos);
96
97static struct file_operations zft_cdev =
98{
99	owner:		THIS_MODULE,
100	read:		zft_read,
101	write:		zft_write,
102	ioctl:		zft_ioctl,
103	mmap:		zft_mmap,
104	open:		zft_open,
105	release:	zft_close,
106};
107
108/*      Open floppy tape device
109 */
110static int zft_open(struct inode *ino, struct file *filep)
111{
112	int result;
113	TRACE_FUN(ft_t_flow);
114
115	TRACE(ft_t_flow, "called for minor %d", MINOR(ino->i_rdev));
116	if (busy_flag) {
117		TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy");
118	}
119	busy_flag = 1;
120	if ((MINOR(ino->i_rdev) & ~(ZFT_MINOR_OP_MASK | FTAPE_NO_REWIND))
121	     >
122	    FTAPE_SEL_D) {
123		busy_flag = 0;
124		TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr");
125	}
126	orig_sigmask = current->blocked;
127	sigfillset(&current->blocked);
128	result = _zft_open(MINOR(ino->i_rdev), filep->f_flags & O_ACCMODE);
129	if (result < 0) {
130		current->blocked = orig_sigmask; /* restore mask */
131		busy_flag = 0;
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 */
145static int zft_close(struct inode *ino, struct file *filep)
146{
147	int result;
148	TRACE_FUN(ft_t_flow);
149
150	lock_kernel();
151	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit) {
152		TRACE(ft_t_err, "failed: not busy or wrong unit");
153		unlock_kernel();
154		TRACE_EXIT 0;
155	}
156	sigfillset(&current->blocked);
157	result = _zft_close();
158	if (result < 0) {
159		TRACE(ft_t_err, "_zft_close failed");
160	}
161	current->blocked = orig_sigmask; /* restore before open state */
162	busy_flag = 0;
163	unlock_kernel();
164	TRACE_EXIT 0;
165}
166
167/*      Ioctl for floppy tape device
168 */
169static int zft_ioctl(struct inode *ino, struct file *filep,
170		     unsigned int command, unsigned long arg)
171{
172	int result = -EIO;
173	sigset_t old_sigmask;
174	TRACE_FUN(ft_t_flow);
175
176	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
177		TRACE_ABORT(-EIO, ft_t_err,
178			    "failed: not busy, failure or wrong unit");
179	}
180	old_sigmask = current->blocked; /* save mask */
181	sigfillset(&current->blocked);
182	/* This will work as long as sizeof(void *) == sizeof(long) */
183	result = _zft_ioctl(command, (void *) arg);
184	current->blocked = old_sigmask; /* restore mask */
185	TRACE_EXIT result;
186}
187
188/*      Ioctl for floppy tape device
189 */
190static int  zft_mmap(struct file *filep, struct vm_area_struct *vma)
191{
192	int result = -EIO;
193	sigset_t old_sigmask;
194	TRACE_FUN(ft_t_flow);
195
196	if (!busy_flag ||
197	    MINOR(filep->f_dentry->d_inode->i_rdev) != zft_unit ||
198	    ft_failure)
199	{
200		TRACE_ABORT(-EIO, ft_t_err,
201			    "failed: not busy, failure or wrong unit");
202	}
203	old_sigmask = current->blocked; /* save mask */
204	sigfillset(&current->blocked);
205	lock_kernel();
206	if ((result = ftape_mmap(vma)) >= 0) {
207#ifndef MSYNC_BUG_WAS_FIXED
208		static struct vm_operations_struct dummy = { NULL, };
209		vma->vm_ops = &dummy;
210#endif
211	}
212	unlock_kernel();
213	current->blocked = old_sigmask; /* restore mask */
214	TRACE_EXIT result;
215}
216
217/*      Read from floppy tape device
218 */
219static ssize_t zft_read(struct file *fp, char *buff,
220			size_t req_len, loff_t *ppos)
221{
222	int result = -EIO;
223	sigset_t old_sigmask;
224	struct inode *ino = fp->f_dentry->d_inode;
225	TRACE_FUN(ft_t_flow);
226
227	TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len);
228	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
229		TRACE_ABORT(-EIO, ft_t_err,
230			    "failed: not busy, failure or wrong unit");
231	}
232	old_sigmask = current->blocked; /* save mask */
233	sigfillset(&current->blocked);
234	result = _zft_read(buff, req_len);
235	current->blocked = old_sigmask; /* restore mask */
236	TRACE(ft_t_data_flow, "return with count: %d", result);
237	TRACE_EXIT result;
238}
239
240/*      Write to tape device
241 */
242static ssize_t zft_write(struct file *fp, const char *buff,
243			 size_t req_len, loff_t *ppos)
244{
245	int result = -EIO;
246	sigset_t old_sigmask;
247	struct inode *ino = fp->f_dentry->d_inode;
248	TRACE_FUN(ft_t_flow);
249
250	TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len);
251	if (!busy_flag || MINOR(ino->i_rdev) != zft_unit || ft_failure) {
252		TRACE_ABORT(-EIO, ft_t_err,
253			    "failed: not busy, failure or wrong unit");
254	}
255	old_sigmask = current->blocked; /* save mask */
256	sigfillset(&current->blocked);
257	result = _zft_write(buff, req_len);
258	current->blocked = old_sigmask; /* restore mask */
259	TRACE(ft_t_data_flow, "return with count: %d", result);
260	TRACE_EXIT result;
261}
262
263/*                    END OF VFS INTERFACE
264 *
265 *****************************************************************************/
266
267/*  driver/module initialization
268 */
269
270/*  the compression module has to call this function to hook into the zftape
271 *  code
272 */
273int zft_cmpr_register(struct zft_cmpr_ops *new_ops)
274{
275	TRACE_FUN(ft_t_flow);
276
277	if (zft_cmpr_ops != NULL) {
278		TRACE_EXIT -EBUSY;
279	} else {
280		zft_cmpr_ops = new_ops;
281		TRACE_EXIT 0;
282	}
283}
284
285struct zft_cmpr_ops *zft_cmpr_unregister(void)
286{
287	struct zft_cmpr_ops *old_ops = zft_cmpr_ops;
288	TRACE_FUN(ft_t_flow);
289
290	zft_cmpr_ops = NULL;
291	TRACE_EXIT old_ops;
292}
293
294/*  lock the zft-compressor() module.
295 */
296int zft_cmpr_lock(int try_to_load)
297{
298	if (zft_cmpr_ops == NULL) {
299#ifdef CONFIG_KMOD
300		if (try_to_load) {
301			request_module("zft-compressor");
302			if (zft_cmpr_ops == NULL) {
303				return -ENOSYS;
304			}
305		} else {
306			return -ENOSYS;
307		}
308#else
309		return -ENOSYS;
310#endif
311	}
312	(*zft_cmpr_ops->lock)();
313	return 0;
314}
315
316#ifdef CONFIG_ZFT_COMPRESSOR
317extern int zft_compressor_init(void);
318#endif
319
320/*  Called by modules package when installing the driver or by kernel
321 *  during the initialization phase
322 */
323int __init zft_init(void)
324{
325	int i;
326	TRACE_FUN(ft_t_flow);
327
328#ifdef MODULE
329	printk(KERN_INFO ZFTAPE_VERSION "\n");
330        if (TRACE_LEVEL >= ft_t_info) {
331		printk(
332KERN_INFO
333"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)\n"
334KERN_INFO
335"vfs interface for ftape floppy tape driver.\n"
336KERN_INFO
337"Support for QIC-113 compatible volume table, dynamic memory allocation\n"
338KERN_INFO
339"and builtin compression (lzrw3 algorithm).\n"
340KERN_INFO
341"Compiled for Linux version %s"
342#ifdef MODVERSIONS
343		       " with versioned symbols"
344#endif
345		       "\n", UTS_RELEASE);
346        }
347#else /* !MODULE */
348	/* print a short no-nonsense boot message */
349	printk(KERN_INFO ZFTAPE_VERSION " for Linux " UTS_RELEASE "\n");
350#endif /* MODULE */
351	TRACE(ft_t_info, "zft_init @ 0x%p", zft_init);
352	TRACE(ft_t_info,
353	      "installing zftape VFS interface for ftape driver ...");
354	TRACE_CATCH(devfs_register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
355
356	for (i = 0; i < 4; i++) {
357		char devname[9];
358
359		sprintf (devname, "qft%i", i);
360		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
361			        QIC117_TAPE_MAJOR, i,
362				S_IFCHR | S_IRUSR | S_IWUSR,
363				&zft_cdev, NULL);
364		sprintf (devname, "nqft%i", i);
365		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
366				QIC117_TAPE_MAJOR, i + 4,
367				S_IFCHR | S_IRUSR | S_IWUSR,
368				&zft_cdev, NULL);
369		sprintf (devname, "zqft%i", i);
370		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
371				QIC117_TAPE_MAJOR, i + 16,
372				S_IFCHR | S_IRUSR | S_IWUSR,
373				&zft_cdev, NULL);
374		sprintf (devname, "nzqft%i", i);
375		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
376				QIC117_TAPE_MAJOR, i + 20,
377				S_IFCHR | S_IRUSR | S_IWUSR,
378				&zft_cdev, NULL);
379		sprintf (devname, "rawqft%i", i);
380		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
381				QIC117_TAPE_MAJOR, i + 32,
382				S_IFCHR | S_IRUSR | S_IWUSR,
383				&zft_cdev, NULL);
384		sprintf (devname, "nrawqft%i", i);
385		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
386				QIC117_TAPE_MAJOR, i + 36,
387				S_IFCHR | S_IRUSR | S_IWUSR,
388				&zft_cdev, NULL);
389	}
390
391#ifdef CONFIG_ZFT_COMPRESSOR
392	(void)zft_compressor_init();
393#endif
394	zft_status = ftape_get_status(); /*  fetch global data of ftape
395					  *  hardware driver
396					  */
397	TRACE_EXIT 0;
398}
399
400
401#ifdef MODULE
402/* Called by modules package before trying to unload the module
403 */
404static int can_unload(void)
405{
406	return (GET_USE_COUNT(THIS_MODULE)||zft_dirty()||busy_flag)?-EBUSY:0;
407}
408/* Called by modules package when installing the driver
409 */
410int init_module(void)
411{
412	if (!mod_member_present(&__this_module, can_unload)) {
413		return -EBUSY;
414	}
415	__this_module.can_unload = can_unload;
416	return zft_init();
417}
418
419/* Called by modules package when removing the driver
420 */
421void cleanup_module(void)
422{
423	int i;
424	char devname[9];
425
426	TRACE_FUN(ft_t_flow);
427
428	if (devfs_unregister_chrdev(QIC117_TAPE_MAJOR, "zft") != 0) {
429		TRACE(ft_t_warn, "failed");
430	} else {
431		TRACE(ft_t_info, "successful");
432	}
433        for (i = 0; i < 4; i++) {
434		sprintf(devname, "qft%i", i);
435		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i, DEVFS_SPECIAL_CHR, 0));
436		sprintf(devname, "nqft%i", i);
437		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 4, DEVFS_SPECIAL_CHR, 0));
438		sprintf(devname, "zqft%i", i);
439		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 16, DEVFS_SPECIAL_CHR, 0));
440		sprintf(devname, "nzqft%i", i);
441		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 20, DEVFS_SPECIAL_CHR, 0));
442		sprintf(devname, "rawqft%i", i);
443		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 32, DEVFS_SPECIAL_CHR, 0));
444		sprintf(devname, "nrawqft%i", i);
445		devfs_unregister(devfs_find_handle(NULL, devname, QIC117_TAPE_MAJOR, i + 36, DEVFS_SPECIAL_CHR, 0));
446	}
447	zft_uninit_mem(); /* release remaining memory, if any */
448        printk(KERN_INFO "zftape successfully unloaded.\n");
449	TRACE_EXIT;
450}
451
452#endif /* MODULE */
453