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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [ftape/] [lowlevel/] [fdc-io.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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