OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [char/] [ftape/] [fdc-io.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/* 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)
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)
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)
105
{
106
        return fdc_wait(usecs, FDC_DATA_READY, FDC_DATA_READY);
107
}
108
 
109
static void fdc_usec_wait(int usecs)
110
{
111
        fdc_wait(usecs, 0, 1);   /* will always timeout ! */
112
}
113
 
114
int fdc_ready_out_wait(int usecs)
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)
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)
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)
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)
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)
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)
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,
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)
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 (waitqueue_active(&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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.