Project

General

Profile

Statistics
| Branch: | Revision:

scoutos / prex-0.9.0 / bsp / drv / dev / block / fdd.c @ 03e9c04a

History | View | Annotate | Download (15.3 KB)

1 03e9c04a Brad Neuman
/*-
2
 * Copyright (c) 2005-2009, Kohsuke Ohtani
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 * 3. Neither the name of the author nor the names of any co-contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
/*
31
 * fdd.c - Floppy disk drive (Intel 82078 FDC)
32
 */
33
34
/*
35
 *  State transition table:
36
 *
37
 *    State     Interrupt Timeout   Error
38
 *    --------- --------- --------- ---------
39
 *    Off       N/A       On        N/A
40
 *    On        N/A       Reset     N/A
41
 *    Reset     Recal     Off       N/A
42
 *    Recal     Seek      Off       Off
43
 *    Seek      IO        Reset     Off
44
 *    IO        Ready     Reset     Off
45
 *    Ready     N/A       Off       N/A
46
 *
47
 */
48
49
#include <driver.h>
50
51
/* #define DEBUG_FDD 1 */
52
53
#ifdef DEBUG_FDD
54
#define DPRINTF(a)        printf a
55
#else
56
#define DPRINTF(a)
57
#endif
58
59
#define FDC_IRQ                6        /* IRQ6 */
60
#define FDC_DMA                2        /* DMA2 */
61
62
#define SECTOR_SIZE        512
63
#define TRACK_SIZE        (SECTOR_SIZE * 18)
64
#define INVALID_TRACK        -1
65
66
/* I/O ports */
67
#define FDC_DOR                0x3f2        /* digital output register */
68
#define FDC_MSR                0x3f4        /* main status register (in) */
69
#define FDC_DSR                0x3f4        /* data rate select register (out) */
70
#define FDC_DAT                0x3f5        /* data register */
71
#define FDC_DIR                0x3f7        /* digital input register (in) */
72
#define FDC_CCR                0x3f7        /* configuration control register (out) */
73
74
/* Command bytes */
75
#define CMD_SPECIFY        0x03        /* specify drive timing */
76
#define CMD_DRVSTS        0x04
77
#define CMD_WRITE        0xc5        /* sector write, multi-track */
78
#define CMD_READ        0xe6        /* sector read */
79
#define CMD_RECAL        0x07        /* recalibrate */
80
#define CMD_SENSE        0x08        /* sense interrupt status */
81
#define CMD_FORMAT        0x4d        /* format track */
82
#define CMD_SEEK        0x0f        /* seek track */
83
#define CMD_VERSION        0x10        /* FDC version */
84
85
/* Floppy Drive Geometries */
86
#define FDG_HEADS        2
87
#define FDG_TRACKS        80
88
#define FDG_SECTORS        18
89
#define FDG_GAP3FMT        0x54
90
#define FDG_GAP3RW        0x1b
91
92
/* FDC state */
93
#define FDS_OFF                0        /* motor off */
94
#define FDS_ON                1        /* motor on */
95
#define FDS_RESET        2        /* reset */
96
#define FDS_RECAL        3        /* recalibrate */
97
#define FDS_SEEK        4        /* seek */
98
#define FDS_IO                5        /* read/write */
99
#define FDS_READY        6        /* ready */
100
101
struct fdd_softc {
102
        device_t        dev;                /* device object */
103
        int                isopen;                /* number of open counts */
104
        int                track;                /* Current track for read buffer */
105
        struct irp        irp;                /* I/O request packet */
106
        dma_t                dma;                /* DMA handle */
107
        irq_t                irq;                /* interrupt handle */
108
        timer_t                tmr;                /* timer id */
109
        int                stat;                /* current state */
110
        void                *rbuf;                /* DMA buffer for read (1 track) */
111
        void                *wbuf;                /* DMA buffer for write (1 sector) */
112
        u_char                result[7];        /* result from fdc */
113
};
114
115
static void        fdc_timeout(void *);
116
117
static int        fdd_open(device_t, int);
118
static int        fdd_close(device_t);
119
static int        fdd_read(device_t, char *, size_t *, int);
120
static int        fdd_write(device_t, char *, size_t *, int);
121
static int        fdd_probe(struct driver *);
122
static int        fdd_init(struct driver *);
123
124
125
static struct devops fdd_devops = {
126
        /* open */        fdd_open,
127
        /* close */        fdd_close,
128
        /* read */        fdd_read,
129
        /* write */        fdd_write,
130
        /* ioctl */        no_ioctl,
131
        /* devctl */        no_devctl,
132
};
133
134
struct driver fdd_driver = {
135
        /* name */        "fdd",
136
        /* devsops */        &fdd_devops,
137
        /* devsz */        sizeof(struct fdd_softc),
138
        /* flags */        0,
139
        /* probe */        fdd_probe,
140
        /* init */        fdd_init,
141
        /* shutdown */        NULL,
142
};
143
144
145
/*
146
 * Send data to FDC
147
 * Return -1 on failure
148
 */
