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(¤t->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 (¤t->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(¤t->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(¤t->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(¤t->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(¤t->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(¤t->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