| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 1993-1996 Bas Laarhoven, | 
|  | 3 | *           (C) 1996-1997 Claus-Justus Heine. | 
|  | 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 | * $Source: /homes/cvs/ftape-stacked/ftape/lowlevel/fdc-io.c,v $ | 
|  | 21 | * $Revision: 1.7.4.2 $ | 
|  | 22 | * $Date: 1997/11/16 14:48:17 $ | 
|  | 23 | * | 
|  | 24 | *      This file contains the low-level floppy disk interface code | 
|  | 25 | *      for the QIC-40/80/3010/3020 floppy-tape driver "ftape" for | 
|  | 26 | *      Linux. | 
|  | 27 | */ | 
|  | 28 |  | 
|  | 29 | #include <linux/config.h> /* for CONFIG_FT_* */ | 
|  | 30 | #include <linux/errno.h> | 
|  | 31 | #include <linux/sched.h> | 
|  | 32 | #include <linux/ioport.h> | 
|  | 33 | #include <linux/interrupt.h> | 
|  | 34 | #include <linux/kernel.h> | 
|  | 35 | #include <asm/system.h> | 
|  | 36 | #include <asm/io.h> | 
|  | 37 | #include <asm/dma.h> | 
|  | 38 | #include <asm/irq.h> | 
|  | 39 |  | 
|  | 40 | #include <linux/ftape.h> | 
|  | 41 | #include <linux/qic117.h> | 
|  | 42 | #include "../lowlevel/ftape-tracing.h" | 
|  | 43 | #include "../lowlevel/fdc-io.h" | 
|  | 44 | #include "../lowlevel/fdc-isr.h" | 
|  | 45 | #include "../lowlevel/ftape-io.h" | 
|  | 46 | #include "../lowlevel/ftape-rw.h" | 
|  | 47 | #include "../lowlevel/ftape-ctl.h" | 
|  | 48 | #include "../lowlevel/ftape-calibr.h" | 
|  | 49 | #include "../lowlevel/fc-10.h" | 
|  | 50 |  | 
|  | 51 | /*      Global vars. | 
|  | 52 | */ | 
|  | 53 | static int ftape_motor; | 
|  | 54 | volatile int ftape_current_cylinder = -1; | 
|  | 55 | volatile fdc_mode_enum fdc_mode = fdc_idle; | 
|  | 56 | fdc_config_info fdc; | 
|  | 57 | DECLARE_WAIT_QUEUE_HEAD(ftape_wait_intr); | 
|  | 58 |  | 
|  | 59 | unsigned int ft_fdc_base       = CONFIG_FT_FDC_BASE; | 
|  | 60 | unsigned int ft_fdc_irq        = CONFIG_FT_FDC_IRQ; | 
|  | 61 | unsigned int ft_fdc_dma        = CONFIG_FT_FDC_DMA; | 
|  | 62 | unsigned int ft_fdc_threshold  = CONFIG_FT_FDC_THR;  /* bytes */ | 
|  | 63 | unsigned int ft_fdc_rate_limit = CONFIG_FT_FDC_MAX_RATE; /* bits/sec */ | 
|  | 64 | int ft_probe_fc10        = CONFIG_FT_PROBE_FC10; | 
|  | 65 | int ft_mach2             = CONFIG_FT_MACH2; | 
|  | 66 |  | 
|  | 67 | /*      Local vars. | 
|  | 68 | */ | 
|  | 69 | static spinlock_t fdc_io_lock; | 
|  | 70 | static unsigned int fdc_calibr_count; | 
|  | 71 | static unsigned int fdc_calibr_time; | 
|  | 72 | static int fdc_status; | 
|  | 73 | volatile __u8 fdc_head;		/* FDC head from sector id */ | 
|  | 74 | volatile __u8 fdc_cyl;		/* FDC track from sector id */ | 
|  | 75 | volatile __u8 fdc_sect;		/* FDC sector from sector id */ | 
|  | 76 | static int fdc_data_rate = 500;	/* data rate (Kbps) */ | 
|  | 77 | static int fdc_rate_code;	/* data rate code (0 == 500 Kbps) */ | 
|  | 78 | static int fdc_seek_rate = 2;	/* step rate (msec) */ | 
|  | 79 | static void (*do_ftape) (void); | 
|  | 80 | static int fdc_fifo_state;	/* original fifo setting - fifo enabled */ | 
|  | 81 | static int fdc_fifo_thr;	/* original fifo setting - threshold */ | 
|  | 82 | static int fdc_lock_state;	/* original lock setting - locked */ | 
|  | 83 | static int fdc_fifo_locked;	/* has fifo && lock set ? */ | 
|  | 84 | static __u8 fdc_precomp;	/* default precomp. value (nsec) */ | 
|  | 85 | static __u8 fdc_prec_code;	/* fdc precomp. select code */ | 
|  | 86 |  | 
|  | 87 | static char ftape_id[] = "ftape";  /* used by request irq and free irq */ | 
|  | 88 |  | 
|  | 89 | static int fdc_set_seek_rate(int seek_rate); | 
|  | 90 |  | 
|  | 91 | void fdc_catch_stray_interrupts(int count) | 
|  | 92 | { | 
|  | 93 | unsigned long flags; | 
|  | 94 |  | 
|  | 95 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 96 | if (count == 0) { | 
|  | 97 | ft_expected_stray_interrupts = 0; | 
|  | 98 | } else { | 
|  | 99 | ft_expected_stray_interrupts += count; | 
|  | 100 | } | 
|  | 101 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 102 | } | 
|  | 103 |  | 
|  | 104 | /*  Wait during a timeout period for a given FDC status. | 
|  | 105 | *  If usecs == 0 then just test status, else wait at least for usecs. | 
|  | 106 | *  Returns -ETIME on timeout. Function must be calibrated first ! | 
|  | 107 | */ | 
|  | 108 | static int fdc_wait(unsigned int usecs, __u8 mask, __u8 state) | 
|  | 109 | { | 
|  | 110 | int count_1 = (fdc_calibr_count * usecs + | 
|  | 111 | fdc_calibr_count - 1) / fdc_calibr_time; | 
|  | 112 |  | 
|  | 113 | do { | 
|  | 114 | fdc_status = inb_p(fdc.msr); | 
|  | 115 | if ((fdc_status & mask) == state) { | 
|  | 116 | return 0; | 
|  | 117 | } | 
|  | 118 | } while (count_1-- >= 0); | 
|  | 119 | return -ETIME; | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | int fdc_ready_wait(unsigned int usecs) | 
|  | 123 | { | 
|  | 124 | return fdc_wait(usecs, FDC_DATA_READY | FDC_BUSY, FDC_DATA_READY); | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | /* Why can't we just use udelay()? | 
|  | 128 | */ | 
|  | 129 | static void fdc_usec_wait(unsigned int usecs) | 
|  | 130 | { | 
|  | 131 | fdc_wait(usecs, 0, 1);	/* will always timeout ! */ | 
|  | 132 | } | 
|  | 133 |  | 
|  | 134 | static int fdc_ready_out_wait(unsigned int usecs) | 
|  | 135 | { | 
|  | 136 | fdc_usec_wait(FT_RQM_DELAY);	/* wait for valid RQM status */ | 
|  | 137 | return fdc_wait(usecs, FDC_DATA_OUT_READY, FDC_DATA_OUT_READY); | 
|  | 138 | } | 
|  | 139 |  | 
|  | 140 | void fdc_wait_calibrate(void) | 
|  | 141 | { | 
|  | 142 | ftape_calibrate("fdc_wait", | 
|  | 143 | fdc_usec_wait, &fdc_calibr_count, &fdc_calibr_time); | 
|  | 144 | } | 
|  | 145 |  | 
|  | 146 | /*  Wait for a (short) while for the FDC to become ready | 
|  | 147 | *  and transfer the next command byte. | 
|  | 148 | *  Return -ETIME on timeout on getting ready (depends on hardware!). | 
|  | 149 | */ | 
|  | 150 | static int fdc_write(const __u8 data) | 
|  | 151 | { | 
|  | 152 | fdc_usec_wait(FT_RQM_DELAY);	/* wait for valid RQM status */ | 
|  | 153 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_IN_READY) < 0) { | 
|  | 154 | return -ETIME; | 
|  | 155 | } else { | 
|  | 156 | outb(data, fdc.fifo); | 
|  | 157 | return 0; | 
|  | 158 | } | 
|  | 159 | } | 
|  | 160 |  | 
|  | 161 | /*  Wait for a (short) while for the FDC to become ready | 
|  | 162 | *  and transfer the next result byte. | 
|  | 163 | *  Return -ETIME if timeout on getting ready (depends on hardware!). | 
|  | 164 | */ | 
|  | 165 | static int fdc_read(__u8 * data) | 
|  | 166 | { | 
|  | 167 | fdc_usec_wait(FT_RQM_DELAY);	/* wait for valid RQM status */ | 
|  | 168 | if (fdc_wait(150, FDC_DATA_READY_MASK, FDC_DATA_OUT_READY) < 0) { | 
|  | 169 | return -ETIME; | 
|  | 170 | } else { | 
|  | 171 | *data = inb(fdc.fifo); | 
|  | 172 | return 0; | 
|  | 173 | } | 
|  | 174 | } | 
|  | 175 |  | 
|  | 176 | /*  Output a cmd_len long command string to the FDC. | 
|  | 177 | *  The FDC should be ready to receive a new command or | 
|  | 178 | *  an error (EBUSY or ETIME) will occur. | 
|  | 179 | */ | 
|  | 180 | int fdc_command(const __u8 * cmd_data, int cmd_len) | 
|  | 181 | { | 
|  | 182 | int result = 0; | 
|  | 183 | unsigned long flags; | 
|  | 184 | int count = cmd_len; | 
|  | 185 | int retry = 0; | 
|  | 186 | #ifdef TESTING | 
|  | 187 | static unsigned int last_time; | 
|  | 188 | unsigned int time; | 
|  | 189 | #endif | 
|  | 190 | TRACE_FUN(ft_t_any); | 
|  | 191 |  | 
|  | 192 | fdc_usec_wait(FT_RQM_DELAY);	/* wait for valid RQM status */ | 
|  | 193 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 194 | if (!in_interrupt()) | 
|  | 195 | /* Yes, I know, too much comments inside this function | 
|  | 196 | * ... | 
|  | 197 | * | 
|  | 198 | * Yet another bug in the original driver. All that | 
|  | 199 | * havoc is caused by the fact that the isr() sends | 
|  | 200 | * itself a command to the floppy tape driver (pause, | 
|  | 201 | * micro step pause).  Now, the problem is that | 
|  | 202 | * commands are transmitted via the fdc_seek | 
|  | 203 | * command. But: the fdc performs seeks in the | 
|  | 204 | * background i.e. it doesn't signal busy while | 
|  | 205 | * sending the step pulses to the drive. Therefore the | 
|  | 206 | * non-interrupt level driver has no chance to tell | 
|  | 207 | * whether the isr() just has issued a seek. Therefore | 
|  | 208 | * we HAVE TO have a look at the ft_hide_interrupt | 
|  | 209 | * flag: it signals the non-interrupt level part of | 
|  | 210 | * the driver that it has to wait for the fdc until it | 
|  | 211 | * has completet seeking. | 
|  | 212 | * | 
|  | 213 | * THIS WAS PRESUMABLY THE REASON FOR ALL THAT | 
|  | 214 | * "fdc_read timeout" errors, I HOPE :-) | 
|  | 215 | */ | 
|  | 216 | if (ft_hide_interrupt) { | 
|  | 217 | restore_flags(flags); | 
|  | 218 | TRACE(ft_t_info, | 
|  | 219 | "Waiting for the isr() completing fdc_seek()"); | 
|  | 220 | if (fdc_interrupt_wait(2 * FT_SECOND) < 0) { | 
|  | 221 | TRACE(ft_t_warn, | 
|  | 222 | "Warning: timeout waiting for isr() seek to complete"); | 
|  | 223 | } | 
|  | 224 | if (ft_hide_interrupt || !ft_seek_completed) { | 
|  | 225 | /* There cannot be another | 
|  | 226 | * interrupt. The isr() only stops | 
|  | 227 | * the tape and the next interrupt | 
|  | 228 | * won't come until we have send our | 
|  | 229 | * command to the drive. | 
|  | 230 | */ | 
|  | 231 | TRACE_ABORT(-EIO, ft_t_bug, | 
|  | 232 | "BUG? isr() is still seeking?\n" | 
|  | 233 | KERN_INFO "hide: %d\n" | 
|  | 234 | KERN_INFO "seek: %d", | 
|  | 235 | ft_hide_interrupt, | 
|  | 236 | ft_seek_completed); | 
|  | 237 |  | 
|  | 238 | } | 
|  | 239 | fdc_usec_wait(FT_RQM_DELAY);	/* wait for valid RQM status */ | 
|  | 240 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 241 | } | 
|  | 242 | fdc_status = inb(fdc.msr); | 
|  | 243 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) { | 
|  | 244 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 245 | TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready"); | 
|  | 246 | } | 
|  | 247 | fdc_mode = *cmd_data;	/* used by isr */ | 
|  | 248 | #ifdef TESTING | 
|  | 249 | if (fdc_mode == FDC_SEEK) { | 
|  | 250 | time = ftape_timediff(last_time, ftape_timestamp()); | 
|  | 251 | if (time < 6000) { | 
|  | 252 | TRACE(ft_t_bug,"Warning: short timeout between seek commands: %d", | 
|  | 253 | time); | 
|  | 254 | } | 
|  | 255 | } | 
|  | 256 | #endif | 
|  | 257 | if (!in_interrupt()) { | 
|  | 258 | /* shouldn't be cleared if called from isr | 
|  | 259 | */ | 
|  | 260 | ft_interrupt_seen = 0; | 
|  | 261 | } | 
|  | 262 | while (count) { | 
|  | 263 | result = fdc_write(*cmd_data); | 
|  | 264 | if (result < 0) { | 
|  | 265 | TRACE(ft_t_fdc_dma, | 
|  | 266 | "fdc_mode = %02x, status = %02x at index %d", | 
|  | 267 | (int) fdc_mode, (int) fdc_status, | 
|  | 268 | cmd_len - count); | 
|  | 269 | if (++retry <= 3) { | 
|  | 270 | TRACE(ft_t_warn, "fdc_write timeout, retry"); | 
|  | 271 | } else { | 
|  | 272 | TRACE(ft_t_err, "fdc_write timeout, fatal"); | 
|  | 273 | /* recover ??? */ | 
|  | 274 | break; | 
|  | 275 | } | 
|  | 276 | } else { | 
|  | 277 | --count; | 
|  | 278 | ++cmd_data; | 
|  | 279 | } | 
|  | 280 | } | 
|  | 281 | #ifdef TESTING | 
|  | 282 | if (fdc_mode == FDC_SEEK) { | 
|  | 283 | last_time = ftape_timestamp(); | 
|  | 284 | } | 
|  | 285 | #endif | 
|  | 286 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 287 | TRACE_EXIT result; | 
|  | 288 | } | 
|  | 289 |  | 
|  | 290 | /*  Input a res_len long result string from the FDC. | 
|  | 291 | *  The FDC should be ready to send the result or an error | 
|  | 292 | *  (EBUSY or ETIME) will occur. | 
|  | 293 | */ | 
|  | 294 | int fdc_result(__u8 * res_data, int res_len) | 
|  | 295 | { | 
|  | 296 | int result = 0; | 
|  | 297 | unsigned long flags; | 
|  | 298 | int count = res_len; | 
|  | 299 | int retry = 0; | 
|  | 300 | TRACE_FUN(ft_t_any); | 
|  | 301 |  | 
|  | 302 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 303 | fdc_status = inb(fdc.msr); | 
|  | 304 | if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) { | 
|  | 305 | TRACE(ft_t_err, "fdc not ready"); | 
|  | 306 | result = -EBUSY; | 
|  | 307 | } else while (count) { | 
|  | 308 | if (!(fdc_status & FDC_BUSY)) { | 
|  | 309 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 310 | TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase"); | 
|  | 311 | } | 
|  | 312 | result = fdc_read(res_data); | 
|  | 313 | if (result < 0) { | 
|  | 314 | TRACE(ft_t_fdc_dma, | 
|  | 315 | "fdc_mode = %02x, status = %02x at index %d", | 
|  | 316 | (int) fdc_mode, | 
|  | 317 | (int) fdc_status, | 
|  | 318 | res_len - count); | 
|  | 319 | if (++retry <= 3) { | 
|  | 320 | TRACE(ft_t_warn, "fdc_read timeout, retry"); | 
|  | 321 | } else { | 
|  | 322 | TRACE(ft_t_err, "fdc_read timeout, fatal"); | 
|  | 323 | /* recover ??? */ | 
|  | 324 | break; | 
|  | 325 | ++retry; | 
|  | 326 | } | 
|  | 327 | } else { | 
|  | 328 | --count; | 
|  | 329 | ++res_data; | 
|  | 330 | } | 
|  | 331 | } | 
|  | 332 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 333 | fdc_usec_wait(FT_RQM_DELAY);	/* allow FDC to negate BSY */ | 
|  | 334 | TRACE_EXIT result; | 
|  | 335 | } | 
|  | 336 |  | 
|  | 337 | /*      Handle command and result phases for | 
|  | 338 | *      commands without data phase. | 
|  | 339 | */ | 
|  | 340 | static int fdc_issue_command(const __u8 * out_data, int out_count, | 
|  | 341 | __u8 * in_data, int in_count) | 
|  | 342 | { | 
|  | 343 | TRACE_FUN(ft_t_any); | 
|  | 344 |  | 
|  | 345 | if (out_count > 0) { | 
|  | 346 | TRACE_CATCH(fdc_command(out_data, out_count),); | 
|  | 347 | } | 
|  | 348 | /* will take 24 - 30 usec for fdc_sense_drive_status and | 
|  | 349 | * fdc_sense_interrupt_status commands. | 
|  | 350 | *    35 fails sometimes (5/9/93 SJL) | 
|  | 351 | * On a loaded system it incidentally takes longer than | 
|  | 352 | * this for the fdc to get ready ! ?????? WHY ?????? | 
|  | 353 | * So until we know what's going on use a very long timeout. | 
|  | 354 | */ | 
|  | 355 | TRACE_CATCH(fdc_ready_out_wait(500 /* usec */),); | 
|  | 356 | if (in_count > 0) { | 
|  | 357 | TRACE_CATCH(fdc_result(in_data, in_count), | 
|  | 358 | TRACE(ft_t_err, "result phase aborted")); | 
|  | 359 | } | 
|  | 360 | TRACE_EXIT 0; | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 | /*      Wait for FDC interrupt with timeout (in milliseconds). | 
|  | 364 | *      Signals are blocked so the wait will not be aborted. | 
|  | 365 | *      Note: interrupts must be enabled ! (23/05/93 SJL) | 
|  | 366 | */ | 
|  | 367 | int fdc_interrupt_wait(unsigned int time) | 
|  | 368 | { | 
|  | 369 | DECLARE_WAITQUEUE(wait,current); | 
|  | 370 | sigset_t old_sigmask; | 
|  | 371 | static int resetting; | 
|  | 372 | long timeout; | 
|  | 373 |  | 
|  | 374 | TRACE_FUN(ft_t_fdc_dma); | 
|  | 375 |  | 
|  | 376 | if (waitqueue_active(&ftape_wait_intr)) { | 
|  | 377 | TRACE_ABORT(-EIO, ft_t_err, "error: nested call"); | 
|  | 378 | } | 
|  | 379 | /* timeout time will be up to USPT microseconds too long ! */ | 
|  | 380 | timeout = (1000 * time + FT_USPT - 1) / FT_USPT; | 
|  | 381 |  | 
|  | 382 | spin_lock_irq(¤t->sighand->siglock); | 
|  | 383 | old_sigmask = current->blocked; | 
|  | 384 | sigfillset(¤t->blocked); | 
|  | 385 | recalc_sigpending(); | 
|  | 386 | spin_unlock_irq(¤t->sighand->siglock); | 
|  | 387 |  | 
|  | 388 | set_current_state(TASK_INTERRUPTIBLE); | 
|  | 389 | add_wait_queue(&ftape_wait_intr, &wait); | 
| Nishanth Aravamudan | da4cd8d | 2005-09-10 00:27:30 -0700 | [diff] [blame] | 390 | while (!ft_interrupt_seen && timeout) | 
|  | 391 | timeout = schedule_timeout_interruptible(timeout); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 392 |  | 
|  | 393 | spin_lock_irq(¤t->sighand->siglock); | 
|  | 394 | current->blocked = old_sigmask; | 
|  | 395 | recalc_sigpending(); | 
|  | 396 | spin_unlock_irq(¤t->sighand->siglock); | 
|  | 397 |  | 
|  | 398 | remove_wait_queue(&ftape_wait_intr, &wait); | 
|  | 399 | /*  the following IS necessary. True: as well | 
|  | 400 | *  wake_up_interruptible() as the schedule() set TASK_RUNNING | 
|  | 401 | *  when they wakeup a task, BUT: it may very well be that | 
|  | 402 | *  ft_interrupt_seen is already set to 1 when we enter here | 
|  | 403 | *  in which case schedule() gets never called, and | 
|  | 404 | *  TASK_RUNNING never set. This has the funny effect that we | 
|  | 405 | *  execute all the code until we leave kernel space, but then | 
|  | 406 | *  the task is stopped (a task CANNOT be preempted while in | 
|  | 407 | *  kernel mode. Sending a pair of SIGSTOP/SIGCONT to the | 
|  | 408 | *  tasks wakes it up again. Funny! :-) | 
|  | 409 | */ | 
|  | 410 | current->state = TASK_RUNNING; | 
|  | 411 | if (ft_interrupt_seen) { /* woken up by interrupt */ | 
|  | 412 | ft_interrupt_seen = 0; | 
|  | 413 | TRACE_EXIT 0; | 
|  | 414 | } | 
|  | 415 | /*  Original comment: | 
|  | 416 | *  In first instance, next statement seems unnecessary since | 
|  | 417 | *  it will be cleared in fdc_command. However, a small part of | 
|  | 418 | *  the software seems to rely on this being cleared here | 
|  | 419 | *  (ftape_close might fail) so stick to it until things get fixed ! | 
|  | 420 | */ | 
|  | 421 | /*  My deeply sought of knowledge: | 
|  | 422 | *  Behold NO! It is obvious. fdc_reset() doesn't call fdc_command() | 
|  | 423 | *  but nevertheless uses fdc_interrupt_wait(). OF COURSE this needs to | 
|  | 424 | *  be reset here. | 
|  | 425 | */ | 
|  | 426 | ft_interrupt_seen = 0;	/* clear for next call */ | 
|  | 427 | if (!resetting) { | 
|  | 428 | resetting = 1;	/* break infinite recursion if reset fails */ | 
|  | 429 | TRACE(ft_t_any, "cleanup reset"); | 
|  | 430 | fdc_reset(); | 
|  | 431 | resetting = 0; | 
|  | 432 | } | 
|  | 433 | TRACE_EXIT (signal_pending(current)) ? -EINTR : -ETIME; | 
|  | 434 | } | 
|  | 435 |  | 
|  | 436 | /*      Start/stop drive motor. Enable DMA mode. | 
|  | 437 | */ | 
|  | 438 | void fdc_motor(int motor) | 
|  | 439 | { | 
|  | 440 | int unit = ft_drive_sel; | 
|  | 441 | int data = unit | FDC_RESET_NOT | FDC_DMA_MODE; | 
|  | 442 | TRACE_FUN(ft_t_any); | 
|  | 443 |  | 
|  | 444 | ftape_motor = motor; | 
|  | 445 | if (ftape_motor) { | 
|  | 446 | data |= FDC_MOTOR_0 << unit; | 
|  | 447 | TRACE(ft_t_noise, "turning motor %d on", unit); | 
|  | 448 | } else { | 
|  | 449 | TRACE(ft_t_noise, "turning motor %d off", unit); | 
|  | 450 | } | 
|  | 451 | if (ft_mach2) { | 
|  | 452 | outb_p(data, fdc.dor2); | 
|  | 453 | } else { | 
|  | 454 | outb_p(data, fdc.dor); | 
|  | 455 | } | 
|  | 456 | ftape_sleep(10 * FT_MILLISECOND); | 
|  | 457 | TRACE_EXIT; | 
|  | 458 | } | 
|  | 459 |  | 
|  | 460 | static void fdc_update_dsr(void) | 
|  | 461 | { | 
|  | 462 | TRACE_FUN(ft_t_any); | 
|  | 463 |  | 
|  | 464 | TRACE(ft_t_flow, "rate = %d Kbps, precomp = %d ns", | 
|  | 465 | fdc_data_rate, fdc_precomp); | 
|  | 466 | if (fdc.type >= i82077) { | 
|  | 467 | outb_p((fdc_rate_code & 0x03) | fdc_prec_code, fdc.dsr); | 
|  | 468 | } else { | 
|  | 469 | outb_p(fdc_rate_code & 0x03, fdc.ccr); | 
|  | 470 | } | 
|  | 471 | TRACE_EXIT; | 
|  | 472 | } | 
|  | 473 |  | 
|  | 474 | void fdc_set_write_precomp(int precomp) | 
|  | 475 | { | 
|  | 476 | TRACE_FUN(ft_t_any); | 
|  | 477 |  | 
|  | 478 | TRACE(ft_t_noise, "New precomp: %d nsec", precomp); | 
|  | 479 | fdc_precomp = precomp; | 
|  | 480 | /*  write precompensation can be set in multiples of 41.67 nsec. | 
|  | 481 | *  round the parameter to the nearest multiple and convert it | 
|  | 482 | *  into a fdc setting. Note that 0 means default to the fdc, | 
|  | 483 | *  7 is used instead of that. | 
|  | 484 | */ | 
|  | 485 | fdc_prec_code = ((fdc_precomp + 21) / 42) << 2; | 
|  | 486 | if (fdc_prec_code == 0 || fdc_prec_code > (6 << 2)) { | 
|  | 487 | fdc_prec_code = 7 << 2; | 
|  | 488 | } | 
|  | 489 | fdc_update_dsr(); | 
|  | 490 | TRACE_EXIT; | 
|  | 491 | } | 
|  | 492 |  | 
|  | 493 | /*  Reprogram the 82078 registers to use Data Rate Table 1 on all drives. | 
|  | 494 | */ | 
|  | 495 | static void fdc_set_drive_specs(void) | 
|  | 496 | { | 
|  | 497 | __u8 cmd[] = { FDC_DRIVE_SPEC, 0x00, 0x00, 0x00, 0x00, 0xc0}; | 
|  | 498 | int result; | 
|  | 499 | TRACE_FUN(ft_t_any); | 
|  | 500 |  | 
|  | 501 | TRACE(ft_t_flow, "Setting of drive specs called"); | 
|  | 502 | if (fdc.type >= i82078_1) { | 
|  | 503 | cmd[1] = (0 << 5) | (2 << 2); | 
|  | 504 | cmd[2] = (1 << 5) | (2 << 2); | 
|  | 505 | cmd[3] = (2 << 5) | (2 << 2); | 
|  | 506 | cmd[4] = (3 << 5) | (2 << 2); | 
|  | 507 | result = fdc_command(cmd, NR_ITEMS(cmd)); | 
|  | 508 | if (result < 0) { | 
|  | 509 | TRACE(ft_t_err, "Setting of drive specs failed"); | 
|  | 510 | } | 
|  | 511 | } | 
|  | 512 | TRACE_EXIT; | 
|  | 513 | } | 
|  | 514 |  | 
|  | 515 | /* Select clock for fdc, must correspond with tape drive setting ! | 
|  | 516 | * This also influences the fdc timing so we must adjust some values. | 
|  | 517 | */ | 
|  | 518 | int fdc_set_data_rate(int rate) | 
|  | 519 | { | 
|  | 520 | int bad_rate = 0; | 
|  | 521 | TRACE_FUN(ft_t_any); | 
|  | 522 |  | 
|  | 523 | /* Select clock for fdc, must correspond with tape drive setting ! | 
|  | 524 | * This also influences the fdc timing so we must adjust some values. | 
|  | 525 | */ | 
|  | 526 | TRACE(ft_t_fdc_dma, "new rate = %d", rate); | 
|  | 527 | switch (rate) { | 
|  | 528 | case 250: | 
|  | 529 | fdc_rate_code = fdc_data_rate_250; | 
|  | 530 | break; | 
|  | 531 | case 500: | 
|  | 532 | fdc_rate_code = fdc_data_rate_500; | 
|  | 533 | break; | 
|  | 534 | case 1000: | 
|  | 535 | if (fdc.type < i82077) { | 
|  | 536 | bad_rate = 1; | 
|  | 537 | } else { | 
|  | 538 | fdc_rate_code = fdc_data_rate_1000; | 
|  | 539 | } | 
|  | 540 | break; | 
|  | 541 | case 2000: | 
|  | 542 | if (fdc.type < i82078_1) { | 
|  | 543 | bad_rate = 1; | 
|  | 544 | } else { | 
|  | 545 | fdc_rate_code = fdc_data_rate_2000; | 
|  | 546 | } | 
|  | 547 | break; | 
|  | 548 | default: | 
|  | 549 | bad_rate = 1; | 
|  | 550 | } | 
|  | 551 | if (bad_rate) { | 
|  | 552 | TRACE_ABORT(-EIO, | 
|  | 553 | ft_t_fdc_dma, "%d is not a valid data rate", rate); | 
|  | 554 | } | 
|  | 555 | fdc_data_rate = rate; | 
|  | 556 | fdc_update_dsr(); | 
|  | 557 | fdc_set_seek_rate(fdc_seek_rate);  /* clock changed! */ | 
|  | 558 | ftape_udelay(1000); | 
|  | 559 | TRACE_EXIT 0; | 
|  | 560 | } | 
|  | 561 |  | 
|  | 562 | /*  keep the unit select if keep_select is != 0, | 
|  | 563 | */ | 
|  | 564 | static void fdc_dor_reset(int keep_select) | 
|  | 565 | { | 
|  | 566 | __u8 fdc_ctl = ft_drive_sel; | 
|  | 567 |  | 
|  | 568 | if (keep_select != 0) { | 
|  | 569 | fdc_ctl |= FDC_DMA_MODE; | 
|  | 570 | if (ftape_motor) { | 
|  | 571 | fdc_ctl |= FDC_MOTOR_0 << ft_drive_sel; | 
|  | 572 | } | 
|  | 573 | } | 
|  | 574 | ftape_udelay(10); /* ??? but seems to be necessary */ | 
|  | 575 | if (ft_mach2) { | 
|  | 576 | outb_p(fdc_ctl & 0x0f, fdc.dor); | 
|  | 577 | outb_p(fdc_ctl, fdc.dor2); | 
|  | 578 | } else { | 
|  | 579 | outb_p(fdc_ctl, fdc.dor); | 
|  | 580 | } | 
|  | 581 | fdc_usec_wait(10); /* delay >= 14 fdc clocks */ | 
|  | 582 | if (keep_select == 0) { | 
|  | 583 | fdc_ctl = 0; | 
|  | 584 | } | 
|  | 585 | fdc_ctl |= FDC_RESET_NOT; | 
|  | 586 | if (ft_mach2) { | 
|  | 587 | outb_p(fdc_ctl & 0x0f, fdc.dor); | 
|  | 588 | outb_p(fdc_ctl, fdc.dor2); | 
|  | 589 | } else { | 
|  | 590 | outb_p(fdc_ctl, fdc.dor); | 
|  | 591 | } | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | /*      Reset the floppy disk controller. Leave the ftape_unit selected. | 
|  | 595 | */ | 
|  | 596 | void fdc_reset(void) | 
|  | 597 | { | 
|  | 598 | int st0; | 
|  | 599 | int i; | 
|  | 600 | int dummy; | 
|  | 601 | unsigned long flags; | 
|  | 602 | TRACE_FUN(ft_t_any); | 
|  | 603 |  | 
|  | 604 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 605 |  | 
|  | 606 | fdc_dor_reset(1); /* keep unit selected */ | 
|  | 607 |  | 
|  | 608 | fdc_mode = fdc_idle; | 
|  | 609 |  | 
|  | 610 | /*  maybe the cli()/sti() pair is not necessary, BUT: | 
|  | 611 | *  the following line MUST be here. Otherwise fdc_interrupt_wait() | 
|  | 612 | *  won't wait. Note that fdc_reset() is called from | 
|  | 613 | *  ftape_dumb_stop() when the fdc is busy transferring data. In this | 
|  | 614 | *  case fdc_isr() MOST PROBABLY sets ft_interrupt_seen, and tries | 
|  | 615 | *  to get the result bytes from the fdc etc. CLASH. | 
|  | 616 | */ | 
|  | 617 | ft_interrupt_seen = 0; | 
|  | 618 |  | 
|  | 619 | /*  Program data rate | 
|  | 620 | */ | 
|  | 621 | fdc_update_dsr();               /* restore data rate and precomp */ | 
|  | 622 |  | 
|  | 623 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 624 |  | 
|  | 625 | /* | 
|  | 626 | *	Wait for first polling cycle to complete | 
|  | 627 | */ | 
|  | 628 | if (fdc_interrupt_wait(1 * FT_SECOND) < 0) { | 
|  | 629 | TRACE(ft_t_err, "no drive polling interrupt!"); | 
|  | 630 | } else {	/* clear all disk-changed statuses */ | 
|  | 631 | for (i = 0; i < 4; ++i) { | 
|  | 632 | if(fdc_sense_interrupt_status(&st0, &dummy) != 0) { | 
|  | 633 | TRACE(ft_t_err, "sense failed for %d", i); | 
|  | 634 | } | 
|  | 635 | if (i == ft_drive_sel) { | 
|  | 636 | ftape_current_cylinder = dummy; | 
|  | 637 | } | 
|  | 638 | } | 
|  | 639 | TRACE(ft_t_noise, "drive polling completed"); | 
|  | 640 | } | 
|  | 641 | /* | 
|  | 642 | *	SPECIFY COMMAND | 
|  | 643 | */ | 
|  | 644 | fdc_set_seek_rate(fdc_seek_rate); | 
|  | 645 | /* | 
|  | 646 | *	DRIVE SPECIFICATION COMMAND (if fdc type known) | 
|  | 647 | */ | 
|  | 648 | if (fdc.type >= i82078_1) { | 
|  | 649 | fdc_set_drive_specs(); | 
|  | 650 | } | 
|  | 651 | TRACE_EXIT; | 
|  | 652 | } | 
|  | 653 |  | 
|  | 654 | #if !defined(CLK_48MHZ) | 
|  | 655 | # define CLK_48MHZ 1 | 
|  | 656 | #endif | 
|  | 657 |  | 
|  | 658 | /*  When we're done, put the fdc into reset mode so that the regular | 
|  | 659 | *  floppy disk driver will figure out that something is wrong and | 
|  | 660 | *  initialize the controller the way it wants. | 
|  | 661 | */ | 
|  | 662 | void fdc_disable(void) | 
|  | 663 | { | 
|  | 664 | __u8 cmd1[] = {FDC_CONFIGURE, 0x00, 0x00, 0x00}; | 
|  | 665 | __u8 cmd2[] = {FDC_LOCK}; | 
|  | 666 | __u8 cmd3[] = {FDC_UNLOCK}; | 
|  | 667 | __u8 stat[1]; | 
|  | 668 | TRACE_FUN(ft_t_flow); | 
|  | 669 |  | 
|  | 670 | if (!fdc_fifo_locked) { | 
|  | 671 | fdc_reset(); | 
|  | 672 | TRACE_EXIT; | 
|  | 673 | } | 
|  | 674 | if (fdc_issue_command(cmd3, 1, stat, 1) < 0 || stat[0] != 0x00) { | 
|  | 675 | fdc_dor_reset(0); | 
|  | 676 | TRACE_ABORT(/**/, ft_t_bug, | 
|  | 677 | "couldn't unlock fifo, configuration remains changed"); | 
|  | 678 | } | 
|  | 679 | fdc_fifo_locked = 0; | 
|  | 680 | if (CLK_48MHZ && fdc.type >= i82078) { | 
|  | 681 | cmd1[0] |= FDC_CLK48_BIT; | 
|  | 682 | } | 
|  | 683 | cmd1[2] = ((fdc_fifo_state) ? 0 : 0x20) + (fdc_fifo_thr - 1); | 
|  | 684 | if (fdc_command(cmd1, NR_ITEMS(cmd1)) < 0) { | 
|  | 685 | fdc_dor_reset(0); | 
|  | 686 | TRACE_ABORT(/**/, ft_t_bug, | 
|  | 687 | "couldn't reconfigure fifo to old state"); | 
|  | 688 | } | 
|  | 689 | if (fdc_lock_state && | 
|  | 690 | fdc_issue_command(cmd2, 1, stat, 1) < 0) { | 
|  | 691 | fdc_dor_reset(0); | 
|  | 692 | TRACE_ABORT(/**/, ft_t_bug, "couldn't lock old state again"); | 
|  | 693 | } | 
|  | 694 | TRACE(ft_t_noise, "fifo restored: %sabled, thr. %d, %slocked", | 
|  | 695 | fdc_fifo_state ? "en" : "dis", | 
|  | 696 | fdc_fifo_thr, (fdc_lock_state) ? "" : "not "); | 
|  | 697 | fdc_dor_reset(0); | 
|  | 698 | TRACE_EXIT; | 
|  | 699 | } | 
|  | 700 |  | 
|  | 701 | /*      Specify FDC seek-rate (milliseconds) | 
|  | 702 | */ | 
|  | 703 | static int fdc_set_seek_rate(int seek_rate) | 
|  | 704 | { | 
|  | 705 | /* set step rate, dma mode, and minimal head load and unload times | 
|  | 706 | */ | 
|  | 707 | __u8 in[3] = { FDC_SPECIFY, 1, (1 << 1)}; | 
|  | 708 |  | 
|  | 709 | fdc_seek_rate = seek_rate; | 
|  | 710 | in[1] |= (16 - (fdc_data_rate * fdc_seek_rate) / 500) << 4; | 
|  | 711 |  | 
|  | 712 | return fdc_command(in, 3); | 
|  | 713 | } | 
|  | 714 |  | 
|  | 715 | /*      Sense drive status: get unit's drive status (ST3) | 
|  | 716 | */ | 
|  | 717 | int fdc_sense_drive_status(int *st3) | 
|  | 718 | { | 
|  | 719 | __u8 out[2]; | 
|  | 720 | __u8 in[1]; | 
|  | 721 | TRACE_FUN(ft_t_any); | 
|  | 722 |  | 
|  | 723 | out[0] = FDC_SENSED; | 
|  | 724 | out[1] = ft_drive_sel; | 
|  | 725 | TRACE_CATCH(fdc_issue_command(out, 2, in, 1),); | 
|  | 726 | *st3 = in[0]; | 
|  | 727 | TRACE_EXIT 0; | 
|  | 728 | } | 
|  | 729 |  | 
|  | 730 | /*      Sense Interrupt Status command: | 
|  | 731 | *      should be issued at the end of each seek. | 
|  | 732 | *      get ST0 and current cylinder. | 
|  | 733 | */ | 
|  | 734 | int fdc_sense_interrupt_status(int *st0, int *current_cylinder) | 
|  | 735 | { | 
|  | 736 | __u8 out[1]; | 
|  | 737 | __u8 in[2]; | 
|  | 738 | TRACE_FUN(ft_t_any); | 
|  | 739 |  | 
|  | 740 | out[0] = FDC_SENSEI; | 
|  | 741 | TRACE_CATCH(fdc_issue_command(out, 1, in, 2),); | 
|  | 742 | *st0 = in[0]; | 
|  | 743 | *current_cylinder = in[1]; | 
|  | 744 | TRACE_EXIT 0; | 
|  | 745 | } | 
|  | 746 |  | 
|  | 747 | /*      step to track | 
|  | 748 | */ | 
|  | 749 | int fdc_seek(int track) | 
|  | 750 | { | 
|  | 751 | __u8 out[3]; | 
|  | 752 | int st0, pcn; | 
|  | 753 | #ifdef TESTING | 
|  | 754 | unsigned int time; | 
|  | 755 | #endif | 
|  | 756 | TRACE_FUN(ft_t_any); | 
|  | 757 |  | 
|  | 758 | out[0] = FDC_SEEK; | 
|  | 759 | out[1] = ft_drive_sel; | 
|  | 760 | out[2] = track; | 
|  | 761 | #ifdef TESTING | 
|  | 762 | time = ftape_timestamp(); | 
|  | 763 | #endif | 
|  | 764 | /*  We really need this command to work ! | 
|  | 765 | */ | 
|  | 766 | ft_seek_completed = 0; | 
|  | 767 | TRACE_CATCH(fdc_command(out, 3), | 
|  | 768 | fdc_reset(); | 
|  | 769 | TRACE(ft_t_noise, "destination was: %d, resetting FDC...", | 
|  | 770 | track)); | 
|  | 771 | /*    Handle interrupts until ft_seek_completed or timeout. | 
|  | 772 | */ | 
|  | 773 | for (;;) { | 
|  | 774 | TRACE_CATCH(fdc_interrupt_wait(2 * FT_SECOND),); | 
|  | 775 | if (ft_seek_completed) { | 
|  | 776 | TRACE_CATCH(fdc_sense_interrupt_status(&st0, &pcn),); | 
|  | 777 | if ((st0 & ST0_SEEK_END) == 0) { | 
|  | 778 | TRACE_ABORT(-EIO, ft_t_err, | 
|  | 779 | "no seek-end after seek completion !??"); | 
|  | 780 | } | 
|  | 781 | break; | 
|  | 782 | } | 
|  | 783 | } | 
|  | 784 | #ifdef TESTING | 
|  | 785 | time = ftape_timediff(time, ftape_timestamp()) / abs(track - ftape_current_cylinder); | 
|  | 786 | if ((time < 900 || time > 3100) && abs(track - ftape_current_cylinder) > 5) { | 
|  | 787 | TRACE(ft_t_warn, "Wrong FDC STEP interval: %d usecs (%d)", | 
|  | 788 | time, track - ftape_current_cylinder); | 
|  | 789 | } | 
|  | 790 | #endif | 
|  | 791 | /*    Verify whether we issued the right tape command. | 
|  | 792 | */ | 
|  | 793 | /* Verify that we seek to the proper track. */ | 
|  | 794 | if (pcn != track) { | 
|  | 795 | TRACE_ABORT(-EIO, ft_t_err, "bad seek.."); | 
|  | 796 | } | 
|  | 797 | ftape_current_cylinder = track; | 
|  | 798 | TRACE_EXIT 0; | 
|  | 799 | } | 
|  | 800 |  | 
|  | 801 | static int perpend_mode; /* set if fdc is in perpendicular mode */ | 
|  | 802 |  | 
|  | 803 | static int perpend_off(void) | 
|  | 804 | { | 
|  | 805 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | 
|  | 806 | TRACE_FUN(ft_t_any); | 
|  | 807 |  | 
|  | 808 | if (perpend_mode) { | 
|  | 809 | /* Turn off perpendicular mode */ | 
|  | 810 | perpend[1] = 0x80; | 
|  | 811 | TRACE_CATCH(fdc_command(perpend, 2), | 
|  | 812 | TRACE(ft_t_err,"Perpendicular mode exit failed!")); | 
|  | 813 | perpend_mode = 0; | 
|  | 814 | } | 
|  | 815 | TRACE_EXIT 0; | 
|  | 816 | } | 
|  | 817 |  | 
|  | 818 | static int handle_perpend(int segment_id) | 
|  | 819 | { | 
|  | 820 | __u8 perpend[] = {FDC_PERPEND, 0x00}; | 
|  | 821 | TRACE_FUN(ft_t_any); | 
|  | 822 |  | 
|  | 823 | /* When writing QIC-3020 tapes, turn on perpendicular mode | 
|  | 824 | * if tape is moving in forward direction (even tracks). | 
|  | 825 | */ | 
|  | 826 | if (ft_qic_std == QIC_TAPE_QIC3020 && | 
|  | 827 | ((segment_id / ft_segments_per_track) & 1) == 0) { | 
|  | 828 | /*  FIXME: some i82077 seem to support perpendicular mode as | 
|  | 829 | *  well. | 
|  | 830 | */ | 
|  | 831 | #if 0 | 
|  | 832 | if (fdc.type < i82077AA) {} | 
|  | 833 | #else | 
|  | 834 | if (fdc.type < i82077 && ft_data_rate < 1000) { | 
|  | 835 | #endif | 
|  | 836 | /*  fdc does not support perpendicular mode: complain | 
|  | 837 | */ | 
|  | 838 | TRACE_ABORT(-EIO, ft_t_err, | 
|  | 839 | "Your FDC does not support QIC-3020."); | 
|  | 840 | } | 
|  | 841 | perpend[1] = 0x03 /* 0x83 + (0x4 << ft_drive_sel) */ ; | 
|  | 842 | TRACE_CATCH(fdc_command(perpend, 2), | 
|  | 843 | TRACE(ft_t_err,"Perpendicular mode entry failed!")); | 
|  | 844 | TRACE(ft_t_flow, "Perpendicular mode set"); | 
|  | 845 | perpend_mode = 1; | 
|  | 846 | TRACE_EXIT 0; | 
|  | 847 | } | 
|  | 848 | TRACE_EXIT perpend_off(); | 
|  | 849 | } | 
|  | 850 |  | 
|  | 851 | static inline void fdc_setup_dma(char mode, | 
|  | 852 | volatile void *addr, unsigned int count) | 
|  | 853 | { | 
|  | 854 | /* Program the DMA controller. | 
|  | 855 | */ | 
|  | 856 | disable_dma(fdc.dma); | 
|  | 857 | clear_dma_ff(fdc.dma); | 
|  | 858 | set_dma_mode(fdc.dma, mode); | 
|  | 859 | set_dma_addr(fdc.dma, virt_to_bus((void*)addr)); | 
|  | 860 | set_dma_count(fdc.dma, count); | 
|  | 861 | enable_dma(fdc.dma); | 
|  | 862 | } | 
|  | 863 |  | 
|  | 864 | /*  Setup fdc and dma for formatting the next segment | 
|  | 865 | */ | 
|  | 866 | int fdc_setup_formatting(buffer_struct * buff) | 
|  | 867 | { | 
|  | 868 | unsigned long flags; | 
|  | 869 | __u8 out[6] = { | 
|  | 870 | FDC_FORMAT, 0x00, 3, 4 * FT_SECTORS_PER_SEGMENT, 0x00, 0x6b | 
|  | 871 | }; | 
|  | 872 | TRACE_FUN(ft_t_any); | 
|  | 873 |  | 
|  | 874 | TRACE_CATCH(handle_perpend(buff->segment_id),); | 
|  | 875 | /* Program the DMA controller. | 
|  | 876 | */ | 
|  | 877 | TRACE(ft_t_fdc_dma, | 
|  | 878 | "phys. addr. = %lx", virt_to_bus((void*) buff->ptr)); | 
|  | 879 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 880 | fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4); | 
|  | 881 | /* Issue FDC command to start reading/writing. | 
|  | 882 | */ | 
|  | 883 | out[1] = ft_drive_sel; | 
|  | 884 | out[4] = buff->gap3; | 
|  | 885 | TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)), | 
|  | 886 | restore_flags(flags); fdc_mode = fdc_idle); | 
|  | 887 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 888 | TRACE_EXIT 0; | 
|  | 889 | } | 
|  | 890 |  | 
|  | 891 |  | 
|  | 892 | /*      Setup Floppy Disk Controller and DMA to read or write the next cluster | 
|  | 893 | *      of good sectors from or to the current segment. | 
|  | 894 | */ | 
|  | 895 | int fdc_setup_read_write(buffer_struct * buff, __u8 operation) | 
|  | 896 | { | 
|  | 897 | unsigned long flags; | 
|  | 898 | __u8 out[9]; | 
|  | 899 | int dma_mode; | 
|  | 900 | TRACE_FUN(ft_t_any); | 
|  | 901 |  | 
|  | 902 | switch(operation) { | 
|  | 903 | case FDC_VERIFY: | 
|  | 904 | if (fdc.type < i82077) { | 
|  | 905 | operation = FDC_READ; | 
|  | 906 | } | 
|  | 907 | case FDC_READ: | 
|  | 908 | case FDC_READ_DELETED: | 
|  | 909 | dma_mode = DMA_MODE_READ; | 
|  | 910 | TRACE(ft_t_fdc_dma, "xfer %d sectors to 0x%p", | 
|  | 911 | buff->sector_count, buff->ptr); | 
|  | 912 | TRACE_CATCH(perpend_off(),); | 
|  | 913 | break; | 
|  | 914 | case FDC_WRITE_DELETED: | 
|  | 915 | TRACE(ft_t_noise, "deleting segment %d", buff->segment_id); | 
|  | 916 | case FDC_WRITE: | 
|  | 917 | dma_mode = DMA_MODE_WRITE; | 
|  | 918 | /* When writing QIC-3020 tapes, turn on perpendicular mode | 
|  | 919 | * if tape is moving in forward direction (even tracks). | 
|  | 920 | */ | 
|  | 921 | TRACE_CATCH(handle_perpend(buff->segment_id),); | 
|  | 922 | TRACE(ft_t_fdc_dma, "xfer %d sectors from 0x%p", | 
|  | 923 | buff->sector_count, buff->ptr); | 
|  | 924 | break; | 
|  | 925 | default: | 
|  | 926 | TRACE_ABORT(-EIO, | 
|  | 927 | ft_t_bug, "bug: invalid operation parameter"); | 
|  | 928 | } | 
|  | 929 | TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr)); | 
|  | 930 | spin_lock_irqsave(&fdc_io_lock, flags); | 
|  | 931 | if (operation != FDC_VERIFY) { | 
|  | 932 | fdc_setup_dma(dma_mode, buff->ptr, | 
|  | 933 | FT_SECTOR_SIZE * buff->sector_count); | 
|  | 934 | } | 
|  | 935 | /* Issue FDC command to start reading/writing. | 
|  | 936 | */ | 
|  | 937 | out[0] = operation; | 
|  | 938 | out[1] = ft_drive_sel; | 
|  | 939 | out[2] = buff->cyl; | 
|  | 940 | out[3] = buff->head; | 
|  | 941 | out[4] = buff->sect + buff->sector_offset; | 
|  | 942 | out[5] = 3;		/* Sector size of 1K. */ | 
|  | 943 | out[6] = out[4] + buff->sector_count - 1;	/* last sector */ | 
|  | 944 | out[7] = 109;		/* Gap length. */ | 
|  | 945 | out[8] = 0xff;		/* No limit to transfer size. */ | 
|  | 946 | TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x", | 
|  | 947 | out[2], out[3], out[4], out[6] - out[4] + 1); | 
|  | 948 | spin_unlock_irqrestore(&fdc_io_lock, flags); | 
|  | 949 | TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle); | 
|  | 950 | TRACE_EXIT 0; | 
|  | 951 | } | 
|  | 952 |  | 
|  | 953 | int fdc_fifo_threshold(__u8 threshold, | 
|  | 954 | int *fifo_state, int *lock_state, int *fifo_thr) | 
|  | 955 | { | 
|  | 956 | const __u8 cmd0[] = {FDC_DUMPREGS}; | 
|  | 957 | __u8 cmd1[] = {FDC_CONFIGURE, 0, (0x0f & (threshold - 1)), 0}; | 
|  | 958 | const __u8 cmd2[] = {FDC_LOCK}; | 
|  | 959 | const __u8 cmd3[] = {FDC_UNLOCK}; | 
|  | 960 | __u8 reg[10]; | 
|  | 961 | __u8 stat; | 
|  | 962 | int i; | 
|  | 963 | int result; | 
|  | 964 | TRACE_FUN(ft_t_any); | 
|  | 965 |  | 
|  | 966 | if (CLK_48MHZ && fdc.type >= i82078) { | 
|  | 967 | cmd1[0] |= FDC_CLK48_BIT; | 
|  | 968 | } | 
|  | 969 | /*  Dump fdc internal registers for examination | 
|  | 970 | */ | 
|  | 971 | TRACE_CATCH(fdc_command(cmd0, NR_ITEMS(cmd0)), | 
|  | 972 | TRACE(ft_t_warn, "dumpreg cmd failed, fifo unchanged")); | 
|  | 973 | /*  Now read fdc internal registers from fifo | 
|  | 974 | */ | 
|  | 975 | for (i = 0; i < (int)NR_ITEMS(reg); ++i) { | 
|  | 976 | fdc_read(®[i]); | 
|  | 977 | TRACE(ft_t_fdc_dma, "Register %d = 0x%02x", i, reg[i]); | 
|  | 978 | } | 
|  | 979 | if (fifo_state && lock_state && fifo_thr) { | 
|  | 980 | *fifo_state = (reg[8] & 0x20) == 0; | 
|  | 981 | *lock_state = reg[7] & 0x80; | 
|  | 982 | *fifo_thr = 1 + (reg[8] & 0x0f); | 
|  | 983 | } | 
|  | 984 | TRACE(ft_t_noise, | 
|  | 985 | "original fifo state: %sabled, threshold %d, %slocked", | 
|  | 986 | ((reg[8] & 0x20) == 0) ? "en" : "dis", | 
|  | 987 | 1 + (reg[8] & 0x0f), (reg[7] & 0x80) ? "" : "not "); | 
|  | 988 | /*  If fdc is already locked, unlock it first ! */ | 
|  | 989 | if (reg[7] & 0x80) { | 
|  | 990 | fdc_ready_wait(100); | 
|  | 991 | TRACE_CATCH(fdc_issue_command(cmd3, NR_ITEMS(cmd3), &stat, 1), | 
|  | 992 | TRACE(ft_t_bug, "FDC unlock command failed, " | 
|  | 993 | "configuration unchanged")); | 
|  | 994 | } | 
|  | 995 | fdc_fifo_locked = 0; | 
|  | 996 | /*  Enable fifo and set threshold at xx bytes to allow a | 
|  | 997 | *  reasonably large latency and reduce number of dma bursts. | 
|  | 998 | */ | 
|  | 999 | fdc_ready_wait(100); | 
|  | 1000 | if ((result = fdc_command(cmd1, NR_ITEMS(cmd1))) < 0) { | 
|  | 1001 | TRACE(ft_t_bug, "configure cmd failed, fifo unchanged"); | 
|  | 1002 | } | 
|  | 1003 | /*  Now lock configuration so reset will not change it | 
|  | 1004 | */ | 
|  | 1005 | if(fdc_issue_command(cmd2, NR_ITEMS(cmd2), &stat, 1) < 0 || | 
|  | 1006 | stat != 0x10) { | 
|  | 1007 | TRACE_ABORT(-EIO, ft_t_bug, | 
|  | 1008 | "FDC lock command failed, stat = 0x%02x", stat); | 
|  | 1009 | } | 
|  | 1010 | fdc_fifo_locked = 1; | 
|  | 1011 | TRACE_EXIT result; | 
|  | 1012 | } | 
|  | 1013 |  | 
|  | 1014 | static int fdc_fifo_enable(void) | 
|  | 1015 | { | 
|  | 1016 | TRACE_FUN(ft_t_any); | 
|  | 1017 |  | 
|  | 1018 | if (fdc_fifo_locked) { | 
|  | 1019 | TRACE_ABORT(0, ft_t_warn, "Fifo not enabled because locked"); | 
|  | 1020 | } | 
|  | 1021 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | 
|  | 1022 | &fdc_fifo_state, | 
|  | 1023 | &fdc_lock_state, | 
|  | 1024 | &fdc_fifo_thr),); | 
|  | 1025 | TRACE_CATCH(fdc_fifo_threshold(ft_fdc_threshold /* bytes */, | 
|  | 1026 | NULL, NULL, NULL),); | 
|  | 1027 | TRACE_EXIT 0; | 
|  | 1028 | } | 
|  | 1029 |  | 
|  | 1030 | /*   Determine fd controller type | 
|  | 1031 | */ | 
|  | 1032 | static __u8 fdc_save_state[2]; | 
|  | 1033 |  | 
|  | 1034 | static int fdc_probe(void) | 
|  | 1035 | { | 
|  | 1036 | __u8 cmd[1]; | 
|  | 1037 | __u8 stat[16]; /* must be able to hold dumpregs & save results */ | 
|  | 1038 | int i; | 
|  | 1039 | TRACE_FUN(ft_t_any); | 
|  | 1040 |  | 
|  | 1041 | /*  Try to find out what kind of fd controller we have to deal with | 
|  | 1042 | *  Scheme borrowed from floppy driver: | 
|  | 1043 | *  first try if FDC_DUMPREGS command works | 
|  | 1044 | *  (this indicates that we have a 82072 or better) | 
|  | 1045 | *  then try the FDC_VERSION command (82072 doesn't support this) | 
|  | 1046 | *  then try the FDC_UNLOCK command (some older 82077's don't support this) | 
|  | 1047 | *  then try the FDC_PARTID command (82078's support this) | 
|  | 1048 | */ | 
|  | 1049 | cmd[0] = FDC_DUMPREGS; | 
|  | 1050 | if (fdc_issue_command(cmd, 1, stat, 1) != 0) { | 
|  | 1051 | TRACE_ABORT(no_fdc, ft_t_bug, "No FDC found"); | 
|  | 1052 | } | 
|  | 1053 | if (stat[0] == 0x80) { | 
|  | 1054 | /* invalid command: must be pre 82072 */ | 
|  | 1055 | TRACE_ABORT(i8272, | 
|  | 1056 | ft_t_warn, "Type 8272A/765A compatible FDC found"); | 
|  | 1057 | } | 
|  | 1058 | fdc_result(&stat[1], 9); | 
|  | 1059 | fdc_save_state[0] = stat[7]; | 
|  | 1060 | fdc_save_state[1] = stat[8]; | 
|  | 1061 | cmd[0] = FDC_VERSION; | 
|  | 1062 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | 
|  | 1063 | TRACE_ABORT(i8272, ft_t_warn, "Type 82072 FDC found"); | 
|  | 1064 | } | 
|  | 1065 | if (*stat != 0x90) { | 
|  | 1066 | TRACE_ABORT(i8272, ft_t_warn, "Unknown FDC found"); | 
|  | 1067 | } | 
|  | 1068 | cmd[0] = FDC_UNLOCK; | 
|  | 1069 | if(fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] != 0x00) { | 
|  | 1070 | TRACE_ABORT(i8272, ft_t_warn, | 
|  | 1071 | "Type pre-1991 82077 FDC found, " | 
|  | 1072 | "treating it like a 82072"); | 
|  | 1073 | } | 
|  | 1074 | if (fdc_save_state[0] & 0x80) { /* was locked */ | 
|  | 1075 | cmd[0] = FDC_LOCK; /* restore lock */ | 
|  | 1076 | (void)fdc_issue_command(cmd, 1, stat, 1); | 
|  | 1077 | TRACE(ft_t_warn, "FDC is already locked"); | 
|  | 1078 | } | 
|  | 1079 | /* Test for a i82078 FDC */ | 
|  | 1080 | cmd[0] = FDC_PARTID; | 
|  | 1081 | if (fdc_issue_command(cmd, 1, stat, 1) < 0 || stat[0] == 0x80) { | 
|  | 1082 | /* invalid command: not a i82078xx type FDC */ | 
|  | 1083 | for (i = 0; i < 4; ++i) { | 
|  | 1084 | outb_p(i, fdc.tdr); | 
|  | 1085 | if ((inb_p(fdc.tdr) & 0x03) != i) { | 
|  | 1086 | TRACE_ABORT(i82077, | 
|  | 1087 | ft_t_warn, "Type 82077 FDC found"); | 
|  | 1088 | } | 
|  | 1089 | } | 
|  | 1090 | TRACE_ABORT(i82077AA, ft_t_warn, "Type 82077AA FDC found"); | 
|  | 1091 | } | 
|  | 1092 | /* FDC_PARTID cmd succeeded */ | 
|  | 1093 | switch (stat[0] >> 5) { | 
|  | 1094 | case 0x0: | 
|  | 1095 | /* i82078SL or i82078-1.  The SL part cannot run at | 
|  | 1096 | * 2Mbps (the SL and -1 dies are identical; they are | 
|  | 1097 | * speed graded after production, according to Intel). | 
|  | 1098 | * Some SL's can be detected by doing a SAVE cmd and | 
|  | 1099 | * look at bit 7 of the first byte (the SEL3V# bit). | 
|  | 1100 | * If it is 0, the part runs off 3Volts, and hence it | 
|  | 1101 | * is a SL. | 
|  | 1102 | */ | 
|  | 1103 | cmd[0] = FDC_SAVE; | 
|  | 1104 | if(fdc_issue_command(cmd, 1, stat, 16) < 0) { | 
|  | 1105 | TRACE(ft_t_err, "FDC_SAVE failed. Dunno why"); | 
|  | 1106 | /* guess we better claim the fdc to be a i82078 */ | 
|  | 1107 | TRACE_ABORT(i82078, | 
|  | 1108 | ft_t_warn, | 
|  | 1109 | "Type i82078 FDC (i suppose) found"); | 
|  | 1110 | } | 
|  | 1111 | if ((stat[0] & FDC_SEL3V_BIT)) { | 
|  | 1112 | /* fdc running off 5Volts; Pray that it's a i82078-1 | 
|  | 1113 | */ | 
|  | 1114 | TRACE_ABORT(i82078_1, ft_t_warn, | 
|  | 1115 | "Type i82078-1 or 5Volt i82078SL FDC found"); | 
|  | 1116 | } | 
|  | 1117 | TRACE_ABORT(i82078, ft_t_warn, | 
|  | 1118 | "Type 3Volt i82078SL FDC (1Mbps) found"); | 
|  | 1119 | case 0x1: | 
|  | 1120 | case 0x2: /* S82078B  */ | 
|  | 1121 | /* The '78B  isn't '78 compatible.  Detect it as a '77AA */ | 
|  | 1122 | TRACE_ABORT(i82077AA, ft_t_warn, "Type i82077AA FDC found"); | 
|  | 1123 | case 0x3: /* NSC PC8744 core; used in several super-IO chips */ | 
|  | 1124 | TRACE_ABORT(i82077AA, | 
|  | 1125 | ft_t_warn, "Type 82077AA compatible FDC found"); | 
|  | 1126 | default: | 
|  | 1127 | TRACE(ft_t_warn, "A previously undetected FDC found"); | 
|  | 1128 | TRACE_ABORT(i82077AA, ft_t_warn, | 
|  | 1129 | "Treating it as a 82077AA. Please report partid= %d", | 
|  | 1130 | stat[0]); | 
|  | 1131 | } /* switch(stat[ 0] >> 5) */ | 
|  | 1132 | TRACE_EXIT no_fdc; | 
|  | 1133 | } | 
|  | 1134 |  | 
|  | 1135 | static int fdc_request_regions(void) | 
|  | 1136 | { | 
|  | 1137 | TRACE_FUN(ft_t_flow); | 
|  | 1138 |  | 
|  | 1139 | if (ft_mach2 || ft_probe_fc10) { | 
|  | 1140 | if (!request_region(fdc.sra, 8, "fdc (ft)")) { | 
|  | 1141 | #ifndef BROKEN_FLOPPY_DRIVER | 
|  | 1142 | TRACE_EXIT -EBUSY; | 
|  | 1143 | #else | 
|  | 1144 | TRACE(ft_t_warn, | 
|  | 1145 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | 
|  | 1146 | #endif | 
|  | 1147 | } | 
|  | 1148 | } else { | 
|  | 1149 | if (!request_region(fdc.sra, 6, "fdc (ft)")) { | 
|  | 1150 | #ifndef BROKEN_FLOPPY_DRIVER | 
|  | 1151 | TRACE_EXIT -EBUSY; | 
|  | 1152 | #else | 
|  | 1153 | TRACE(ft_t_warn, | 
|  | 1154 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra); | 
|  | 1155 | #endif | 
|  | 1156 | } | 
|  | 1157 | if (!request_region(fdc.sra + 7, 1, "fdc (ft)")) { | 
|  | 1158 | #ifndef BROKEN_FLOPPY_DRIVER | 
|  | 1159 | release_region(fdc.sra, 6); | 
|  | 1160 | TRACE_EXIT -EBUSY; | 
|  | 1161 | #else | 
|  | 1162 | TRACE(ft_t_warn, | 
|  | 1163 | "address 0x%03x occupied (by floppy driver?), using it anyway", fdc.sra + 7); | 
|  | 1164 | #endif | 
|  | 1165 | } | 
|  | 1166 | } | 
|  | 1167 | TRACE_EXIT 0; | 
|  | 1168 | } | 
|  | 1169 |  | 
|  | 1170 | void fdc_release_regions(void) | 
|  | 1171 | { | 
|  | 1172 | TRACE_FUN(ft_t_flow); | 
|  | 1173 |  | 
|  | 1174 | if (fdc.sra != 0) { | 
|  | 1175 | if (fdc.dor2 != 0) { | 
|  | 1176 | release_region(fdc.sra, 8); | 
|  | 1177 | } else { | 
|  | 1178 | release_region(fdc.sra, 6); | 
|  | 1179 | release_region(fdc.dir, 1); | 
|  | 1180 | } | 
|  | 1181 | } | 
|  | 1182 | TRACE_EXIT; | 
|  | 1183 | } | 
|  | 1184 |  | 
|  | 1185 | static int fdc_config_regs(unsigned int fdc_base, | 
|  | 1186 | unsigned int fdc_irq, | 
|  | 1187 | unsigned int fdc_dma) | 
|  | 1188 | { | 
|  | 1189 | TRACE_FUN(ft_t_flow); | 
|  | 1190 |  | 
|  | 1191 | fdc.irq = fdc_irq; | 
|  | 1192 | fdc.dma = fdc_dma; | 
|  | 1193 | fdc.sra = fdc_base; | 
|  | 1194 | fdc.srb = fdc_base + 1; | 
|  | 1195 | fdc.dor = fdc_base + 2; | 
|  | 1196 | fdc.tdr = fdc_base + 3; | 
|  | 1197 | fdc.msr = fdc.dsr = fdc_base + 4; | 
|  | 1198 | fdc.fifo = fdc_base + 5; | 
|  | 1199 | fdc.dir = fdc.ccr = fdc_base + 7; | 
|  | 1200 | fdc.dor2 = (ft_mach2 || ft_probe_fc10) ? fdc_base + 6 : 0; | 
|  | 1201 | TRACE_CATCH(fdc_request_regions(), fdc.sra = 0); | 
|  | 1202 | TRACE_EXIT 0; | 
|  | 1203 | } | 
|  | 1204 |  | 
|  | 1205 | static int fdc_config(void) | 
|  | 1206 | { | 
|  | 1207 | static int already_done; | 
|  | 1208 | TRACE_FUN(ft_t_any); | 
|  | 1209 |  | 
|  | 1210 | if (already_done) { | 
|  | 1211 | TRACE_CATCH(fdc_request_regions(),); | 
|  | 1212 | *(fdc.hook) = fdc_isr;	/* hook our handler in */ | 
|  | 1213 | TRACE_EXIT 0; | 
|  | 1214 | } | 
|  | 1215 | if (ft_probe_fc10) { | 
|  | 1216 | int fc_type; | 
|  | 1217 |  | 
|  | 1218 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, | 
|  | 1219 | ft_fdc_irq, ft_fdc_dma),); | 
|  | 1220 | fc_type = fc10_enable(); | 
|  | 1221 | if (fc_type != 0) { | 
|  | 1222 | TRACE(ft_t_warn, "FC-%c0 controller found", '0' + fc_type); | 
|  | 1223 | fdc.type = fc10; | 
|  | 1224 | fdc.hook = &do_ftape; | 
|  | 1225 | *(fdc.hook) = fdc_isr;	/* hook our handler in */ | 
|  | 1226 | already_done = 1; | 
|  | 1227 | TRACE_EXIT 0; | 
|  | 1228 | } else { | 
|  | 1229 | TRACE(ft_t_warn, "FC-10/20 controller not found"); | 
|  | 1230 | fdc_release_regions(); | 
|  | 1231 | fdc.type = no_fdc; | 
|  | 1232 | ft_probe_fc10 = 0; | 
|  | 1233 | ft_fdc_base   = 0x3f0; | 
|  | 1234 | ft_fdc_irq    = 6; | 
|  | 1235 | ft_fdc_dma    = 2; | 
|  | 1236 | } | 
|  | 1237 | } | 
|  | 1238 | TRACE(ft_t_warn, "fdc base: 0x%x, irq: %d, dma: %d", | 
|  | 1239 | ft_fdc_base, ft_fdc_irq, ft_fdc_dma); | 
|  | 1240 | TRACE_CATCH(fdc_config_regs(ft_fdc_base, ft_fdc_irq, ft_fdc_dma),); | 
|  | 1241 | fdc.hook = &do_ftape; | 
|  | 1242 | *(fdc.hook) = fdc_isr;	/* hook our handler in */ | 
|  | 1243 | already_done = 1; | 
|  | 1244 | TRACE_EXIT 0; | 
|  | 1245 | } | 
|  | 1246 |  | 
|  | 1247 | static irqreturn_t ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 
|  | 1248 | { | 
|  | 1249 | void (*handler) (void) = *fdc.hook; | 
|  | 1250 | int handled = 0; | 
|  | 1251 | TRACE_FUN(ft_t_any); | 
|  | 1252 |  | 
|  | 1253 | *fdc.hook = NULL; | 
|  | 1254 | if (handler) { | 
|  | 1255 | handled = 1; | 
|  | 1256 | handler(); | 
|  | 1257 | } else { | 
|  | 1258 | TRACE(ft_t_bug, "Unexpected ftape interrupt"); | 
|  | 1259 | } | 
|  | 1260 | TRACE_EXIT IRQ_RETVAL(handled); | 
|  | 1261 | } | 
|  | 1262 |  | 
|  | 1263 | static int fdc_grab_irq_and_dma(void) | 
|  | 1264 | { | 
|  | 1265 | TRACE_FUN(ft_t_any); | 
|  | 1266 |  | 
|  | 1267 | if (fdc.hook == &do_ftape) { | 
|  | 1268 | /*  Get fast interrupt handler. | 
|  | 1269 | */ | 
|  | 1270 | if (request_irq(fdc.irq, ftape_interrupt, | 
|  | 1271 | SA_INTERRUPT, "ft", ftape_id)) { | 
|  | 1272 | TRACE_ABORT(-EIO, ft_t_bug, | 
|  | 1273 | "Unable to grab IRQ%d for ftape driver", | 
|  | 1274 | fdc.irq); | 
|  | 1275 | } | 
|  | 1276 | if (request_dma(fdc.dma, ftape_id)) { | 
|  | 1277 | free_irq(fdc.irq, ftape_id); | 
|  | 1278 | TRACE_ABORT(-EIO, ft_t_bug, | 
|  | 1279 | "Unable to grab DMA%d for ftape driver", | 
|  | 1280 | fdc.dma); | 
|  | 1281 | } | 
|  | 1282 | } | 
|  | 1283 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | 
|  | 1284 | /* Using same dma channel or irq as standard fdc, need | 
|  | 1285 | * to disable the dma-gate on the std fdc. This | 
|  | 1286 | * couldn't be done in the floppy driver as some | 
|  | 1287 | * laptops are using the dma-gate to enter a low power | 
|  | 1288 | * or even suspended state :-( | 
|  | 1289 | */ | 
|  | 1290 | outb_p(FDC_RESET_NOT, 0x3f2); | 
|  | 1291 | TRACE(ft_t_noise, "DMA-gate on standard fdc disabled"); | 
|  | 1292 | } | 
|  | 1293 | TRACE_EXIT 0; | 
|  | 1294 | } | 
|  | 1295 |  | 
|  | 1296 | int fdc_release_irq_and_dma(void) | 
|  | 1297 | { | 
|  | 1298 | TRACE_FUN(ft_t_any); | 
|  | 1299 |  | 
|  | 1300 | if (fdc.hook == &do_ftape) { | 
|  | 1301 | disable_dma(fdc.dma);	/* just in case... */ | 
|  | 1302 | free_dma(fdc.dma); | 
|  | 1303 | free_irq(fdc.irq, ftape_id); | 
|  | 1304 | } | 
|  | 1305 | if (ft_fdc_base != 0x3f0 && (ft_fdc_dma == 2 || ft_fdc_irq == 6)) { | 
|  | 1306 | /* Using same dma channel as standard fdc, need to | 
|  | 1307 | * disable the dma-gate on the std fdc. This couldn't | 
|  | 1308 | * be done in the floppy driver as some laptops are | 
|  | 1309 | * using the dma-gate to enter a low power or even | 
|  | 1310 | * suspended state :-( | 
|  | 1311 | */ | 
|  | 1312 | outb_p(FDC_RESET_NOT | FDC_DMA_MODE, 0x3f2); | 
|  | 1313 | TRACE(ft_t_noise, "DMA-gate on standard fdc enabled again"); | 
|  | 1314 | } | 
|  | 1315 | TRACE_EXIT 0; | 
|  | 1316 | } | 
|  | 1317 |  | 
|  | 1318 | int fdc_init(void) | 
|  | 1319 | { | 
|  | 1320 | TRACE_FUN(ft_t_any); | 
|  | 1321 |  | 
|  | 1322 | /* find a FDC to use */ | 
|  | 1323 | TRACE_CATCH(fdc_config(),); | 
|  | 1324 | TRACE_CATCH(fdc_grab_irq_and_dma(), fdc_release_regions()); | 
|  | 1325 | ftape_motor = 0; | 
|  | 1326 | fdc_catch_stray_interrupts(0);	/* clear number of awainted | 
|  | 1327 | * stray interrupte | 
|  | 1328 | */ | 
|  | 1329 | fdc_catch_stray_interrupts(1);	/* one always comes (?) */ | 
|  | 1330 | TRACE(ft_t_flow, "resetting fdc"); | 
|  | 1331 | fdc_set_seek_rate(2);		/* use nominal QIC step rate */ | 
|  | 1332 | fdc_reset();			/* init fdc & clear track counters */ | 
|  | 1333 | if (fdc.type == no_fdc) {	/* no FC-10 or FC-20 found */ | 
|  | 1334 | fdc.type = fdc_probe(); | 
|  | 1335 | fdc_reset();		/* update with new knowledge */ | 
|  | 1336 | } | 
|  | 1337 | if (fdc.type == no_fdc) { | 
|  | 1338 | fdc_release_irq_and_dma(); | 
|  | 1339 | fdc_release_regions(); | 
|  | 1340 | TRACE_EXIT -ENXIO; | 
|  | 1341 | } | 
|  | 1342 | if (fdc.type >= i82077) { | 
|  | 1343 | if (fdc_fifo_enable() < 0) { | 
|  | 1344 | TRACE(ft_t_warn, "couldn't enable fdc fifo !"); | 
|  | 1345 | } else { | 
|  | 1346 | TRACE(ft_t_flow, "fdc fifo enabled and locked"); | 
|  | 1347 | } | 
|  | 1348 | } | 
|  | 1349 | TRACE_EXIT 0; | 
|  | 1350 | } |