149
static int
150
fdc_out(int dat)
151
{
152
        int i;
153
154
        for (i = 0; i < 100000; i++) {
155
                if ((bus_read_8(FDC_MSR) & 0xc0) == 0x80) {
156
                        delay_usec(1);
157
                        bus_write_8(FDC_DAT, (u_char)(dat & 0xff));
158
                        delay_usec(1);
159
                        return 0;
160
                }
161
        }
162
        DPRINTF(("fdc: timeout msr=%x\n", bus_read_8(FDC_MSR)));
163
        return -1;
164
}
165
166
/* Return number of result bytes */
167
static int
168
fdc_result(struct fdd_softc *sc)
169
{
170
        int i, msr, index = 0;
171
172
        for (i = 0; i < 50000; i++) {        /* timeout=500msec */
173
                msr = bus_read_8(FDC_MSR);
174
                if ((msr & 0xd0) == 0x80) {
175
                        return index;
176
                }
177
                if ((msr & 0xd0) == 0xd0) {
178
                        if (index > 6) {
179
                                DPRINTF(("fdc: overrun\n"));
180
                                return -1;
181
                        }
182
                        sc->result[index++] = bus_read_8(FDC_DAT);
183
                }
184
                delay_usec(10);
185
        }
186
        DPRINTF(("fdc: timeout\n"));
187
        return -1;
188
}
189
190
/*
191
 * Stop motor. (No interrupt)
192
 */
193
static void
194
fdc_off(struct fdd_softc *sc)
195
{
196
        DPRINTF(("fdc: motor off\n"));
197
198
        sc->stat = FDS_OFF;
199
        timer_stop(&sc->tmr);
200
        bus_write_8(FDC_DOR, 0x0c);
201
        delay_usec(1);
202
}
203
204
/*
205
 * Start motor and wait 250msec. (No interrupt)
206
 */
207
static void
208
fdc_on(struct fdd_softc *sc)
209
{
210
        DPRINTF(("fdc: motor on\n"));
211
212
        sc->stat = FDS_ON;
213
        bus_write_8(FDC_DOR, 0x1c);
214
        delay_usec(1);
215
216
        timer_callout(&sc->tmr, 250, &fdc_timeout, sc);
217
}
218
219
static void
220
fdc_error(struct fdd_softc *sc, int error)
221
{
222
        struct irp *irp = &sc->irp;
223
224
        DPRINTF(("fdc: error=%d\n", error));
225
226
        dma_stop(sc->dma);
227
        irp->error = error;
228
        sched_wakeup(&irp->iocomp);
229
        fdc_off(sc);
230
}
231
232
/*
233
 * Reset FDC and wait an intterupt.
234
 * Timeout is 500msec.
235
 */
236
static void
237
fdc_reset(struct fdd_softc *sc)
238
{
239
        DPRINTF(("fdc: reset\n"));
240
241
        sc->stat = FDS_RESET;
242
        timer_callout(&sc->tmr, 500, &fdc_timeout, sc);
243
        bus_write_8(FDC_DOR, 0x18);        /* motor0 enable, DMA enable */
244
        delay_usec(20);                        /* wait 20 usec while reset */
245
        bus_write_8(FDC_DOR, 0x1c);        /* clear reset */
246
        delay_usec(1);
247
}
248
249
/*
250
 * Recalibrate FDC and wait an interrupt.
251
 * Timeout is 5sec.
252
 */
