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