root/drivers/char/ftape/fdc-io.c

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

DEFINITIONS

This source file includes following definitions.
  1. fdc_catch_stray_interrupts
  2. fdc_wait
  3. fdc_ready_wait
  4. fdc_usec_wait
  5. fdc_ready_out_wait
  6. fdc_ready_in_wait
  7. fdc_wait_calibrate
  8. fdc_write
  9. fdc_read
  10. fdc_command
  11. fdc_result
  12. fdc_issue_command
  13. fdc_interrupt_wait
  14. fdc_motor
  15. fdc_update_dsr
  16. fdc_set_write_precomp
  17. fdc_save_drive_specs
  18. fdc_restore_drive_specs
  19. fdc_set_data_rate
  20. fdc_reset
  21. fdc_disable
  22. fdc_set_seek_rate
  23. fdc_sense_drive_status
  24. fdc_sense_interrupt_status
  25. fdc_seek
  26. fdc_recalibrate
  27. setup_fdc_and_dma
  28. fdc_fifo_enable
  29. fdc_probe
  30. fdc_config_regs
  31. fdc_config
  32. ftape_interrupt
  33. fdc_grab_irq_and_dma
  34. fdc_release_irq_and_dma
  35. fdc_uninit
  36. fdc_init

   1 /* Yo, Emacs! we're -*- Linux-C -*-
   2  *
   3  *      Copyright (C) 1993-1995 Bas Laarhoven.
   4 
   5  This program is free software; you can redistribute it and/or modify
   6  it under the terms of the GNU General Public License as published by
   7  the Free Software Foundation; either version 2, or (at your option)
   8  any later version.
   9 
  10  This program is distributed in the hope that it will be useful,
  11  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13  GNU General Public License for more details.
  14 
  15  You should have received a copy of the GNU General Public License
  16  along with this program; see the file COPYING.  If not, write to
  17  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18 
  19  *
  20  *      This file contains the low-level floppy disk interface code
  21  *      for the QIC-40/80 tape streamer device driver.
  22  */
  23 
  24 #include <linux/module.h>
  25 #include <linux/errno.h>
  26 #include <linux/sched.h>
  27 #include <linux/ioport.h>
  28 #include <linux/ftape.h>
  29 #include <asm/system.h>
  30 #include <asm/io.h>
  31 #include <asm/dma.h>
  32 #include <asm/irq.h>
  33 
  34 #include "tracing.h"
  35 #include "fdc-io.h"
  36 #include "fdc-isr.h"
  37 #include "ftape-io.h"
  38 #include "ftape-rw.h"
  39 #include "calibr.h"
  40 #include "fc-10.h"
  41 #include "qic117.h"
  42 
  43 
  44 /*      Global vars.
  45  */
  46 int ftape_unit = -1;
  47 int ftape_motor = 0;
  48 int current_cylinder = -1;
  49 fdc_mode_enum fdc_mode = fdc_idle;
  50 fdc_config_info fdc = {0};
  51 
  52 /*      Local vars.
  53  */
  54 static int fdc_calibr_count;
  55 static int fdc_calibr_time;
  56 static int fdc_confused = 0;
  57 static int fdc_status;
  58 volatile byte fdc_head;         /* FDC head */
  59 volatile byte fdc_cyl;          /* FDC track */
  60 volatile byte fdc_sect;         /* FDC sector */
  61 static int fdc_data_rate = 0;   /* default rate = 500 Kbps */
  62 static int fdc_seek_rate = 14;  /* default rate = 2 msec @ 500 Kbps */
  63 static void (*do_ftape) (void);
  64 static int fdc_fifo_state;      /* original fifo setting - fifo enabled */
  65 static int fdc_fifo_thr;        /* original fifo setting - thresshold */
  66 static int fdc_lock_state;      /* original lock setting - locked */
  67 static int fdc_fifo_locked = 0; /* has fifo && lock set ? */
  68 static byte fdc_precomp = 0;    /* sets fdc to default precomp. value */
  69 static byte fdc_drv_spec[4];    /* drive specification bytes for i82078 */
  70 static int perpend_mode;        /* true if fdc is in perpendicular mode */
  71 
  72 void fdc_catch_stray_interrupts(unsigned count)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         unsigned long flags;
  75 
  76         save_flags(flags);
  77         cli();
  78         if (count == 0) {
  79                 expected_stray_interrupts = 0;
  80         } else {
  81                 expected_stray_interrupts += count;
  82         }
  83         restore_flags(flags);
  84 }
  85 
  86 /*  Wait during a timeout period for a given FDC status.
  87  *  If usecs == 0 then just test status, else wait at least for usecs.
  88  *  Returns -ETIME on timeout. Function must be calibrated first !
  89  */
  90 int fdc_wait(int usecs, byte mask, byte state)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92         int count_1 = (fdc_calibr_count * usecs - 1) / fdc_calibr_time;
  93 
  94         do {
  95                 fdc_status = inb_p(fdc.msr);
  96                 if ((fdc_status & mask) == state) {
  97                         return 0;
  98                 }
  99         } while (count_1-- >= 0);
 100         return -ETIME;
 101 }
 102 
 103 int fdc_ready_wait(int usecs)
     /* [previous][next][first][last][top][bottom][index][help] */
 104 {
 105         return fdc_wait(usecs, FDC_DATA_READY, FDC_DATA_READY);
 106 }
 107 
 108 static void fdc_usec_wait(int usecs)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         fdc_wait(usecs, 0, 1);  /* will always timeout ! */
 111 }
 112 
 113 int fdc_ready_out_wait(int usecs)
     /* [previous][next][first][last][top][bottom][index][help] */
 114 {
 115         fdc_usec_wait(RQM_DELAY);       /* wait for valid RQM status */
 116         return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY);
 117 }
 118 
 119 int fdc_ready_in_wait(int usecs)
     /* [previous][next][first][last][top][bottom][index][help] */
 120 {
 121         fdc_usec_wait(RQM_DELAY);       /* wait for valid RQM status */
 122         return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_IN_READY);
 123 }
 124 
 125 int fdc_wait_calibrate(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 126 {
 127         return calibrate("fdc_wait",
 128                      fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time);
 129 }
 130 
 131 /*  Wait for a (short) while for the FDC to become ready
 132  *  and transfer the next command byte.
 133  *  Return -ETIME on timeout on getting ready (depends on hardware!).
 134  */
 135 int fdc_write(byte data)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137         fdc_usec_wait(RQM_DELAY);       /* wait for valid RQM status */
 138         if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) {
 139                 return -ETIME;
 140         } else {
 141                 outb(data, fdc.fifo);
 142                 return 0;
 143         }
 144 }
 145 
 146 /*  Wait for a (short) while for the FDC to become ready
 147  *  and transfer the next result byte.
 148  *  Return -ETIME if timeout on getting ready (depends on hardware!).
 149  */
 150 int fdc_read(byte * data)
     /* [previous][next][first][last][top][bottom][index][help] */
 151 {
 152         fdc_usec_wait(RQM_DELAY);       /* wait for valid RQM status */
 153         if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) {
 154                 return -ETIME;
 155         } else {
 156                 *data = inb(fdc.fifo);
 157                 return 0;
 158         }
 159 }
 160 
 161 /*  Output a cmd_len long command string to the FDC.
 162  *  The FDC should be ready to receive a new command or
 163  *  an error (EBUSY) will occur.
 164  */
 165 int fdc_command(byte * cmd_data, int cmd_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 166 {
 167         TRACE_FUN(8, "fdc_command");
 168         int result = 0;
 169         unsigned long flags;
 170         int count = cmd_len;
 171 
 172         fdc_usec_wait(RQM_DELAY);       /* wait for valid RQM status */
 173         save_flags(flags);
 174         cli();
 175         fdc_status = inb(fdc.msr);
 176         if ((fdc_status & FDC_DATA_READY_MASK) == FDC_DATA_IN_READY) {
 177                 int retry = 0;
 178                 fdc_mode = *cmd_data;   /* used by isr */
 179                 interrupt_seen = 0;
 180                 while (count) {
 181                         result = fdc_write(*cmd_data);
 182                         if (result < 0) {
 183                                 TRACEx3(6, "fdc_mode = %02x, status = %02x at index %d",
 184                                         (int) fdc_mode, (int) fdc_status, cmd_len - count);
 185                                 if (++retry <= 3) {
 186                                         TRACE(2, "fdc_write timeout, retry");
 187                                 } else {
 188                                         TRACE(1, "fdc_write timeout, fatal");
 189                                         fdc_confused = 1;
 190                                         /* recover ??? */
 191                                         break;
 192                                 }
 193                         } else {
 194                                 --count;
 195                                 ++cmd_data;
 196                         }
 197                 }
 198         } else {
 199                 TRACE(1, "fdc not ready");
 200                 result = -EBUSY;
 201         }
 202         restore_flags(flags);
 203         TRACE_EXIT;
 204         return result;
 205 }
 206 
 207 /*  Input a res_len long result string from the FDC.
 208  *  The FDC should be ready to send the result or an error
 209  *  (EBUSY) will occur.
 210  */
 211 int fdc_result(byte * res_data, int res_len)
     /* [previous][next][first][last][top][bottom][index][help] */
 212 {
 213         TRACE_FUN(8, "fdc_result");
 214         int result = 0;
 215         unsigned long flags;
 216         int count = res_len;
 217 
 218         save_flags(flags);
 219         cli();
 220         fdc_status = inb(fdc.msr);
 221         if ((fdc_status & FDC_DATA_READY_MASK) == FDC_DATA_OUT_READY) {
 222                 int retry = 0;
 223                 while (count) {
 224                         if (!(fdc_status & FDC_BUSY)) {
 225                                 TRACE(1, "premature end of result phase");
 226                         }
 227                         result = fdc_read(res_data);
 228                         if (result < 0) {
 229                                 TRACEx3(6, "fdc_mode = %02x, status = %02x at index %d",
 230                                         (int) fdc_mode, (int) fdc_status, res_len - count);
 231                                 if (++retry <= 3) {
 232                                         TRACE(2, "fdc_read timeout, retry");
 233                                 } else {
 234                                         TRACE(1, "fdc_read timeout, fatal");
 235                                         fdc_confused = 1;
 236                                         /* recover ??? */
 237                                         break;
 238                                 }
 239                         } else {
 240                                 --count;
 241                                 ++res_data;
 242                         }
 243                 }
 244         } else {
 245                 TRACE(1, "fdc not ready");
 246                 result = -EBUSY;
 247         }
 248         restore_flags(flags);
 249         fdc_usec_wait(RQM_DELAY);       /* allow FDC to negate BSY */
 250         TRACE_EXIT;
 251         return result;
 252 }
 253 
 254 /*      Handle command and result phases for
 255  *      commands without data phase.
 256  */
 257 int fdc_issue_command(byte * out_data, int out_count,
     /* [previous][next][first][last][top][bottom][index][help] */
 258                       byte * in_data, int in_count)
 259 {
 260         TRACE_FUN(8, "fdc_issue_command");
 261         int result;
 262         int t0, t1;
 263 
 264         if (out_count > 0) {
 265                 result = fdc_command(out_data, out_count);
 266                 if (result < 0) {
 267                         TRACE(1, "fdc_command failed");
 268                         TRACE_EXIT;
 269                         return result;
 270                 }
 271         }
 272         /* will take 24 - 30 usec for fdc_sense_drive_status and
 273          * fdc_sense_interrupt_status commands.
 274          *    35 fails sometimes (5/9/93 SJL)
 275          * On a loaded system it incidentally takes longer than
 276          * this for the fdc to get ready ! ?????? WHY ??????
 277          * So until we know what's going on use a very long timeout.
 278          */
 279         t0 = timestamp();
 280         result = fdc_ready_out_wait(500 /* usec */ );
 281         t1 = timestamp();
 282         if (result < 0) {
 283                 TRACEi(1, "fdc_ready_out_wait failed after:", timediff(t0, t1));
 284                 TRACE_EXIT;
 285                 return result;
 286         }
 287         if (in_count > 0) {
 288                 result = fdc_result(in_data, in_count);
 289                 if (result < 0) {
 290                         TRACE(1, "result phase aborted");
 291                         TRACE_EXIT;
 292                         return result;
 293                 }
 294         }
 295         TRACE_EXIT;
 296         return 0;
 297 }
 298 
 299 /*      Wait for FDC interrupt with timeout.
 300  *      Signals are blocked so the wait will not be aborted.
 301  *      Note: interrupts must be enabled ! (23/05/93 SJL)
 302  */
 303 int fdc_interrupt_wait(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         TRACE_FUN(8, "fdc_interrupt_wait");
 306         struct wait_queue wait =
 307         {current, NULL};
 308         int result = -ETIME;
 309         int need_cleanup = 0;
 310         int current_blocked = current->blocked;
 311         static int resetting = 0;
 312 
 313         if (wait_intr) {
 314                 TRACE(1, "error: nested call");
 315                 return -EIO;    /* return error... */
 316         }
 317         if (interrupt_seen == 0) {
 318                 /* timeout time will be between 0 and MSPT milliseconds too long !
 319                  */
 320                 current->timeout = jiffies + 1 + (time + MSPT - 1) / MSPT;
 321                 current->state = TASK_INTERRUPTIBLE;
 322                 current->blocked = _BLOCK_ALL;
 323                 add_wait_queue(&wait_intr, &wait);
 324                 do {
 325                         schedule();     /* sets TASK_RUNNING on timeout */
 326                 } while (!interrupt_seen && current->state != TASK_RUNNING);
 327                 current->blocked = current_blocked;     /* restore */
 328                 remove_wait_queue(&wait_intr, &wait);
 329                 if (interrupt_seen) {
 330                         current->timeout = 0;   /* interrupt hasn't cleared this */
 331                         result = 0;
 332                 } else {
 333 #if 1
 334 /*** remove me when sure this doesn't happen ***/
 335                         if (current->timeout > 0) {
 336                                 TRACE(-1, "*** BUG: unexpected schedule exit ***");
 337                                 if (current->signal & ~current->blocked) {
 338                                         TRACE(4, "caused by signal ?");
 339                                 }
 340                         }
 341 #endif
 342                         if (current->signal & ~current->blocked) {
 343                                 result = -EINTR;
 344                         } else {
 345                                 result = -ETIME;
 346                         }
 347                         need_cleanup = 1;       /* missing interrupt, reset fdc. */
 348                 }
 349         } else {
 350                 result = 0;
 351         }
 352         /*  In first instance, next statement seems unnecessary since
 353          *  it will be cleared in fdc_command. However, a small part of
 354          *  the software seems to rely on this being cleared here
 355          *  (ftape_close might fail) so stick to it until things get fixed !
 356          */
 357         interrupt_seen = 0;     /* clear for next call */
 358 
 359         if (need_cleanup & !resetting) {
 360                 resetting = 1;  /* break infinite recursion if reset fails */
 361                 TRACE(8, "cleanup reset");
 362                 fdc_reset();
 363                 resetting = 0;
 364         }
 365         TRACE_EXIT;
 366         return result;
 367 }
 368 
 369 /*      Start/stop drive motor. Enable DMA mode.
 370  */
 371 void fdc_motor(int motor)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373         TRACE_FUN(8, "fdc_motor");
 374         int unit = FTAPE_UNIT;
 375         int data = unit | FDC_RESET_NOT | FDC_DMA_MODE;
 376 
 377         ftape_motor = motor;
 378         if (ftape_motor) {
 379                 data |= FDC_MOTOR_0 << unit;
 380                 TRACEx1(4, "turning motor %d on", unit);
 381         } else {
 382                 TRACEx1(4, "turning motor %d off", unit);
 383         }
 384 #ifdef MACH2
 385         outb_p(data, fdc.dor2);
 386 #else
 387         outb_p(data, fdc.dor);
 388 #endif
 389         ftape_sleep(10 * MILLISECOND);
 390         TRACE_EXIT;
 391 }
 392 
 393 static void fdc_update_dsr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 394 {
 395         TRACE_FUN(8, "fdc_update_dsr");
 396 
 397         TRACEx2(5, "rate = %d, precomp = %d", fdc_data_rate, fdc_precomp);
 398         if (fdc.type >= i82077) {
 399                 outb_p((fdc_data_rate & 0x03) | fdc_precomp, fdc.dsr);
 400         } else {
 401                 outb_p(fdc_data_rate, fdc.ccr);
 402         }
 403         TRACE_EXIT;
 404 }
 405 
 406 void fdc_set_write_precomp(int precomp)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408         /*  write precompensation can be set in multiples of 41.67 nsec.
 409          *  round the parameter to the nearest multiple and convert it
 410          *  into a fdc setting. Note that 0 means default to the fdc,
 411          *  7 is used instead of that.
 412          */
 413         fdc_precomp = ((precomp + 21) / 42) << 2;
 414         if (fdc_precomp == 0) {
 415                 fdc_precomp = 7 << 2;
 416         }
 417         fdc_update_dsr();
 418 }
 419 
 420 /* Read back the Drive Specification regs on a i82078, so that we
 421  * are able to restore them later
 422  */
 423 void fdc_save_drive_specs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 424 {
 425         byte cmd1[] =
 426         {FDC_DRIVE_SPEC, 0x80};
 427         byte cmd2[] =
 428         {FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0};
 429         int result;
 430 
 431         TRACE_FUN(8, "fdc_save_drive_specs");
 432         if (fdc.type >= i82078_1) {
 433                 result = fdc_issue_command(cmd1, NR_ITEMS(cmd1), fdc_drv_spec, 4);
 434                 if (result >= 0) {
 435                         cmd2[1] = (fdc_drv_spec[0] & 0x03) | 0x04;
 436                         cmd2[2] = (fdc_drv_spec[1] & 0x03) | 0x24;
 437                         cmd2[3] = (fdc_drv_spec[2] & 0x03) | 0x44;
 438                         cmd2[4] = (fdc_drv_spec[3] & 0x03) | 0x64;
 439                         fdc_command(cmd2, NR_ITEMS(cmd2));
 440                         if (result < 0) {
 441                                 TRACE(1, "Setting of drive specs failed");
 442                                 return;
 443                         }
 444                 } else {
 445                         TRACE(2, "Save of drive specs failed");
 446                 }
 447         }
 448         TRACE_EXIT;
 449 }
 450 
 451 /* Restore the previously saved Drive Specification values */
 452 void fdc_restore_drive_specs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 453 {
 454         byte cmd[] =
 455         {FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0};
 456         int result;
 457 
 458         TRACE_FUN(8, "fdc_restore_drive_specs");
 459         if (fdc.type > i82078_1) {
 460                 cmd[1] = (fdc_drv_spec[0] & 0x1f) | 0x00;
 461                 cmd[2] = (fdc_drv_spec[1] & 0x1f) | 0x20;
 462                 cmd[3] = (fdc_drv_spec[2] & 0x1f) | 0x40;
 463                 cmd[4] = (fdc_drv_spec[3] & 0x1f) | 0x60;
 464                 result = fdc_command(cmd, NR_ITEMS(cmd));
 465                 if (result < 0) {
 466                         TRACE(2, "Restoration of drive specs failed");
 467                 }
 468         }
 469         TRACE_EXIT;
 470 }
 471 
 472 /* Select clock for fdc, must correspond with tape drive setting !
 473  * This also influences the fdc timing so we must adjust some values.
 474  */
 475 void fdc_set_data_rate(int rate)
     /* [previous][next][first][last][top][bottom][index][help] */
 476 {
 477         /* Select clock for fdc, must correspond with tape drive setting !
 478          * This also influences the fdc timing so we must adjust some values.
 479          */
 480         fdc_data_rate = rate;
 481         fdc_update_dsr();
 482         fdc_set_seek_rate(fdc_seek_rate);       /* re-adjust for changed clock */
 483 }
 484 
 485 /*      Reset the floppy disk controller. Leave the ftape_unit selected.
 486  */
 487 void fdc_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {
 489         TRACE_FUN(8, "fdc_reset");
 490         int unit = FTAPE_UNIT;
 491         byte fdc_ctl = unit | FDC_DMA_MODE;
 492         int st0;
 493         int i;
 494         int result;
 495         int dummy;
 496 
 497         if (ftape_motor) {
 498                 fdc_ctl |= FDC_MOTOR_0 << unit;
 499         }
 500 #ifdef MACH2
 501         outb_p(fdc_ctl & 0x0f, fdc.dor);
 502         outb_p(fdc_ctl, fdc.dor2);
 503 #else
 504         outb_p(fdc_ctl, fdc.dor);       /* assert reset, keep unit selected */
 505 #endif
 506         fdc_usec_wait(10 /* usec */ );  /* delay >= 14 fdc clocks */
 507         fdc_ctl |= FDC_RESET_NOT;
 508         fdc_mode = fdc_idle;
 509 #ifdef MACH2
 510         outb_p(fdc_ctl & 0x0f, fdc.dor);
 511         outb_p(fdc_ctl, fdc.dor2);
 512 #else
 513         outb_p(fdc_ctl, fdc.dor);       /* release reset */
 514 #endif
 515         result = fdc_interrupt_wait(1 * SECOND);
 516         if (result < 0) {
 517                 TRACE(1, "missing interrupt after reset");
 518         }
 519         fdc_set_data_rate(fdc_data_rate);       /* keep original setting */
 520         fdc_usec_wait(1000 /* usec */ );        /* don't know why, but needed */
 521         for (i = 0; i < 4; ++i) {       /* clear disk-change status */
 522                 fdc_sense_interrupt_status(&st0, &dummy);
 523                 if (i == unit) {
 524                         current_cylinder = dummy;
 525                 }
 526         }
 527         fdc_set_seek_rate(2);
 528         TRACE_EXIT;
 529 }
 530 
 531 /* When we're done, put the fdc into reset mode so that the regular
 532    floppy disk driver will figure out that something is wrong and
 533    initialize the controller the way it wants. */
 534 void fdc_disable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 535 {
 536         TRACE_FUN(8, "fdc_disable");
 537         int result;
 538         byte cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00};
 539         byte cmd2[] = {FDC_LOCK};
 540         byte cmd3[] = {FDC_UNLOCK};
 541         byte stat[1];
 542 
 543         if (CLK_48MHZ && fdc.type >= i82078)
 544                 cmd1[0] |= FDC_CLK48_BIT;
 545         if (fdc_fifo_locked) {
 546                 result = fdc_issue_command(cmd3, 1, stat, 1);
 547                 if (result < 0 || stat[0] != 0x00) {
 548                         TRACE(-1, "couldn't unlock fifo, configuration remains changed");
 549                 } else {
 550                         cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1);
 551                         result = fdc_command(cmd1, NR_ITEMS(cmd1));
 552                         if (result < 0) {
 553                                 TRACE(-1, "couldn't reconfigure fifo to old state");
 554                         } else if (fdc_lock_state) {
 555                                 result = fdc_issue_command(cmd2, 1, stat, 1);
 556                                 if (result < 0) {
 557                                         TRACE(-1, "couldn't lock old state again");
 558                                 }
 559                         }
 560                         TRACEx3(5, "fifo restored: %sabled, thr. %d, %slocked",
 561                                 fdc_fifo_state ? "en" : "dis",
 562                            fdc_fifo_thr, (fdc_lock_state) ? "" : "not ");
 563                 }
 564                 fdc_fifo_locked = 0;
 565         }
 566 #ifdef MACH2
 567         outb_p(FTAPE_UNIT & 0x0f, fdc.dor);
 568         outb_p(FTAPE_UNIT, fdc.dor2);
 569         udelay(10);
 570         outb_p(FDC_RESET_NOT & 0x0f, fdc.dor);
 571         outb_p(FDC_RESET_NOT, fdc.dor2);
 572 #else
 573         outb_p(FTAPE_UNIT, fdc.dor);
 574         udelay(10);
 575         outb_p(FDC_RESET_NOT, fdc.dor);
 576 #endif
 577         TRACE_EXIT;
 578 }
 579 
 580 /*      Specify FDC seek-rate
 581  */
 582 int fdc_set_seek_rate(int seek_rate)
     /* [previous][next][first][last][top][bottom][index][help] */
 583 {
 584         byte in[3];
 585         const int hut = 1;      /* minimize head unload time */
 586         const int hlt = 1;      /* minimize head load time */
 587         const int rates[] = {250, 2000, 500, 1000};
 588 
 589         in[0] = FDC_SPECIFY;
 590         in[1] = (((16 - (rates[fdc_data_rate & 0x03] * seek_rate) / 500) << 4) |
 591                  hut);
 592         in[2] = (hlt << 1) | 0;
 593         fdc_seek_rate = seek_rate;
 594 
 595         return fdc_command(in, 3);
 596 }
 597 
 598 /*      Sense drive status: get unit's drive status (ST3)
 599  */
 600 int fdc_sense_drive_status(int *st3)
     /* [previous][next][first][last][top][bottom][index][help] */
 601 {
 602         TRACE_FUN(8, "fdc_sense_drive_status");
 603         int result;
 604         byte out[2];
 605         byte in[1];
 606 
 607         out[0] = FDC_SENSED;
 608         out[1] = FTAPE_UNIT;
 609         result = fdc_issue_command(out, 2, in, 1);
 610         if (result < 0) {
 611                 TRACE(1, "issue_command failed");
 612         } else {
 613                 *st3 = in[0];
 614                 result = 0;
 615         }
 616         TRACE_EXIT;
 617         return result;
 618 }
 619 
 620 /*      Sense Interrupt Status command:
 621  *      should be issued at the end of each seek.
 622  *      get ST0 and current cylinder.
 623  */
 624 int fdc_sense_interrupt_status(int *st0, int *current_cylinder)
     /* [previous][next][first][last][top][bottom][index][help] */
 625 {
 626         TRACE_FUN(8, "fdc_sense_interrupt_status");
 627         int result;
 628         byte out[1];
 629         byte in[2];
 630 
 631         out[0] = FDC_SENSEI;
 632         result = fdc_issue_command(out, 1, in, 2);
 633         if (result) {
 634                 TRACE(1, "issue_command failed");
 635         } else {
 636                 *st0 = in[0];
 637                 *current_cylinder = in[1];
 638                 result = 0;
 639         }
 640         TRACE_EXIT;
 641         return result;
 642 }
 643 
 644 /*      step to track
 645  */
 646 int fdc_seek(int track)
     /* [previous][next][first][last][top][bottom][index][help] */
 647 {
 648         TRACE_FUN(8, "fdc_seek");
 649         int result;
 650         byte out[3];
 651         int st0, pcn;
 652 
 653         out[0] = FDC_SEEK;
 654         out[1] = FTAPE_UNIT;
 655         out[2] = track;
 656         seek_completed = 0;
 657         result = fdc_command(out, 3);
 658         if (result != 0) {
 659                 TRACEi(1, "failed, status =", result);
 660                 TRACEx1(4, "destination was: %d, resetting FDC...", track);
 661                 /*  We really need this command to work !
 662                  */
 663                 fdc_reset();
 664                 TRACE_EXIT;
 665                 return result;
 666         }
 667         /*    Handle interrupts until seek_completed or timeout.
 668          */
 669         for (;;) {
 670                 result = fdc_interrupt_wait(2 * SECOND);
 671                 if (result < 0) {
 672                         TRACEi(2, "fdc_interrupt_wait timeout, status =", result);
 673                         TRACE_EXIT;
 674                         return result;
 675                 } else if (seek_completed) {
 676                         result = fdc_sense_interrupt_status(&st0, &pcn);
 677                         if (result != 0) {
 678                                 TRACEi(1, "fdc_sense_interrupt_status failed, status =", result);
 679                                 TRACE_EXIT;
 680                                 return result;
 681                         }
 682                         if ((st0 & ST0_SEEK_END) == 0) {
 683                                 TRACE(1, "no seek-end after seek completion !??");
 684                                 TRACE_EXIT;
 685                                 return -EIO;
 686                         }
 687                         break;
 688                 }
 689         }
 690         /*    Verify whether we issued the right tape command.
 691          */
 692         /* Verify that we seek to the proper track. */
 693         if (pcn != track) {
 694                 TRACE(1, "bad seek..");
 695                 TRACE_EXIT;
 696                 return -EIO;
 697         }
 698         current_cylinder = pcn;
 699         TRACE_EXIT;
 700         return 0;
 701 }
 702 
 703 /*      Recalibrate and wait until home.
 704  */
 705 int fdc_recalibrate(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 706 {
 707         TRACE_FUN(8, "fdc_recalibrate");
 708         int result;
 709         byte out[2];
 710         int st0;
 711         int pcn;
 712         int retry;
 713 
 714         result = fdc_set_seek_rate(6);
 715         if (result) {
 716                 TRACEi(1, "fdc_set_seek_rate failed, status =", result);
 717                 TRACE_EXIT;
 718                 return result;
 719         }
 720         out[0] = FDC_RECAL;
 721         out[1] = FTAPE_UNIT;
 722         seek_completed = 0;
 723         result = fdc_command(out, 2);
 724         if (result) {
 725                 TRACEi(1, "fdc_command failed, status =", result);
 726                 TRACE_EXIT;
 727                 return result;
 728         }
 729         /*    Handle interrupts until seek_completed or timeout.
 730          */
 731         for (retry = 0;; ++retry) {
 732                 result = fdc_interrupt_wait(2 * SECOND);
 733                 if (result < 0) {
 734                         TRACE(1, "fdc_interrupt_wait failed");
 735                         TRACE_EXIT;
 736                         return result;
 737                 } else if (result == 0 && seek_completed) {
 738                         result = fdc_sense_interrupt_status(&st0, &pcn);
 739                         if (result != 0) {
 740                                 TRACEi(1, "fdc_sense_interrupt_status failed, status =", result);
 741                                 TRACE_EXIT;
 742                                 return result;
 743                         }
 744                         if ((st0 & ST0_SEEK_END) == 0) {
 745                                 if (retry < 1) {
 746                                         continue;       /* some drives/fdc's give an extra interrupt */
 747                                 } else {
 748                                         TRACE(1, "no seek-end after seek completion !??");
 749                                         TRACE_EXIT;
 750                                         return -EIO;
 751                                 }
 752                         }
 753                         break;
 754                 }
 755         }
 756         current_cylinder = pcn;
 757         if (pcn != 0) {
 758                 TRACEi(1, "failed: resulting track =", pcn);
 759         }
 760         result = fdc_set_seek_rate(2);
 761         if (result != 0) {
 762                 TRACEi(1, "fdc_set_seek_rate failed, status =", result);
 763                 TRACE_EXIT;
 764                 return result;
 765         }
 766         TRACE_EXIT;
 767         return 0;
 768 }
 769 
 770 /*      Setup Floppy Disk Controller and DMA to read or write the next cluster
 771  *      of good sectors from or to the current segment.
 772  */
 773 int setup_fdc_and_dma(buffer_struct * buff, unsigned char operation)
     /* [previous][next][first][last][top][bottom][index][help] */
 774 {
 775         TRACE_FUN(8, "setup_fdc_and_dma");
 776         unsigned long flags;
 777         byte perpend[] = {FDC_PERPEND, 0x00};
 778         unsigned char out[9];
 779         int result;
 780         int dma_mode;
 781 
 782         if (operation == FDC_READ || operation == FDC_READ_DELETED) {
 783                 dma_mode = DMA_MODE_READ;
 784                 if (qic_std == QIC_TAPE_QIC3020) {
 785                         if (fdc.type < i82077AA) {
 786                                 /* fdc does not support perpendicular mode. complain */
 787                                 TRACE(0, "Your FDC does not support QIC-3020.");
 788                                 return -EIO;
 789                         }
 790                         /* enable perpendicular mode */
 791                         perpend[1] = 0x83 + (0x04 << FTAPE_UNIT);
 792                         result = fdc_command(perpend, 2);
 793                         if (result < 0) {
 794                                 TRACE(1, "Perpendicular mode entry failed!");
 795                         } else {
 796                                 TRACE(4, "Perpendicular mode entered");
 797                                 perpend_mode = 1;
 798                         }
 799                 } else if (perpend_mode) {
 800                         /* Turn off perpendicular mode */
 801                         perpend[1] = 0x80;
 802                         result = fdc_command(perpend, 2);
 803                         if (result < 0) {
 804                                 TRACE(1, "Perpendicular mode exit failed!");
 805                         } else {
 806                                 TRACE(4, "Perpendicular mode exited");
 807                                 perpend_mode = 0;
 808                         }
 809                 }
 810                 TRACEx2(5, "xfer %d sectors to 0x%p", buff->sector_count, buff->ptr);
 811         } else if (operation == FDC_WRITE || operation == FDC_WRITE_DELETED) {
 812                 dma_mode = DMA_MODE_WRITE;
 813                 /* When writing QIC-3020 tapes, turn on perpendicular mode.
 814                  */
 815                 if (qic_std == QIC_TAPE_QIC3020) {
 816                         if (fdc.type < i82077AA) {
 817                                 /* fdc does not support perpendicular mode: complain */
 818                                 TRACE(0, "Your FDC does not support QIC-3020.");
 819                                 return -EIO;
 820                         }
 821                         perpend[1] = 0x83 + (0x4 << FTAPE_UNIT);
 822                         result = fdc_command(perpend, 2);
 823                         if (result < 0) {
 824                                 TRACE(1, "Perpendicular mode entry failed!");
 825                         } else {
 826                                 TRACE(4, "Perpendicular mode entered");
 827                                 perpend_mode = 1;
 828                         }
 829                 } else if (perpend_mode) {
 830                         perpend[1] = 0x80;
 831                         result = fdc_command(perpend, 2);
 832                         if (result < 0) {
 833                                 TRACE(1, "Perpendicular mode exit failed!");
 834                         } else {
 835                                 TRACE(4, "Perpendicular mode exited");
 836                                 perpend_mode = 0;
 837                         }
 838                 }
 839                 TRACEx2(5, "xfer %d sectors from 0x%p", buff->sector_count, buff->ptr);
 840         } else {
 841                 TRACE(-1, "bug: illegal operation parameter");
 842                 TRACE_EXIT;
 843                 return -EIO;
 844         }
 845         /* Program the DMA controller.
 846          */
 847         save_flags(flags);
 848         cli();                  /* could be called from ISR ! */
 849         disable_dma(fdc.dma);
 850         clear_dma_ff(fdc.dma);
 851         set_dma_mode(fdc.dma, dma_mode);
 852         set_dma_addr(fdc.dma, (unsigned) buff->ptr);
 853         set_dma_count(fdc.dma, SECTOR_SIZE * buff->sector_count);
 854 #ifdef GCC_2_4_5_BUG
 855         /*  This seemingly stupid construction confuses the gcc-2.4.5
 856          *  code generater enough to create correct code.
 857          */
 858         if (1) {
 859                 int i;
 860 
 861                 for (i = 0; i < 1; ++i) {
 862                         udelay(1);
 863                 }
 864         }
 865 #endif
 866         enable_dma(fdc.dma);
 867         /* Issue FDC command to start reading/writing.
 868          */
 869         out[0] = operation;
 870         out[1] = FTAPE_UNIT;
 871         out[2] = buff->cyl;
 872         out[3] = buff->head;
 873         out[4] = buff->sect + buff->sector_offset;
 874         out[5] = 3;             /* Sector size of 1K. */
 875         out[6] = out[4] + buff->sector_count - 1;       /* last sector */
 876         out[7] = 109;           /* Gap length. */
 877         out[8] = 0xff;          /* No limit to transfer size. */
 878         restore_flags(flags);
 879         TRACEx4(6, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x",
 880                 out[2], out[3], out[4], out[6] - out[4] + 1);
 881         result = fdc_command(out, 9);
 882         if (result != 0) {
 883                 fdc_mode = fdc_idle;
 884                 TRACE(1, "fdc_command failed");
 885         }
 886         fdc_setup_error = result;
 887         TRACE_EXIT;
 888         return result;
 889 }
 890 
 891 int fdc_fifo_enable(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 892 {
 893         TRACE_FUN(8, "fdc_fifo_enable");
 894         int result = 0;
 895         byte cmd0[] = {FDC_DUMPREGS};
 896         byte cmd1[] = {FDC_CONFIGURE, 0, 0x07, 0}; /* enable fifo, thr = 8 */
 897         byte cmd2[] = {FDC_LOCK};
 898         byte cmd3[] = {FDC_UNLOCK};
 899         byte stat;
 900         byte reg[10];
 901         int i;
 902 
 903         if (CLK_48MHZ && fdc.type >= i82078)
 904                 cmd1[0] |= FDC_CLK48_BIT;
 905         if (!fdc_fifo_locked) {
 906                 /*  Dump fdc internal registers for examination
 907                  */
 908                 result = fdc_command(cmd0, NR_ITEMS(cmd0));
 909                 if (result < 0) {
 910                         TRACE(2, "FDC dumpreg command failed, fifo unchanged");
 911                         result = -EIO;
 912                 } else {
 913                         /*  Now read fdc internal registers from fifo
 914                          */
 915                         for (i = 0; i < NR_ITEMS(reg); ++i) {
 916                                 fdc_read(&reg[i]);
 917                                 TRACEx2(6, "Register %d = 0x%02x", i, reg[i]);
 918                         }
 919                         fdc_fifo_state = (reg[8] & 0x20) == 0;
 920                         fdc_lock_state = reg[7] & 0x80;
 921                         fdc_fifo_thr = 1 + (reg[8] & 0x0f);
 922                         TRACEx3(5, "original fifo state: %sabled, thresshold %d, %slocked",
 923                                 (fdc_fifo_state) ? "en" : "dis",
 924                            fdc_fifo_thr, (fdc_lock_state) ? "" : "not ");
 925                         /*  If fdc is already locked, unlock it first !
 926                          */
 927                         if (fdc_lock_state) {
 928                                 fdc_ready_wait(100);
 929                                 result = fdc_command(cmd3, NR_ITEMS(cmd3));
 930                                 if (result < 0) {
 931                                         TRACE(-1, "FDC unlock command failed, configuration unchanged");
 932                                         result = -EIO;
 933                                 }
 934                         }
 935                         /*  Enable fifo and set thresshold at xx bytes to allow a
 936                          *  reasonably large latency and reduce number of dma bursts.
 937                          */
 938                         fdc_ready_wait(100);
 939                         result = fdc_command(cmd1, NR_ITEMS(cmd1));
 940                         if (result < 0) {
 941                                 TRACE(-1, "FDC configure command failed, fifo unchanged");
 942                                 result = -EIO;
 943                         } else {
 944                                 /*  Now lock configuration so reset will not change it
 945                                  */
 946                                 result = fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1);
 947                                 if (result < 0 || stat != 0x10) {
 948                                         TRACEx1(-1, "FDC lock command failed, stat = 0x%02x", stat);
 949                                         result = -EIO;
 950                                 } else {
 951                                         fdc_fifo_locked = 1;
 952                                         result = 0;
 953                                 }
 954                         }
 955                 }
 956         } else {
 957                 TRACE(2, "Fifo not enabled because locked");
 958         }
 959         TRACE_EXIT;
 960         return result;
 961 }
 962 
 963 /*   Determine fd controller type 
 964  */
 965 static byte fdc_save_state[2] = {0, 0};
 966 
 967 int fdc_probe(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 968 {
 969         TRACE_FUN(8, "fdc_probe");
 970         byte cmd[1];
 971         byte stat[16];          /* must be able to hold dumpregs & save results */
 972         int result;
 973 
 974         /*  Try to find out what kind of fd controller we have to deal with
 975          *  Scheme borrowed from floppy driver:
 976          *  first try if FDC_DUMPREGS command works
 977          *  (this indicates that we have a 82072 or better)
 978          *  then try the FDC_VERSION command (82072 doesn't support this)
 979          *  then try the FDC_UNLOCK command (some older 82077's don't support this)
 980          *  then try the FDC_PARTID command (82078's support this)
 981          */
 982         cmd[0] = FDC_DUMPREGS;
 983         result = fdc_issue_command(cmd, 1, stat, 1);
 984         if (result == 0) {
 985                 if (stat[0] == 0x80) {
 986                         /* invalid command: must be pre 82072
 987                          */
 988                         TRACE(2, "Type 8272A/765A compatible FDC found");
 989                         result = i8272;
 990                 } else {
 991                         fdc_result(&stat[1], 9);
 992                         fdc_save_state[0] = stat[7];
 993                         fdc_save_state[1] = stat[8];
 994                         cmd[0] = FDC_VERSION;
 995                         result = fdc_issue_command(cmd, 1, stat, 1);
 996                         if (result < 0 || stat[0] == 0x80) {
 997                                 TRACE(2, "Type 82072 FDC found");
 998                                 result = i8272;
 999                         } else if (*stat == 0x90) {
1000                                 cmd[0] = FDC_UNLOCK;
1001                                 result = fdc_issue_command(cmd, 1, stat, 1);
1002                                 if (result < 0 || stat[0] != 0x00) {
1003                                         TRACE(2, "Type pre-1991 82077 FDC found, treating it like a 82072");
1004                                         result = i8272;
1005                                 } else {
1006                                         int i;
1007 
1008                                         if (fdc_save_state[0] & 0x80) { /* was locked */
1009                                                 cmd[0] = FDC_LOCK; /* restore lock */
1010                                                 result = fdc_issue_command(cmd, 1, stat, 1);
1011                                                 TRACE(2, "FDC is already locked");
1012                                         }
1013                                         /* Test for a i82078 FDC */
1014                                         cmd[0] = FDC_PARTID;
1015                                         result = fdc_issue_command(cmd, 1, stat, 1);
1016                                         if (result < 0 || stat[0] == 0x80) {
1017                                                 /* invalid command: not a i82078xx type FDC */
1018                                                 result = no_fdc;
1019                                                 for (i = 0; i < 4; ++i) {
1020                                                         outb_p(i, fdc.tdr);
1021                                                         if ((inb_p(fdc.tdr) & 0x03) != i) {
1022                                                                 result = i82077;
1023                                                                 break;
1024                                                         }
1025                                                 }
1026                                                 if (result == no_fdc) {
1027                                                         result = i82077AA;
1028                                                         TRACE(2, "Type 82077AA FDC found");
1029                                                 } else {
1030                                                         TRACE(2, "Type 82077 FDC found");
1031                                                 }
1032                                         } else {
1033                                                 /* FDC_PARTID cmd succeeded */
1034                                                 switch (stat[0] >> 5) {
1035                                                 case 0x0:
1036                                                         /* i82078SL or i82078-1.  The SL part cannot run at 2Mbps (the
1037                                                          * SL and -1 dies are identical; they are speed graded after
1038                                                          * production, according to Intel).  Some SL's can be detected
1039                                                          * by doing a SAVE cmd and look at bit 7 of the first byte (the
1040                                                          * SEL3V# bit).  If it is 0, the part runs off 3Volts, and hence
1041                                                          * it is a SL.
1042                                                          */
1043                                                         cmd[0] = FDC_SAVE;
1044                                                         result = fdc_issue_command(cmd, 1, stat, 16);
1045                                                         if (result < 0) {
1046                                                                 TRACE(1, "FDC_SAVE failed. Dunno why");
1047                                                                 /* guess we better claim the fdc to be a i82078 */
1048                                                                 result = i82078;
1049                                                                 TRACE(2, "Type i82078 FDC (i suppose) found");
1050                                                         } else {
1051                                                                 if ((stat[0] & FDC_SEL3V_BIT)) {
1052                                                                         /* fdc running off 5Volts; Pray that it's a i82078-1
1053                                                                          */
1054                                                                         TRACE(2, "Type i82078-1 or 5Volt i82078SL FDC found");
1055                                                                         TRACE(2, "Treating it as an i82078-1 (2Mbps) FDC");
1056                                                                         result = i82078_1;
1057                                                                 } else {
1058                                                                         TRACE(2, "Type 3Volt i82078SL FDC (1Mbps) found");
1059                                                                         result = i82078;
1060                                                                 }
1061                                                         }
1062                                                         break;
1063                                                 case 0x1:
1064                                                 case 0x2: /* S82078B (?!) */
1065                                                         /* 44pin i82078 found */
1066                                                         result = i82078;
1067                                                         TRACE(2, "Type i82078 FDC found");
1068                                                         break;
1069                                                 case 0x3: /* NSC PC8744 core; used in several super-IO chips */
1070                                                         result = i82077AA;
1071                                                         TRACE(2, "Type 82077AA compatible FDC found");
1072                                                         break;
1073                                                 default:
1074                                                         TRACE(2, "A previously undetected FDC found");
1075                                                         TRACEi(2, "Treating it as a 82077AA. Please report partid=",
1076                                                                stat[0]);
1077                                                         result = i82077AA;
1078                                                 } /* switch(stat[ 0] >> 5) */
1079                                         } /* if (result < 0 || stat[ 0] == 0x80) */
1080                                 }
1081                         } else {
1082                                 TRACE(2, "Unknown FDC found");
1083                                 result = i8272;
1084                         }
1085                 }
1086         } else {
1087                 TRACE(-1, "No FDC found");
1088                 result = no_fdc;
1089         }
1090         TRACE_EXIT;
1091         return result;
1092 }
1093 
1094 void fdc_config_regs(unsigned fdc_base, unsigned fdc_irq, unsigned fdc_dma)
     /* [previous][next][first][last][top][bottom][index][help] */
1095 {
1096         fdc.irq = fdc_irq;
1097         fdc.dma = fdc_dma;
1098         fdc.sra = fdc_base;
1099         fdc.srb = fdc_base + 1;
1100         fdc.dor = fdc_base + 2;
1101         fdc.tdr = fdc_base + 3;
1102         fdc.msr = fdc.dsr = fdc_base + 4;
1103         fdc.fifo = fdc_base + 5;
1104 #if defined MACH2 || defined PROBE_FC10
1105         fdc.dor2 = fdc_base + 6;
1106 #endif
1107         fdc.dir = fdc.ccr = fdc_base + 7;
1108 }
1109 
1110 /*  If probing for a FC-10/20 controller the fdc base address, interrupt
1111  *  and dma channel must be specified.
1112  *  If using an alternate fdc controller, base address, interrupt and
1113  *  dma channel must be specified.
1114  */
1115 #if defined PROBE_FC10 && !defined FDC_BASE
1116 #error No FDC base address (FDC_BASE) specified in Makefile!
1117 #endif
1118 #if defined FDC_BASE && !defined FDC_IRQ
1119 #error No interrupt (FDC_IRQ) specified in Makefile!
1120 #endif
1121 #if defined FDC_BASE && !defined FDC_DMA
1122 #error No dma channel (FDC_DMA) specified in Makefile!
1123 #endif
1124 
1125 void fdc_config(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1126 {
1127         TRACE_FUN(8, "fdc_config");
1128         static int already_done = 0;
1129 
1130         if (!already_done) {
1131 #ifdef PROBE_FC10
1132                 int fc_type;
1133 
1134                 fdc_config_regs(FDC_BASE, FDC_IRQ, FDC_DMA);
1135                 fc_type = fc10_enable();
1136                 if (fc_type != 0) {
1137                         TRACEx1(2, "FC-%c0 controller found", '0' + fc_type);
1138                         fdc.type = fc10;
1139                         fdc.hook = &do_ftape;
1140                 } else {
1141                         TRACE(2, "FC-10/20 controller not found");
1142                         fdc.type = no_fdc;
1143                         fdc.dor2 = 0;   /* not used with std fdc */
1144                         fdc_config_regs(0x3f0, 6, 2);   /* back to std fdc again */
1145                         fdc.hook = &do_ftape;
1146                 }
1147 #else
1148 #ifdef FDC_BASE
1149                 TRACE(2, "Using fdc controller at alternate address");
1150                 fdc_config_regs(FDC_BASE, FDC_IRQ, FDC_DMA);
1151                 fdc.hook = &do_ftape;
1152 #else
1153                 TRACE(2, "Using the standard fdc controller");
1154                 fdc_config_regs(0x3f0, 6, 2);   /* std fdc */
1155                 fdc.hook = &do_ftape;
1156 #endif /* !FDC_BASE */
1157 #endif /* !PROBE_FC10 */
1158         }
1159         *(fdc.hook) = fdc_isr;  /* hook our handler in */
1160         already_done = 1;
1161         TRACE_EXIT;
1162 }
1163 
1164 static void ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
1165 {
1166         TRACE_FUN(8, "ftape_interrupt");
1167         void (*handler) (void) = *fdc.hook;
1168 
1169         *fdc.hook = NULL;
1170         if (handler) {
1171                 handler();
1172         } else {
1173                 TRACE(-1, "Unexpected ftape interrupt");
1174         }
1175         TRACE_EXIT;
1176 }
1177 
1178 int fdc_grab_irq_and_dma(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1179 {
1180         TRACE_FUN(8, "fdc_grab_irq_and_dma");
1181         int result = 0;
1182         static char ftape_id[] = "ftape";
1183 
1184         if (fdc.hook == &do_ftape) {
1185                 /*  Get fast interrupt handler.
1186                  */
1187                 result = request_irq(fdc.irq, ftape_interrupt, SA_INTERRUPT,
1188                                      "ftape", ftape_id);
1189                 if (result) {
1190                         TRACEx1(-1, "Unable to grab IRQ%d for ftape driver", fdc.irq);
1191                         result = -EIO;
1192                 } else {
1193                         result = request_dma(fdc.dma, ftape_id);
1194                         if (result) {
1195                                 TRACEx1(-1, "Unable to grab DMA%d for ftape driver", fdc.dma);
1196                                 free_irq(fdc.irq, NULL);
1197                                 result = -EIO;
1198                         } else {
1199                                 enable_irq(fdc.irq);
1200                         }
1201                 }
1202         }
1203 #ifdef FDC_DMA
1204         if (result == 0 && FDC_DMA == 2) {
1205                 /*  Using same dma channel as standard fdc, need to disable the
1206                  *  dma-gate on the std fdc. This couldn't be done in the floppy
1207                  *  driver as some laptops are using the dma-gate to enter a
1208                  *  low power or even suspended state :-(
1209                  */
1210                 outb_p(FDC_RESET_NOT, 0x3f2);
1211                 TRACE(2, "DMA-gate on standard fdc disabled");
1212         }
1213 #endif
1214         TRACE_EXIT;
1215         return result;
1216 }
1217 
1218 int fdc_release_irq_and_dma(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1219 {
1220         TRACE_FUN(8, "fdc_grab_irq_and_dma");
1221         int result = 0;
1222 
1223         if (fdc.hook == &do_ftape) {
1224                 disable_dma(fdc.dma);   /* just in case... */
1225                 free_dma(fdc.dma);
1226                 disable_irq(fdc.irq);
1227                 free_irq(fdc.irq, NULL);
1228         }
1229 #ifdef FDC_DMA
1230         if (result == 0 && FDC_DMA == 2) {
1231                 /*  Using same dma channel as standard fdc, need to disable the
1232                  *  dma-gate on the std fdc. This couldn't be done in the floppy
1233                  *  driver as some laptops are using the dma-gate to enter a
1234                  *  low power or even suspended state :-(
1235                  */
1236                 outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2);
1237                 TRACE(2, "DMA-gate on standard fdc enabled again");
1238         }
1239 #endif
1240         TRACE_EXIT;
1241         return result;
1242 }
1243 
1244 int fdc_uninit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1245 {
1246         TRACE_FUN(8, "fdc_uninit");
1247         int result = 0;
1248 
1249         if (fdc.sra != 0) {
1250                 if (fdc.dor2 == 0) {
1251                         release_region(fdc.sra, 6);
1252                         release_region(fdc.sra + 7, 1);
1253                 } else {
1254                         release_region(fdc.sra, 8);
1255                 }
1256         }
1257         TRACE_EXIT;
1258         return result;
1259 }
1260 
1261 int fdc_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1262 {
1263         TRACE_FUN(8, "fdc_init");
1264         int result = 0;
1265 
1266         fdc_config();
1267         if (fdc_grab_irq_and_dma() < 0) {
1268                 result = -EBUSY;
1269         } else {
1270                 ftape_motor = 0;
1271                 fdc_catch_stray_interrupts(1);  /* one always comes */
1272                 TRACE(5, "resetting fdc");
1273                 fdc_reset();    /* init fdc & clear track counters */
1274                 if (fdc.type == no_fdc) {       /* default, means no FC-10 or 20 found */
1275                         fdc.type = fdc_probe();
1276                 }
1277                 if (fdc.type != no_fdc) {
1278                         if (fdc.type >= i82077) {
1279                                 if (fdc_fifo_enable() < 0) {
1280                                         TRACE(2, "couldn't enable fdc fifo !");
1281                                 } else {
1282                                         TRACE(5, "fdc fifo enabled and locked");
1283                                 }
1284                         }
1285                 } else {
1286                         fdc_release_irq_and_dma();
1287                         result = -EIO;
1288                 }
1289         }
1290         if (result >= 0) {
1291                 if (fdc.dor2 == 0) {
1292                         request_region(fdc.sra, 6, "fdc (ftape)");
1293                         request_region(fdc.sra + 7, 1, "fdc (ftape)");
1294                 } else {
1295                         request_region(fdc.sra, 8, "fdc (ftape)");
1296                 }
1297         }
1298         TRACE_EXIT;
1299         return result;
1300 }

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