253
static void
254
fdc_recal(struct fdd_softc *sc)
255
{
256
        DPRINTF(("fdc: recalibrate\n"));
257
258
        sc->stat = FDS_RECAL;
259
        timer_callout(&sc->tmr, 5000, &fdc_timeout, sc);
260
        fdc_out(CMD_RECAL);
261
        fdc_out(0);                /* Drive 0 */
262
}
263
264
/*
265
 * Seek FDC and wait an interrupt.
266
 * Timeout is 4sec.
267
 */
268
static void
269
fdc_seek(struct fdd_softc *sc)
270
{
271
        struct irp *irp = &sc->irp;
272
        int head, track;
273
274
        DPRINTF(("fdc: seek\n"));
275
        sc->stat = FDS_SEEK;
276
        head = (irp->blkno % (FDG_SECTORS * FDG_HEADS)) / FDG_SECTORS;
277
        track = irp->blkno / (FDG_SECTORS * FDG_HEADS);
278
279
        timer_callout(&sc->tmr, 4000, &fdc_timeout, sc);
280
281
        fdc_out(CMD_SPECIFY);        /* specify command parameter */
282
        fdc_out(0xd1);                /* Step rate = 3msec, Head unload time = 16msec */
283
        fdc_out(0x02);                /* Head load time = 2msec, Dma on (0) */
284
285
        fdc_out(CMD_SEEK);
286
        fdc_out(head << 2);
287
        fdc_out(track);
288
}
289
290
/*
291
 * Read/write data and wait an interrupt.
292
 * Timeout is 2sec.
293
 */
294
static void
295
fdc_io(struct fdd_softc *sc)
296
{
297
        struct irp *irp = &sc->irp;
298
        int head, track, sect;
299
        u_long io_size;
300
        int read;
301
302
        DPRINTF(("fdc: read/write\n"));
303
        sc->stat = FDS_IO;
304
305
        head = (irp->blkno % (FDG_SECTORS * FDG_HEADS)) / FDG_SECTORS;
306
        track = irp->blkno / (FDG_SECTORS * FDG_HEADS);
307
        sect = irp->blkno % FDG_SECTORS + 1;
308
        io_size = irp->blksz * SECTOR_SIZE;
309
        read = (irp->cmd == IO_READ) ? 1 : 0;
310
311
        DPRINTF(("fdc: hd=%x trk=%x sec=%x size=%d read=%d\n",
312
                 head, track, sect, io_size, read));
313
314
        timer_callout(&sc->tmr, 2000, &fdc_timeout, sc);
315
316
        dma_setup(sc->dma, irp->buf, io_size, read);
317
318
        /* Send command */
319
        fdc_out(read ? CMD_READ : CMD_WRITE);
320
        fdc_out(head << 2);
321
        fdc_out(track);
322
        fdc_out(head);
323
        fdc_out(sect);
324
        fdc_out(2);                /* sector size = 512 bytes */
325
        fdc_out(FDG_SECTORS);
326
        fdc_out(FDG_GAP3RW);
327
        fdc_out(0xff);
328
}
329
330
/*
331
 * Wake up iorequester.
332
 * FDC motor is set to off after 5sec.
333
 */
334
static void
335
fdc_ready(struct fdd_softc *sc)
336
{
337
        struct irp *irp = &sc->irp;
338
339
        DPRINTF(("fdc: wakeup requester\n"));
340
341
        sc->stat = FDS_READY;
342
        sched_wakeup(&irp->iocomp);
343
        timer_callout(&sc->tmr, 5000, &fdc_timeout, sc);
344
}
345
346
/*
347
 * Timeout handler
348
 */
