|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/dev/block/fdd.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |