Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/dev/block/fdd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fdc_out
  2. fdc_result
  3. fdc_off
  4. fdc_on
  5. fdc_error
  6. fdc_reset
  7. fdc_recal
  8. fdc_seek
  9. fdc_io
  10. fdc_ready
  11. fdc_timeout
  12. fdc_isr
  13. fdc_ist
  14. fdd_open
  15. fdd_close
  16. fdd_rw
  17. fdd_read
  18. fdd_write
  19. fdd_probe
  20. fdd_init

   1 /*-
   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 }

/* [<][>][^][v][top][bottom][index][help] */