root/drivers/char/ftape/kernel-interface.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __get_order
  2. dmaalloc
  3. dmafree
  4. ftape_init
  5. cleanup_module
  6. ftape_open
  7. ftape_close
  8. ftape_ioctl
  9. ftape_read
  10. ftape_write

   1 /*
   2  *      Copyright (C) 1993-1995 Bas Laarhoven.
   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 interfaces the kernel
  20  *      for the QIC-40/80 floppy-tape driver for Linux.
  21  */
  22 
  23 #include <linux/module.h>
  24 #include <linux/version.h>
  25 #include <linux/errno.h>
  26 #include <linux/fs.h>
  27 #include <asm/segment.h>
  28 #include <linux/kernel.h>
  29 #include <linux/signal.h>
  30 #include <linux/major.h>
  31 #include <linux/malloc.h>
  32 #include <linux/ftape.h>
  33 #include <asm/dma.h>
  34 
  35 #include "tracing.h"
  36 #include "kernel-interface.h"
  37 #include "ftape-read.h"
  38 #include "ftape-write.h"
  39 #include "ftape-io.h"
  40 #include "ftape-ctl.h"
  41 #include "ftape-rw.h"
  42 #include "fdc-io.h"
  43 
  44 
  45 /*      Global vars.
  46  */
  47 
  48 /* Allocating a 96Kb DMAable buffer in one chunk wont work due to
  49  * memory fragmentation.  To avoid this, it is broken up into
  50  * NR_BUFFERS chunks of 32Kbyte. --khp
  51  */
  52 
  53 byte *tape_buffer[NR_BUFFERS] = {NULL};
  54 
  55 /*      Local vars.
  56  */
  57 static int busy_flag = 0;
  58 static int old_sigmask;
  59 
  60 static int ftape_open(struct inode *ino, struct file *filep);
  61 static void ftape_close(struct inode *ino, struct file *filep);
  62 static int ftape_ioctl(struct inode *ino, struct file *filep,
  63                        unsigned int command, unsigned long arg);
  64 static int ftape_read(struct inode *ino, struct file *fp, char *buff,
  65                       int req_len);
  66 static int ftape_write(struct inode *ino, struct file *fp, const char *buff,
  67                        int req_len);
  68 
  69 static struct file_operations ftape_cdev =
  70 {
  71         NULL,                   /* lseek */
  72         ftape_read,             /* read */
  73         ftape_write,            /* write */
  74         NULL,                   /* readdir */
  75         NULL,                   /* select */
  76         ftape_ioctl,            /* ioctl */
  77         NULL,                   /* mmap */
  78         ftape_open,             /* open */
  79         ftape_close,            /* release */
  80         NULL,                   /* fsync */
  81 };
  82 
  83 /*
  84  * DMA'able memory allocation stuff.
  85  */
  86 
  87 /* Pure 2^n version of get_order */
  88 static inline int __get_order(unsigned long size)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90         int order;
  91 
  92         size = (size-1) >> (PAGE_SHIFT-1);
  93         order = -1;
  94         do {
  95                 size >>= 1;
  96                 order++;
  97         } while (size);
  98         return order;
  99 }
 100 
 101 static inline
 102 void *dmaalloc(int order)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         return (void *) __get_dma_pages(GFP_KERNEL, order);
 105 }
 106 
 107 static inline
 108 void dmafree(void *addr, int order)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         free_pages((unsigned long) addr, order);
 111 }
 112 
 113 /*
 114  * Called by modules package when installing the driver
 115  * or by kernel during the initialization phase
 116  */
 117 
 118 #ifdef MODULE
 119 #define ftape_init init_module
 120 #endif
 121 
 122 int ftape_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         int n;
 125         int order;
 126         TRACE_FUN(5, "ftape_init");
 127 #ifdef MODULE
 128         printk(KERN_INFO "ftape-2.08 960314\n"
 129                KERN_INFO " (c) 1993-1995 Bas Laarhoven (bas@vimec.nl)\n"
 130                KERN_INFO " (c) 1995-1996 Kai Harrekilde-Petersen (khp@pip.dknet.dk)\n"
 131         KERN_INFO " QIC-117 driver for QIC-40/80/3010/3020 tape drives\n"
 132                KERN_INFO " Compiled for kernel version %s"
 133 #ifdef MODVERSIONS
 134                " with versioned symbols"
 135 #endif
 136                "\n", kernel_version);
 137 #else /* !MODULE */
 138         /* print a short no-nonsense boot message */
 139         printk("ftape-2.08 960314 for Linux 1.3.70\n");
 140 #endif                          /* MODULE */
 141         TRACE(3, "installing QIC-117 ftape driver...");
 142         if (register_chrdev(QIC117_TAPE_MAJOR, "ft", &ftape_cdev)) {
 143                 TRACE(1, "register_chrdev failed");
 144                 TRACE_EXIT;
 145                 return -EIO;
 146         }
 147         TRACEx1(3, "ftape_init @ 0x%p", ftape_init);
 148         /*
 149          * Allocate the DMA buffers. They are deallocated at cleanup() time.
 150          */
 151         order = __get_order(BUFF_SIZE);
 152         for (n = 0; n < NR_BUFFERS; n++) {
 153                 tape_buffer[n] = (byte *) dmaalloc(order);
 154                 if (!tape_buffer[n]) {
 155                         TRACE(1, "dmaalloc() failed");
 156                         for (n = 0; n < NR_BUFFERS; n++) {
 157                                 if (tape_buffer[n]) {
 158                                         dmafree(tape_buffer[n], order);
 159                                         tape_buffer[n] = NULL;
 160                                 }
 161                         }
 162                         current->blocked = old_sigmask;         /* restore mask */
 163                         if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) {
 164                                 TRACE(3, "unregister_chrdev failed");
 165                         }
 166                         TRACE_EXIT;
 167                         return -ENOMEM;
 168                 } else {
 169                         TRACEx2(3, "dma-buffer #%d @ %p", n, tape_buffer[n]);
 170                 }
 171         }
 172         busy_flag = 0;
 173         ftape_unit = -1;
 174         ftape_failure = 1;      /* inhibit any operation but open */
 175         udelay_calibrate();     /* must be before fdc_wait_calibrate ! */
 176         fdc_wait_calibrate();
 177         TRACE_EXIT;
 178 #ifdef MODULE
 179         register_symtab(0);     /* remove global ftape symbols */
 180 #endif
 181         return 0;
 182 }
 183 
 184 
 185 #ifdef MODULE
 186 /*      Called by modules package when removing the driver
 187  */
 188 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 189 {
 190         int n;
 191         int order;
 192         TRACE_FUN(5, "cleanup_module");
 193 
 194         if (unregister_chrdev(QIC117_TAPE_MAJOR, "ft") != 0) {
 195                 TRACE(3, "failed");
 196         } else {
 197                 TRACE(3, "successful");
 198         }
 199         order = __get_order(BUFF_SIZE);
 200         for (n = 0; n < NR_BUFFERS; n++) {
 201                 if (tape_buffer[n]) {
 202                         dmafree(tape_buffer[n], order);
 203                         tape_buffer[n] = NULL;
 204                         TRACEx1(3, "removed dma-buffer #%d", n);
 205                 } else {
 206                         TRACEx1(1, "dma-buffer #%d == NULL (bug?)", n);
 207                 }
 208         }
 209         TRACE_EXIT;
 210 }
 211 #endif                          /* MODULE */
 212 
 213 /*      Open ftape device
 214  */
 215 static int ftape_open(struct inode *ino, struct file *filep)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         TRACE_FUN(4, "ftape_open");
 218         int result;
 219         MOD_INC_USE_COUNT;      /* lock module in memory */
 220 
 221         TRACEi(5, "called for minor", MINOR(ino->i_rdev));
 222         if (busy_flag) {
 223                 TRACE(1, "failed: already busy");
 224                 MOD_DEC_USE_COUNT;      /* unlock module in memory */
 225                 TRACE_EXIT;
 226                 return -EBUSY;
 227         }
 228         if ((MINOR(ino->i_rdev) & ~FTAPE_NO_REWIND) > 3) {
 229                 TRACE(1, "failed: illegal unit nr");
 230                 MOD_DEC_USE_COUNT;      /* unlock module in memory */
 231                 TRACE_EXIT;
 232                 return -ENXIO;
 233         }
 234         if (ftape_unit == -1 || FTAPE_UNIT != (MINOR(ino->i_rdev) & 3)) {
 235                 /*  Other selection than last time
 236                  */
 237                 ftape_init_driver();
 238         }
 239         ftape_unit = MINOR(ino->i_rdev);
 240         ftape_failure = 0;      /* allow tape operations */
 241         old_sigmask = current->blocked;
 242         current->blocked = _BLOCK_ALL;
 243         fdc_save_drive_specs(); /* save Drive Specification regs on i82078-1's */
 244         result = _ftape_open();
 245         if (result < 0) {
 246                 TRACE(1, "_ftape_open failed");
 247                 current->blocked = old_sigmask;         /* restore mask */
 248                 MOD_DEC_USE_COUNT;      /* unlock module in memory */
 249                 TRACE_EXIT;
 250                 return result;
 251         } else {
 252                 busy_flag = 1;
 253                 /*  Mask signals that will disturb proper operation of the
 254                  *  program that is calling.
 255                  */
 256                 current->blocked = old_sigmask | _DO_BLOCK;
 257                 TRACE_EXIT;
 258                 return 0;
 259         }
 260 }
 261 
 262 /*      Close ftape device
 263  */
 264 static void ftape_close(struct inode *ino, struct file *filep)
     /* [previous][next][first][last][top][bottom][index][help] */
 265 {
 266         TRACE_FUN(4, "ftape_close");
 267         int result;
 268 
 269         if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit) {
 270                 TRACE(1, "failed: not busy or wrong unit");
 271                 TRACE_EXIT;
 272                 return;         /* keep busy_flag !(?) */
 273         }
 274         current->blocked = _BLOCK_ALL;
 275         result = _ftape_close();
 276         if (result < 0) {
 277                 TRACE(1, "_ftape_close failed");
 278         }
 279         fdc_restore_drive_specs();      /* restore original values */
 280         ftape_failure = 1;      /* inhibit any operation but open */
 281         busy_flag = 0;
 282         current->blocked = old_sigmask;         /* restore before open state */
 283         TRACE_EXIT;
 284         MOD_DEC_USE_COUNT;      /* unlock module in memory */
 285 }
 286 
 287 /*      Ioctl for ftape device
 288  */
 289 static int ftape_ioctl(struct inode *ino, struct file *filep,
     /* [previous][next][first][last][top][bottom][index][help] */
 290                        unsigned int command, unsigned long arg)
 291 {
 292         TRACE_FUN(4, "ftape_ioctl");
 293         int result = -EIO;
 294         int old_sigmask;
 295 
 296         if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit || ftape_failure) {
 297                 TRACE(1, "failed: not busy, failure or wrong unit");
 298                 TRACE_EXIT;
 299                 return -EIO;
 300         }
 301         old_sigmask = current->blocked;         /* save mask */
 302         current->blocked = _BLOCK_ALL;
 303         /* This will work as long as sizeof( void*) == sizeof( long)
 304          */
 305         result = _ftape_ioctl(command, (void *) arg);
 306         current->blocked = old_sigmask;         /* restore mask */
 307         TRACE_EXIT;
 308         return result;
 309 }
 310 
 311 /*      Read from tape device
 312  */
 313 static int ftape_read(struct inode *ino, struct file *fp, char *buff, int req_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 314 {
 315         TRACE_FUN(5, "ftape_read");
 316         int result = -EIO;
 317         int old_sigmask;
 318 
 319         TRACEi(5, "called with count:", req_len);
 320         if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit || ftape_failure) {
 321                 TRACE(1, "failed: not busy, failure or wrong unit");
 322                 TRACE_EXIT;
 323                 return -EIO;
 324         }
 325         old_sigmask = current->blocked;         /* save mask */
 326         current->blocked = _BLOCK_ALL;
 327         result = _ftape_read(buff, req_len);
 328         TRACEi(7, "return with count:", result);
 329         current->blocked = old_sigmask;         /* restore mask */
 330         TRACE_EXIT;
 331         return result;
 332 }
 333 
 334 /*      Write to tape device
 335  */
 336 static int ftape_write(struct inode *ino, struct file *fp, const char *buff, int req_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 337 {
 338         TRACE_FUN(8, "ftape_write");
 339         int result = -EIO;
 340         int old_sigmask;
 341 
 342         TRACEi(5, "called with count:", req_len);
 343         if (!busy_flag || MINOR(ino->i_rdev) != ftape_unit || ftape_failure) {
 344                 TRACE(1, "failed: not busy, failure or wrong unit");
 345                 TRACE_EXIT;
 346                 return -EIO;
 347         }
 348         old_sigmask = current->blocked;         /* save mask */
 349         current->blocked = _BLOCK_ALL;
 350         result = _ftape_write(buff, req_len);
 351         TRACEi(7, "return with count:", result);
 352         current->blocked = old_sigmask;         /* restore mask */
 353         TRACE_EXIT;
 354         return result;
 355 }

/* [previous][next][first][last][top][bottom][index][help] */