349
static void
350
fdc_timeout(void *arg)
351
{
352
        struct fdd_softc *sc = arg;
353
        struct irp *irp = &sc->irp;
354
355
        DPRINTF(("fdc: stat=%d\n", sc->stat));
356
357
        switch (sc->stat) {
358
        case FDS_ON:
359
                fdc_reset(sc);
360
                break;
361
        case FDS_RESET:
362
        case FDS_RECAL:
363
                DPRINTF(("fdc: reset/recal timeout\n"));
364
                fdc_error(sc, EIO);
365
                break;
366
        case FDS_SEEK:
367
        case FDS_IO:
368
                DPRINTF(("fdc: seek/io timeout retry=%d\n", irp->nr_retry));
369
                if (++irp->ntries <= 3)
370
                        fdc_reset(sc);
371
                else
372
                        fdc_error(sc, EIO);
373
                break;
374
        case FDS_READY:
375
                fdc_off(sc);
376
                break;
377
        default:
378
                panic("fdc: unknown timeout");
379
        }
380
}
381
382
/*
383
 * Interrupt service routine
384
 * Do not change the fdc_stat in isr.
385
 */
386
static int
387
fdc_isr(void *arg)
388
{
389
        struct fdd_softc *sc = arg;
390
        struct irp *irp = &sc->irp;
391
392
        DPRINTF(("fdc_stat=%d\n", sc->stat));
393
394
        timer_stop(&sc->tmr);
395
396
        switch (sc->stat) {
397
        case FDS_IO:
398
                dma_stop(sc->dma);
399
                /* Fall through */
400
        case FDS_RESET:
401
        case FDS_RECAL:
402
        case FDS_SEEK:
403
                if (irp->cmd == IO_NONE) {
404
                        DPRINTF(("fdc: invalid interrupt\n"));
405
                        timer_stop(&sc->tmr);
406
                        break;
407
                }
408
                return INT_CONTINUE;
409
        case FDS_OFF:
410
                break;
411
        default:
412
                DPRINTF(("fdc: unknown interrupt\n"));
413
                break;
414
        }
415
        return 0;
416
}
417
418
/*
419
 * Interrupt service thread
420
 * This is called when command completion.
421
 */
422
static void
423
fdc_ist(void *arg)
424
{
425
        struct fdd_softc *sc = arg;
426
        struct irp *irp = &sc->irp;
427
        int i;
428
429
        DPRINTF(("fdc_stat=%d\n", sc->stat));
430
        if (irp->cmd == IO_NONE)
431
                return;
432
433
        switch (sc->stat) {
434
        case FDS_RESET:
435
                /* clear output buffer */
436
                for (i = 0; i < 4; i++) {
437
                        fdc_out(CMD_SENSE);
438
                        fdc_result(sc);
439
                }
440
                fdc_recal(sc);
441
                break;
442
        case FDS_RECAL:
443
                fdc_out(CMD_SENSE);
444
                fdc_result(sc);
445
                if ((sc->result[0] & 0xf8) != 0x20) {
446
                        DPRINTF(("fdc: recal error\n"));
447
                        fdc_error(sc, EIO);
448
                        break;
449
                }
450
                fdc_seek(sc);
451
                break;
452
        case FDS_SEEK:
453
                fdc_out(CMD_SENSE);
454
                fdc_result(sc);
455
                if ((sc->result[0] & 0xf8) != 0x20) {
456
                        DPRINTF(("fdc: seek error\n"));
457
                        if (++irp->ntries <= 3)
458
                                fdc_reset(sc);
459
                        else
460
                                fdc_error(sc, EIO);
461
                        break;
462
                }
463
                fdc_io(sc);
464
                break;
465
        case FDS_IO:
466
                fdc_result(sc);
467
                if ((sc->result[0] & 0xd8) != 0x00) {
468
                        if (++irp->ntries <= 3)
469
                                fdc_reset(sc);
470
                        else
471
                                fdc_error(sc, EIO);
472
                        break;
473
                }
474
                DPRINTF(("fdc: i/o complete\n"));
475
                fdc_ready(sc);
476
                break;
477
        case FDS_OFF:
478
                /* Ignore */
479
                break;
480
        default:
481
                ASSERT(0);
482
        }
483
}
484
485
486
static int
487
fdd_open(device_t dev, int mode)
488
{
489
        struct fdd_softc *sc = device_private(dev);
490
491
        if (sc->isopen > 0)
492
                return EBUSY;
493
494
        sc->isopen++;
495
        sc->irp.cmd = IO_NONE;
496
        return 0;
497
}
498
499
static int
500
fdd_close(device_t dev)
501
{
502
        struct fdd_softc *sc = device_private(dev);
503
504
        if (sc->isopen != 1)
505
                return EINVAL;
506
507
        sc->isopen--;
508
        sc->irp.cmd = IO_NONE;
509
510
        fdc_off(sc);
511
        return 0;
512
}
513
514
/*
515
 * Common routine for read/write
516
 */
517
static int
518
fdd_rw(struct fdd_softc *sc, int cmd, char *buf, u_long blksz, int blkno)
519
{
520
        struct irp *irp = &sc->irp;
521
        int error;
522
523
        DPRINTF(("fdd_rw: cmd=%x buf=%x blksz=%d blkno=%x\n",
524
                 cmd, buf, blksz, blkno));
525
526
        irp->cmd = cmd;
527
        irp->ntries = 0;
528
        irp->blkno = blkno;
529
        irp->blksz = blksz;
530
        irp->buf = buf;
531
        irp->error = 0;
532
533
        sched_lock();
534
        if (sc->stat == FDS_OFF)
535
                fdc_on(sc);
536
        else
537
                fdc_seek(sc);
538
539
        if (sched_sleep(&irp->iocomp) == SLP_INTR)
540
                error = EINTR;
541
        else
542
                error = irp->error;
543
544
        sched_unlock();
545
        return error;
546
}
547
548
/*
549
 * Read
550
 *
551
 * Error:
552
 *  EINTR   ... Interrupted by signal
553
 *  EIO     ... Low level I/O error
554
 *  ENXIO   ... Write protected
555
 *  EFAULT  ... No physical memory is mapped to buffer
556
 */
557
static int
558
fdd_read(device_t dev, char *buf, size_t *nbyte, int blkno)
559
{
560
        struct fdd_softc *sc = device_private(dev);
561
        char *kbuf;
562
        int track, sect, error;
563
        u_int i, nr_sect;
564
565
        DPRINTF(("fdd_read: buf=%x nbyte=%d blkno=%x\n", buf, *nbyte, blkno));
566
567
        /* Check overrun */
568
        if (blkno > FDG_HEADS * FDG_TRACKS * FDG_SECTORS)
569
                return EIO;
570
571
        /* Translate buffer address to kernel address */
572
        if ((kbuf = kmem_map(buf, *nbyte)) == NULL)
573
                return EFAULT;
574
575
        nr_sect = *nbyte / SECTOR_SIZE;
576
        error = 0;
577
        for (i = 0; i < nr_sect; i++) {
578
                /* Translate the logical sector# to logical track#/sector#. */
579
                track = blkno / FDG_SECTORS;
580
                sect = blkno % FDG_SECTORS;
581
582
                /*
583
                 * If target sector does not exist in buffer,
584
                 * read 1 track (18 sectors) at once.
585
                 */
586
                if (track != sc->track) {
587
                        error = fdd_rw(sc, IO_READ, sc->rbuf, FDG_SECTORS,
588
                                       track * FDG_SECTORS);
589
                        if (error != 0) {
590
                                sc->track = INVALID_TRACK;
591
                                break;
592
                        }
593
                        sc->track = track;
594
                }
595
                memcpy(kbuf, (char *)sc->rbuf + sect * SECTOR_SIZE,
596
                       SECTOR_SIZE);
597
                blkno++;
598
                kbuf += SECTOR_SIZE;
599
        }
600
        *nbyte = i * SECTOR_SIZE;
601
        return error;
602
}
603
604
/*
605
 * Write
606
 *
607
 * Error:
608
 *  EINTR   ... Interrupted by signal
609
 *  EIO     ... Low level I/O error
610
 *  ENXIO   ... Write protected
611
 *  EFAULT  ... No physical memory is mapped to buffer
612
 */
613
static int
614
fdd_write(device_t dev, char *buf, size_t *nbyte, int blkno)
615
{
616
        struct fdd_softc *sc = device_private(dev);
617
        char *kbuf, *wbuf;
618
        int track, sect, error;
619
        u_int i, nr_sect;
620
621
        DPRINTF(("fdd_write: buf=%x nbyte=%d blkno=%x\n", buf, *nbyte, blkno));
622
623
        /* Check overrun */
624
        if (blkno > FDG_HEADS * FDG_TRACKS * FDG_SECTORS)
625
                return EIO;
626
627
        /* Translate buffer address to kernel address */
628
        if ((kbuf = kmem_map(buf, *nbyte)) == NULL)
629
                return EFAULT;
630
631
        nr_sect = *nbyte / SECTOR_SIZE;
632
        error = 0;
633
        for (i = 0; i < nr_sect; i++) {
634
                /* Translate the logical sector# to track#/sector#. */
635
                track = blkno / FDG_SECTORS;
636
                sect = blkno % FDG_SECTORS;
637
638
                /*
639
                 * If target sector exists in read buffer, use it as
640
                 * write buffer to keep the cache cohrency.
641
                 */
642
                if (track == sc->track)
643
                        wbuf = (char *)sc->rbuf + sect * SECTOR_SIZE;
644
                else
645
                        wbuf = sc->wbuf;
646
647
                memcpy(wbuf, kbuf, SECTOR_SIZE);
648
                error = fdd_rw(sc, IO_WRITE, wbuf, 1, blkno);
649
                if (error != 0) {
650
                        sc->track = INVALID_TRACK;
651
                        break;
652
                }
653
                blkno++;
654
                kbuf += SECTOR_SIZE;
655
        }
656
        *nbyte = i * SECTOR_SIZE;
657
658
        DPRINTF(("fdd_write: error=%d\n", error));
659
        return error;
660
}
661
662
static int
663
fdd_probe(struct driver *self)
664
{
665
666
        if (bus_read_8(FDC_MSR) == 0xff) {
667
                printf("Floppy drive not found!\n");
668
                return ENXIO;
669
        }
670
        return 0;
671
}
672
673
static int
674
fdd_init(struct driver *self)
675
{
676
        struct fdd_softc *sc;
677
        struct irp *irp;
678
        device_t dev;
679
        char *buf;
680
        int i;
681
682
        dev = device_create(self, "fd0", D_BLK|D_PROT);
683
        sc = device_private(dev);
684
        sc->dev = dev;
685
        sc->isopen = 0;
686
687
        /* Initialize I/O request packet */
688
        irp = &sc->irp;
689
        irp->cmd = IO_NONE;
690
        event_init(&irp->iocomp, "fdd i/o");
691
692
        /*
693
         * Allocate physical pages for DMA buffer.
694
         * Buffer: 1 track for read, 1 sector for write.
695
         */
696
        buf = dma_alloc(TRACK_SIZE + SECTOR_SIZE);
697
        ASSERT(buf != NULL);
698
        sc->rbuf = buf;
699
        sc->wbuf = buf + TRACK_SIZE;
700
        sc->dma = dma_attach(FDC_DMA);
701
702
        /*
703
         * Attach IRQ.
704
         */
705
        sc->irq = irq_attach(FDC_IRQ, IPL_BLOCK, 0, fdc_isr, fdc_ist, sc);
706
707
        sc->stat = FDS_OFF;
708
        sc->track = INVALID_TRACK;
709
710
        /* Reset FDC */
711
        bus_write_8(FDC_DOR, 0x08);
712
        delay_usec(20);
713
        bus_write_8(FDC_DOR, 0x0C);
714
        delay_usec(1);
715
716
        /* Data rate 500k bps */
717
        bus_write_8(FDC_CCR, 0x00);
718
719
        /* Clear output buffer */
720
        for (i = 0; i < 4; i++) {
721
                fdc_out(CMD_SENSE);
722
                fdc_result(sc);
723
        }
724
        return 0;
725
}